From 7c3dee8e71912cefbb193fd6727794185d0503a8 Mon Sep 17 00:00:00 2001 From: Daniil Skrynnik Date: Thu, 21 Dec 2023 10:01:55 +0000 Subject: [PATCH 001/151] ADCM-5134: tests for hosts in Config-Groups after change HC map --- python/api_v2/tests/test_group_config.py | 34 ++++- python/api_v2/tests/test_mapping.py | 163 ++++++++++++++++++++++- 2 files changed, 195 insertions(+), 2 deletions(-) diff --git a/python/api_v2/tests/test_group_config.py b/python/api_v2/tests/test_group_config.py index b4208a2a06..7613da2254 100644 --- a/python/api_v2/tests/test_group_config.py +++ b/python/api_v2/tests/test_group_config.py @@ -56,6 +56,9 @@ def setUp(self) -> None: bundle=self.provider_bundle, provider=self.provider, fqdn="host_for_service" ) self.add_host_to_cluster(cluster=self.cluster_1, host=self.host_for_service) + self.host_in_cluster = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_in_cluster", cluster=self.cluster_1 + ) self.component_1 = ServiceComponent.objects.get( cluster=self.cluster_1, service=self.service_1, prototype__name="component_1" @@ -403,6 +406,33 @@ def test_add_host_success(self): self.assertEqual(response.status_code, HTTP_201_CREATED) self.assertDictEqual(response.json(), {"id": 3, "name": "host_for_service"}) + def test_add_not_mapped_host_fail(self): + initial_hosts_count = self.service_1_group_config.hosts.count() + + response = self.client.post( + path=reverse( + viewname="v2:service-group-config-hosts-list", + kwargs={ + "cluster_pk": self.cluster_1.pk, + "service_pk": self.service_1.pk, + "group_config_pk": self.service_1_group_config.pk, + }, + ), + data={"hostId": self.host_in_cluster.pk}, + ) + + self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) + self.assertDictEqual( + response.json(), + { + "code": "GROUP_CONFIG_HOST_ERROR", + "level": "error", + "desc": "host is not available for this object, " + "or host already is a member of another group of this object", + }, + ) + self.assertEqual(self.service_1_group_config.hosts.count(), initial_hosts_count) + def test_delete_host_success(self): response = self.client.delete( path=reverse( @@ -587,7 +617,9 @@ def test_add_host_success(self): ) self.assertEqual(response.status_code, HTTP_201_CREATED) - self.assertDictEqual(response.json(), {"id": 4, "name": "host_for_component"}) + self.assertDictEqual( + d1=response.json(), d2={"id": self.host_for_component.pk, "name": self.host_for_component.name} + ) def test_list_host_candidates_success(self): response = self.client.get( diff --git a/python/api_v2/tests/test_mapping.py b/python/api_v2/tests/test_mapping.py index deb889a660..90ba60c3dd 100644 --- a/python/api_v2/tests/test_mapping.py +++ b/python/api_v2/tests/test_mapping.py @@ -14,7 +14,15 @@ from api_v2.cluster.utils import get_requires from api_v2.tests.base import BaseAPITestCase -from cm.models import Host, HostComponent, MaintenanceMode, ServiceComponent +from cm.models import ( + Cluster, + ClusterObject, + GroupConfig, + Host, + HostComponent, + MaintenanceMode, + ServiceComponent, +) from django.urls import reverse from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_409_CONFLICT @@ -1103,3 +1111,156 @@ def test_host_in_mm_fail(self): }, ) self.assertEqual(HostComponent.objects.count(), 0) + + +class GroupConfigRelatedTests(BaseAPITestCase): + def setUp(self) -> None: + super().setUp() + + self.add_services_to_cluster(service_names=["service_1"], cluster=self.cluster_1) + + self.host_1 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_1", cluster=self.cluster_1 + ) + self.host_2 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster_1 + ) + + self.service_1 = ClusterObject.objects.get(prototype__name="service_1", cluster=self.cluster_1) + self.component_1_from_s1 = ServiceComponent.objects.get(prototype__name="component_1", service=self.service_1) + self.component_2_from_s1 = ServiceComponent.objects.get(prototype__name="component_2", service=self.service_1) + + def _prepare_config_group_via_api( + self, obj: Cluster | ClusterObject | ServiceComponent, hosts: list[Host], name: str, description: str = "" + ) -> GroupConfig: + match type(obj).__name__: + case ServiceComponent.__name__: + viewname_create = "v2:component-group-config-list" + viewname_add_host = "v2:component-group-config-hosts-list" + kwargs = {"cluster_pk": obj.cluster.pk, "service_pk": obj.service.pk, "component_pk": obj.pk} + case ClusterObject.__name__: + viewname_create = "v2:service-group-config-list" + viewname_add_host = "v2:service-group-config-hosts-list" + kwargs = { + "cluster_pk": obj.cluster.pk, + "service_pk": obj.pk, + } + case Cluster.__name__: + viewname_create = "v2:cluster-group-config-list" + viewname_add_host = "v2:cluster-group-config-hosts-list" + kwargs = { + "cluster_pk": obj.pk, + } + case _: + raise NotImplemented(str(obj)) + + response = self.client.post( + path=reverse(viewname=viewname_create, kwargs=kwargs), + data={"name": name, "description": description}, + ) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config = GroupConfig.objects.get(pk=response.json()["id"]) + kwargs.update({"group_config_pk": group_config.pk}) + + for host in hosts: + response = self.client.post( + path=reverse(viewname=viewname_add_host, kwargs=kwargs), + data={"hostId": host.pk}, + ) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config.refresh_from_db() + self.assertEqual(group_config.hosts.count(), len(hosts)) + + return group_config + + def test_host_removed_from_component_group_config_on_mapping_change(self): + mapping_url = reverse(viewname="v2:cluster-mapping", kwargs={"pk": self.cluster_1.pk}) + mapping_data = [{"hostId": self.host_1.pk, "componentId": self.component_1_from_s1.pk}] + + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config = self._prepare_config_group_via_api( + obj=self.component_1_from_s1, hosts=[self.host_1], name="component config group" + ) + + mapping_data[0].update({"componentId": self.component_2_from_s1.pk}) + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config.refresh_from_db() + self.assertEqual(group_config.hosts.count(), 0) + + def test_host_not_removed_from_component_group_config_on_mapping_remain(self): + mapping_url = reverse(viewname="v2:cluster-mapping", kwargs={"pk": self.cluster_1.pk}) + mapping_data = [{"hostId": self.host_1.pk, "componentId": self.component_1_from_s1.pk}] + + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config = self._prepare_config_group_via_api( + obj=self.component_1_from_s1, hosts=[self.host_1], name="component config group" + ) + + mapping_data.append({"hostId": self.host_2.pk, "componentId": self.component_2_from_s1.pk}) + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config.refresh_from_db() + self.assertSetEqual(set(group_config.hosts.values_list("pk", flat=True)), {self.host_1.pk}) + + def test_host_removed_from_service_group_config_on_mapping_change(self): + mapping_url = reverse(viewname="v2:cluster-mapping", kwargs={"pk": self.cluster_1.pk}) + mapping_data = [{"hostId": self.host_1.pk, "componentId": self.component_1_from_s1.pk}] + + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config = self._prepare_config_group_via_api( + obj=self.service_1, hosts=[self.host_1], name="service config group" + ) + + mapping_data[0].update({"componentId": self.component_2_from_s1.pk}) + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config.refresh_from_db() + self.assertEqual(group_config.hosts.count(), 0) + + def test_host_not_removed_from_service_group_config_on_mapping_remain(self): + mapping_url = reverse(viewname="v2:cluster-mapping", kwargs={"pk": self.cluster_1.pk}) + mapping_data = [{"hostId": self.host_1.pk, "componentId": self.component_1_from_s1.pk}] + + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config = self._prepare_config_group_via_api( + obj=self.service_1, hosts=[self.host_1], name="service config group" + ) + + mapping_data.insert(0, {"hostId": self.host_2.pk, "componentId": self.component_2_from_s1.pk}) + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config.refresh_from_db() + self.assertSetEqual(set(group_config.hosts.values_list("pk", flat=True)), {self.host_1.pk}) + + def test_host_not_removed_from_cluster_group_config_on_mapping_change(self): + mapping_url = reverse(viewname="v2:cluster-mapping", kwargs={"pk": self.cluster_1.pk}) + mapping_data = [{"hostId": self.host_1.pk, "componentId": self.component_1_from_s1.pk}] + + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config = self._prepare_config_group_via_api( + obj=self.cluster_1, hosts=[self.host_1], name="cluster config group" + ) + + mapping_data[0].update({"componentId": self.component_2_from_s1.pk}) + response: Response = self.client.post(path=mapping_url, data=mapping_data) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + group_config.refresh_from_db() + self.assertSetEqual(set(group_config.hosts.values_list("pk", flat=True)), {self.host_1.pk}) From c10523fbc183ea5b00b71ccf5f4ba6319e8dfe3e Mon Sep 17 00:00:00 2001 From: astarovo Date: Mon, 25 Dec 2023 07:07:59 +0300 Subject: [PATCH 002/151] ADCM-5145: Fix response code for add host to Config-Group --- python/api_v2/tests/test_group_config.py | 5 +++-- python/cm/errors.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/python/api_v2/tests/test_group_config.py b/python/api_v2/tests/test_group_config.py index 7613da2254..7c0778d27f 100644 --- a/python/api_v2/tests/test_group_config.py +++ b/python/api_v2/tests/test_group_config.py @@ -20,6 +20,7 @@ HTTP_204_NO_CONTENT, HTTP_400_BAD_REQUEST, HTTP_404_NOT_FOUND, + HTTP_409_CONFLICT, ) @@ -153,7 +154,7 @@ def test_add_host_from_another_group_config_fail(self): data={"hostId": self.host.pk}, ) - self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) + self.assertEqual(response.status_code, HTTP_409_CONFLICT) self.assertDictEqual( response.json(), { @@ -421,7 +422,7 @@ def test_add_not_mapped_host_fail(self): data={"hostId": self.host_in_cluster.pk}, ) - self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) + self.assertEqual(response.status_code, HTTP_409_CONFLICT) self.assertDictEqual( response.json(), { diff --git a/python/cm/errors.py b/python/cm/errors.py index 344acf1ff9..5d931c1598 100644 --- a/python/cm/errors.py +++ b/python/cm/errors.py @@ -144,7 +144,7 @@ "ISSUE_INTEGRITY_ERROR": ("Issue object integrity error", HTTP_409_CONFLICT, ERR), "GROUP_CONFIG_HOST_ERROR": ( "host is not available for this object, or host already is a member of another group of this object", - HTTP_400_BAD_REQUEST, + HTTP_409_CONFLICT, ), "GROUP_CONFIG_HOST_EXISTS": ( "the host is already a member of this group ", From 48c3d2969a12bfb076fa302ee2abef9b0875efdf Mon Sep 17 00:00:00 2001 From: Igor Kuzmin Date: Wed, 27 Dec 2023 09:53:09 +0000 Subject: [PATCH 003/151] feature/ADCM-5001 validate mapping tests Task: https://tracker.yandex.ru/ADCM-5001 --- adcm-web/app/src/App.test.tsx | 11 - .../LicenseAcceptPanel.types.ts | 2 +- .../BundleOverviewLicense.tsx | 2 +- .../ClusterMapping/ClusterMapping.types.ts | 10 +- .../ClusterMapping.utils.test.ts | 476 ++++++++++++++---- .../ClusterMapping/ClusterMapping.utils.ts | 20 +- .../useRequiredServicesDialog.ts | 4 +- .../ClusterMapping/useClusterMapping.ts | 7 +- adcm-web/app/src/models/adcm/license.ts | 2 +- adcm-web/app/src/models/adcm/service.ts | 2 +- .../adcm/cluster/mapping/mappingSlice.ts | 1 + 11 files changed, 402 insertions(+), 135 deletions(-) delete mode 100644 adcm-web/app/src/App.test.tsx diff --git a/adcm-web/app/src/App.test.tsx b/adcm-web/app/src/App.test.tsx deleted file mode 100644 index 882fea19af..0000000000 --- a/adcm-web/app/src/App.test.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/Init repo/i); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - expect(linkElement).toBeInTheDocument(); -}); diff --git a/adcm-web/app/src/components/common/Dialog/LicenseAcceptanceDialog/LicenseAcceptPanel/LicenseAcceptPanel.types.ts b/adcm-web/app/src/components/common/Dialog/LicenseAcceptanceDialog/LicenseAcceptPanel/LicenseAcceptPanel.types.ts index 48f292ff96..5dd9ed88e0 100644 --- a/adcm-web/app/src/components/common/Dialog/LicenseAcceptanceDialog/LicenseAcceptPanel/LicenseAcceptPanel.types.ts +++ b/adcm-web/app/src/components/common/Dialog/LicenseAcceptanceDialog/LicenseAcceptPanel/LicenseAcceptPanel.types.ts @@ -5,7 +5,7 @@ export interface LicensePanel { id: number; title: string; licenseStatus: AdcmLicenseStatus; - licenseText?: string; + licenseText: string | null; } export interface LicenseAcceptanceDialogProps { diff --git a/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewLicenceContent/BundleOverviewLicense/BundleOverviewLicense.tsx b/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewLicenceContent/BundleOverviewLicense/BundleOverviewLicense.tsx index 9473313583..34980755c5 100644 --- a/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewLicenceContent/BundleOverviewLicense/BundleOverviewLicense.tsx +++ b/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewLicenceContent/BundleOverviewLicense/BundleOverviewLicense.tsx @@ -2,7 +2,7 @@ import React from 'react'; import s from './BundleOverviewLicense.module.scss'; interface BundleOverviewLicense { - licenseText?: string; + licenseText?: string | null; } const BundleOverviewLicense = ({ licenseText }: BundleOverviewLicense) => { diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.types.ts b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.types.ts index ccf80ce035..dfe3837e62 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.types.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.types.ts @@ -12,10 +12,12 @@ export type ValidationResult = ValidationError | ValidationSuccess; export type HostId = AdcmHostShortView['id']; export type ComponentId = AdcmMappingComponent['id']; export type ServiceId = AdcmMappingComponentService['id']; +export type ServicePrototypeId = AdcmServicePrototype['id']; export type HostsDictionary = Record; export type ComponentHostsDictionary = Record; export type ComponentsDictionary = Record; +export type ServicesDictionary = Record; export type HostMappingFilter = { componentDisplayName: string; @@ -61,12 +63,12 @@ export type ComponentValidateResult = { }; export type ValidateCache = { - componentsCache: Map; - servicesCache: Map; + componentsCache: Map; + servicesCache: Map; }; export type ValidateRelatedData = { - servicesMappingDictionary: Record; - notAddedServicesDictionary: Record; + servicesMappingDictionary: Record; + notAddedServicesDictionary: ServicesDictionary; allHostsCount: number; }; diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.test.ts b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.test.ts index 4bd71289bb..ed817a0990 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.test.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.test.ts @@ -1,134 +1,248 @@ -import { AdcmHostShortView, AdcmMappingComponent, AdcmMaintenanceMode, AdcmMapping } from '@models/adcm'; -import { HostMapping, ServiceMapping } from './ClusterMapping.types'; -import { getComponentsMapping, getHostsMapping, getServicesMapping, mapHostsToComponent } from './ClusterMapping.utils'; +/* eslint-disable spellcheck/spell-checker */ +import { + AdcmMappingComponent, + AdcmMaintenanceMode, + AdcmMapping, + AdcmLicenseStatus, + AdcmPrototypeType, +} from '@models/adcm'; +import { HostMapping, ServiceMapping, ValidateRelatedData } from './ClusterMapping.types'; +import { + getComponentsMapping, + getHostsMapping, + getServicesMapping, + mapHostsToComponent, + getConstraintsLimit, + validate, +} from './ClusterMapping.utils'; import { arrayToHash } from '@utils/arrayUtils'; import { validateConstraints } from './ClusterMapping.utils'; -const emptyMapping: AdcmMapping[] = []; - -const mapping: AdcmMapping[] = [ - { hostId: 1, componentId: 1 }, - { hostId: 1, componentId: 2 }, - { hostId: 3, componentId: 3 }, -]; - -const services = [ - { +const servicesDictionaryByName = { + HBase: { id: 1, - name: 'service 1', - displayName: 'Service 1', - state: 'create', + name: 'hbase', + displayName: 'HBase', + state: 'created', prototype: { - id: 1, - name: 'service 1', - displayName: 'Service 1', - version: '0.1', + id: 6, + name: 'hbase', + displayName: 'HBase', + version: '2.2.7', }, }, - { + Zookeeper: { id: 2, - name: 'service 2', - displayName: 'Service 2', - state: 'create', + name: 'zookeeper', + displayName: 'Zookeeper', + state: 'created', prototype: { - id: 2, - name: 'service 2', - displayName: 'Service 2', - version: '0.2', + id: 19, + name: 'zookeeper', + displayName: 'Zookeeper', + version: '3.5.10', }, }, -]; +}; -const hosts: AdcmHostShortView[] = [ - { +const candidateServicesDictionaryByName = { + HDFS: { + id: 7, + name: 'hdfs', + displayName: 'HDFS', + version: '3.1.2', + isRequired: false, + dependOn: null, + type: 'service' as AdcmPrototypeType.Service, + license: { + status: 'absent' as AdcmLicenseStatus, + text: null, + }, + }, +}; + +const hostsDictionaryByName = { + host1: { id: 1, - name: 'h1', + name: 'host 1', isMaintenanceModeAvailable: false, maintenanceMode: AdcmMaintenanceMode.Off, }, - { + host2: { id: 2, - name: 'h2', + name: 'host 2', isMaintenanceModeAvailable: false, maintenanceMode: AdcmMaintenanceMode.Off, }, - { + host3: { id: 3, - name: 'h3', + name: 'host 3', isMaintenanceModeAvailable: false, maintenanceMode: AdcmMaintenanceMode.Off, }, -]; +}; -const components: AdcmMappingComponent[] = [ - { +const hosts = [hostsDictionaryByName.host1, hostsDictionaryByName.host2, hostsDictionaryByName.host3]; + +const componentsDictionaryByName = { + hBaseClient: { id: 1, - name: 'component 1', - displayName: 'Component 1', - isMaintenanceModeAvailable: false, - maintenanceMode: AdcmMaintenanceMode.Off, - constraints: [0, 1], - dependOn: null, - service: services[0], + name: 'client', + displayName: 'HBase Client', + isMaintenanceModeAvailable: true, + maintenanceMode: 'off' as AdcmMaintenanceMode, + constraints: [0, '+'], prototype: { - id: 1, - name: 'component 1', - displayName: 'Component 1', - version: '0.11', + id: 32, + name: 'client', + displayName: 'HBase Client', + version: '2.2.7', }, + dependOn: [ + { + servicePrototype: { + id: 19, + name: 'zookeeper', + displayName: 'Zookeeper', + version: '3.5.10', + license: { + status: 'absent' as AdcmLicenseStatus, + text: null, + }, + componentPrototypes: [ + { + id: 73, + name: 'SERVER', + displayName: 'Zookeeper Server', + version: '3.5.10', + }, + ], + }, + }, + { + servicePrototype: { + id: 7, + name: 'hdfs', + displayName: 'HDFS', + version: '3.1.2', + license: { + status: 'absent' as AdcmLicenseStatus, + text: null, + }, + componentPrototypes: [ + { + id: 39, + name: 'namenode', + displayName: 'HDFS NameNode', + version: '3.1.2', + }, + ], + }, + }, + ], + service: servicesDictionaryByName.HBase, }, - { + hBaseMaster: { id: 2, - name: 'component 2', - displayName: 'Component 2', - isMaintenanceModeAvailable: false, - maintenanceMode: AdcmMaintenanceMode.Off, - constraints: [0, 1], - dependOn: null, - service: services[0], + name: 'master', + displayName: 'HBase Master Server', + isMaintenanceModeAvailable: true, + maintenanceMode: 'off' as AdcmMaintenanceMode, + constraints: [1, '+'], prototype: { - id: 2, - name: 'component 2', - displayName: 'Component 2', - version: '0.11', + id: 33, + name: 'master', + displayName: 'HBase Master Server', + version: '2.2.7', }, + dependOn: [ + { + servicePrototype: { + id: 19, + name: 'zookeeper', + displayName: 'Zookeeper', + version: '3.5.10', + license: { + status: 'absent' as AdcmLicenseStatus, + text: null, + }, + componentPrototypes: [ + { + id: 73, + name: 'SERVER', + displayName: 'Zookeeper Server', + version: '3.5.10', + }, + ], + }, + }, + { + servicePrototype: { + id: 7, + name: 'hdfs', + displayName: 'HDFS', + version: '3.1.2', + license: { + status: 'absent' as AdcmLicenseStatus, + text: null, + }, + componentPrototypes: [ + { + id: 39, + name: 'namenode', + displayName: 'HDFS NameNode', + version: '3.1.2', + }, + ], + }, + }, + ], + service: servicesDictionaryByName.HBase, }, - { - id: 3, - name: 'service 3', - displayName: 'Service 3', - isMaintenanceModeAvailable: false, - maintenanceMode: AdcmMaintenanceMode.Off, - constraints: [0, 1], - dependOn: null, - service: services[1], + zookeeperServer: { + id: 7, + name: 'SERVER', + displayName: 'Zookeeper Server', + isMaintenanceModeAvailable: true, + maintenanceMode: 'off' as AdcmMaintenanceMode, + constraints: ['odd'], prototype: { - id: 3, - name: 'component 3', - displayName: 'Component 3', - version: '0.11', + id: 73, + name: 'SERVER', + displayName: 'Zookeeper Server', + version: '3.5.10', }, + dependOn: null, + service: servicesDictionaryByName.Zookeeper, }, +}; + +const components: AdcmMappingComponent[] = [ + componentsDictionaryByName.hBaseClient, + componentsDictionaryByName.hBaseMaster, + componentsDictionaryByName.zookeeperServer, ]; +const emptyMapping: AdcmMapping[] = []; const componentsDictionary = arrayToHash(components, (c) => c.id); const hostsDictionary = arrayToHash(hosts, (h) => h.id); describe('Cluster mapping utils', () => { test('test getHostsMapping empty mapping', () => { - const hostsMapping = getHostsMapping(emptyMapping, hosts, componentsDictionary); + const mapping: AdcmMapping[] = []; + const hostsMapping = getHostsMapping(mapping, hosts, componentsDictionary); const expected: HostMapping[] = [ { - host: hosts[0], + host: hostsDictionaryByName.host1, components: [], }, { - host: hosts[1], + host: hostsDictionaryByName.host2, components: [], }, { - host: hosts[2], + host: hostsDictionaryByName.host3, components: [], }, ]; @@ -137,20 +251,26 @@ describe('Cluster mapping utils', () => { }); test('test getHostsMapping', () => { + const mapping: AdcmMapping[] = [ + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseClient.id }, + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseMaster.id }, + { hostId: hostsDictionaryByName.host3.id, componentId: componentsDictionaryByName.zookeeperServer.id }, + ]; + const hostsMapping = getHostsMapping(mapping, hosts, componentsDictionary); const expected: HostMapping[] = [ { - host: hosts[0], - components: [components[0], components[1]], + host: hostsDictionaryByName.host1, + components: [componentsDictionaryByName.hBaseClient, componentsDictionaryByName.hBaseMaster], }, { - host: hosts[1], + host: hostsDictionaryByName.host2, components: [], }, { - host: hosts[2], - components: [components[2]], + host: hostsDictionaryByName.host3, + components: [componentsDictionaryByName.zookeeperServer], }, ]; @@ -163,23 +283,23 @@ describe('Cluster mapping utils', () => { const expected: ServiceMapping[] = [ { - service: services[0], + service: servicesDictionaryByName.HBase, componentsMapping: [ { - component: components[0], + component: componentsDictionaryByName.hBaseClient, hosts: [], }, { - component: components[1], + component: componentsDictionaryByName.hBaseMaster, hosts: [], }, ], }, { - service: services[1], + service: servicesDictionaryByName.Zookeeper, componentsMapping: [ { - component: components[2], + component: componentsDictionaryByName.zookeeperServer, hosts: [], }, ], @@ -190,29 +310,35 @@ describe('Cluster mapping utils', () => { }); test('test getServicesMapping mapping', () => { + const mapping: AdcmMapping[] = [ + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseClient.id }, + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseMaster.id }, + { hostId: hostsDictionaryByName.host3.id, componentId: componentsDictionaryByName.zookeeperServer.id }, + ]; + const componentsMapping = getComponentsMapping(mapping, components, hostsDictionary); const servicesMapping = getServicesMapping(componentsMapping); const expected: ServiceMapping[] = [ { - service: services[0], + service: servicesDictionaryByName.HBase, componentsMapping: [ { - component: components[0], - hosts: [hosts[0]], + component: componentsDictionaryByName.hBaseClient, + hosts: [hostsDictionaryByName.host1], }, { - component: components[1], - hosts: [hosts[0]], + component: componentsDictionaryByName.hBaseMaster, + hosts: [hostsDictionaryByName.host1], }, ], }, { - service: services[1], + service: servicesDictionaryByName.Zookeeper, componentsMapping: [ { - component: components[2], - hosts: [hosts[2]], + component: componentsDictionaryByName.zookeeperServer, + hosts: [hostsDictionaryByName.host3], }, ], }, @@ -222,14 +348,26 @@ describe('Cluster mapping utils', () => { }); test('test mapHostsToComponent', () => { + const mapping: AdcmMapping[] = [ + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseClient.id }, + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseMaster.id }, + { hostId: hostsDictionaryByName.host3.id, componentId: componentsDictionaryByName.zookeeperServer.id }, + ]; + const componentsMapping = getComponentsMapping(mapping, components, hostsDictionary); const servicesMapping = getServicesMapping(componentsMapping); - const newMapping = mapHostsToComponent(servicesMapping, [hosts[1]], components[0]); + + // moving hbaseMaster from host1 to host2 + const newMapping = mapHostsToComponent( + servicesMapping, + [hostsDictionaryByName.host2], + componentsDictionaryByName.hBaseMaster, + ); const expected: AdcmMapping[] = [ - { hostId: 1, componentId: 2 }, - { hostId: 2, componentId: 1 }, - { hostId: 3, componentId: 3 }, + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseClient.id }, + { hostId: hostsDictionaryByName.host2.id, componentId: componentsDictionaryByName.hBaseMaster.id }, + { hostId: hostsDictionaryByName.host3.id, componentId: componentsDictionaryByName.zookeeperServer.id }, ]; expect(newMapping).toEqual(expect.arrayContaining(expected)); @@ -286,4 +424,140 @@ describe('Cluster mapping utils', () => { errors: ['1 or more components should be installed. Total amount should be odd.'], }); }); + + test('test getConstraintsLimit', () => { + expect(getConstraintsLimit(['odd'])).toBe(1); + expect(getConstraintsLimit([1, 22])).toBe(22); + expect(getConstraintsLimit([42])).toBe(42); + expect(getConstraintsLimit([42, '+'])).toBe(42); + }); + + test('test validate constraints', () => { + const mapping: AdcmMapping[] = [ + { hostId: hostsDictionaryByName.host3.id, componentId: componentsDictionaryByName.zookeeperServer.id }, + ]; + + const componentMapping = getComponentsMapping(mapping, components, hostsDictionary); + const serviceMapping = getServicesMapping(componentMapping); + const servicesMappingDictionary = arrayToHash(serviceMapping, (sm) => sm.service.prototype.id); + + const relatedData: ValidateRelatedData = { + allHostsCount: hosts.length, + servicesMappingDictionary, + notAddedServicesDictionary: {}, + }; + + const validationResult = validate(componentMapping, relatedData); + + expect(validationResult).toStrictEqual({ + isAllMappingValid: false, + byComponents: { + [componentsDictionaryByName.hBaseClient.id]: { + constraintsValidationResult: { isValid: true }, + requireValidationResults: { isValid: true }, + isValid: true, + }, + [componentsDictionaryByName.hBaseMaster.id]: { + constraintsValidationResult: { isValid: false, errors: ['1 or more components should be installed.'] }, + requireValidationResults: { isValid: true }, + isValid: false, + }, + [componentsDictionaryByName.zookeeperServer.id]: { + constraintsValidationResult: { isValid: true }, + requireValidationResults: { isValid: true }, + isValid: true, + }, + }, + }); + }); + + test('test validate service without component', () => { + const mapping: AdcmMapping[] = [ + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseClient.id }, + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseMaster.id }, + { hostId: hostsDictionaryByName.host3.id, componentId: componentsDictionaryByName.zookeeperServer.id }, + ]; + + const componentMapping = getComponentsMapping(mapping, components, hostsDictionary); + const serviceMapping = getServicesMapping(componentMapping); + const servicesMappingDictionary = arrayToHash(serviceMapping, (sm) => sm.service.prototype.id); + + const relatedData: ValidateRelatedData = { + allHostsCount: hosts.length, + servicesMappingDictionary, + notAddedServicesDictionary: {}, + }; + + const validationResult = validate(componentMapping, relatedData); + + expect(validationResult).toStrictEqual({ + isAllMappingValid: true, + byComponents: { + [componentsDictionaryByName.hBaseClient.id]: { + constraintsValidationResult: { isValid: true }, + requireValidationResults: { isValid: true }, + isValid: true, + }, + [componentsDictionaryByName.hBaseMaster.id]: { + constraintsValidationResult: { isValid: true }, + requireValidationResults: { isValid: true }, + isValid: true, + }, + [componentsDictionaryByName.zookeeperServer.id]: { + constraintsValidationResult: { isValid: true }, + requireValidationResults: { isValid: true }, + isValid: true, + }, + }, + }); + }); + + test('test validate dependOn', () => { + const mapping: AdcmMapping[] = [ + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseClient.id }, + { hostId: hostsDictionaryByName.host1.id, componentId: componentsDictionaryByName.hBaseMaster.id }, + { hostId: hostsDictionaryByName.host3.id, componentId: componentsDictionaryByName.zookeeperServer.id }, + ]; + + const componentMapping = getComponentsMapping(mapping, components, hostsDictionary); + const serviceMapping = getServicesMapping(componentMapping); + const servicesMappingDictionary = arrayToHash(serviceMapping, (sm) => sm.service.prototype.id); + + const relatedData: ValidateRelatedData = { + allHostsCount: hosts.length, + servicesMappingDictionary, + notAddedServicesDictionary: { + [candidateServicesDictionaryByName.HDFS.id]: candidateServicesDictionaryByName.HDFS, + }, + }; + + const validationResult = validate(componentMapping, relatedData); + + expect(validationResult).toStrictEqual({ + isAllMappingValid: false, + byComponents: { + [componentsDictionaryByName.hBaseClient.id]: { + constraintsValidationResult: { isValid: true }, + requireValidationResults: { + errors: ['Requires mapping of service "HDFS" (components: HDFS NameNode)'], + isValid: false, + }, + isValid: false, + }, + [componentsDictionaryByName.hBaseMaster.id]: { + constraintsValidationResult: { isValid: true }, + requireValidationResults: { + errors: ['Requires mapping of service "HDFS" (components: HDFS NameNode)'], + isValid: false, + }, + isValid: false, + }, + [componentsDictionaryByName.zookeeperServer.id]: { + constraintsValidationResult: { isValid: true }, + requireValidationResults: { isValid: true }, + isValid: true, + }, + }, + }); + }); }); diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.ts b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.ts index e585246293..c8ff9b3c8f 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.ts @@ -96,13 +96,13 @@ export const getServicesMapping = (componentMapping: ComponentMapping[]): Servic export const validate = (componentMapping: ComponentMapping[], relatedData: ValidateRelatedData): MappingValidation => { const byComponents: Record = {}; let isAllMappingValid = true; - const validateCash: ValidateCache = { + const validateCache: ValidateCache = { componentsCache: new Map(), servicesCache: new Map(), }; for (const cm of componentMapping) { - const { constraintsValidationResult, requireValidationResults } = validateComponent(cm, relatedData, validateCash); + const { constraintsValidationResult, requireValidationResults } = validateComponent(cm, relatedData, validateCache); const isValid = constraintsValidationResult.isValid && requireValidationResults.isValid; @@ -204,7 +204,7 @@ export const getConstraintsLimit = (constraints: AdcmComponentConstraint[]) => { export const validateDependOn = ( component: AdcmMappingComponent, relatedData: ValidateRelatedData, - validateCash: ValidateCache, + validateCache: ValidateCache, ): ValidationResult => { // component have not dependencies if (!component.dependOn || component.dependOn.length === 0) { @@ -214,7 +214,7 @@ export const validateDependOn = ( const errors = []; for (const { servicePrototype: dependService } of component.dependOn) { // component depend on not added service - if (!validateServiceRequire(dependService, relatedData, validateCash)) { + if (!validateServiceRequire(dependService, relatedData, validateCache)) { let error = `Requires mapping of service "${dependService.displayName}"`; // when component depend on special components of service @@ -239,9 +239,9 @@ export const validateDependOn = ( const validateServiceRequire = ( servicePrototype: AdcmDependOnService['servicePrototype'], relatedData: ValidateRelatedData, - validateCash: ValidateCache, + validateCache: ValidateCache, ) => { - const { servicesCache } = validateCash; + const { servicesCache } = validateCache; if (servicesCache.has(servicePrototype.id)) { return servicesCache.get(servicePrototype.id); } @@ -271,7 +271,7 @@ const validateServiceRequire = ( const { constraintsValidationResult, requireValidationResults } = validateComponent( requiredComponentItem, relatedData, - validateCash, + validateCache, ); const isValidChildComponent = constraintsValidationResult.isValid && requireValidationResults.isValid; @@ -290,9 +290,9 @@ const validateServiceRequire = ( const validateComponent = ( componentMapping: ComponentMapping, relatedData: ValidateRelatedData, - validateCash: ValidateCache, + validateCache: ValidateCache, ) => { - const { componentsCache } = validateCash; + const { componentsCache } = validateCache; if (componentsCache.has(componentMapping.component.id)) { return componentsCache.get(componentMapping.component.id) as ComponentValidateResult; } @@ -306,7 +306,7 @@ const validateComponent = ( // if component can be not mapping (constraint = [0,...]) and user not mapped some hosts to this component // then we can ignore validateDependOn for this component const requireValidationResults = isMandatoryComponent(componentMapping) - ? validateDependOn(componentMapping.component, relatedData, validateCash) + ? validateDependOn(componentMapping.component, relatedData, validateCache) : ({ isValid: true } as ValidationSuccess); const result = { diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/RequiredServicesDialog/useRequiredServicesDialog.ts b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/RequiredServicesDialog/useRequiredServicesDialog.ts index 424f552e4d..6baf63a352 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/RequiredServicesDialog/useRequiredServicesDialog.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/RequiredServicesDialog/useRequiredServicesDialog.ts @@ -1,7 +1,7 @@ import { useMemo, useState } from 'react'; import { closeRequiredServicesDialog, - getMappings, + loadMappingComponents, getNotAddedServices, } from '@store/adcm/cluster/mapping/mappingSlice'; import { useDispatch, useForm, useStore } from '@hooks'; @@ -68,7 +68,7 @@ export const useRequiredServicesDialog = () => { ) .unwrap() .then(() => { - dispatch(getMappings({ clusterId })); + dispatch(loadMappingComponents({ clusterId })); dispatch(getNotAddedServices({ clusterId })); }); } diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts b/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts index a30697343e..1a97de3b58 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts @@ -55,9 +55,10 @@ export const useClusterMapping = () => { [isLoaded, componentsMapping], ); - const servicesMappingDictionary = useMemo(() => { - return Object.fromEntries(servicesMapping.map((item) => [item.service.prototype.id, item])); - }, [servicesMapping]); + const servicesMappingDictionary = useMemo( + () => arrayToHash(servicesMapping, (sm) => sm.service.prototype.id), + [servicesMapping], + ); const mappingValidation = useMemo(() => { return validate(componentsMapping, { diff --git a/adcm-web/app/src/models/adcm/license.ts b/adcm-web/app/src/models/adcm/license.ts index d94b15e81d..631dfd4190 100644 --- a/adcm-web/app/src/models/adcm/license.ts +++ b/adcm-web/app/src/models/adcm/license.ts @@ -6,5 +6,5 @@ export enum AdcmLicenseStatus { export interface AdcmLicense { status: AdcmLicenseStatus; - text?: string; + text: string | null; } diff --git a/adcm-web/app/src/models/adcm/service.ts b/adcm-web/app/src/models/adcm/service.ts index 2c3c84742e..23929ccca2 100644 --- a/adcm-web/app/src/models/adcm/service.ts +++ b/adcm-web/app/src/models/adcm/service.ts @@ -45,7 +45,7 @@ export interface AdcmServicePrototype { version: string; license: { status: AdcmLicenseStatus; - text: string; + text: string | null; }; isRequired: boolean; dependOn: AdcmDependOnService[] | null; diff --git a/adcm-web/app/src/store/adcm/cluster/mapping/mappingSlice.ts b/adcm-web/app/src/store/adcm/cluster/mapping/mappingSlice.ts index e3db9b3533..ffd50345a9 100644 --- a/adcm-web/app/src/store/adcm/cluster/mapping/mappingSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/mapping/mappingSlice.ts @@ -200,5 +200,6 @@ export { getNotAddedServices, openRequiredServicesDialog, closeRequiredServicesDialog, + loadMappingComponents, }; export default mappingSlice.reducer; From 5f829d4c05c2be3f14b54cfd7693f96cb1ed5d19 Mon Sep 17 00:00:00 2001 From: Dmitriy Bardin Date: Wed, 27 Dec 2023 21:30:14 +0000 Subject: [PATCH 004/151] ADCM-5161 - [UI] Reset button fix height https://tracker.yandex.ru/ADCM-5161 --- .../common/Table/TableFilters/TableFilters.module.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/adcm-web/app/src/components/common/Table/TableFilters/TableFilters.module.scss b/adcm-web/app/src/components/common/Table/TableFilters/TableFilters.module.scss index b8e7c478c8..6c810ff3bb 100644 --- a/adcm-web/app/src/components/common/Table/TableFilters/TableFilters.module.scss +++ b/adcm-web/app/src/components/common/Table/TableFilters/TableFilters.module.scss @@ -2,6 +2,7 @@ display: flex; column-gap: 16px; flex: 1; + align-items: center; :global(.search-input) { max-width: 225px; From 4ceb8737f5b9ae27048810b4846912ac42b88df8 Mon Sep 17 00:00:00 2001 From: Kirill Fedorenko Date: Wed, 27 Dec 2023 21:30:48 +0000 Subject: [PATCH 005/151] ADCM-5162 [UI] Add tooltips for the theme switcher https://tracker.yandex.ru/ADCM-5162 --- .../partials/ThemeSwitcher/ThemeSwitcher.tsx | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/adcm-web/app/src/components/layouts/partials/ThemeSwitcher/ThemeSwitcher.tsx b/adcm-web/app/src/components/layouts/partials/ThemeSwitcher/ThemeSwitcher.tsx index f85142e97e..0b9a904454 100644 --- a/adcm-web/app/src/components/layouts/partials/ThemeSwitcher/ThemeSwitcher.tsx +++ b/adcm-web/app/src/components/layouts/partials/ThemeSwitcher/ThemeSwitcher.tsx @@ -3,6 +3,7 @@ import s from './ThemeSwitcher.module.scss'; import { useLocalStorage } from '@uikit/hooks/useLocalStorage'; import Icon from '@uikit/Icon/Icon'; import cn from 'classnames'; +import { ConditionalWrapper, Tooltip } from '@uikit'; enum THEME { Dark = 'dark', @@ -46,22 +47,24 @@ const ThemeSwitcher: React.FC = () => { return (
- - + + + + + +
); }; From 8eab61f45108d89e77f9ca5e4c23caf1bac95b67 Mon Sep 17 00:00:00 2001 From: Dmitriy Bardin Date: Thu, 28 Dec 2023 10:42:05 +0000 Subject: [PATCH 006/151] ADCM-5166 - [UI] Users slice. Load state https://tracker.yandex.ru/ADCM-5166 --- .../AccessManagerUsersTable.tsx | 3 ++- .../src/components/uikit/Table/Table.utils.ts | 4 ++++ adcm-web/app/src/models/loadState.ts | 5 +++++ adcm-web/app/src/store/adcm/users/usersSlice.ts | 17 +++++++++-------- 4 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 adcm-web/app/src/components/uikit/Table/Table.utils.ts create mode 100644 adcm-web/app/src/models/loadState.ts diff --git a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerUsersPage/AccessManagerUsersTable/AccessManagerUsersTable.tsx b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerUsersPage/AccessManagerUsersTable/AccessManagerUsersTable.tsx index 5f5aad57f0..69796f57ab 100644 --- a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerUsersPage/AccessManagerUsersTable/AccessManagerUsersTable.tsx +++ b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerUsersPage/AccessManagerUsersTable/AccessManagerUsersTable.tsx @@ -12,11 +12,12 @@ import { SortParams } from '@uikit/types/list.types'; import { AdcmUser, AdcmUserStatus } from '@models/adcm'; import { useSelectedItems } from '@uikit/hooks/useSelectedItems'; import { openDeleteDialog } from '@store/adcm/users/usersActionsSlice'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const AccessManagerUsersTable = () => { const dispatch = useDispatch(); const users = useStore((s) => s.adcm.users.users); - const isLoading = useStore((s) => s.adcm.users.isLoading); + const isLoading = useStore((s) => isShowSpinner(s.adcm.users.loadState)); const sortParams = useStore((s) => s.adcm.usersTable.sortParams); const selectedItemsIds = useStore(({ adcm }) => adcm.usersActions.selectedItemsIds); diff --git a/adcm-web/app/src/components/uikit/Table/Table.utils.ts b/adcm-web/app/src/components/uikit/Table/Table.utils.ts new file mode 100644 index 0000000000..c32e1292b4 --- /dev/null +++ b/adcm-web/app/src/components/uikit/Table/Table.utils.ts @@ -0,0 +1,4 @@ +import { LoadState } from '@models/loadState'; + +export const isShowSpinner = (loadState: LoadState): loadState is LoadState.Loading | LoadState.NotLoaded => + loadState === LoadState.Loading || loadState === LoadState.NotLoaded; diff --git a/adcm-web/app/src/models/loadState.ts b/adcm-web/app/src/models/loadState.ts new file mode 100644 index 0000000000..e524b19211 --- /dev/null +++ b/adcm-web/app/src/models/loadState.ts @@ -0,0 +1,5 @@ +export enum LoadState { + NotLoaded = 'notLoaded', + Loading = 'loading', + Loaded = 'loaded', +} diff --git a/adcm-web/app/src/store/adcm/users/usersSlice.ts b/adcm-web/app/src/store/adcm/users/usersSlice.ts index f5a54f32c3..07bc32e982 100644 --- a/adcm-web/app/src/store/adcm/users/usersSlice.ts +++ b/adcm-web/app/src/store/adcm/users/usersSlice.ts @@ -4,11 +4,12 @@ import { createAsyncThunk } from '@store/redux'; import { AdcmUser } from '@models/adcm'; import { executeWithMinDelay } from '@utils/requestUtils'; import { defaultSpinnerDelay } from '@constants'; +import { LoadState } from '@models/loadState'; interface AdcmUsersState { users: AdcmUser[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; } const loadFromBackend = createAsyncThunk('adcm/users/loadFromBackend', async (arg, thunkAPI) => { @@ -27,7 +28,7 @@ const loadFromBackend = createAsyncThunk('adcm/users/loadFromBackend', async (ar }); const getUsers = createAsyncThunk('adcm/users/getUsers', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadFromBackend()); @@ -36,7 +37,7 @@ const getUsers = createAsyncThunk('adcm/users/getUsers', async (arg, thunkAPI) = startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -48,15 +49,15 @@ const refreshUsers = createAsyncThunk('adcm/users/refreshUsers', async (arg, thu const createInitialState = (): AdcmUsersState => ({ users: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, }); const usersSlice = createSlice({ name: 'adcm/users', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupUsers() { return createInitialState(); @@ -74,6 +75,6 @@ const usersSlice = createSlice({ }, }); -const { setIsLoading, cleanupUsers } = usersSlice.actions; -export { getUsers, refreshUsers, cleanupUsers }; +const { setLoadState, cleanupUsers } = usersSlice.actions; +export { getUsers, refreshUsers, cleanupUsers, setLoadState }; export default usersSlice.reducer; From b5132eaed5c9c6ab0491704e3c27f94cabde6a64 Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Thu, 28 Dec 2023 12:56:36 +0000 Subject: [PATCH 007/151] [UI] ADCM-5160: Add proxy to backend https://tracker.yandex.ru/ADCM-5160 --- adcm-web/app/.env.development | 4 ++-- adcm-web/app/vite.config.ts | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/adcm-web/app/.env.development b/adcm-web/app/.env.development index 58826194b1..263531b61f 100644 --- a/adcm-web/app/.env.development +++ b/adcm-web/app/.env.development @@ -1,3 +1,3 @@ -ADCM_API_HOST=http://localhost:8000 -ADCM_WS_HOST=ws://localhost:8000 +# ADCM_API_HOST=http://localhost:8000 +# ADCM_WS_HOST=ws://localhost:8000 ADCM_VERSION=2.0.0 diff --git a/adcm-web/app/vite.config.ts b/adcm-web/app/vite.config.ts index 2872e9cd87..9f3c34976f 100644 --- a/adcm-web/app/vite.config.ts +++ b/adcm-web/app/vite.config.ts @@ -12,6 +12,21 @@ export default defineConfig(({ command, mode }) => { const withQaAttributes = env.WITH_QA_ATTRIBUTES === 'true'; return { + server: { + port: 5173, + proxy: { + '/api': { + target: 'http://localhost:8000', + changeOrigin: true, + }, + '/ws': { + target: 'ws://localhost:8000', + changeOrigin: false, + ws: true, + }, + }, + cors: true, + }, envPrefix: 'ADCM_', plugins: [ tsconfigPaths(), From d1f4f90024adf8a6a0667ff2b91afac2b49afd35 Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Fri, 29 Dec 2023 08:13:35 +0000 Subject: [PATCH 008/151] [UI] ADCM-5169: Add LoadStates to Audit https://tracker.yandex.ru/ADCM-5169 --- .../AuditLoginsTable/AuditLoginsTable.tsx | 3 ++- .../AuditOperationsTable.tsx | 3 ++- .../adcm/audit/auditLogins/auditLoginsSlice.ts | 17 +++++++++-------- .../auditOperations/auditOperationsSlice.ts | 17 +++++++++-------- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/adcm-web/app/src/components/pages/audit/AuditLoginsPage/AuditLoginsTable/AuditLoginsTable.tsx b/adcm-web/app/src/components/pages/audit/AuditLoginsPage/AuditLoginsTable/AuditLoginsTable.tsx index 42a543b55f..1fe4f85d22 100644 --- a/adcm-web/app/src/components/pages/audit/AuditLoginsPage/AuditLoginsTable/AuditLoginsTable.tsx +++ b/adcm-web/app/src/components/pages/audit/AuditLoginsPage/AuditLoginsTable/AuditLoginsTable.tsx @@ -6,12 +6,13 @@ import { setSortParams } from '@store/adcm/audit/auditLogins/auditLoginsTableSli import { SortParams } from '@models/table'; import DateTimeCell from '@commonComponents/Table/Cells/DateTimeCell'; import { orElseGet } from '@utils/checkUtils'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const AuditLoginsTable = () => { const dispatch = useDispatch(); const auditLogins = useStore(({ adcm }) => adcm.auditLogins.auditLogins); - const isLoading = useStore(({ adcm }) => adcm.auditLogins.isLoading); + const isLoading = useStore(({ adcm }) => isShowSpinner(adcm.auditLogins.loadState)); const sortParams = useStore(({ adcm }) => adcm.auditLoginsTable.sortParams); const handleSorting = (sortParams: SortParams) => { diff --git a/adcm-web/app/src/components/pages/audit/AuditOperationsPage/AuditOperationsTable/AuditOperationsTable.tsx b/adcm-web/app/src/components/pages/audit/AuditOperationsPage/AuditOperationsTable/AuditOperationsTable.tsx index bf787602f4..1558acb736 100644 --- a/adcm-web/app/src/components/pages/audit/AuditOperationsPage/AuditOperationsTable/AuditOperationsTable.tsx +++ b/adcm-web/app/src/components/pages/audit/AuditOperationsPage/AuditOperationsTable/AuditOperationsTable.tsx @@ -12,6 +12,7 @@ import AuditOperationsTableExpandedContent from '@pages/audit/AuditOperationsPag import { orElseGet } from '@utils/checkUtils'; import s from './AuditOperationsTable.module.scss'; import cn from 'classnames'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const AuditOperationsTable = () => { const dispatch = useDispatch(); @@ -19,7 +20,7 @@ const AuditOperationsTable = () => { const [expandableRows, setExpandableRows] = useState>({}); const auditOperations = useStore(({ adcm }) => adcm.auditOperations.auditOperations); - const isLoading = useStore(({ adcm }) => adcm.auditOperations.isLoading); + const isLoading = useStore(({ adcm }) => isShowSpinner(adcm.auditOperations.loadState)); const sortParams = useStore(({ adcm }) => adcm.auditOperationsTable.sortParams); const handleExpandClick = (id: number) => { diff --git a/adcm-web/app/src/store/adcm/audit/auditLogins/auditLoginsSlice.ts b/adcm-web/app/src/store/adcm/audit/auditLogins/auditLoginsSlice.ts index c40a1fc378..addde6eaea 100644 --- a/adcm-web/app/src/store/adcm/audit/auditLogins/auditLoginsSlice.ts +++ b/adcm-web/app/src/store/adcm/audit/auditLogins/auditLoginsSlice.ts @@ -5,11 +5,12 @@ import { executeWithMinDelay } from '@utils/requestUtils'; import { defaultSpinnerDelay } from '@constants'; import { AdcmAuditApi } from '@api/adcm/audit'; import { localDateToServerDate } from '@utils/date/dateConvertUtils'; +import { LoadState } from '@models/loadState'; type AdcmAuditLoginsState = { auditLogins: AdcmAuditLogin[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; }; const loadAuditLogins = createAsyncThunk('adcm/auditLogins/loadAuditLogins', async (arg, thunkAPI) => { @@ -34,7 +35,7 @@ const loadAuditLogins = createAsyncThunk('adcm/auditLogins/loadAuditLogins', asy }); const getAuditLogins = createAsyncThunk('adcm/auditLogins/getAuditLogins', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadAuditLogins()); @@ -43,7 +44,7 @@ const getAuditLogins = createAsyncThunk('adcm/auditLogins/getAuditLogins', async startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -55,15 +56,15 @@ const refreshAuditLogins = createAsyncThunk('adcm/auditLogins/refreshAuditLogins const createInitialState = (): AdcmAuditLoginsState => ({ auditLogins: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, }); const auditLoginsSlice = createSlice({ name: 'adcm/auditLogins', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupAuditLogins() { return createInitialState(); @@ -80,7 +81,7 @@ const auditLoginsSlice = createSlice({ }, }); -const { setIsLoading, cleanupAuditLogins } = auditLoginsSlice.actions; -export { getAuditLogins, cleanupAuditLogins, refreshAuditLogins }; +const { setLoadState, cleanupAuditLogins } = auditLoginsSlice.actions; +export { getAuditLogins, cleanupAuditLogins, refreshAuditLogins, setLoadState }; export default auditLoginsSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/audit/auditOperations/auditOperationsSlice.ts b/adcm-web/app/src/store/adcm/audit/auditOperations/auditOperationsSlice.ts index 9054fa5501..59b797ba83 100644 --- a/adcm-web/app/src/store/adcm/audit/auditOperations/auditOperationsSlice.ts +++ b/adcm-web/app/src/store/adcm/audit/auditOperations/auditOperationsSlice.ts @@ -5,11 +5,12 @@ import { executeWithMinDelay } from '@utils/requestUtils'; import { defaultSpinnerDelay } from '@constants'; import { AdcmAuditApi } from '@api/adcm/audit'; import { localDateToServerDate } from '@utils/date/dateConvertUtils'; +import { LoadState } from '@models/loadState'; type AdcmAuditOperationsState = { auditOperations: AdcmAuditOperation[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; }; const loadAuditOperations = createAsyncThunk('adcm/auditOperations/loadAuditOperations', async (arg, thunkAPI) => { @@ -34,7 +35,7 @@ const loadAuditOperations = createAsyncThunk('adcm/auditOperations/loadAuditOper }); const getAuditOperations = createAsyncThunk('adcm/auditOperations/getAuditOperations', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadAuditOperations()); @@ -43,7 +44,7 @@ const getAuditOperations = createAsyncThunk('adcm/auditOperations/getAuditOperat startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -58,15 +59,15 @@ const refreshAuditOperations = createAsyncThunk( const createInitialState = (): AdcmAuditOperationsState => ({ auditOperations: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, }); const auditOperationsSlice = createSlice({ name: 'adcm/auditOperations', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupAuditOperations() { return createInitialState(); @@ -83,7 +84,7 @@ const auditOperationsSlice = createSlice({ }, }); -const { setIsLoading, cleanupAuditOperations } = auditOperationsSlice.actions; -export { getAuditOperations, cleanupAuditOperations, refreshAuditOperations }; +const { setLoadState, cleanupAuditOperations } = auditOperationsSlice.actions; +export { getAuditOperations, cleanupAuditOperations, refreshAuditOperations, setLoadState }; export default auditOperationsSlice.reducer; From 018732d718e545baf7133ab696feeaff7d496e2f Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Fri, 29 Dec 2023 09:52:02 +0000 Subject: [PATCH 009/151] [UI] ADCM-5170: Add LoadStates to Bundles https://tracker.yandex.ru/ADCM-5170 --- .../BundleOverviewPage/BundleOverviewPage.tsx | 3 ++- .../BundlesPage/BundlesTable/BundlesTable.tsx | 5 +++-- adcm-web/app/src/models/adcm/index.ts | 1 + .../app/src/store/adcm/bundle/bundleSlice.ts | 17 +++++++++-------- .../src/store/adcm/bundles/bundlesSlice.ts | 19 ++++++++++--------- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewPage.tsx b/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewPage.tsx index 34e3798da7..43dd041641 100644 --- a/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewPage.tsx +++ b/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewPage.tsx @@ -7,13 +7,14 @@ import BundleOverviewTable from './BundleOverviewTable/BundleOverviewTable'; import BundleOverviewLicenseContent from './BundleOverviewLicenceContent/BundleOverviewLicenseContent'; import { Spinner } from '@uikit'; import s from './BundleOverviewPage.module.scss'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const BundleOverviewPage: React.FC = () => { useRequestBundle(); const dispatch = useDispatch(); const bundle = useStore(({ adcm }) => adcm.bundle.bundle); const isBundleLicensePresent = bundle?.mainPrototype.license?.text !== null; - const isLicenseLoading = useStore(({ adcm }) => adcm.bundle.isLicenseLoading); + const isLicenseLoading = useStore(({ adcm }) => isShowSpinner(adcm.bundle.licenseLoadState)); useEffect(() => { if (bundle) { diff --git a/adcm-web/app/src/components/pages/BundlesPage/BundlesTable/BundlesTable.tsx b/adcm-web/app/src/components/pages/BundlesPage/BundlesTable/BundlesTable.tsx index 2bc3bbe774..8edb8d08ce 100644 --- a/adcm-web/app/src/components/pages/BundlesPage/BundlesTable/BundlesTable.tsx +++ b/adcm-web/app/src/components/pages/BundlesPage/BundlesTable/BundlesTable.tsx @@ -4,13 +4,14 @@ import { columns } from './BundlesTable.constants'; import { Checkbox, IconButton, Table, TableCell, TableRow } from '@uikit'; import { orElseGet } from '@utils/checkUtils'; import { useSelectedItems } from '@uikit/hooks/useSelectedItems'; -import { AdcmBundle } from '@models/adcm/bundle'; +import { AdcmBundle } from '@models/adcm'; import DateTimeCell from '@commonComponents/Table/Cells/DateTimeCell'; import { setDeletableId, setSelectedItemsIds as setSelectedBundlesIds } from '@store/adcm/bundles/bundlesSlice'; import { SortParams } from '@uikit/types/list.types'; import { setSortParams } from '@store/adcm/bundles/bundlesTableSlice'; import { Link } from 'react-router-dom'; import cn from 'classnames'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const getBundleUniqKey = ({ id }: AdcmBundle) => id; @@ -18,7 +19,7 @@ const BundlesTable: React.FC = () => { const dispatch = useDispatch(); const bundles = useStore(({ adcm }) => adcm.bundles.bundles); - const isLoading = useStore(({ adcm }) => adcm.bundles.isLoading); + const isLoading = useStore(({ adcm }) => isShowSpinner(adcm.bundles.loadState)); const selectedItemsIds = useStore(({ adcm }) => adcm.bundles.selectedItemsIds); const sortParams = useStore((s) => s.adcm.bundlesTable.sortParams); diff --git a/adcm-web/app/src/models/adcm/index.ts b/adcm-web/app/src/models/adcm/index.ts index 03e704c038..916b80a09e 100644 --- a/adcm-web/app/src/models/adcm/index.ts +++ b/adcm-web/app/src/models/adcm/index.ts @@ -24,6 +24,7 @@ export * from './dynamicAction'; export * from './upgrades'; export * from './backendEvents'; export * from './settings'; +export * from './bundle'; export interface Batch { results: T[]; diff --git a/adcm-web/app/src/store/adcm/bundle/bundleSlice.ts b/adcm-web/app/src/store/adcm/bundle/bundleSlice.ts index 3a8989cf91..778b42b606 100644 --- a/adcm-web/app/src/store/adcm/bundle/bundleSlice.ts +++ b/adcm-web/app/src/store/adcm/bundle/bundleSlice.ts @@ -1,6 +1,7 @@ import { AdcmBundlesApi, AdcmPrototypesApi, RequestError } from '@api'; import { defaultSpinnerDelay } from '@constants'; import { AdcmBundle } from '@models/adcm/bundle'; +import { LoadState } from '@models/loadState'; import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; import { showError, showInfo } from '@store/notificationsSlice'; import { getErrorMessage } from '@utils/httpResponseUtils'; @@ -8,7 +9,7 @@ import { executeWithMinDelay } from '@utils/requestUtils'; interface AdcmBundleState { bundle?: AdcmBundle; - isLicenseLoading: boolean; + licenseLoadState: LoadState; } interface AcceptBundleLicensePayload { @@ -26,7 +27,7 @@ const loadBundleFromBackend = createAsyncThunk('adcm/bundle/loadBundle', async ( }); const getBundle = createAsyncThunk('adcm/bundle/getBundle', async (arg: number, thunkAPI) => { - thunkAPI.dispatch(setIsLicenseLoading(true)); + thunkAPI.dispatch(setLicenseLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadBundleFromBackend(arg)); @@ -35,7 +36,7 @@ const getBundle = createAsyncThunk('adcm/bundle/getBundle', async (arg: number, startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLicenseLoading(false)); + thunkAPI.dispatch(setLicenseLoadState(LoadState.Loaded)); }, }); }); @@ -71,15 +72,15 @@ const deleteBundle = createAsyncThunk('adcm/bundle/deleteBundle', async (bundleI const createInitialState = (): AdcmBundleState => ({ bundle: undefined, - isLicenseLoading: false, + licenseLoadState: LoadState.NotLoaded, }); const bundleSlice = createSlice({ name: 'adcm/bundle', initialState: createInitialState(), reducers: { - setIsLicenseLoading(state, action) { - state.isLicenseLoading = action.payload; + setLicenseLoadState(state, action) { + state.licenseLoadState = action.payload; }, cleanupBundle() { return createInitialState(); @@ -95,6 +96,6 @@ const bundleSlice = createSlice({ }, }); -const { cleanupBundle, setIsLicenseLoading } = bundleSlice.actions; -export { getBundle, acceptBundleLicenseWithUpdate, cleanupBundle, deleteBundle }; +const { cleanupBundle, setLicenseLoadState } = bundleSlice.actions; +export { getBundle, acceptBundleLicenseWithUpdate, cleanupBundle, deleteBundle, setLicenseLoadState }; export default bundleSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/bundles/bundlesSlice.ts b/adcm-web/app/src/store/adcm/bundles/bundlesSlice.ts index b76eeb8606..74aac3e4b2 100644 --- a/adcm-web/app/src/store/adcm/bundles/bundlesSlice.ts +++ b/adcm-web/app/src/store/adcm/bundles/bundlesSlice.ts @@ -7,11 +7,12 @@ import { AdcmBundlesApi, RequestError } from '@api'; import { rejectedFilter } from '@utils/promiseUtils'; import { showError, showInfo } from '@store/notificationsSlice'; import { getErrorMessage } from '@utils/httpResponseUtils'; +import { LoadState } from '@models/loadState'; type AdcmBundlesState = { bundles: AdcmBundle[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; isUploading: boolean; itemsForActions: { deletableId: number | null; @@ -35,7 +36,7 @@ const loadBundles = createAsyncThunk('adcm/bundles/loadBundles', async (arg, thu }); const getBundles = createAsyncThunk('adcm/bundles/getBundles', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadBundles()); @@ -44,7 +45,7 @@ const getBundles = createAsyncThunk('adcm/bundles/getBundles', async (arg, thunk startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -78,10 +79,10 @@ const deleteBundles = createAsyncThunk('adcm/bundles/deleteBundles', async (sele const deleteWithUpdateBundles = createAsyncThunk( 'adcm/bundles/deleteWithUpdateBundles', async (selectedBundlesIds: number[], thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); await thunkAPI.dispatch(deleteBundles(selectedBundlesIds)); await thunkAPI.dispatch(getBundles()); - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, ); @@ -121,7 +122,7 @@ const uploadWithUpdateBundles = createAsyncThunk( const createInitialState = (): AdcmBundlesState => ({ bundles: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, isUploading: false, itemsForActions: { deletableId: null, @@ -133,8 +134,8 @@ const bundlesSlice = createSlice({ name: 'adcm/bundles', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, setIsUploading(state, action) { state.isUploading = action.payload; @@ -177,7 +178,7 @@ const bundlesSlice = createSlice({ }); export const { - setIsLoading, + setLoadState, cleanupBundles, setIsUploading, setDeletableId, From 729aa2dca8842b783a0ce621909206b95c81295d Mon Sep 17 00:00:00 2001 From: Kirill Fedorenko Date: Fri, 29 Dec 2023 10:02:58 +0000 Subject: [PATCH 010/151] ADCM-5168 [UI] Change isLoading to LoadState in groups, policies and roles slices https://tracker.yandex.ru/ADCM-5168 --- .../AccessManagerGroupsTable.tsx | 4 +++- .../AccessManagerPoliciesTable.tsx | 3 ++- .../AccessManagerRolesTable.tsx | 3 ++- .../app/src/store/adcm/groups/groupsSlice.ts | 15 ++++++++------- .../src/store/adcm/policies/policiesSlice.ts | 19 ++++++++++--------- .../app/src/store/adcm/roles/rolesSlice.ts | 15 ++++++++------- 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTable/AccessManagerGroupsTable.tsx b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTable/AccessManagerGroupsTable.tsx index 075394bc64..4705dbf6c4 100644 --- a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTable/AccessManagerGroupsTable.tsx +++ b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTable/AccessManagerGroupsTable.tsx @@ -8,10 +8,12 @@ import { SortParams } from '@uikit/types/list.types'; import { AdcmGroup } from '@models/adcm'; import { useSelectedItems } from '@uikit/hooks/useSelectedItems'; import { openUpdateDialog } from '@store/adcm/groups/groupActionsSlice'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const AccessManagerGroupsTable = () => { const dispatch = useDispatch(); - const { groups, isLoading, selectedItemsIds } = useStore((s) => s.adcm.groups); + const { groups, selectedItemsIds } = useStore((s) => s.adcm.groups); + const isLoading = useStore((s) => isShowSpinner(s.adcm.groups.loadState)); const sortParams = useStore((s) => s.adcm.groupsTable.sortParams); const setSelectedItemsIds = useCallback>>( diff --git a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.tsx b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.tsx index 04b540385a..4b5403f719 100644 --- a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.tsx +++ b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.tsx @@ -10,12 +10,13 @@ import { AdcmPolicy } from '@models/adcm'; import cn from 'classnames'; import s from './AccessManagerPoliciesTable.module.scss'; import AccessManagerPoliciesTableExpandedContent from './AccessManagerPoliciesTableExpandedContent/AccessManagerPoliciesTableExpandedContent'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const AccessManagerPoliciesTable: React.FC = () => { const dispatch = useDispatch(); const policies = useStore(({ adcm }) => adcm.policies.policies); - const isLoading = useStore(({ adcm }) => adcm.policies.isLoading); + const isLoading = useStore(({ adcm }) => isShowSpinner(adcm.policies.loadState)); const sortParams = useStore(({ adcm }) => adcm.policiesTable.sortParams); const handleEditClick = (policy: AdcmPolicy) => () => { diff --git a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerRolesPage/AccessManagerRolesTable/AccessManagerRolesTable.tsx b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerRolesPage/AccessManagerRolesTable/AccessManagerRolesTable.tsx index 8511978668..5093a7c5b8 100644 --- a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerRolesPage/AccessManagerRolesTable/AccessManagerRolesTable.tsx +++ b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerRolesPage/AccessManagerRolesTable/AccessManagerRolesTable.tsx @@ -9,12 +9,13 @@ import AccessManagerRolesTableExpandedContent from './AccessManagerRolesTableExp import s from './AccessManagerRolesTable.module.scss'; import cn from 'classnames'; import { AdcmRole } from '@models/adcm'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const AccessManagerRolesTable = () => { const dispatch = useDispatch(); const roles = useStore((s) => s.adcm.roles.roles); - const isLoading = useStore((s) => s.adcm.roles.isLoading); + const isLoading = useStore((s) => isShowSpinner(s.adcm.roles.loadState)); const sortParams = useStore((s) => s.adcm.rolesTable.sortParams); const [expandableRows, setExpandableRows] = useState>({}); diff --git a/adcm-web/app/src/store/adcm/groups/groupsSlice.ts b/adcm-web/app/src/store/adcm/groups/groupsSlice.ts index bf2facbcde..6be006e84c 100644 --- a/adcm-web/app/src/store/adcm/groups/groupsSlice.ts +++ b/adcm-web/app/src/store/adcm/groups/groupsSlice.ts @@ -7,6 +7,7 @@ import { defaultSpinnerDelay } from '@constants'; import { showError, showInfo } from '@store/notificationsSlice'; import { getErrorMessage } from '@utils/httpResponseUtils'; import { rejectedFilter } from '@utils/promiseUtils'; +import { LoadState } from '@models/loadState'; interface AdcmGroupsState { groups: AdcmGroup[]; @@ -14,7 +15,7 @@ interface AdcmGroupsState { itemsForActions: { deletableId: number | null; }; - isLoading: boolean; + loadState: LoadState; selectedItemsIds: number[]; } @@ -34,7 +35,7 @@ const loadFromBackend = createAsyncThunk('adcm/groups/loadFromBackend', async (a }); const getGroups = createAsyncThunk('adcm/groups/getGroups', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadFromBackend()); @@ -43,7 +44,7 @@ const getGroups = createAsyncThunk('adcm/groups/getGroups', async (arg, thunkAPI startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -75,7 +76,7 @@ const createInitialState = (): AdcmGroupsState => ({ itemsForActions: { deletableId: null, }, - isLoading: true, + loadState: LoadState.NotLoaded, selectedItemsIds: [], }); @@ -83,8 +84,8 @@ const groupsSlice = createSlice({ name: 'adcm/groups', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupGroups() { return createInitialState(); @@ -117,6 +118,6 @@ const groupsSlice = createSlice({ }, }); -const { setIsLoading, cleanupGroups, setDeletableId, setSelectedItemsIds } = groupsSlice.actions; +const { setLoadState, cleanupGroups, setDeletableId, setSelectedItemsIds } = groupsSlice.actions; export { getGroups, refreshGroups, deleteGroupsWithUpdate, cleanupGroups, setDeletableId, setSelectedItemsIds }; export default groupsSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/policies/policiesSlice.ts b/adcm-web/app/src/store/adcm/policies/policiesSlice.ts index 72a202d490..f600c54c26 100644 --- a/adcm-web/app/src/store/adcm/policies/policiesSlice.ts +++ b/adcm-web/app/src/store/adcm/policies/policiesSlice.ts @@ -8,11 +8,12 @@ import { AdcmObjectCandidates, AdcmPolicy } from '@models/adcm/policy'; import { AdcmClustersApi, AdcmHostProvidersApi, AdcmHostsApi, AdcmPoliciesApi, RequestError } from '@api'; import { SortParams } from '@models/table'; import { AdcmCluster, AdcmHost, AdcmHostProvider, AdcmService } from '@models/adcm'; +import { LoadState } from '@models/loadState'; interface AdcmPoliciesState { policies: AdcmPolicy[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; relatedData: { clusters: AdcmCluster[]; services: AdcmService[]; @@ -40,7 +41,7 @@ const loadPoliciesFromBackend = createAsyncThunk('adcm/policies/loadPoliciesFrom }); const getPolicies = createAsyncThunk('adcm/policies/getPolicies', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadPoliciesFromBackend()); @@ -49,7 +50,7 @@ const getPolicies = createAsyncThunk('adcm/policies/getPolicies', async (arg, th startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -59,7 +60,7 @@ const refreshPolicies = createAsyncThunk('adcm/policies/refreshPolicies', async }); const getObjectCandidates = createAsyncThunk('adcm/policies/getObjectCandidates', async (roleId: number, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadObjectCandidates(roleId)); @@ -68,7 +69,7 @@ const getObjectCandidates = createAsyncThunk('adcm/policies/getObjectCandidates' startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -118,7 +119,7 @@ const loadHostProviders = createAsyncThunk('adcm/policies/loadHostProviders', as const createInitialState = (): AdcmPoliciesState => ({ policies: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, relatedData: { clusters: [], services: [], @@ -138,8 +139,8 @@ const policiesSlice = createSlice({ name: 'adcm/policies', initialState: createInitialState(), reducers: { - setIsLoading: (state, action) => { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupPolicies: () => { return createInitialState(); @@ -187,7 +188,7 @@ const policiesSlice = createSlice({ }, }); -const { setIsLoading, cleanupPolicies } = policiesSlice.actions; +const { setLoadState, cleanupPolicies } = policiesSlice.actions; export { getPolicies, refreshPolicies, diff --git a/adcm-web/app/src/store/adcm/roles/rolesSlice.ts b/adcm-web/app/src/store/adcm/roles/rolesSlice.ts index c07ce57a18..64956a0d5d 100644 --- a/adcm-web/app/src/store/adcm/roles/rolesSlice.ts +++ b/adcm-web/app/src/store/adcm/roles/rolesSlice.ts @@ -4,11 +4,12 @@ import { executeWithMinDelay } from '@utils/requestUtils'; import { defaultSpinnerDelay } from '@constants'; import { AdcmRole } from '@models/adcm'; import { AdcmRolesApi } from '@api'; +import { LoadState } from '@models/loadState'; interface AdcmRolesState { roles: AdcmRole[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; relatedData: { categories: string[]; }; @@ -30,7 +31,7 @@ const loadFromBackend = createAsyncThunk('adcm/roles/loadFromBackend', async (ar }); const getRoles = createAsyncThunk('adcm/roles/getRoles', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadFromBackend()); @@ -39,7 +40,7 @@ const getRoles = createAsyncThunk('adcm/roles/getRoles', async (arg, thunkAPI) = startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -59,7 +60,7 @@ const refreshRoles = createAsyncThunk('adcm/roles/refreshRoles', async (arg, thu const createInitialState = (): AdcmRolesState => ({ roles: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, relatedData: { categories: [], }, @@ -69,8 +70,8 @@ const rolesSlice = createSlice({ name: 'adcm/roles', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupRoles() { return createInitialState(); @@ -94,6 +95,6 @@ const rolesSlice = createSlice({ }, }); -const { setIsLoading, cleanupRoles } = rolesSlice.actions; +const { setLoadState, cleanupRoles } = rolesSlice.actions; export { getRoles, getProducts, refreshRoles, cleanupRoles }; export default rolesSlice.reducer; From 9c76bdf7fa013e1f3ec3e8723e574fc448831ce9 Mon Sep 17 00:00:00 2001 From: Vladislav Paskov Date: Fri, 29 Dec 2023 10:13:33 +0000 Subject: [PATCH 011/151] ADCM-5171: Bundle list scrolling is not working while creating a cluster https://tracker.yandex.ru/ADCM-5171 --- .../Dialogs/CreateClusterDialog/CreateClusterDialog.tsx | 1 + .../src/components/uikit/Select/SingleSelect/Select/Select.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/adcm-web/app/src/components/pages/ClustersPage/Dialogs/CreateClusterDialog/CreateClusterDialog.tsx b/adcm-web/app/src/components/pages/ClustersPage/Dialogs/CreateClusterDialog/CreateClusterDialog.tsx index 5e52f4b7a8..ed95dcb6d4 100644 --- a/adcm-web/app/src/components/pages/ClustersPage/Dialogs/CreateClusterDialog/CreateClusterDialog.tsx +++ b/adcm-web/app/src/components/pages/ClustersPage/Dialogs/CreateClusterDialog/CreateClusterDialog.tsx @@ -82,6 +82,7 @@ const CreateClusterDialog = () => { value={formData.productVersion} onChange={handleProductVersionChange} options={productVersionsOptions} + maxHeight={200} /> diff --git a/adcm-web/app/src/components/uikit/Select/SingleSelect/Select/Select.tsx b/adcm-web/app/src/components/uikit/Select/SingleSelect/Select/Select.tsx index a5a9fca036..acc646b62d 100644 --- a/adcm-web/app/src/components/uikit/Select/SingleSelect/Select/Select.tsx +++ b/adcm-web/app/src/components/uikit/Select/SingleSelect/Select/Select.tsx @@ -18,7 +18,7 @@ function SelectComponent( value, onChange, noneLabel, - maxHeight, + maxHeight = 200, isSearchable, searchPlaceholder, containerRef, From dd5b9a45483a2fbb869b6f9d82aafada9168f03a Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Fri, 29 Dec 2023 13:49:43 +0000 Subject: [PATCH 012/151] [UI] ADCM-5174: Add LoadStates to Clusters services https://tracker.yandex.ru/ADCM-5174 --- .../ClustersTable/ClustersTable.tsx | 3 ++- .../ClusterServicesTable.tsx | 3 ++- .../ServiceComponentsTable.tsx | 3 ++- .../serviceComponents/serviceComponentsSlice.ts | 15 ++++++++------- .../adcm/cluster/services/servicesSlice.ts | 15 ++++++++------- .../src/store/adcm/clusters/clustersSlice.ts | 17 +++++++++-------- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/adcm-web/app/src/components/pages/ClustersPage/ClustersTable/ClustersTable.tsx b/adcm-web/app/src/components/pages/ClustersPage/ClustersTable/ClustersTable.tsx index 6e4af793cf..3c83270acc 100644 --- a/adcm-web/app/src/components/pages/ClustersPage/ClustersTable/ClustersTable.tsx +++ b/adcm-web/app/src/components/pages/ClustersPage/ClustersTable/ClustersTable.tsx @@ -11,11 +11,12 @@ import { SortParams } from '@uikit/types/list.types'; import ClusterDynamicActionsIcon from '@pages/ClustersPage/ClustersTable/ClusterDynamicActionsIcon/ClusterDynamicActionsIcon'; import MultiStateCell from '@commonComponents/Table/Cells/MultiStateCell'; import { openClusterUpgradeDialog } from '@store/adcm/clusters/clusterUpgradesSlice'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const ClustersTable = () => { const dispatch = useDispatch(); const clusters = useStore((s) => s.adcm.clusters.clusters); - const isLoading = useStore((s) => s.adcm.clusters.isLoading); + const isLoading = useStore((s) => isShowSpinner(s.adcm.clusters.loadState)); const sortParams = useStore((s) => s.adcm.clustersTable.sortParams); const handleUpgradeClick = (cluster: AdcmCluster) => { diff --git a/adcm-web/app/src/components/pages/cluster/ClusterServices/ClusterServicesTable/ClusterServicesTable.tsx b/adcm-web/app/src/components/pages/cluster/ClusterServices/ClusterServicesTable/ClusterServicesTable.tsx index b5833f9ea8..abf7f19cb7 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterServices/ClusterServicesTable/ClusterServicesTable.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterServices/ClusterServicesTable/ClusterServicesTable.tsx @@ -12,13 +12,14 @@ import MultiStateCell from '@commonComponents/Table/Cells/MultiStateCell'; import MaintenanceModeButton from '@commonComponents/MaintenanceModeButton/MaintenanceModeButton'; import { AdcmService } from '@models/adcm'; import { openMaintenanceModeDialog } from '@store/adcm/cluster/services/servicesActionsSlice'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const ClusterServicesTable = () => { const dispatch = useDispatch(); const { clusterId: clusterIdFromUrl } = useParams(); const clusterId = Number(clusterIdFromUrl); const services = useStore((s) => s.adcm.services.services); - const isLoading = useStore((s) => s.adcm.services.isLoading); + const isLoading = useStore((s) => isShowSpinner(s.adcm.services.loadState)); const sortParams = useStore((s) => s.adcm.servicesTable.sortParams); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); const isAddingServices = useStore(({ adcm }) => adcm.servicesActions.isAddingServices); diff --git a/adcm-web/app/src/components/pages/cluster/service/ServiceComponents/ServiceComponentsTable/ServiceComponentsTable.tsx b/adcm-web/app/src/components/pages/cluster/service/ServiceComponents/ServiceComponentsTable/ServiceComponentsTable.tsx index 8ee6ea8a17..6a27539b02 100644 --- a/adcm-web/app/src/components/pages/cluster/service/ServiceComponents/ServiceComponentsTable/ServiceComponentsTable.tsx +++ b/adcm-web/app/src/components/pages/cluster/service/ServiceComponents/ServiceComponentsTable/ServiceComponentsTable.tsx @@ -11,11 +11,12 @@ import { openMaintenanceModeDialog } from '@store/adcm/cluster/services/serviceC import { AdcmServiceComponent } from '@models/adcm'; import ClusterServiceComponentsDynamicActionsIcon from '../ServiceComponentsDynamicActionsIcon/ServiceComponentsDynamicActionsIcon'; import { usePersistServiceComponentsTableSettings } from '../usePersistServiceComponentsTableSettings'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const ServiceComponentsTable = () => { const dispatch = useDispatch(); const components = useStore((s) => s.adcm.serviceComponents.serviceComponents); - const isLoading = useStore((s) => s.adcm.serviceComponents.isLoading); + const isLoading = useStore((s) => isShowSpinner(s.adcm.serviceComponents.loadState)); const sortParams = useStore((s) => s.adcm.serviceComponentsTable.sortParams); usePersistServiceComponentsTableSettings(); diff --git a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponentsSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponentsSlice.ts index d1fa7f568d..6d9bdad417 100644 --- a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponentsSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponentsSlice.ts @@ -9,11 +9,12 @@ import { executeWithMinDelay } from '@utils/requestUtils'; import { updateIfExists } from '@utils/objectUtils'; import { wsActions } from '@store/middlewares/wsMiddleware.constants'; import { toggleMaintenanceMode } from '@store/adcm/cluster/services/serviceComponents/serviceComponentsActionsSlice'; +import { LoadState } from '@models/loadState'; interface AdcmServiceComponentsState { serviceComponents: AdcmServiceComponent[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; } interface LoadClusterServiceComponentsPayload { @@ -48,7 +49,7 @@ const loadClusterServiceComponentsFromBackend = createAsyncThunk( const getServiceComponents = createAsyncThunk( 'adcm/cluster/services/serviceComponents/getServiceComponents', async (arg: LoadClusterServiceComponentsPayload, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadClusterServiceComponentsFromBackend(arg)); @@ -57,7 +58,7 @@ const getServiceComponents = createAsyncThunk( startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }, @@ -73,15 +74,15 @@ const refreshServiceComponents = createAsyncThunk( const createInitialState = (): AdcmServiceComponentsState => ({ serviceComponents: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, }); const serviceComponentsSlice = createSlice({ name: 'adcm/cluster/services/serviceComponents', initialState: createInitialState(), reducers: { - setIsLoading: (state, action) => { - state.isLoading = action.payload; + setLoadState: (state, action) => { + state.loadState = action.payload; }, cleanupServiceComponents: () => { return createInitialState(); @@ -134,7 +135,7 @@ const serviceComponentsSlice = createSlice({ }, }); -const { setIsLoading, cleanupServiceComponents } = serviceComponentsSlice.actions; +const { setLoadState, cleanupServiceComponents } = serviceComponentsSlice.actions; export { getServiceComponents, refreshServiceComponents, diff --git a/adcm-web/app/src/store/adcm/cluster/services/servicesSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/servicesSlice.ts index 0067601154..1888538489 100644 --- a/adcm-web/app/src/store/adcm/cluster/services/servicesSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/services/servicesSlice.ts @@ -10,12 +10,13 @@ import { updateIfExists } from '@utils/objectUtils'; import { AdcmPrototypesApi, RequestError } from '@api'; import { wsActions } from '@store/middlewares/wsMiddleware.constants'; import { toggleMaintenanceMode } from '@store/adcm/cluster/services/servicesActionsSlice'; +import { LoadState } from '@models/loadState'; type AdcmServicesState = { services: AdcmService[]; serviceLicense: Omit[] | []; totalCount: number; - isLoading: boolean; + loadState: LoadState; }; interface LoadClusterServicesPayload { @@ -41,7 +42,7 @@ const loadClusterServiceFromBackend = createAsyncThunk( ); const getServices = createAsyncThunk('adcm/services/getServices', async (arg: LoadClusterServicesPayload, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadClusterServiceFromBackend(arg)); @@ -49,7 +50,7 @@ const getServices = createAsyncThunk('adcm/services/getServices', async (arg: Lo startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -77,15 +78,15 @@ const createInitialState = (): AdcmServicesState => ({ services: [], serviceLicense: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, }); const servicesSlice = createSlice({ name: 'adcm/services', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupServices() { return createInitialState(); @@ -148,7 +149,7 @@ const servicesSlice = createSlice({ }, }); -export const { setIsLoading, cleanupServices, cleanupServiceLicense } = servicesSlice.actions; +export const { setLoadState, cleanupServices, cleanupServiceLicense } = servicesSlice.actions; export { getServices, refreshServices, acceptServiceLicense }; export default servicesSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/clusters/clustersSlice.ts b/adcm-web/app/src/store/adcm/clusters/clustersSlice.ts index 1895a5efea..ccfe4323ca 100644 --- a/adcm-web/app/src/store/adcm/clusters/clustersSlice.ts +++ b/adcm-web/app/src/store/adcm/clusters/clustersSlice.ts @@ -6,11 +6,12 @@ import { executeWithMinDelay } from '@utils/requestUtils'; import { updateIfExists } from '@utils/objectUtils'; import { defaultSpinnerDelay } from '@constants'; import { wsActions } from '@store/middlewares/wsMiddleware.constants'; +import { LoadState } from '@models/loadState'; type AdcmClustersState = { clusters: AdcmCluster[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; }; const loadClustersFromBackend = createAsyncThunk('adcm/clusters/loadClustersFromBackend', async (arg, thunkAPI) => { @@ -29,7 +30,7 @@ const loadClustersFromBackend = createAsyncThunk('adcm/clusters/loadClustersFrom }); const getClusters = createAsyncThunk('adcm/clusters/getClusters', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadClustersFromBackend()); @@ -38,7 +39,7 @@ const getClusters = createAsyncThunk('adcm/clusters/getClusters', async (arg, th startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -50,15 +51,15 @@ const refreshClusters = createAsyncThunk('adcm/clusters/refreshClusters', async const createInitialState = (): AdcmClustersState => ({ clusters: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, }); const clustersSlice = createSlice({ name: 'adcm/clusters', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupClusters() { return createInitialState(); @@ -103,6 +104,6 @@ const clustersSlice = createSlice({ }, }); -const { setIsLoading, cleanupClusters } = clustersSlice.actions; -export { getClusters, refreshClusters, cleanupClusters }; +const { setLoadState, cleanupClusters } = clustersSlice.actions; +export { getClusters, refreshClusters, cleanupClusters, setLoadState }; export default clustersSlice.reducer; From 66da19b2c56d582f6cb9c55ec0fae9926619f2b9 Mon Sep 17 00:00:00 2001 From: Kirill Fedorenko Date: Tue, 9 Jan 2024 07:25:57 +0000 Subject: [PATCH 013/151] ADCM-5173 [UI] HostProvider. Hosts. LoadState https://tracker.yandex.ru/ADCM-5173 --- .../HostProvidersTable/HostProvidersTable.tsx | 3 ++- .../pages/HostsPage/HostsTable/HostsTable.tsx | 3 ++- .../ClusterHostsTable/ClusterHostsTable.tsx | 3 ++- .../HostComponentsTable/HostComponentsTable.tsx | 3 ++- .../src/store/adcm/cluster/hosts/hostsSlice.ts | 15 ++++++++------- .../adcm/hostComponents/hostComponentsSlice.ts | 15 ++++++++------- .../hostProviders/hostProvidersActionsSlice.ts | 5 +++-- .../adcm/hostProviders/hostProvidersSlice.ts | 17 +++++++++-------- adcm-web/app/src/store/adcm/hosts/hostsSlice.ts | 15 ++++++++------- 9 files changed, 44 insertions(+), 35 deletions(-) diff --git a/adcm-web/app/src/components/pages/HostProvidersPage/HostProvidersTable/HostProvidersTable.tsx b/adcm-web/app/src/components/pages/HostProvidersPage/HostProvidersTable/HostProvidersTable.tsx index a155ee4790..2e3ecf52f1 100644 --- a/adcm-web/app/src/components/pages/HostProvidersPage/HostProvidersTable/HostProvidersTable.tsx +++ b/adcm-web/app/src/components/pages/HostProvidersPage/HostProvidersTable/HostProvidersTable.tsx @@ -11,12 +11,13 @@ import MultiStateCell from '@commonComponents/Table/Cells/MultiStateCell'; import HostProvidersDynamicActionsIcon from '../HostProvidersDynamicActionsIcon/HostProvidersDynamicActionsIcon'; import { AdcmHostProvider } from '@models/adcm'; import { opeHostProviderUpgradeDialog } from '@store/adcm/hostProviders/hostProviderUpgradesSlice'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const HostProviderTable = () => { const dispatch = useDispatch(); const hostProviders = useStore(({ adcm }) => adcm.hostProviders.hostProviders); - const isLoading = useStore(({ adcm }) => adcm.hostProviders.isLoading); + const isLoading = useStore(({ adcm }) => isShowSpinner(adcm.hostProviders.loadState)); const sortParams = useStore(({ adcm }) => adcm.hostProvidersTable.sortParams); const handleDeleteAction = (id: number) => { diff --git a/adcm-web/app/src/components/pages/HostsPage/HostsTable/HostsTable.tsx b/adcm-web/app/src/components/pages/HostsPage/HostsTable/HostsTable.tsx index 75f1392fb1..1b9ec2d55e 100644 --- a/adcm-web/app/src/components/pages/HostsPage/HostsTable/HostsTable.tsx +++ b/adcm-web/app/src/components/pages/HostsPage/HostsTable/HostsTable.tsx @@ -15,12 +15,13 @@ import MultiStateCell from '@commonComponents/Table/Cells/MultiStateCell'; import Concern from '@commonComponents/Concern/Concern'; import { AdcmEntitySystemState } from '@models/adcm'; import { Link } from 'react-router-dom'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const HostsTable: React.FC = () => { const dispatch = useDispatch(); const hosts = useStore(({ adcm }) => adcm.hosts.hosts); - const isLoading = useStore(({ adcm }) => adcm.hosts.isLoading); + const isLoading = useStore(({ adcm }) => isShowSpinner(adcm.hosts.loadState)); const sortParams = useStore((s) => s.adcm.hostsTable.sortParams); const handleClickMaintenanceMode = (host: AdcmHost) => () => { diff --git a/adcm-web/app/src/components/pages/cluster/ClusterHosts/ClusterHostsTable/ClusterHostsTable.tsx b/adcm-web/app/src/components/pages/cluster/ClusterHosts/ClusterHostsTable/ClusterHostsTable.tsx index 74cf6fdace..e58b468652 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterHosts/ClusterHostsTable/ClusterHostsTable.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterHosts/ClusterHostsTable/ClusterHostsTable.tsx @@ -13,13 +13,14 @@ import { Link, generatePath } from 'react-router-dom'; import ClusterHostsDynamicActionsButton from '../ClusterHostsDynamicActionsButton/ClusterHostsDynamicActionsButton'; import MultiStateCell from '@commonComponents/Table/Cells/MultiStateCell'; import Concern from '@commonComponents/Concern/Concern'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const ClusterHostsTable: React.FC = () => { const dispatch = useDispatch(); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); const clusterHosts = useStore(({ adcm }) => adcm.clusterHosts.hosts); - const isLoading = useStore(({ adcm }) => adcm.clusterHosts.isLoading); + const isLoading = useStore(({ adcm }) => isShowSpinner(adcm.clusterHosts.loadState)); const sortParams = useStore((s) => s.adcm.clusterHostsTable.sortParams); const handleSorting = (sortParams: SortParams) => { diff --git a/adcm-web/app/src/components/pages/cluster/host/HostComponents/HostComponentsTable/HostComponentsTable.tsx b/adcm-web/app/src/components/pages/cluster/host/HostComponents/HostComponentsTable/HostComponentsTable.tsx index 936df17b3f..d5a508f11b 100644 --- a/adcm-web/app/src/components/pages/cluster/host/HostComponents/HostComponentsTable/HostComponentsTable.tsx +++ b/adcm-web/app/src/components/pages/cluster/host/HostComponents/HostComponentsTable/HostComponentsTable.tsx @@ -9,13 +9,14 @@ import { SortParams } from '@uikit/types/list.types'; import { useDispatch, useStore } from '@hooks'; import HostComponentsDynamicActionsIcon from './HostComponentsDynamicActionsIcon/HostComponentsDynamicActionsIcon'; import { setSortParams } from '@store/adcm/hostComponents/hostComponentsTableSlice'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; const HostComponentsTable: React.FC = () => { const dispatch = useDispatch(); const { hostId: hostIdFromUrl } = useParams(); const hostId = Number(hostIdFromUrl); const hostComponents = useStore((s) => s.adcm.hostComponents.hostComponents); - const isLoading = useStore((s) => s.adcm.hostComponents.isLoading); + const isLoading = useStore((s) => isShowSpinner(s.adcm.hostComponents.loadState)); const sortParams = useStore((s) => s.adcm.hostComponentsTable.sortParams); const handleSorting = (sortParams: SortParams) => { diff --git a/adcm-web/app/src/store/adcm/cluster/hosts/hostsSlice.ts b/adcm-web/app/src/store/adcm/cluster/hosts/hostsSlice.ts index 6a7067bb88..2d3f6362b5 100644 --- a/adcm-web/app/src/store/adcm/cluster/hosts/hostsSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/hosts/hostsSlice.ts @@ -7,11 +7,12 @@ import { AdcmClusterHost } from '@models/adcm/clusterHosts'; import { wsActions } from '@store/middlewares/wsMiddleware.constants'; import { updateIfExists } from '@utils/objectUtils'; import { toggleMaintenanceMode } from '@store/adcm/cluster/hosts/hostsActionsSlice'; +import { LoadState } from '@models/loadState'; type AdcmClusterHostsState = { hosts: AdcmClusterHost[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; }; const loadClusterHostsFromBackend = createAsyncThunk( @@ -33,7 +34,7 @@ const loadClusterHostsFromBackend = createAsyncThunk( ); const getClusterHosts = createAsyncThunk('adcm/clusters/getClusterHosts', async (clusterId: number, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadClusterHostsFromBackend(clusterId)); @@ -42,7 +43,7 @@ const getClusterHosts = createAsyncThunk('adcm/clusters/getClusterHosts', async startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -57,15 +58,15 @@ const refreshClusterHosts = createAsyncThunk( const createInitialState = (): AdcmClusterHostsState => ({ hosts: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, }); const clusterHostsSlice = createSlice({ name: 'adcm/clusterHosts', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupClusterHosts() { return createInitialState(); @@ -116,6 +117,6 @@ const clusterHostsSlice = createSlice({ }, }); -const { setIsLoading, cleanupClusterHosts } = clusterHostsSlice.actions; +const { setLoadState, cleanupClusterHosts } = clusterHostsSlice.actions; export { getClusterHosts, refreshClusterHosts, cleanupClusterHosts }; export default clusterHostsSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/hostComponents/hostComponentsSlice.ts b/adcm-web/app/src/store/adcm/hostComponents/hostComponentsSlice.ts index 9689519d56..078bb04d06 100644 --- a/adcm-web/app/src/store/adcm/hostComponents/hostComponentsSlice.ts +++ b/adcm-web/app/src/store/adcm/hostComponents/hostComponentsSlice.ts @@ -1,6 +1,7 @@ import { AdcmClusterHostsApi, RequestError } from '@api'; import { defaultSpinnerDelay } from '@constants'; import { AdcmServiceComponent } from '@models/adcm'; +import { LoadState } from '@models/loadState'; import { createSlice } from '@reduxjs/toolkit'; import { wsActions } from '@store/middlewares/wsMiddleware.constants'; import { showError } from '@store/notificationsSlice'; @@ -10,7 +11,7 @@ import { updateIfExists } from '@utils/objectUtils'; import { executeWithMinDelay } from '@utils/requestUtils'; interface AdcmHostComponentsState { - isLoading: boolean; + loadState: LoadState; hostComponents: AdcmServiceComponent[]; totalCount: number; } @@ -47,7 +48,7 @@ const loadHostComponents = createAsyncThunk( const getHostComponents = createAsyncThunk( 'adcm/hostComponents/getHostComponents', async (arg: ClusterHostComponentsPayload, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadHostComponents(arg)); @@ -57,7 +58,7 @@ const getHostComponents = createAsyncThunk( delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }, @@ -71,7 +72,7 @@ const refreshHostComponents = createAsyncThunk( ); const createInitialState = (): AdcmHostComponentsState => ({ - isLoading: true, + loadState: LoadState.NotLoaded, hostComponents: [], totalCount: 0, }); @@ -80,8 +81,8 @@ const hostComponentsSlice = createSlice({ name: 'adcm/hostComponents', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupHostComponents() { return createInitialState(); @@ -129,6 +130,6 @@ const hostComponentsSlice = createSlice({ }, }); -const { setIsLoading, cleanupHostComponents } = hostComponentsSlice.actions; +const { setLoadState, cleanupHostComponents } = hostComponentsSlice.actions; export { getHostComponents, refreshHostComponents, cleanupHostComponents }; export default hostComponentsSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/hostProviders/hostProvidersActionsSlice.ts b/adcm-web/app/src/store/adcm/hostProviders/hostProvidersActionsSlice.ts index 7630aeeec1..f9bd62d3f4 100644 --- a/adcm-web/app/src/store/adcm/hostProviders/hostProvidersActionsSlice.ts +++ b/adcm-web/app/src/store/adcm/hostProviders/hostProvidersActionsSlice.ts @@ -3,7 +3,8 @@ import { createAsyncThunk } from '@store/redux'; import { AdcmHostProvidersApi, RequestError } from '@api'; import { showError, showInfo } from '@store/notificationsSlice'; import { getErrorMessage } from '@utils/httpResponseUtils'; -import { getHostProviders, setIsLoading } from './hostProvidersSlice'; +import { getHostProviders, setLoadState } from './hostProvidersSlice'; +import { LoadState } from '@models/loadState'; interface AdcmHostProvidersActionsState { deleteDialog: { @@ -28,7 +29,7 @@ const deleteHostProvider = createAsyncThunk( const deleteWithUpdateHostProvider = createAsyncThunk( 'adcm/hostProvidersActions/deleteWithUpdateHostProvider', async (deletableId: number, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); await thunkAPI.dispatch(deleteHostProvider(deletableId)); await thunkAPI.dispatch(getHostProviders()); }, diff --git a/adcm-web/app/src/store/adcm/hostProviders/hostProvidersSlice.ts b/adcm-web/app/src/store/adcm/hostProviders/hostProvidersSlice.ts index 8a239acd27..2d300a9f96 100644 --- a/adcm-web/app/src/store/adcm/hostProviders/hostProvidersSlice.ts +++ b/adcm-web/app/src/store/adcm/hostProviders/hostProvidersSlice.ts @@ -6,11 +6,12 @@ import { executeWithMinDelay } from '@utils/requestUtils'; import { updateIfExists } from '@utils/objectUtils'; import { defaultSpinnerDelay } from '@constants'; import { wsActions } from '@store/middlewares/wsMiddleware.constants'; +import { LoadState } from '@models/loadState'; interface AdcmHostProvidersState { hostProviders: AdcmHostProvider[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; } const loadHostProviders = createAsyncThunk('adcm/hostProviders/loadHostProviders', async (arg, thunkAPI) => { @@ -29,7 +30,7 @@ const loadHostProviders = createAsyncThunk('adcm/hostProviders/loadHostProviders }); const getHostProviders = createAsyncThunk('adcm/hostProviders/getHostProviders', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadHostProviders()); @@ -38,7 +39,7 @@ const getHostProviders = createAsyncThunk('adcm/hostProviders/getHostProviders', startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -50,15 +51,15 @@ const refreshHostProviders = createAsyncThunk('adcm/hostProviders/refreshHostPro const createInitialState = (): AdcmHostProvidersState => ({ hostProviders: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, }); const hostProvidersSlice = createSlice({ name: 'adcm/hostProviders', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupHostProviders() { return createInitialState(); @@ -104,7 +105,7 @@ const hostProvidersSlice = createSlice({ }, }); -const { setIsLoading, cleanupHostProviders } = hostProvidersSlice.actions; -export { getHostProviders, cleanupHostProviders, refreshHostProviders, setIsLoading }; +const { setLoadState, cleanupHostProviders } = hostProvidersSlice.actions; +export { getHostProviders, cleanupHostProviders, refreshHostProviders, setLoadState }; export default hostProvidersSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/hosts/hostsSlice.ts b/adcm-web/app/src/store/adcm/hosts/hostsSlice.ts index b28cd1ea73..0485547040 100644 --- a/adcm-web/app/src/store/adcm/hosts/hostsSlice.ts +++ b/adcm-web/app/src/store/adcm/hosts/hostsSlice.ts @@ -7,11 +7,12 @@ import { AdcmHostsApi } from '@api'; import { updateIfExists } from '@utils/objectUtils'; import { wsActions } from '@store/middlewares/wsMiddleware.constants'; import { toggleMaintenanceMode } from '@store/adcm/hosts/hostsActionsSlice'; +import { LoadState } from '@models/loadState'; type AdcmHostsState = { hosts: AdcmHost[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; }; const loadHosts = createAsyncThunk('adcm/hosts/loadHosts', async (arg, thunkAPI) => { @@ -30,7 +31,7 @@ const loadHosts = createAsyncThunk('adcm/hosts/loadHosts', async (arg, thunkAPI) }); const getHosts = createAsyncThunk('adcm/hosts/getHosts', async (arg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadHosts()); @@ -39,7 +40,7 @@ const getHosts = createAsyncThunk('adcm/hosts/getHosts', async (arg, thunkAPI) = startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }); @@ -51,15 +52,15 @@ const refreshHosts = createAsyncThunk('adcm/hosts/refreshHosts', async (arg, thu const createInitialState = (): AdcmHostsState => ({ hosts: [], totalCount: 0, - isLoading: true, + loadState: LoadState.NotLoaded, }); const hostsSlice = createSlice({ name: 'adcm/hosts', initialState: createInitialState(), reducers: { - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, cleanupHosts() { return createInitialState(); @@ -110,7 +111,7 @@ const hostsSlice = createSlice({ }, }); -export const { setIsLoading, cleanupHosts } = hostsSlice.actions; +export const { setLoadState, cleanupHosts } = hostsSlice.actions; export { getHosts, refreshHosts }; export default hostsSlice.reducer; From 53f51128e453c60f84bb930a72bfc06f4611ebdc Mon Sep 17 00:00:00 2001 From: Egor Araslanov Date: Tue, 9 Jan 2024 16:09:47 +0500 Subject: [PATCH 014/151] ADCM-5178 Added missing unit test on case when user is trying to add host that is already added to target cluster --- python/api_v2/tests/test_host.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/python/api_v2/tests/test_host.py b/python/api_v2/tests/test_host.py index 00883c609e..33f3dbb54a 100644 --- a/python/api_v2/tests/test_host.py +++ b/python/api_v2/tests/test_host.py @@ -261,6 +261,20 @@ def test_create_belonging_to_another_cluster_fail(self): {"code": "FOREIGN_HOST", "desc": "Host already linked to another cluster.", "level": "error"}, ) + def test_create_already_added_fail(self) -> None: + self.add_host_to_cluster(cluster=self.cluster_1, host=self.host) + + response = self.client.post( + path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data={"hostId": self.host.pk}, + ) + + self.assertEqual(response.status_code, HTTP_409_CONFLICT) + self.assertDictEqual( + response.json(), + {"code": "HOST_CONFLICT", "desc": "The host is already associated with this cluster.", "level": "error"}, + ) + def test_create_not_found_fail(self): response = self.client.post( path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), From 752484217599238de106220f4bf3cb575ebb603d Mon Sep 17 00:00:00 2001 From: Vladimir Remizov Date: Tue, 9 Jan 2024 15:01:01 +0000 Subject: [PATCH 015/151] [UI] feature/ADCM-1474 fix throttle job page with many subtask https://tracker.yandex.ru/ADCM-5123 --- adcm-web/app/.eslintrc.json | 1 + .../BundleOverviewTable.tsx | 1 - .../pages/JobsPage/JobPage/JobPage.tsx | 4 +- .../JobPageChildJobsTable.tsx | 91 +++++++++---------- .../TaskChildRow/TaskChildRow.tsx | 48 ++++++++++ .../JobPage/JobPageLog/JobPageLog.module.scss | 4 + .../JobPage/JobPageLog/JobPageLog.tsx | 7 ++ .../JobPageLog/useRequestJobLogPage.ts | 9 +- .../AuditOperationsTable.module.scss | 22 ++++- .../CodeHighlighter.module.scss | 6 ++ .../uikit/CodeHighlighter/CodeHighlighter.tsx | 41 ++++++--- .../uikit/Table/TableRow/ExpandableRow.tsx | 32 +------ adcm-web/app/src/hooks/index.ts | 1 + adcm-web/app/src/hooks/useExpandableTable.ts | 24 +++++ 14 files changed, 189 insertions(+), 102 deletions(-) create mode 100644 adcm-web/app/src/components/pages/JobsPage/JobPage/JobPageChildJobsTable/TaskChildRow/TaskChildRow.tsx create mode 100644 adcm-web/app/src/hooks/useExpandableTable.ts diff --git a/adcm-web/app/.eslintrc.json b/adcm-web/app/.eslintrc.json index 0c63027985..a0d06cc018 100644 --- a/adcm-web/app/.eslintrc.json +++ b/adcm-web/app/.eslintrc.json @@ -114,6 +114,7 @@ "tgz", "toggler", "tooltip", + "txt", "ttl", "ul", "unlink", diff --git a/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewTable/BundleOverviewTable.tsx b/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewTable/BundleOverviewTable.tsx index caed1daa82..133fa916b0 100644 --- a/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewTable/BundleOverviewTable.tsx +++ b/adcm-web/app/src/components/pages/BundleOverviewPage/BundleOverviewTable/BundleOverviewTable.tsx @@ -24,7 +24,6 @@ const BundleOverviewTable: React.FC = () => { {orElseGet(licenseLink, () => { return ( - // eslint-disable-next-line spellcheck/spell-checker EULA.txt diff --git a/adcm-web/app/src/components/pages/JobsPage/JobPage/JobPage.tsx b/adcm-web/app/src/components/pages/JobsPage/JobPage/JobPage.tsx index 856e17434a..2838b04bf1 100644 --- a/adcm-web/app/src/components/pages/JobsPage/JobPage/JobPage.tsx +++ b/adcm-web/app/src/components/pages/JobsPage/JobPage/JobPage.tsx @@ -12,12 +12,12 @@ const JobPage: React.FC = () => { const { task, dispatch } = useRequestJobPage(); useEffect(() => { - if (task) { + if (task.displayName) { const jobBreadcrumbs = [{ href: '/jobs', label: 'Jobs' }, { label: task.displayName }]; dispatch(setBreadcrumbs(jobBreadcrumbs)); } - }, [task, dispatch]); + }, [task.displayName, dispatch]); return ( <> diff --git a/adcm-web/app/src/components/pages/JobsPage/JobPage/JobPageChildJobsTable/JobPageChildJobsTable.tsx b/adcm-web/app/src/components/pages/JobsPage/JobPage/JobPageChildJobsTable/JobPageChildJobsTable.tsx index 5d54cc2ad1..3257b96264 100644 --- a/adcm-web/app/src/components/pages/JobsPage/JobPage/JobPageChildJobsTable/JobPageChildJobsTable.tsx +++ b/adcm-web/app/src/components/pages/JobsPage/JobPage/JobPageChildJobsTable/JobPageChildJobsTable.tsx @@ -1,39 +1,57 @@ -import { Table, TableCell, IconButton, Button, ExpandableRowComponent } from '@uikit'; -import { useDispatch, useStore } from '@hooks'; +import React, { useCallback } from 'react'; +import { Table, ExpandableRowComponent } from '@uikit'; +import { useDispatch, useExpandableTable, useStore } from '@hooks'; import { columns } from './JobPageChildJobsTable.constants'; import { setSortParams } from '@store/adcm/jobs/jobsTableSlice'; import { SortParams } from '@uikit/types/list.types'; import { openStopDialog } from '@store/adcm/jobs/jobsActionsSlice'; -import { AdcmJobStatus } from '@models/adcm'; +import { AdcmJob } from '@models/adcm'; import s from './JobPageChildJobsTable.module.scss'; -import DateTimeCell from '@commonComponents/Table/Cells/DateTimeCell'; -import { secondsToDuration } from '@utils/date/timeConvertUtils'; import cn from 'classnames'; import JobPageLog from '../JobPageLog/JobPageLog'; -import { useState } from 'react'; -import JobsStatusCell from '@commonComponents/Table/Cells/JobsStatusCell/JobsStatusCell'; +import { orElseGet } from '@utils/checkUtils'; +import TaskChildRow from './TaskChildRow/TaskChildRow'; + +const callForJob = (el: HTMLElement, callback: (jobId: number) => void) => { + // eslint want that jobId (in camelCase), but JSX demands set data attributes in lowercase + // eslint-disable-next-line spellcheck/spell-checker + const jobId = orElseGet(el.dataset.jobid, Number, null); + if (jobId) { + callback(jobId); + } +}; const JobPageChildJobsTable = () => { const dispatch = useDispatch(); const task = useStore((s) => s.adcm.jobs.task); const isTaskLoading = useStore((s) => s.adcm.jobs.isTaskLoading); - const [expandableRows, setExpandableRows] = useState>({}); + const { expandableRows, toggleRow } = useExpandableTable(); - const handleExpandClick = (id: number) => () => { - setExpandableRows({ - ...expandableRows, - [id]: !expandableRows[id], - }); - }; + const handleExpandClick = useCallback( + ({ currentTarget }: React.MouseEvent) => { + callForJob(currentTarget, (jobId) => { + toggleRow(jobId); + }); + }, + [toggleRow], + ); - const handleStopClick = (id: number) => () => { - dispatch(openStopDialog(id)); - }; + const handleStopClick = useCallback( + ({ currentTarget }: React.MouseEvent) => { + callForJob(currentTarget, (jobId) => { + dispatch(openStopDialog(jobId)); + }); + }, + [dispatch], + ); - const handleSorting = (sortParams: SortParams) => { - dispatch(setSortParams(sortParams)); - }; + const handleSorting = useCallback( + (sortParams: SortParams) => { + dispatch(setSortParams(sortParams)); + }, + [dispatch], + ); return ( @@ -42,37 +60,12 @@ const JobPageChildJobsTable = () => { } - className={cn(s.rolesTable__roleRow, { [s.expandedRow]: expandableRows[job.id] })} + isExpanded={expandableRows.has(job.id)} + expandedContent={} + className={cn(s.rolesTable__roleRow)} expandedClassName={s.rolesTable__expandedRoleRow} > - - {job.displayName} - - {job.status} - {secondsToDuration(job.duration)} - - - - - - - setIsExpandHovered(true)} - onMouseLeave={() => setIsExpandHovered(false)} - > +
diff --git a/adcm-web/app/src/hooks/index.ts b/adcm-web/app/src/hooks/index.ts index 09890fd97d..618164ad4f 100644 --- a/adcm-web/app/src/hooks/index.ts +++ b/adcm-web/app/src/hooks/index.ts @@ -12,3 +12,4 @@ export { useRequestTimer } from './useRequestTimer'; export { useDownloadFile } from './useDownloadFile'; export { useForm } from './useForm'; export { usePersistSettings } from './usePersistSettings'; +export { useExpandableTable } from './useExpandableTable'; diff --git a/adcm-web/app/src/hooks/useExpandableTable.ts b/adcm-web/app/src/hooks/useExpandableTable.ts new file mode 100644 index 0000000000..295dc3f51d --- /dev/null +++ b/adcm-web/app/src/hooks/useExpandableTable.ts @@ -0,0 +1,24 @@ +import { useState, useCallback } from 'react'; + +export const useExpandableTable = () => { + const [expandableRows, setExpandableRows] = useState>(new Set()); + + const toggleRow = useCallback( + (key: T) => { + setExpandableRows((prev) => { + if (prev.has(key)) { + prev.delete(key); + } else { + prev.add(key); + } + return new Set([...prev]); + }); + }, + [setExpandableRows], + ); + + return { + expandableRows, + toggleRow, + }; +}; From 8571fa25618ca65b22b38af5d51668ae5d1d4d79 Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Wed, 10 Jan 2024 08:17:28 +0000 Subject: [PATCH 016/151] [UI] ADCM-5175: Add LoadStates to Clusters Import https://tracker.yandex.ru/ADCM-5175 --- .../useClusterImportsService.ts | 4 +++- .../ClusterImportsCluster/useClusterImports.ts | 4 +++- .../imports/cluster/clusterImportsSlice.ts | 17 +++++++++-------- .../service/clusterImportsServiceSlice.ts | 15 ++++++++------- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportServices/useClusterImportsService.ts b/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportServices/useClusterImportsService.ts index 36f40cd62a..15d0ab8a75 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportServices/useClusterImportsService.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportServices/useClusterImportsService.ts @@ -29,6 +29,7 @@ import { } from '@pages/cluster/ClusterImport/ClusterImport.utils'; import { PaginationParams } from '@models/table'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; export const useClusterImportsService = () => { const dispatch = useDispatch(); @@ -50,7 +51,8 @@ export const useClusterImportsService = () => { clusters: new Set(), services: new Set(), }); - const { clusterImports, hasSaveError, isLoading, totalCount } = useStore(({ adcm }) => adcm.clusterImportsService); + const { clusterImports, hasSaveError, totalCount } = useStore(({ adcm }) => adcm.clusterImportsService); + const isLoading = useStore((s) => isShowSpinner(s.adcm.clusterImportsService.loadState)); const { paginationParams, relatedData: { serviceList }, diff --git a/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportsCluster/useClusterImports.ts b/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportsCluster/useClusterImports.ts index 46f058e4f6..4339249e60 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportsCluster/useClusterImports.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportsCluster/useClusterImports.ts @@ -21,6 +21,7 @@ import { } from '@pages/cluster/ClusterImport/ClusterImport.utils'; import { setPaginationParams } from '@store/adcm/cluster/imports/cluster/clusterImportsFilterSlice'; import { PaginationParams } from '@models/table'; +import { isShowSpinner } from '@uikit/Table/Table.utils'; export const useClusterImports = () => { const dispatch = useDispatch(); @@ -39,7 +40,8 @@ export const useClusterImports = () => { clusters: new Set(), services: new Set(), }); - const { clusterImports, hasSaveError, isLoading, totalCount } = useStore(({ adcm }) => adcm.clusterImports); + const { clusterImports, hasSaveError, totalCount } = useStore(({ adcm }) => adcm.clusterImports); + const isLoading = useStore((s) => isShowSpinner(s.adcm.clusterImports.loadState)); const { paginationParams } = useStore(({ adcm }) => adcm.clusterImportsFilter); useEffect(() => { diff --git a/adcm-web/app/src/store/adcm/cluster/imports/cluster/clusterImportsSlice.ts b/adcm-web/app/src/store/adcm/cluster/imports/cluster/clusterImportsSlice.ts index b748e07433..0e9cf24f1b 100644 --- a/adcm-web/app/src/store/adcm/cluster/imports/cluster/clusterImportsSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/imports/cluster/clusterImportsSlice.ts @@ -5,6 +5,7 @@ import { AdcmClusterImport, AdcmClusterImportPostPayload, AdcmError } from '@mod import { executeWithMinDelay } from '@utils/requestUtils'; import { defaultSpinnerDelay } from '@constants'; import { showError, showInfo } from '@store/notificationsSlice'; +import { LoadState } from '@models/loadState'; type GetClusterImportsArg = { clusterId: number; @@ -18,7 +19,7 @@ export interface AdcmSaveClusterImportsArgs { type AdcmClusterImportsState = { clusterImports: AdcmClusterImport[]; totalCount: number; - isLoading: boolean; + loadState: LoadState; hasSaveError: boolean; }; @@ -57,7 +58,7 @@ const saveClusterImports = createAsyncThunk( const getClusterImports = createAsyncThunk( 'adcm/cluster/imports/getClusterImports', async (arg: GetClusterImportsArg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadClusterImports(arg)); @@ -66,7 +67,7 @@ const getClusterImports = createAsyncThunk( startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }, @@ -75,7 +76,7 @@ const getClusterImports = createAsyncThunk( const createInitialState = (): AdcmClusterImportsState => ({ clusterImports: [], hasSaveError: false, - isLoading: true, + loadState: LoadState.NotLoaded, totalCount: 0, }); @@ -86,8 +87,8 @@ const clusterImportsSlice = createSlice({ cleanupClusterImports() { return createInitialState(); }, - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, }, extraReducers: (builder) => { @@ -107,6 +108,6 @@ const clusterImportsSlice = createSlice({ }, }); -const { cleanupClusterImports, setIsLoading } = clusterImportsSlice.actions; -export { cleanupClusterImports, getClusterImports, saveClusterImports }; +const { cleanupClusterImports, setLoadState } = clusterImportsSlice.actions; +export { cleanupClusterImports, getClusterImports, saveClusterImports, setLoadState }; export default clusterImportsSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/imports/service/clusterImportsServiceSlice.ts b/adcm-web/app/src/store/adcm/cluster/imports/service/clusterImportsServiceSlice.ts index d2718a2a4b..6cbe919764 100644 --- a/adcm-web/app/src/store/adcm/cluster/imports/service/clusterImportsServiceSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/imports/service/clusterImportsServiceSlice.ts @@ -5,6 +5,7 @@ import { AdcmClusterImport, AdcmClusterImportPostPayload, AdcmError } from '@mod import { executeWithMinDelay } from '@utils/requestUtils'; import { defaultSpinnerDelay } from '@constants'; import { showError, showInfo } from '@store/notificationsSlice'; +import { LoadState } from '@models/loadState'; type GetClusterImportsArg = { clusterId: number; @@ -18,7 +19,7 @@ export interface AdcmSaveClusterImportsArgs { type AdcmClusterImportsState = { clusterImports: AdcmClusterImport[]; hasSaveError: boolean; - isLoading: boolean; + loadState: LoadState; totalCount: number; }; @@ -76,7 +77,7 @@ const saveClusterServiceImports = createAsyncThunk( const getClusterServiceImports = createAsyncThunk( 'adcm/cluster/imports/service/getClusterImports', async ({ clusterId }: GetClusterImportsArg, thunkAPI) => { - thunkAPI.dispatch(setIsLoading(true)); + thunkAPI.dispatch(setLoadState(LoadState.Loading)); const startDate = new Date(); await thunkAPI.dispatch(loadClusterServiceImports({ clusterId })); @@ -85,7 +86,7 @@ const getClusterServiceImports = createAsyncThunk( startDate, delay: defaultSpinnerDelay, callback: () => { - thunkAPI.dispatch(setIsLoading(false)); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, }); }, @@ -94,7 +95,7 @@ const getClusterServiceImports = createAsyncThunk( const createInitialState = (): AdcmClusterImportsState => ({ clusterImports: [], hasSaveError: false, - isLoading: false, + loadState: LoadState.Loaded, totalCount: 0, }); @@ -105,8 +106,8 @@ const clusterImportsServiceSlice = createSlice({ cleanupClusterServiceImports() { return createInitialState(); }, - setIsLoading(state, action) { - state.isLoading = action.payload; + setLoadState(state, action) { + state.loadState = action.payload; }, }, extraReducers: (builder) => { @@ -127,6 +128,6 @@ const clusterImportsServiceSlice = createSlice({ }, }); -const { cleanupClusterServiceImports, setIsLoading } = clusterImportsServiceSlice.actions; +const { cleanupClusterServiceImports, setLoadState } = clusterImportsServiceSlice.actions; export { cleanupClusterServiceImports, getClusterServiceImports, saveClusterServiceImports }; export default clusterImportsServiceSlice.reducer; From ee158e644466184a2ef842ed2fae638341005b0e Mon Sep 17 00:00:00 2001 From: Kirill Fedorenko Date: Wed, 10 Jan 2024 10:49:36 +0000 Subject: [PATCH 017/151] ADCM-5176 [UI] Move Bundles actions to their separate slice https://tracker.yandex.ru/ADCM-5176 --- .../BundleItemDeleteDialog.tsx | 6 +- .../BundlesPage/BundlesTable/BundlesTable.tsx | 9 +- .../BundleUploadButton/BundleUploadButton.tsx | 4 +- .../BundlesDeleteButton.tsx | 4 +- .../usePersistBundlesTableSettings.ts | 3 +- .../store/adcm/bundles/bundlesActionsSlice.ts | 130 ++++++++++++++++++ .../src/store/adcm/bundles/bundlesSlice.ts | 116 +--------------- .../store/adcm/bundles/bundlesTableSlice.ts | 7 +- adcm-web/app/src/store/store.ts | 2 + 9 files changed, 154 insertions(+), 127 deletions(-) create mode 100644 adcm-web/app/src/store/adcm/bundles/bundlesActionsSlice.ts diff --git a/adcm-web/app/src/components/pages/BundlesPage/BundlesActionsDialogs/BundleItemDeleteDialog/BundleItemDeleteDialog.tsx b/adcm-web/app/src/components/pages/BundlesPage/BundlesActionsDialogs/BundleItemDeleteDialog/BundleItemDeleteDialog.tsx index 957e1bd030..7586a23921 100644 --- a/adcm-web/app/src/components/pages/BundlesPage/BundlesActionsDialogs/BundleItemDeleteDialog/BundleItemDeleteDialog.tsx +++ b/adcm-web/app/src/components/pages/BundlesPage/BundlesActionsDialogs/BundleItemDeleteDialog/BundleItemDeleteDialog.tsx @@ -1,18 +1,18 @@ import React from 'react'; import Dialog from '@uikit/Dialog/Dialog'; import { useDispatch, useStore } from '@hooks'; -import { deleteWithUpdateBundles, setDeletableId } from '@store/adcm/bundles/bundlesSlice'; +import { deleteWithUpdateBundles, closeDeleteDialog } from '@store/adcm/bundles/bundlesActionsSlice'; const BundleItemDeleteDialog: React.FC = () => { const dispatch = useDispatch(); const bundles = useStore(({ adcm }) => adcm.bundles.bundles); - const deletableId = useStore(({ adcm }) => adcm.bundles.itemsForActions.deletableId); + const deletableId = useStore(({ adcm }) => adcm.bundlesActions.deleteDialog.id); const isOpen = deletableId !== null; const handleCloseDialog = () => { - dispatch(setDeletableId(null)); + dispatch(closeDeleteDialog()); }; const handleConfirmDialog = () => { diff --git a/adcm-web/app/src/components/pages/BundlesPage/BundlesTable/BundlesTable.tsx b/adcm-web/app/src/components/pages/BundlesPage/BundlesTable/BundlesTable.tsx index 8edb8d08ce..8c3765686a 100644 --- a/adcm-web/app/src/components/pages/BundlesPage/BundlesTable/BundlesTable.tsx +++ b/adcm-web/app/src/components/pages/BundlesPage/BundlesTable/BundlesTable.tsx @@ -6,7 +6,10 @@ import { orElseGet } from '@utils/checkUtils'; import { useSelectedItems } from '@uikit/hooks/useSelectedItems'; import { AdcmBundle } from '@models/adcm'; import DateTimeCell from '@commonComponents/Table/Cells/DateTimeCell'; -import { setDeletableId, setSelectedItemsIds as setSelectedBundlesIds } from '@store/adcm/bundles/bundlesSlice'; +import { + openDeleteDialog, + setSelectedItemsIds as setSelectedBundlesIds, +} from '@store/adcm/bundles/bundlesActionsSlice'; import { SortParams } from '@uikit/types/list.types'; import { setSortParams } from '@store/adcm/bundles/bundlesTableSlice'; import { Link } from 'react-router-dom'; @@ -20,7 +23,7 @@ const BundlesTable: React.FC = () => { const bundles = useStore(({ adcm }) => adcm.bundles.bundles); const isLoading = useStore(({ adcm }) => isShowSpinner(adcm.bundles.loadState)); - const selectedItemsIds = useStore(({ adcm }) => adcm.bundles.selectedItemsIds); + const selectedItemsIds = useStore(({ adcm }) => adcm.bundlesActions.selectedItemsIds); const sortParams = useStore((s) => s.adcm.bundlesTable.sortParams); const setSelectedItemsIds = useCallback>>( @@ -40,7 +43,7 @@ const BundlesTable: React.FC = () => { const getHandleDeleteClick = (bundleId: number) => () => { // set deletable id for show Delete Confirm Dialog - dispatch(setDeletableId(bundleId)); + dispatch(openDeleteDialog(bundleId)); }; const handleSorting = (sortParams: SortParams) => { diff --git a/adcm-web/app/src/components/pages/BundlesPage/BundlesTableToolbar/BundleUploadButton/BundleUploadButton.tsx b/adcm-web/app/src/components/pages/BundlesPage/BundlesTableToolbar/BundleUploadButton/BundleUploadButton.tsx index 6f76c86460..b3e9dd7fa3 100644 --- a/adcm-web/app/src/components/pages/BundlesPage/BundlesTableToolbar/BundleUploadButton/BundleUploadButton.tsx +++ b/adcm-web/app/src/components/pages/BundlesPage/BundlesTableToolbar/BundleUploadButton/BundleUploadButton.tsx @@ -1,11 +1,11 @@ import React, { ChangeEvent, useRef } from 'react'; import { Button } from '@uikit'; import { useDispatch, useStore } from '@hooks'; -import { uploadWithUpdateBundles } from '@store/adcm/bundles/bundlesSlice'; +import { uploadWithUpdateBundles } from '@store/adcm/bundles/bundlesActionsSlice'; const BundleUploadButton: React.FC = () => { const dispatch = useDispatch(); - const isUploading = useStore(({ adcm }) => adcm.bundles.isUploading); + const isUploading = useStore(({ adcm }) => adcm.bundlesActions.isUploading); const inputRef = useRef(null); diff --git a/adcm-web/app/src/components/pages/BundlesPage/BundlesTableToolbar/BundlesDeleteButton/BundlesDeleteButton.tsx b/adcm-web/app/src/components/pages/BundlesPage/BundlesTableToolbar/BundlesDeleteButton/BundlesDeleteButton.tsx index 013fe18624..e8ad9c1fa7 100644 --- a/adcm-web/app/src/components/pages/BundlesPage/BundlesTableToolbar/BundlesDeleteButton/BundlesDeleteButton.tsx +++ b/adcm-web/app/src/components/pages/BundlesPage/BundlesTableToolbar/BundlesDeleteButton/BundlesDeleteButton.tsx @@ -1,11 +1,11 @@ import React, { useState } from 'react'; import { Button, Dialog } from '@uikit'; import { useDispatch, useStore } from '@hooks'; -import { deleteWithUpdateBundles } from '@store/adcm/bundles/bundlesSlice'; +import { deleteWithUpdateBundles } from '@store/adcm/bundles/bundlesActionsSlice'; const BundlesDeleteButton: React.FC = () => { const dispatch = useDispatch(); - const selectedItemsIds = useStore(({ adcm }) => adcm.bundles.selectedItemsIds); + const selectedItemsIds = useStore(({ adcm }) => adcm.bundlesActions.selectedItemsIds); const isSelectedSomeRows = selectedItemsIds.length > 0; const [isOpenDeleteConfirm, setIsOpenDeleteConfirm] = useState(false); diff --git a/adcm-web/app/src/components/pages/BundlesPage/usePersistBundlesTableSettings.ts b/adcm-web/app/src/components/pages/BundlesPage/usePersistBundlesTableSettings.ts index b71041044e..2930ab64d6 100644 --- a/adcm-web/app/src/components/pages/BundlesPage/usePersistBundlesTableSettings.ts +++ b/adcm-web/app/src/components/pages/BundlesPage/usePersistBundlesTableSettings.ts @@ -9,6 +9,7 @@ import { } from '@store/adcm/bundles/bundlesTableSlice'; import { mergePaginationParams } from '@hooks/usePersistSettings'; import { AdcmBundlesFilter } from '@models/adcm/bundle'; +import { LoadState } from '@models/loadState'; const mergeFilters = ( filterFromStorage: AdcmBundlesFilter, @@ -34,7 +35,7 @@ export const usePersistBundlesTableSettings = () => { const requestFrequency = useStore(({ adcm }) => adcm.bundlesTable.requestFrequency); const products = useStore(({ adcm }) => adcm.bundlesTable.relatedData.products); - const isAllDataLoaded = useStore(({ adcm }) => adcm.bundlesTable.relatedData.isProductsLoaded); + const isAllDataLoaded = useStore(({ adcm }) => adcm.bundlesTable.relatedData.productsLoadState) === LoadState.Loaded; const { perPage } = paginationParams; diff --git a/adcm-web/app/src/store/adcm/bundles/bundlesActionsSlice.ts b/adcm-web/app/src/store/adcm/bundles/bundlesActionsSlice.ts new file mode 100644 index 0000000000..56e4716d7b --- /dev/null +++ b/adcm-web/app/src/store/adcm/bundles/bundlesActionsSlice.ts @@ -0,0 +1,130 @@ +import { createSlice } from '@reduxjs/toolkit'; +import { createAsyncThunk } from '@store/redux'; +import { getBundles, refreshBundles, setLoadState } from './bundlesSlice'; +import { AdcmBundlesApi, RequestError } from '@api'; +import { LoadState } from '@models/loadState'; +import { showInfo, showError } from '@store/notificationsSlice'; +import { getErrorMessage } from '@utils/httpResponseUtils'; +import { rejectedFilter } from '@utils/promiseUtils'; + +interface AdcmBundlesActionsState { + isUploading: boolean; + deleteDialog: { + id: number | null; + }; + selectedItemsIds: number[]; +} + +const deleteBundles = createAsyncThunk( + 'adcm/bundlesActions/deleteBundles', + async (selectedBundlesIds: number[], thunkAPI) => { + try { + const deletePromises = await Promise.allSettled(selectedBundlesIds.map((id) => AdcmBundlesApi.deleteBundle(id))); + const responsesList = rejectedFilter(deletePromises); + + if (responsesList.length > 0) { + throw responsesList[0]; + } + const message = + selectedBundlesIds.length > 1 ? 'All selected bundles have been deleted' : 'The bundle has been deleted'; + thunkAPI.dispatch(showInfo({ message })); + return []; + } catch (error) { + thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); + return thunkAPI.rejectWithValue([]); + } + }, +); + +/** + * Deleted some bundles + * And update bundles list + */ +const deleteWithUpdateBundles = createAsyncThunk( + 'adcm/bundlesActions/deleteWithUpdateBundles', + async (selectedBundlesIds: number[], thunkAPI) => { + thunkAPI.dispatch(setLoadState(LoadState.Loading)); + await thunkAPI.dispatch(deleteBundles(selectedBundlesIds)); + await thunkAPI.dispatch(getBundles()); + thunkAPI.dispatch(setLoadState(LoadState.Loaded)); + }, +); + +const uploadBundles = createAsyncThunk('adcm/bundlesActions/uploadBundles', async (files: File[], thunkAPI) => { + thunkAPI.dispatch(setIsUploading(true)); + const uploadPromises = await Promise.allSettled( + files.map(async (file) => { + try { + const res = await AdcmBundlesApi.uploadBundle(file); + thunkAPI.dispatch(showInfo({ message: `Bundle "${file.name}" was upload success` })); + return res; + } catch (error) { + thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); + return error; + } + }), + ); + const rejectedResponsesList = rejectedFilter(uploadPromises); + + thunkAPI.dispatch(setIsUploading(false)); + + if (rejectedResponsesList.length > 0) { + return thunkAPI.rejectWithValue([]); + } else { + return thunkAPI.fulfillWithValue([]); + } +}); + +const uploadWithUpdateBundles = createAsyncThunk( + 'adcm/bundlesActions/uploadWithUpdateBundles', + async (files: File[], thunkAPI) => { + await thunkAPI.dispatch(uploadBundles(files)); + await thunkAPI.dispatch(getBundles()); + }, +); + +const createInitialState = (): AdcmBundlesActionsState => ({ + isUploading: false, + deleteDialog: { + id: null, + }, + selectedItemsIds: [], +}); + +const bundlesActionsSlice = createSlice({ + name: 'adcm/bundlesActions', + initialState: createInitialState(), + reducers: { + setIsUploading(state, action) { + state.isUploading = action.payload; + }, + openDeleteDialog(state, action) { + state.deleteDialog.id = action.payload; + }, + closeDeleteDialog(state) { + state.deleteDialog.id = null; + }, + setSelectedItemsIds(state, action) { + state.selectedItemsIds = action.payload; + }, + }, + extraReducers: (builder) => { + builder.addCase(deleteBundles.pending, (state) => { + // hide dialog, when + state.deleteDialog.id = null; + }); + builder.addCase(getBundles.pending, (state) => { + // hide dialogs, when load new bundles list (not silent refresh) + bundlesActionsSlice.caseReducers.closeDeleteDialog(state); + }); + // brake selected rows after full update + builder.addCase(getBundles.fulfilled, (state) => { + state.selectedItemsIds = []; + }); + }, +}); + +export const { setIsUploading, openDeleteDialog, closeDeleteDialog, setSelectedItemsIds } = bundlesActionsSlice.actions; +export { getBundles, refreshBundles, deleteBundles, deleteWithUpdateBundles, uploadWithUpdateBundles }; + +export default bundlesActionsSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/bundles/bundlesSlice.ts b/adcm-web/app/src/store/adcm/bundles/bundlesSlice.ts index 74aac3e4b2..722e91fd36 100644 --- a/adcm-web/app/src/store/adcm/bundles/bundlesSlice.ts +++ b/adcm-web/app/src/store/adcm/bundles/bundlesSlice.ts @@ -3,21 +3,13 @@ import { createAsyncThunk } from '@store/redux'; import { executeWithMinDelay } from '@utils/requestUtils'; import { defaultSpinnerDelay } from '@constants'; import { AdcmBundle } from '@models/adcm/bundle'; -import { AdcmBundlesApi, RequestError } from '@api'; -import { rejectedFilter } from '@utils/promiseUtils'; -import { showError, showInfo } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; +import { AdcmBundlesApi } from '@api'; import { LoadState } from '@models/loadState'; type AdcmBundlesState = { bundles: AdcmBundle[]; totalCount: number; loadState: LoadState; - isUploading: boolean; - itemsForActions: { - deletableId: number | null; - }; - selectedItemsIds: number[]; }; const loadBundles = createAsyncThunk('adcm/bundles/loadBundles', async (arg, thunkAPI) => { @@ -54,80 +46,10 @@ const refreshBundles = createAsyncThunk('adcm/bundles/refreshBundles', async (ar thunkAPI.dispatch(loadBundles()); }); -const deleteBundles = createAsyncThunk('adcm/bundles/deleteBundles', async (selectedBundlesIds: number[], thunkAPI) => { - try { - const deletePromises = await Promise.allSettled(selectedBundlesIds.map((id) => AdcmBundlesApi.deleteBundle(id))); - const responsesList = rejectedFilter(deletePromises); - - if (responsesList.length > 0) { - throw responsesList[0]; - } - const message = - selectedBundlesIds.length > 1 ? 'All selected bundles have been deleted' : 'The bundle has been deleted'; - thunkAPI.dispatch(showInfo({ message })); - return []; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue([]); - } -}); - -/** - * Deleted some bundles - * And update bundles list - */ -const deleteWithUpdateBundles = createAsyncThunk( - 'adcm/bundles/deleteWithUpdateBundles', - async (selectedBundlesIds: number[], thunkAPI) => { - thunkAPI.dispatch(setLoadState(LoadState.Loading)); - await thunkAPI.dispatch(deleteBundles(selectedBundlesIds)); - await thunkAPI.dispatch(getBundles()); - thunkAPI.dispatch(setLoadState(LoadState.Loaded)); - }, -); - -const uploadBundles = createAsyncThunk('adcm/bundles/uploadBundles', async (files: File[], thunkAPI) => { - thunkAPI.dispatch(setIsUploading(true)); - const uploadPromises = await Promise.allSettled( - files.map(async (file) => { - try { - const res = await AdcmBundlesApi.uploadBundle(file); - thunkAPI.dispatch(showInfo({ message: `Bundle "${file.name}" was upload success` })); - return res; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return error; - } - }), - ); - const rejectedResponsesList = rejectedFilter(uploadPromises); - - thunkAPI.dispatch(setIsUploading(false)); - - if (rejectedResponsesList.length > 0) { - return thunkAPI.rejectWithValue([]); - } else { - return thunkAPI.fulfillWithValue([]); - } -}); - -const uploadWithUpdateBundles = createAsyncThunk( - 'adcm/bundles/uploadWithUpdateBundles', - async (files: File[], thunkAPI) => { - await thunkAPI.dispatch(uploadBundles(files)); - await thunkAPI.dispatch(getBundles()); - }, -); - const createInitialState = (): AdcmBundlesState => ({ bundles: [], totalCount: 0, loadState: LoadState.NotLoaded, - isUploading: false, - itemsForActions: { - deletableId: null, - }, - selectedItemsIds: [], }); const bundlesSlice = createSlice({ @@ -137,21 +59,9 @@ const bundlesSlice = createSlice({ setLoadState(state, action) { state.loadState = action.payload; }, - setIsUploading(state, action) { - state.isUploading = action.payload; - }, cleanupBundles() { return createInitialState(); }, - cleanupItemsForActions(state) { - state.itemsForActions = createInitialState().itemsForActions; - }, - setSelectedItemsIds(state, action) { - state.selectedItemsIds = action.payload; - }, - setDeletableId(state, action) { - state.itemsForActions.deletableId = action.payload; - }, }, extraReducers: (builder) => { builder.addCase(loadBundles.fulfilled, (state, action) => { @@ -161,30 +71,10 @@ const bundlesSlice = createSlice({ builder.addCase(loadBundles.rejected, (state) => { state.bundles = []; }); - - builder.addCase(deleteBundles.pending, (state) => { - // hide dialog, when - state.itemsForActions.deletableId = null; - }); - builder.addCase(getBundles.pending, (state) => { - // hide dialogs, when load new bundles list (not silent refresh) - bundlesSlice.caseReducers.cleanupItemsForActions(state); - }); - // brake selected rows after full update - builder.addCase(getBundles.fulfilled, (state) => { - state.selectedItemsIds = []; - }); }, }); -export const { - setLoadState, - cleanupBundles, - setIsUploading, - setDeletableId, - cleanupItemsForActions, - setSelectedItemsIds, -} = bundlesSlice.actions; -export { getBundles, refreshBundles, deleteBundles, deleteWithUpdateBundles, uploadWithUpdateBundles }; +export const { setLoadState, cleanupBundles } = bundlesSlice.actions; +export { getBundles, refreshBundles }; export default bundlesSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/bundles/bundlesTableSlice.ts b/adcm-web/app/src/store/adcm/bundles/bundlesTableSlice.ts index 8793ba4e57..95aaf4aaff 100644 --- a/adcm-web/app/src/store/adcm/bundles/bundlesTableSlice.ts +++ b/adcm-web/app/src/store/adcm/bundles/bundlesTableSlice.ts @@ -3,11 +3,12 @@ import { ListState } from '@models/table'; import { AdcmBundlesFilter } from '@models/adcm/bundle'; import { AdcmPrototypesApi } from '@api'; import { AdcmPrototypeType, AdcmPrototypeVersions } from '@models/adcm'; +import { LoadState } from '@models/loadState'; type AdcmBundlesTableState = ListState & { relatedData: { products: AdcmPrototypeVersions[]; - isProductsLoaded: boolean; + productsLoadState: LoadState; }; }; @@ -27,7 +28,7 @@ const createInitialState = (): AdcmBundlesTableState => ({ }, relatedData: { products: [], - isProductsLoaded: false, + productsLoadState: LoadState.NotLoaded, }, }); @@ -58,7 +59,7 @@ const bundlesTableSlice = createListSlice({ extraReducers: (builder) => { builder.addCase(loadPrototypeVersions.fulfilled, (state, action) => { state.relatedData.products = action.payload; - state.relatedData.isProductsLoaded = true; + state.relatedData.productsLoadState = LoadState.Loaded; }); builder.addCase(loadPrototypeVersions.rejected, (state) => { state.relatedData.products = []; diff --git a/adcm-web/app/src/store/store.ts b/adcm-web/app/src/store/store.ts index 13a0b6b68e..2824948fc1 100644 --- a/adcm-web/app/src/store/store.ts +++ b/adcm-web/app/src/store/store.ts @@ -113,6 +113,7 @@ import hostProviderConfigGroupConfigurationsCompareSlice from '@store/adcm/hostP import bellSlice from '@store/adcm/bell/bellSlice'; import adcmSettingsSlice from '@store/adcm/settings/settingsSlice'; import adcmSettingsDynamicActionsSlice from '@store/adcm/settings/settingsDynamicActionsSlice'; +import bundlesActionsSlice from './adcm/bundles/bundlesActionsSlice.ts'; const rootReducer = combineReducers({ auth: authSlice, @@ -143,6 +144,7 @@ const rootReducer = combineReducers({ clusterServicesConfigurationsCompare: clusterServicesConfigurationsCompareSlice, bundle: bundleSlice, bundles: bundlesSlice, + bundlesActions: bundlesActionsSlice, bundlesTable: bundlesTableSlice, breadcrumbs: breadcrumbsSlice, hostComponents: hostComponentsSlice, From f2464b140bff1edeb9df56f1bc24bd0746ddd01f Mon Sep 17 00:00:00 2001 From: Daniil S Date: Wed, 10 Jan 2024 15:03:24 +0300 Subject: [PATCH 018/151] ADCM-5156: BusinessLogicMixin --- poetry.lock | 14 +--- pyproject.toml | 2 +- python/adcm/tests/base.py | 119 ++++++++++++++++++++++++++++++++- python/api_v2/tests/base.py | 127 ++---------------------------------- 4 files changed, 125 insertions(+), 137 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1ce19c778f..2b84450baf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "adcm-version" @@ -1470,8 +1470,8 @@ astroid = ">=3.0.0,<=3.1.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, ] isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.8" @@ -1585,7 +1585,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1593,15 +1592,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1618,7 +1610,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1626,7 +1617,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, diff --git a/pyproject.toml b/pyproject.toml index cc51e65aa6..43e9ccc3af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,7 +88,7 @@ fail-on = ["useless-suppression"] [tool.pylint."messages control"] disable = ["missing-docstring", "missing-timeout", "no-else-return", "no-member", "too-few-public-methods", - "too-many-arguments"] + "too-many-arguments", "too-many-ancestors"] good-names = ["db", "e", "f", "i", "pk"] [tool.pylint.format] diff --git a/python/adcm/tests/base.py b/python/adcm/tests/base.py index 87034325a3..90f136f0c4 100644 --- a/python/adcm/tests/base.py +++ b/python/adcm/tests/base.py @@ -12,29 +12,42 @@ import random import string +import tarfile from contextlib import contextmanager from pathlib import Path from shutil import rmtree from tempfile import mkdtemp +from typing import TypedDict +from api_v2.prototype.utils import accept_license +from api_v2.service.utils import bulk_add_services_to_cluster +from cm.api import add_cluster, add_hc, add_host, add_host_provider, add_host_to_cluster +from cm.bundle import prepare_bundle, process_file from cm.models import ( ADCM, ADCMEntity, + ADCMModel, Bundle, Cluster, ClusterObject, ConfigLog, Host, + HostComponent, HostProvider, ObjectType, Prototype, ServiceComponent, ) from django.conf import settings +from django.db.models import QuerySet from django.test import Client, TestCase, override_settings from django.urls import reverse from init_db import init -from rbac.models import Group, Role, RoleTypes, User +from rbac.models import Group, Policy, Role, RoleTypes, User +from rbac.services.group import create as create_group +from rbac.services.policy import policy_create +from rbac.services.role import role_create +from rbac.services.user import create_user from rbac.upgrade.role import init_roles from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED @@ -42,6 +55,12 @@ APPLICATION_JSON = "application/json" +class HostComponentMapDictType(TypedDict): + host_id: int + service_id: int + component_id: int + + class ParallelReadyTestCase: def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) @@ -392,3 +411,101 @@ def create_hostcomponent(self, cluster_pk: int, hostcomponent_data: list[dict[st @staticmethod def get_random_str_num(length: int) -> str: return "".join(random.sample(f"{string.ascii_letters}{string.digits}", length)) + + +class BusinessLogicMixin: + @staticmethod + def prepare_bundle_file(source_dir: Path) -> str: + bundle_file = f"{source_dir.name}.tar" + with tarfile.open(settings.DOWNLOAD_DIR / bundle_file, "w") as tar: + for file in source_dir.iterdir(): + tar.add(name=file, arcname=file.name) + + return bundle_file + + def add_bundle(self, source_dir: Path) -> Bundle: + bundle_file = self.prepare_bundle_file(source_dir=source_dir) + bundle_hash, path = process_file(bundle_file=bundle_file) + return prepare_bundle(bundle_file=bundle_file, bundle_hash=bundle_hash, path=path) + + @staticmethod + def add_cluster(bundle: Bundle, name: str, description: str = "") -> Cluster: + prototype = Prototype.objects.filter(bundle=bundle, type=ObjectType.CLUSTER).first() + if prototype.license_path is not None: + accept_license(prototype=prototype) + prototype.refresh_from_db(fields=["license"]) + return add_cluster(prototype=prototype, name=name, description=description) + + @staticmethod + def add_provider(bundle: Bundle, name: str, description: str = "") -> HostProvider: + prototype = Prototype.objects.filter(bundle=bundle, type=ObjectType.PROVIDER).first() + return add_host_provider(prototype=prototype, name=name, description=description) + + def add_host( + self, bundle: Bundle, provider: HostProvider, fqdn: str, description: str = "", cluster: Cluster | None = None + ) -> Host: + prototype = Prototype.objects.filter(bundle=bundle, type=ObjectType.HOST).first() + host = add_host(prototype=prototype, provider=provider, fqdn=fqdn, description=description) + if cluster is not None: + self.add_host_to_cluster(cluster=cluster, host=host) + + return host + + @staticmethod + def add_host_to_cluster(cluster: Cluster, host: Host) -> Host: + return add_host_to_cluster(cluster=cluster, host=host) + + @staticmethod + def add_services_to_cluster(service_names: list[str], cluster: Cluster) -> QuerySet[ClusterObject]: + service_prototypes = Prototype.objects.filter( + type=ObjectType.SERVICE, name__in=service_names, bundle=cluster.prototype.bundle + ) + return bulk_add_services_to_cluster(cluster=cluster, prototypes=service_prototypes) + + @staticmethod + def add_hostcomponent_map(cluster: Cluster, hc_map: list[HostComponentMapDictType]) -> list[HostComponent]: + return add_hc(cluster=cluster, hc_in=hc_map) + + @staticmethod + def get_non_existent_pk(model: type[ADCMEntity | ADCMModel | User | Role | Group | Policy]): + try: + return model.objects.order_by("-pk").first().pk + 1 + except model.DoesNotExist: + return 1 + + def create_user(self, user_data: dict | None = None) -> User: + if user_data is None: + user_data = { + "username": "test_user_username", + "password": "test_user_password", + "email": "testuser@mail.ru", + "first_name": "test_user_first_name", + "last_name": "test_user_last_name", + "profile": "", + } + + return create_user(**user_data) + + @contextmanager + def grant_permissions(self, to: User, on: list[ADCMEntity] | ADCMEntity, role_name: str): + if not isinstance(on, list): + on = [on] + + group = create_group(name_to_display=f"Group for role `{role_name}`", user_set=[{"id": to.pk}]) + target_role = Role.objects.get(name=role_name) + delete_role = True + + if target_role.type != RoleTypes.ROLE: + custom_role = role_create(display_name=f"Custom `{role_name}` role", child=[target_role]) + else: + custom_role = target_role + delete_role = False + + policy = policy_create(name=f"Policy for role `{role_name}`", role=custom_role, group=[group], object=on) + + yield + + policy.delete() + if delete_role: + custom_role.delete() + group.delete() diff --git a/python/api_v2/tests/base.py b/python/api_v2/tests/base.py index 7893ea3c77..792e4e9743 100644 --- a/python/api_v2/tests/base.py +++ b/python/api_v2/tests/base.py @@ -9,57 +9,35 @@ # 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 tarfile -from contextlib import contextmanager from pathlib import Path from shutil import rmtree -from typing import Any, TypeAlias, TypedDict +from typing import Any, TypeAlias -from api_v2.prototype.utils import accept_license -from api_v2.service.utils import bulk_add_services_to_cluster from audit.models import AuditLog, AuditSession -from cm.api import add_cluster, add_hc, add_host, add_host_provider, add_host_to_cluster -from cm.bundle import prepare_bundle, process_file from cm.models import ( ADCM, - ADCMEntity, - ADCMModel, Bundle, Cluster, ClusterObject, ConfigLog, Host, - HostComponent, HostProvider, - ObjectType, - Prototype, ServiceComponent, ) from django.conf import settings -from django.db.models import QuerySet from init_db import init -from rbac.models import Group, Policy, Role, RoleTypes, User -from rbac.services.group import create as create_group -from rbac.services.policy import policy_create -from rbac.services.role import role_create -from rbac.services.user import create_user +from rbac.models import Group, Policy, Role, User from rbac.upgrade.role import init_roles from rest_framework.test import APITestCase -from adcm.tests.base import ParallelReadyTestCase +from adcm.tests.base import BusinessLogicMixin, ParallelReadyTestCase AuditTarget: TypeAlias = ( Bundle | Cluster | ClusterObject | ServiceComponent | HostProvider | Host | User | Group | Role | Policy ) -class HostComponentMapDictType(TypedDict): - host_id: int - service_id: int - component_id: int - - -class BaseAPITestCase(APITestCase, ParallelReadyTestCase): +class BaseAPITestCase(APITestCase, ParallelReadyTestCase, BusinessLogicMixin): @classmethod def setUpClass(cls): super().setUpClass() @@ -107,79 +85,6 @@ def tearDown(self) -> None: if item.name != ".gitkeep": item.unlink() - @staticmethod - def prepare_bundle_file(source_dir: Path) -> str: - bundle_file = f"{source_dir.name}.tar" - with tarfile.open(settings.DOWNLOAD_DIR / bundle_file, "w") as tar: - for file in source_dir.iterdir(): - tar.add(name=file, arcname=file.name) - - return bundle_file - - def add_bundle(self, source_dir: Path) -> Bundle: - bundle_file = self.prepare_bundle_file(source_dir=source_dir) - bundle_hash, path = process_file(bundle_file=bundle_file) - return prepare_bundle(bundle_file=bundle_file, bundle_hash=bundle_hash, path=path) - - @staticmethod - def add_cluster(bundle: Bundle, name: str, description: str = "") -> Cluster: - prototype = Prototype.objects.filter(bundle=bundle, type=ObjectType.CLUSTER).first() - if prototype.license_path is not None: - accept_license(prototype=prototype) - prototype.refresh_from_db(fields=["license"]) - return add_cluster(prototype=prototype, name=name, description=description) - - @staticmethod - def add_provider(bundle: Bundle, name: str, description: str = "") -> HostProvider: - prototype = Prototype.objects.filter(bundle=bundle, type=ObjectType.PROVIDER).first() - return add_host_provider(prototype=prototype, name=name, description=description) - - @staticmethod - def add_host( - bundle: Bundle, provider: HostProvider, fqdn: str, description: str = "", cluster: Cluster | None = None - ) -> Host: - prototype = Prototype.objects.filter(bundle=bundle, type=ObjectType.HOST).first() - host = add_host(prototype=prototype, provider=provider, fqdn=fqdn, description=description) - if cluster is not None: - BaseAPITestCase.add_host_to_cluster(cluster=cluster, host=host) - - return host - - @staticmethod - def add_host_to_cluster(cluster: Cluster, host: Host) -> Host: - return add_host_to_cluster(cluster=cluster, host=host) - - @staticmethod - def add_services_to_cluster(service_names: list[str], cluster: Cluster) -> QuerySet[ClusterObject]: - service_prototypes = Prototype.objects.filter( - type=ObjectType.SERVICE, name__in=service_names, bundle=cluster.prototype.bundle - ) - return bulk_add_services_to_cluster(cluster=cluster, prototypes=service_prototypes) - - @staticmethod - def add_hostcomponent_map(cluster: Cluster, hc_map: list[HostComponentMapDictType]) -> list[HostComponent]: - return add_hc(cluster=cluster, hc_in=hc_map) - - @staticmethod - def get_non_existent_pk(model: type[ADCMEntity | ADCMModel | User | Role | Group | Policy]): - try: - return model.objects.order_by("-pk").first().pk + 1 - except model.DoesNotExist: - return 1 - - def create_user(self, user_data: dict | None = None) -> User: - if user_data is None: - user_data = { - "username": "test_user_username", - "password": "test_user_password", - "email": "testuser@mail.ru", - "first_name": "test_user_first_name", - "last_name": "test_user_last_name", - "profile": "", - } - - return create_user(**user_data) - def check_last_audit_record( self, model: type[AuditLog | AuditSession] = AuditLog, @@ -249,27 +154,3 @@ def prepare_audit_object_arguments( "audit_object__object_type": type_, "audit_object__is_deleted": is_deleted, } - - @contextmanager - def grant_permissions(self, to: User, on: list[ADCMEntity] | ADCMEntity, role_name: str): - if not isinstance(on, list): - on = [on] - - group = create_group(name_to_display=f"Group for role `{role_name}`", user_set=[{"id": to.pk}]) - target_role = Role.objects.get(name=role_name) - delete_role = True - - if target_role.type != RoleTypes.ROLE: - custom_role = role_create(display_name=f"Custom `{role_name}` role", child=[target_role]) - else: - custom_role = target_role - delete_role = False - - policy = policy_create(name=f"Policy for role `{role_name}`", role=custom_role, group=[group], object=on) - - yield - - policy.delete() - if delete_role: - custom_role.delete() - group.delete() From b46a9696c29a453525be65f133d7da6eaa37fb43 Mon Sep 17 00:00:00 2001 From: Daniil S Date: Wed, 10 Jan 2024 15:08:53 +0300 Subject: [PATCH 019/151] ADCM-5156: NotImplementedError --- python/api_v2/tests/test_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/api_v2/tests/test_mapping.py b/python/api_v2/tests/test_mapping.py index 90ba60c3dd..824b8455cd 100644 --- a/python/api_v2/tests/test_mapping.py +++ b/python/api_v2/tests/test_mapping.py @@ -1152,7 +1152,7 @@ def _prepare_config_group_via_api( "cluster_pk": obj.pk, } case _: - raise NotImplemented(str(obj)) + raise NotImplementedError(str(obj)) response = self.client.post( path=reverse(viewname=viewname_create, kwargs=kwargs), From e767eaa4173a8d3c93eb1d4866cadcc5fbc582c1 Mon Sep 17 00:00:00 2001 From: Daniil S Date: Wed, 10 Jan 2024 16:13:10 +0300 Subject: [PATCH 020/151] ADCM-5156: restore poetry.lock --- poetry.lock | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 2b84450baf..1ce19c778f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "adcm-version" @@ -1470,8 +1470,8 @@ astroid = ">=3.0.0,<=3.1.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, ] isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.8" @@ -1585,6 +1585,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1592,8 +1593,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1610,6 +1618,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1617,6 +1626,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, From ad6a1517606db8c88facdc85c31b4bf0fbfae0b0 Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Wed, 10 Jan 2024 14:15:02 +0000 Subject: [PATCH 021/151] ADCM-5179 Add service as single object Changed: 1. Allowed to add single service to cluster (passing it like an object) 2. Audit adopted to single service case --- python/api_v2/service/views.py | 16 +++++++++++----- python/api_v2/tests/test_service.py | 25 +++++++++++++++++++++++-- python/audit/cases/cluster.py | 5 ++++- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/python/api_v2/service/views.py b/python/api_v2/service/views.py index cede4d0406..6859f69282 100644 --- a/python/api_v2/service/views.py +++ b/python/api_v2/service/views.py @@ -91,19 +91,25 @@ def create(self, request: Request, *args, **kwargs): ) check_custom_perm(user=request.user, action_type=ADD_SERVICE_PERM, model=Cluster.__name__.lower(), obj=cluster) + multiple_services = isinstance(request.data, list) serializer = self.get_serializer( - data=request.data, many=True, context={"cluster": cluster, **self.get_serializer_context()} + data=request.data, many=multiple_services, context={"cluster": cluster, **self.get_serializer_context()} ) serializer.is_valid(raise_exception=True) - service_prototypes, error = validate_service_prototypes(cluster=cluster, data=serializer.validated_data) + service_prototypes, error = validate_service_prototypes( + cluster=cluster, data=serializer.validated_data if multiple_services else [serializer.validated_data] + ) if error is not None: raise error added_services = bulk_add_services_to_cluster(cluster=cluster, prototypes=service_prototypes) - return Response( - status=HTTP_201_CREATED, data=ServiceRetrieveSerializer(instance=added_services, many=True).data - ) + if multiple_services: + return Response( + status=HTTP_201_CREATED, data=ServiceRetrieveSerializer(instance=added_services, many=True).data + ) + + return Response(status=HTTP_201_CREATED, data=ServiceRetrieveSerializer(instance=added_services[0]).data) @audit def destroy(self, request: Request, *args, **kwargs): diff --git a/python/api_v2/tests/test_service.py b/python/api_v2/tests/test_service.py index 7dd8abf733..58497733f3 100644 --- a/python/api_v2/tests/test_service.py +++ b/python/api_v2/tests/test_service.py @@ -131,10 +131,31 @@ def test_create_success(self): response = self.client.post( path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), - data=[{"prototype_id": manual_add_service_proto.pk}], + data=[{"prototypeId": manual_add_service_proto.pk}], ) self.assertEqual(response.status_code, HTTP_201_CREATED) + data = response.json() + self.assertIsInstance(data, list) + self.assertEqual(len(data), 1) + self.assertEqual(data[0]["prototype"]["id"], manual_add_service_proto.pk) + + self.assertEqual(ClusterObject.objects.count(), initial_service_count + 1) + + def test_add_one_success(self): + initial_service_count = ClusterObject.objects.count() + manual_add_service_proto = Prototype.objects.get(type=ObjectType.SERVICE, name="service_3_manual_add") + + response = self.client.post( + path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data={"prototypeId": manual_add_service_proto.pk}, + ) + + self.assertEqual(response.status_code, HTTP_201_CREATED) + data = response.json() + self.assertIsInstance(data, dict) + self.assertEqual(data["prototype"]["id"], manual_add_service_proto.pk) + self.assertEqual(ClusterObject.objects.count(), initial_service_count + 1) def test_create_wrong_data_fail(self): @@ -143,7 +164,7 @@ def test_create_wrong_data_fail(self): response = self.client.post( path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), - data={"prototype_id": manual_add_service_proto.pk}, + data={"somekey": manual_add_service_proto.pk}, ) self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) diff --git a/python/audit/cases/cluster.py b/python/audit/cases/cluster.py index a4810c7c25..0bdb03d5dd 100644 --- a/python/audit/cases/cluster.py +++ b/python/audit/cases/cluster.py @@ -215,7 +215,10 @@ def cluster_case( service_display_name = [] if response and response.data: - service_display_name = [data["display_name"] for data in response.data] + service_display_name = [ + data["display_name"] + for data in (response.data if isinstance(response.data, list) else [response.data]) + ] elif isinstance(view.request.data, list) and all("prototype_id" in data for data in view.request.data): service_display_name = ( Prototype.objects.filter(pk__in=[data["prototype_id"] for data in view.request.data]) From 8a703690266e7fabf11ae95e8c3eab56e4b9f3ef Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Wed, 10 Jan 2024 14:53:35 +0000 Subject: [PATCH 022/151] [UI] ADCM-5177: Add products filter update to Bundles https://tracker.yandex.ru/ADCM-5177 --- adcm-web/app/src/store/adcm/bundles/bundlesActionsSlice.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/adcm-web/app/src/store/adcm/bundles/bundlesActionsSlice.ts b/adcm-web/app/src/store/adcm/bundles/bundlesActionsSlice.ts index 56e4716d7b..738fd20da7 100644 --- a/adcm-web/app/src/store/adcm/bundles/bundlesActionsSlice.ts +++ b/adcm-web/app/src/store/adcm/bundles/bundlesActionsSlice.ts @@ -6,6 +6,7 @@ import { LoadState } from '@models/loadState'; import { showInfo, showError } from '@store/notificationsSlice'; import { getErrorMessage } from '@utils/httpResponseUtils'; import { rejectedFilter } from '@utils/promiseUtils'; +import { loadRelatedData } from './bundlesTableSlice'; interface AdcmBundlesActionsState { isUploading: boolean; @@ -46,6 +47,7 @@ const deleteWithUpdateBundles = createAsyncThunk( thunkAPI.dispatch(setLoadState(LoadState.Loading)); await thunkAPI.dispatch(deleteBundles(selectedBundlesIds)); await thunkAPI.dispatch(getBundles()); + await thunkAPI.dispatch(loadRelatedData()); thunkAPI.dispatch(setLoadState(LoadState.Loaded)); }, ); @@ -80,6 +82,7 @@ const uploadWithUpdateBundles = createAsyncThunk( async (files: File[], thunkAPI) => { await thunkAPI.dispatch(uploadBundles(files)); await thunkAPI.dispatch(getBundles()); + await thunkAPI.dispatch(loadRelatedData()); }, ); From 3af307b999b9b7a627780a60ea6a175768eecfdc Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Thu, 11 Jan 2024 07:34:42 +0000 Subject: [PATCH 023/151] [UI] ADCM-5182: Fix text color of Add service dialog https://tracker.yandex.ru/ADCM-5182 --- .../WarningMessage/WarningMessage.module.scss | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/adcm-web/app/src/components/uikit/WarningMessage/WarningMessage.module.scss b/adcm-web/app/src/components/uikit/WarningMessage/WarningMessage.module.scss index d3b5aa9450..8c7ed934dc 100644 --- a/adcm-web/app/src/components/uikit/WarningMessage/WarningMessage.module.scss +++ b/adcm-web/app/src/components/uikit/WarningMessage/WarningMessage.module.scss @@ -1,3 +1,13 @@ +:global { + body.theme-dark { + --warning-text-color: var(--color-xgray-lighter); + } + + body.theme-light { + --warning-text-color: var(--color-xgray-light); + } +} + .warning { display: flex; align-items: center; @@ -14,14 +24,10 @@ } &__text { - color: var(--color-xgray-lighter); + color: var(--warning-text-color); font-size: 15px; max-height: 104px; overflow: auto; width: 100%; - - strong { - color: var(--color-xwhite-off); - } } } From 97408be2e7482d16f728075119f4d67729b1db85 Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Thu, 11 Jan 2024 10:57:53 +0000 Subject: [PATCH 024/151] ADCM-5185 Cut long stdout/stderr logs in API v2 response Changed: 1. `LogStorageSerializer` to cut content if amount of characters (spaces included) is above 1500*1000 --- python/adcm/settings.py | 5 + python/api_v2/log_storage/serializers.py | 63 +++++----- python/api_v2/tests/test_jobs.py | 151 ++++++++++++++++++++++- 3 files changed, 189 insertions(+), 30 deletions(-) diff --git a/python/adcm/settings.py b/python/adcm/settings.py index 01824fca5b..74f544dacd 100644 --- a/python/adcm/settings.py +++ b/python/adcm/settings.py @@ -338,3 +338,8 @@ } USERNAME_MAX_LENGTH = 150 + +STDOUT_STDERR_LOG_CUT_LENGTH = 1500 +STDOUT_STDERR_LOG_LINE_CUT_LENGTH = 1000 +STDOUT_STDERR_LOG_MAX_UNCUT_LENGTH = STDOUT_STDERR_LOG_CUT_LENGTH * STDOUT_STDERR_LOG_LINE_CUT_LENGTH +STDOUT_STDERR_TRUNCATED_LOG_MESSAGE = "" diff --git a/python/api_v2/log_storage/serializers.py b/python/api_v2/log_storage/serializers.py index 6373af2fb0..d100faece2 100644 --- a/python/api_v2/log_storage/serializers.py +++ b/python/api_v2/log_storage/serializers.py @@ -12,14 +12,14 @@ # pylint: disable=duplicate-code import json +from contextlib import suppress from cm.ansible_plugin import get_checklogs_data_by_job_id from cm.models import LogStorage +from django.conf import settings from rest_framework.fields import SerializerMethodField from rest_framework.serializers import ModelSerializer -from adcm import settings - class LogStorageSerializer(ModelSerializer): content = SerializerMethodField() @@ -34,32 +34,39 @@ class Meta: "content", ) - @staticmethod - def _get_ansible_content(obj): - path_file = settings.RUN_DIR / f"{obj.job.id}" / f"{obj.name}-{obj.type}.{obj.format}" - try: - with open(path_file, encoding=settings.ENCODING_UTF_8) as f: - content = f.read() - except FileNotFoundError: - content = "" + def get_content(self, obj: LogStorage) -> str: + content = obj.body + log_type = obj.type + + # retrieve if empty + if content is None: + if log_type in {"stdout", "stderr"}: + logfile = settings.RUN_DIR / f"{obj.job_id}" / f"{obj.name}-{obj.type}.{obj.format}" + if logfile.exists(): + content = logfile.read_text(encoding="utf-8") - return content + if log_type == "check": + content = get_checklogs_data_by_job_id(obj.job_id) - def get_content(self, obj: LogStorage) -> str: - if obj.type in {"stdout", "stderr"}: - if obj.body is None: - obj.body = self._get_ansible_content(obj) - elif obj.type == "check": - if obj.body is None: - obj.body = get_checklogs_data_by_job_id(obj.job_id) - if isinstance(obj.body, str): - obj.body = json.loads(obj.body) - elif obj.type == "custom": - if obj.format == "json" and isinstance(obj.body, str): - try: - custom_content = json.loads(obj.body) - obj.body = json.dumps(custom_content, indent=4) - except json.JSONDecodeError: - pass + # postprocessing + if log_type in {"stdout", "stderr"} and len(content or "") >= settings.STDOUT_STDERR_LOG_MAX_UNCUT_LENGTH: + cut_lines = "\n".join( + ( + line + if len(line) <= settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH + else ( + line[: settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH] + + settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE + ) + for line in obj.body.splitlines()[-1500:] + ) + ) + content = f"{settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE}\n{cut_lines}\n" + elif log_type == "check" and isinstance(content, str): + content = json.loads(obj.body) + elif log_type == "custom" and obj.format == "json" and isinstance(content, str): + with suppress(json.JSONDecodeError): + custom_content = json.loads(content) + content = json.dumps(custom_content) - return obj.body + return content or "" diff --git a/python/api_v2/tests/test_jobs.py b/python/api_v2/tests/test_jobs.py index 20116737c9..01f60ff0b9 100644 --- a/python/api_v2/tests/test_jobs.py +++ b/python/api_v2/tests/test_jobs.py @@ -23,6 +23,7 @@ SubAction, TaskLog, ) +from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.urls import reverse from django.utils import timezone @@ -32,7 +33,9 @@ from adcm.tests.base import BaseTestCase -class TestJob(BaseTestCase): +class TestJob(BaseTestCase): # pylint: disable=too-many-instance-attributes + TRUNCATED_LOG_MESSAGE = settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE + def setUp(self) -> None: super().setUp() @@ -74,9 +77,64 @@ def setUp(self) -> None: format="txt", ) + self.job_with_logs = JobLog.objects.create( + status=JobStatus.FAILED, + start_date=timezone.now() - timedelta(hours=2), + finish_date=timezone.now(), + ) + self.word_10_symbols = "logline908" + self.ansible_stdout_many_lines = LogStorage.objects.create( + job=self.job_with_logs, + name="ansible", + type="stdout", + format="txt", + body="\n".join((self.word_10_symbols for _ in range(200_000))), + ) + self.long_line = "word" * 1000 + self.short_line = "word" * 4 + self.ansible_stderr_long_lines = LogStorage.objects.create( + job=self.job_with_logs, + name="ansible", + type="stderr", + format="txt", + body=f"{self.long_line}\n{self.short_line}\n{self.long_line}\n" + f"{self.short_line}\n{self.short_line}\n{self.long_line}\n", + ) + many_lines_long_message = "\n".join( + ( + *[self.word_10_symbols for _ in range(200_000)], + "", + self.long_line, + self.short_line, + self.long_line, + "logline", + ) + ) + self.custom_log_long_and_many_lines = LogStorage.objects.create( + job=self.job_with_logs, + name="anythingelse", + type="custom", + format="txt", + body=many_lines_long_message, + ) + self.another_stdout_long_and_many_lines = LogStorage.objects.create( + job=self.job_with_logs, + name="anotherone", + type="stdout", + format="txt", + body=many_lines_long_message, + ) + self.long_one_liner_log = LogStorage.objects.create( + job=self.job_with_logs, + name="anotherone", + type="stderr", + format="txt", + body=many_lines_long_message.replace("\n", " "), + ) + def test_job_list_success(self): response: Response = self.client.get(path=reverse(viewname="v2:joblog-list")) - self.assertEqual(len(response.data["results"]), 2) + self.assertEqual(len(response.data["results"]), 3) self.assertEqual(response.status_code, HTTP_200_OK) def test_job_retrieve_success(self): @@ -97,6 +155,95 @@ def test_job_log_list_success(self): self.assertEqual(response.status_code, HTTP_200_OK) self.assertEqual(len(response.json()), 1) + def test_job_log_detail_success(self): + expected_truncated_line = ( + f"{self.long_line[:settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH]}{self.TRUNCATED_LOG_MESSAGE}" + ) + + with self.subTest("Many lines [CUT]"): + response = self.client.get( + path=reverse( + viewname="v2:log-detail", + kwargs={"job_pk": self.job_with_logs.pk, "pk": self.ansible_stdout_many_lines.pk}, + ) + ) + self.assertEqual(response.status_code, HTTP_200_OK) + log = response.json()["content"].splitlines() + self.assertEqual(log[0], self.TRUNCATED_LOG_MESSAGE) + log_itself = log[1:] + self.assertEqual(len(log_itself), settings.STDOUT_STDERR_LOG_CUT_LENGTH) + self.assertTrue(all(line == self.word_10_symbols for line in log_itself)) + + with self.subTest("Long lines, less than cutoff [UNCUT]"): + response = self.client.get( + path=reverse( + viewname="v2:log-detail", + kwargs={"job_pk": self.job_with_logs.pk, "pk": self.ansible_stderr_long_lines.pk}, + ) + ) + self.assertEqual(response.status_code, HTTP_200_OK) + log = response.json()["content"].splitlines() + self.assertEqual( + log, + [ + self.long_line, + self.short_line, + self.long_line, + self.short_line, + self.short_line, + self.long_line, + ], + ) + + with self.subTest("Custom log [UNCUT]"): + response = self.client.get( + path=reverse( + viewname="v2:log-detail", + kwargs={"job_pk": self.job_with_logs.pk, "pk": self.custom_log_long_and_many_lines.pk}, + ) + ) + self.assertEqual(response.status_code, HTTP_200_OK) + log = response.json()["content"] + self.assertEqual(log, self.custom_log_long_and_many_lines.body) + + with self.subTest("Long both ways non-ansible stdout [CUT]"): + response = self.client.get( + path=reverse( + viewname="v2:log-detail", + kwargs={"job_pk": self.job_with_logs.pk, "pk": self.another_stdout_long_and_many_lines.pk}, + ) + ) + self.assertEqual(response.status_code, HTTP_200_OK) + log = response.json()["content"].splitlines() + self.assertEqual(log[0], self.TRUNCATED_LOG_MESSAGE) + expected_last_lines = [ + "", + expected_truncated_line, + self.short_line, + expected_truncated_line, + "logline", + ] + self.assertEqual(log[-5:], expected_last_lines) + main_log = log[1:-5] + self.assertEqual(len(main_log), settings.STDOUT_STDERR_LOG_CUT_LENGTH - 5) + self.assertTrue(all(line == self.word_10_symbols for line in main_log)) + + with self.subTest("Long one line [CUT]"): + response = self.client.get( + path=reverse( + viewname="v2:log-detail", + kwargs={"job_pk": self.job_with_logs.pk, "pk": self.long_one_liner_log.pk}, + ) + ) + self.assertEqual(response.status_code, HTTP_200_OK) + log = response.json()["content"] + self.assertEqual( + log, + f"{self.TRUNCATED_LOG_MESSAGE}\n" + f"{self.long_one_liner_log.body[: settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH]}" + f"{self.TRUNCATED_LOG_MESSAGE}\n", + ) + def test_job_log_download_success(self): response: Response = self.client.get( path=reverse(viewname="v2:log-download", kwargs={"job_pk": self.job_1.pk, "pk": self.log_1.pk}) From 7c65775551248e9db91d83763278a566cd4173e7 Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Fri, 12 Jan 2024 13:34:06 +0000 Subject: [PATCH 025/151] Introduce dev tools --- .gitignore | 1 + dev/profiling/README.md | 125 ++++++++++++++++++++++++++++ dev/profiling/silk/silk_settings.py | 10 +++ dev/profiling/silk/silk_urls.py | 7 ++ poetry.lock | 55 +++++++++--- pyproject.toml | 6 ++ python/adcm/settings.py | 3 +- python/cm/utils.py | 18 ++-- 8 files changed, 203 insertions(+), 22 deletions(-) create mode 100644 dev/profiling/README.md create mode 100644 dev/profiling/silk/silk_settings.py create mode 100644 dev/profiling/silk/silk_urls.py diff --git a/.gitignore b/.gitignore index bead615364..9d582abf30 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ data/ config.json go/bin/ wwwroot/ +python/adcm/silk_*.py diff --git a/dev/profiling/README.md b/dev/profiling/README.md new file mode 100644 index 0000000000..e2b6c6da88 --- /dev/null +++ b/dev/profiling/README.md @@ -0,0 +1,125 @@ +# Gather ADCM Performance Statistics + +## Summary + +By target + +| Target | Tools | +|--------|------------------| +| API | Silk, nginx logs | +| DB | Silk, PGBadger | +| Python | Silk, CProfile | + +## Tools + +### Nginx Logs + +#### Description + +Altering format of Nginx logs can be useful for gathering info about time spent on requests. + +Thou it can't help with monitoring DB interactions or resource usage, +it doesn't require container restart, image re-build, etc. + +#### How To + +ADCM has custom nginx config stored in project at `os/etc/nginx/http.d/adcm.conf` +which is placed at `/etc/nginx/http.d/adcm.conf` inside the container. + +What we need to do is to: +1. Edit this file in container +2. Add custom log format at "root" (a.k.a. `http` node) +``` +log_format upstream_time '$request_method | $status | ' + 'request_time=$request_time | upstream=$upstream_response_time | ' + '$uri | $query_string'; +``` +2. Add `access_log /adcm/data/log/nginx/upstream_time.log upstream_time;` + to `server` nodes we want to log +3. Save changes, validate them with `nginx -t` +4. Reload `nginx -s reload` + +Example of `adcm.conf` after changes: +```text +upstream django { + server unix:///run/adcm.sock; +} + +map $status $abnormal { + ~^200 0; + default 1; +} + +log_format upstream_time '$request_method | $status | ' + 'request_time=$request_time | upstream=$upstream_response_time | ' + '$uri | $query_string'; + +server { + listen 8000; + access_log /adcm/data/log/nginx/upstream_time.log upstream_time; + include "http.d/proxy.inc"; +} + +server { + listen 8443 ssl; + access_log /adcm/data/log/nginx/upstream_time.log upstream_time; + ssl_certificate /adcm/data/conf/ssl/cert.pem; + ssl_certificate_key /adcm/data/conf/ssl/key.pem; + include "http.d/proxy.inc"; +} +``` + +You can customize `log_format` for your need, check out +[documentation on instruction](https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format) +and [available variables](https://nginx.org/en/docs/http/ngx_http_core_module.html#var_status) + +Logs will be placed at `/adcm/data/log/nginx/upstream_time.log` inside the container + +### Silk + +#### Description + +[django-silk](https://github.com/jazzband/django-silk) +is a tool to gather information about Django application performance: +API response time, amount of DB queries and time spent on them, python performance. + +#### How To + +You can set up it by yourself following guidelines from documentation +and checking out examples here. + +Below comes the description how to prepare ADCM to be launched with silk. + +###### Alter generic settings and URLs + +Alternative to editing files by yourself + +```shell +# when in ADCM project root +cp dev/profiling/silk/* python/adcm/ +``` + +Then during container launch you can specify `DJANGO_SETTINGS_MODULE` env variable to enable silk +and don't specify it for "regular" launch + +```shell +docker run ... -e DJANGO_SETTINGS_MODULE=adcm.silk_settings +``` + +###### Install dependencies + +Silk can be installed with `profiling` dependencies group (or directly via `pip`) + +```shell +poetry install --with profiling --no-root +``` + +The most simple way to prepare ADCM for silk profiling is: + +1. Run ADCM with your code +2. Install profiling group `docker exec adcm poetry install --with profiling --no-root -C /adcm` + or (if profiling group is not available) `docker exec adcm pip install django-silk` +3. Then collect static for silk with `docker exec -it adcm-pg-code /adcm/python/manage.py collectstatic` +4. Commit your container state to new image (e.g. `docker commit adcm-pg-code hub.adsw.io/adcm/adcm:adcm-prof`) +5. Run container from new image providing `DJANGO_SETTINGS_MODULE` as env variable + and provide `-e DEBUG=1` diff --git a/dev/profiling/silk/silk_settings.py b/dev/profiling/silk/silk_settings.py new file mode 100644 index 0000000000..cd8efb2fc2 --- /dev/null +++ b/dev/profiling/silk/silk_settings.py @@ -0,0 +1,10 @@ +from .settings import * + +INSTALLED_APPS.append("silk") + +MIDDLEWARE.insert(0, "silk.middleware.SilkyMiddleware") + +DEBUG = True +SILKY_PYTHON_PROFILER = True + +ROOT_URLCONF = "adcm.silk_urls" diff --git a/dev/profiling/silk/silk_urls.py b/dev/profiling/silk/silk_urls.py new file mode 100644 index 0000000000..81800a68de --- /dev/null +++ b/dev/profiling/silk/silk_urls.py @@ -0,0 +1,7 @@ +from django.conf.urls import include +from django.urls import path + +from .urls import urlpatterns + + +urlpatterns += [path("api/silk/", include("silk.urls", namespace="silk"))] diff --git a/poetry.lock b/poetry.lock index 1ce19c778f..dff096101b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -126,6 +126,21 @@ files = [ pyflakes = ">=3.0.0" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} +[[package]] +name = "autopep8" +version = "2.0.4" +description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" +optional = false +python-versions = ">=3.6" +files = [ + {file = "autopep8-2.0.4-py2.py3-none-any.whl", hash = "sha256:067959ca4a07b24dbd5345efa8325f5f58da4298dab0dde0443d5ed765de80cb"}, + {file = "autopep8-2.0.4.tar.gz", hash = "sha256:2913064abd97b3419d1cc83ea71f042cb821f87e45b9c88cad5ad3c4ea87fe0c"}, +] + +[package.dependencies] +pycodestyle = ">=2.10.0" +tomli = {version = "*", markers = "python_version < \"3.11\""} + [[package]] name = "black" version = "23.9.1" @@ -603,6 +618,23 @@ files = [ [package.dependencies] Django = ">=2.2" +[[package]] +name = "django-silk" +version = "5.0.4" +description = "Silky smooth profiling for the Django Framework" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-silk-5.0.4.tar.gz", hash = "sha256:8cbfbc647d182527726d8d52d3fcfa193f4d250f21406c3fb1062efa6fb95c63"}, + {file = "django_silk-5.0.4-py3-none-any.whl", hash = "sha256:b345d3973d1d382e09735eb525eaf3eebd3edee9a69d1003eb9b01badb2438db"}, +] + +[package.dependencies] +autopep8 = "*" +Django = ">=3.2" +gprof2dot = ">=2017.09.19" +sqlparse = "*" + [[package]] name = "djangorestframework" version = "3.14.0" @@ -754,6 +786,17 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4 [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] +[[package]] +name = "gprof2dot" +version = "2022.7.29" +description = "Generate a dot graph from the output of several profilers." +optional = false +python-versions = ">=2.7" +files = [ + {file = "gprof2dot-2022.7.29-py2.py3-none-any.whl", hash = "sha256:f165b3851d3c52ee4915eb1bd6cca571e5759823c2cd0f71a79bda93c2dc85d6"}, + {file = "gprof2dot-2022.7.29.tar.gz", hash = "sha256:45b4d298bd36608fccf9511c3fd88a773f7a1abc04d6cd39445b11ba43133ec5"}, +] + [[package]] name = "grpcio" version = "1.56.0" @@ -1585,7 +1628,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1593,15 +1635,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1618,7 +1653,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1626,7 +1660,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1915,4 +1948,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "1c7778431c3f7ac72e1024b9f7eae6e08b62ac818335c3f98b548eb5bb0941e4" +content-hash = "ff59bf3390898baf789d7d11a7362d801036ceea4be58d036c46384f732fc9b2" diff --git a/pyproject.toml b/pyproject.toml index cc51e65aa6..9e6d48f13f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,12 @@ optional = true [tool.poetry.group.dev.dependencies] pre-commit = "^3.6.0" +[tool.poetry.group.profiling] +optional = true + +[tool.poetry.group.profiling.dependencies] +django-silk = "^5.0.4" + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/python/adcm/settings.py b/python/adcm/settings.py index 74f544dacd..b023af25c3 100644 --- a/python/adcm/settings.py +++ b/python/adcm/settings.py @@ -49,7 +49,8 @@ ANSIBLE_VAULT_HEADER = "$ANSIBLE_VAULT;1.1;AES256" DEFAULT_SALT = b'"j\xebi\xc0\xea\x82\xe0\xa8\xba\x9e\x12E>\x11D' -ADCM_TOKEN = get_adcm_token() + +ADCM_TOKEN = get_adcm_token(ADCM_TOKEN_FILE) if SECRETS_FILE.is_file(): with open(SECRETS_FILE, encoding=ENCODING_UTF_8) as f: data = json.load(f) diff --git a/python/cm/utils.py b/python/cm/utils.py index 8af5df7fe4..ae5557f44d 100644 --- a/python/cm/utils.py +++ b/python/cm/utils.py @@ -17,8 +17,6 @@ from secrets import token_hex from typing import Any, Iterable, Protocol, TypeVar -from django.conf import settings - class WithPK(Protocol): pk: int @@ -32,26 +30,26 @@ def build_id_object_mapping(objects: Iterable[ObjectWithPk]) -> dict[int, Object def dict_json_get_or_create(path: str | Path, field: str, value: Any = None) -> Any: - with open(path, encoding=settings.ENCODING_UTF_8) as f: + with open(path, encoding="utf-8") as f: data = json.load(f) if field not in data: data[field] = value - with open(path, "w", encoding=settings.ENCODING_UTF_8) as f: + with open(path, "w", encoding="utf-8") as f: json.dump(data, f) return data[field] -def get_adcm_token() -> str: - if not settings.ADCM_TOKEN_FILE.is_file(): - settings.ADCM_TOKEN_FILE.parent.mkdir(parents=True, exist_ok=True) - with open(file=settings.ADCM_TOKEN_FILE, mode="w", encoding=settings.ENCODING_UTF_8) as f: +def get_adcm_token(token_path: Path) -> str: + if not token_path.is_file(): + token_path.parent.mkdir(parents=True, exist_ok=True) + with token_path.open(mode="w", encoding="utf-8") as f: f.write(token_hex(20)) - with open(file=settings.ADCM_TOKEN_FILE, encoding=settings.ENCODING_UTF_8) as f: + with token_path.open(encoding="utf-8") as f: adcm_token = f.read().strip() - adcm_token.encode(encoding="idna").decode(encoding=settings.ENCODING_UTF_8) + adcm_token.encode(encoding="idna").decode(encoding="utf-8") return adcm_token From 1aa44d98615fee4defbc271f785036ea0bcff12e Mon Sep 17 00:00:00 2001 From: Daniil Skrynnik Date: Mon, 15 Jan 2024 07:24:51 +0000 Subject: [PATCH 026/151] ADCM-5181: Add tests for link components with hosts --- python/cm/tests/bundles/cluster_1/config.yaml | 86 +++ .../cm/tests/bundles/cluster_1/playbook.yaml | 10 + python/cm/tests/bundles/provider/config.yaml | 39 ++ .../cm/tests/bundles/provider/playbook.yaml | 10 + .../files/response_templates/cluster.json.j2 | 23 + .../files/response_templates/one_host.json.j2 | 17 + .../files/response_templates/provider.json.j2 | 22 + .../service_one_component.json.j2 | 47 ++ .../service_two_components.json.j2 | 69 ++ .../response_templates/two_hosts.json.j2 | 32 + .../two_services_two_components_each.json.j2 | 136 ++++ python/cm/tests/test_inventory.py | 608 +++++++++++++++++- 12 files changed, 1098 insertions(+), 1 deletion(-) create mode 100644 python/cm/tests/bundles/cluster_1/config.yaml create mode 100644 python/cm/tests/bundles/cluster_1/playbook.yaml create mode 100644 python/cm/tests/bundles/provider/config.yaml create mode 100644 python/cm/tests/bundles/provider/playbook.yaml create mode 100644 python/cm/tests/files/response_templates/cluster.json.j2 create mode 100644 python/cm/tests/files/response_templates/one_host.json.j2 create mode 100644 python/cm/tests/files/response_templates/provider.json.j2 create mode 100644 python/cm/tests/files/response_templates/service_one_component.json.j2 create mode 100644 python/cm/tests/files/response_templates/service_two_components.json.j2 create mode 100644 python/cm/tests/files/response_templates/two_hosts.json.j2 create mode 100644 python/cm/tests/files/response_templates/two_services_two_components_each.json.j2 diff --git a/python/cm/tests/bundles/cluster_1/config.yaml b/python/cm/tests/bundles/cluster_1/config.yaml new file mode 100644 index 0000000000..4b7105c1d2 --- /dev/null +++ b/python/cm/tests/bundles/cluster_1/config.yaml @@ -0,0 +1,86 @@ +--- +- type: cluster + name: cluster_1 + version: &version '1.0' + edition: community + config_group_customization: true + allow_maintenance_mode: true + config: &config + - name: integer + type: integer + required: false + default: 10 + - name: password + type: password + required: false + default: password + - name: string + type: string + required: false + default: string + - name: list + type: list + required: false + default: + - value1 + - value2 + - value3 + actions: + action_on_cluster: &action + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any + +- name: service_one_component + type: service + version: *version + config: *config + actions: + action_on_service: *action + + components: + component_1: + constraint: [ 0, + ] + config: *config + actions: + action_on_component: *action + +- name: service_two_components + type: service + version: *version + config: *config + actions: + action_on_service: *action + + components: + component_1: + constraint: [ 0, + ] + config: *config + actions: + action_on_component_1: *action + component_2: + constraint: [ 0, + ] + config: *config + actions: + action_on_component_2: *action + +- name: another_service_two_components + type: service + version: *version + config: *config + actions: + action_on_service: *action + + components: + component_1: + constraint: [ 0, + ] + config: *config + actions: + action_on_component_1: *action + component_2: + constraint: [ 0, + ] + config: *config + actions: + action_on_component_2: *action diff --git a/python/cm/tests/bundles/cluster_1/playbook.yaml b/python/cm/tests/bundles/cluster_1/playbook.yaml new file mode 100644 index 0000000000..be7ea53778 --- /dev/null +++ b/python/cm/tests/bundles/cluster_1/playbook.yaml @@ -0,0 +1,10 @@ +--- +- name: sleep + hosts: all + connection: local + gather_facts: no + + tasks: + - name: sleep + pause: + seconds: 1 diff --git a/python/cm/tests/bundles/provider/config.yaml b/python/cm/tests/bundles/provider/config.yaml new file mode 100644 index 0000000000..3510904340 --- /dev/null +++ b/python/cm/tests/bundles/provider/config.yaml @@ -0,0 +1,39 @@ +--- +- type: provider + name: provider + version: &version '1.0' + config_group_customization: true + config: &config + - name: integer + type: integer + required: false + default: 10 + - name: password + type: password + required: false + default: password + - name: string + type: string + required: false + default: string + - name: list + type: list + required: false + default: + - value1 + - value2 + - value3 + actions: + action_on_provider: &action + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any + +- type: host + name: host + version: *version + config: *config + actions: + action_on_host: *action diff --git a/python/cm/tests/bundles/provider/playbook.yaml b/python/cm/tests/bundles/provider/playbook.yaml new file mode 100644 index 0000000000..be7ea53778 --- /dev/null +++ b/python/cm/tests/bundles/provider/playbook.yaml @@ -0,0 +1,10 @@ +--- +- name: sleep + hosts: all + connection: local + gather_facts: no + + tasks: + - name: sleep + pause: + seconds: 1 diff --git a/python/cm/tests/files/response_templates/cluster.json.j2 b/python/cm/tests/files/response_templates/cluster.json.j2 new file mode 100644 index 0000000000..738e834bf8 --- /dev/null +++ b/python/cm/tests/files/response_templates/cluster.json.j2 @@ -0,0 +1,23 @@ +{ + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "name": "cluster_1", + "id": {{ id }}, + "version": "1.0", + "edition": "community", + "state": "created", + "multi_state": [], + "before_upgrade": { + "state": null + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/one_host.json.j2 b/python/cm/tests/files/response_templates/one_host.json.j2 new file mode 100644 index 0000000000..c8d616ffc8 --- /dev/null +++ b/python/cm/tests/files/response_templates/one_host.json.j2 @@ -0,0 +1,17 @@ +{ + "{{ host_fqdn }}": { + "integer": 10, + "password": { + "__ansible_vault": "{{ password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ], + "adcm_hostid": {{ adcm_hostid }}, + "state": "created", + "multi_state": [] + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/provider.json.j2 b/python/cm/tests/files/response_templates/provider.json.j2 new file mode 100644 index 0000000000..0752743aa1 --- /dev/null +++ b/python/cm/tests/files/response_templates/provider.json.j2 @@ -0,0 +1,22 @@ +{ + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "name": "provider", + "id": {{ id }}, + "host_prototype_id": {{ host_prototype_id }}, + "state": "created", + "multi_state": [], + "before_upgrade": { + "state": null + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/service_one_component.json.j2 b/python/cm/tests/files/response_templates/service_one_component.json.j2 new file mode 100644 index 0000000000..fb312a6525 --- /dev/null +++ b/python/cm/tests/files/response_templates/service_one_component.json.j2 @@ -0,0 +1,47 @@ +{ + "service_one_component": { + "id": {{ service_id }}, + "version": "1.0", + "state": "created", + "multi_state": [], + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ service_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "maintenance_mode": false, + "display_name": "service_one_component", + "before_upgrade": { + "state": null + }, + "component_1": { + "component_id": {{ component_id }}, + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ component_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "component_1", + "before_upgrade": { + "state": null + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/service_two_components.json.j2 b/python/cm/tests/files/response_templates/service_two_components.json.j2 new file mode 100644 index 0000000000..bc677c351b --- /dev/null +++ b/python/cm/tests/files/response_templates/service_two_components.json.j2 @@ -0,0 +1,69 @@ +{ + "service_two_components": { + "id": {{ service_id }}, + "version": "1.0", + "state": "created", + "multi_state": [], + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ service_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "maintenance_mode": false, + "display_name": "service_two_components", + "before_upgrade": { + "state": null + }, + "component_1": { + "component_id": {{ component_1_id }}, + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ component_1_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "component_1", + "before_upgrade": { + "state": null + } + }, + "component_2": { + "component_id": {{ component_2_id }}, + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ component_2_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "component_2", + "before_upgrade": { + "state": null + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/two_hosts.json.j2 b/python/cm/tests/files/response_templates/two_hosts.json.j2 new file mode 100644 index 0000000000..59e3f34683 --- /dev/null +++ b/python/cm/tests/files/response_templates/two_hosts.json.j2 @@ -0,0 +1,32 @@ +{ + "host_1": { + "integer": 10, + "password": { + "__ansible_vault": "{{ host_1_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ], + "adcm_hostid": {{ host_1_id }}, + "state": "created", + "multi_state": [] + }, + "host_2": { + "integer": 10, + "password": { + "__ansible_vault": "{{ host_2_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ], + "adcm_hostid": {{ host_2_id }}, + "state": "created", + "multi_state": [] + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/two_services_two_components_each.json.j2 b/python/cm/tests/files/response_templates/two_services_two_components_each.json.j2 new file mode 100644 index 0000000000..89b203ff02 --- /dev/null +++ b/python/cm/tests/files/response_templates/two_services_two_components_each.json.j2 @@ -0,0 +1,136 @@ +{ + "service_two_components": { + "id": {{ service_1_id }}, + "version": "1.0", + "state": "created", + "multi_state": [], + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ service_1_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "maintenance_mode": false, + "display_name": "service_two_components", + "before_upgrade": { + "state": null + }, + "component_1": { + "component_id": {{ component_1_s1_id }}, + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ component_1_s1_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "component_1", + "before_upgrade": { + "state": null + } + }, + "component_2": { + "component_id": {{ component_2_s1_id }}, + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ component_2_s1_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "component_2", + "before_upgrade": { + "state": null + } + } + }, + "another_service_two_components": { + "id": {{ service_2_id }}, + "version": "1.0", + "state": "created", + "multi_state": [], + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ service_2_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "maintenance_mode": false, + "display_name": "another_service_two_components", + "before_upgrade": { + "state": null + }, + "component_1": { + "component_id": {{ component_1_s2_id }}, + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ component_1_s2_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "component_1", + "before_upgrade": { + "state": null + } + }, + "component_2": { + "component_id": {{ component_2_s2_id }}, + "config": { + "integer": 10, + "password": { + "__ansible_vault": "{{ component_2_s2_password }}" + }, + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "component_2", + "before_upgrade": { + "state": null + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/test_inventory.py b/python/cm/tests/test_inventory.py index 6bc370db6a..37209d4e2f 100644 --- a/python/cm/tests/test_inventory.py +++ b/python/cm/tests/test_inventory.py @@ -10,10 +10,15 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pylint: disable=too-many-lines, attribute-defined-outside-init, too-many-locals + +from functools import reduce from json import loads from pathlib import Path +from typing import Any, Mapping, TypeAlias from unittest.mock import Mock, patch +from api_v2.service.utils import bulk_add_services_to_cluster from cm.api import add_hc, add_service_to_cluster, update_obj_config from cm.inventory import ( MAINTENANCE_MODE, @@ -23,6 +28,7 @@ get_host, get_host_groups, get_host_vars, + get_inventory_data, get_obj_config, get_provider_config, get_provider_hosts, @@ -38,6 +44,7 @@ HostComponent, JobLog, MaintenanceMode, + ObjectType, Prototype, ServiceComponent, TaskLog, @@ -59,10 +66,13 @@ from django.urls import reverse from django.utils import timezone from init_db import init as init_adcm +from jinja2 import Template from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from adcm.tests.base import APPLICATION_JSON, BaseTestCase, BusinessLogicMixin + +TemplatesData: TypeAlias = Mapping[tuple[str, ...], tuple[Path, Mapping[str, Any]]] class TestInventory(BaseTestCase): @@ -724,3 +734,599 @@ def test_host_in_target_group_hostaction_on_host_not_in_mm_success(self): )["target"]["hosts"] self.assertIn(self.host_target_group_2.fqdn, target_hosts_data) + + +class TestInventoryComponents(BusinessLogicMixin, BaseTestCase): + def setUp(self) -> None: + self.maxDiff = None # pylint: disable=invalid-name + + bundles_dir = Path(__file__).parent / "bundles" + self.templates_dir = Path(__file__).parent / "files/response_templates" + + self.provider_bundle = self.add_bundle(source_dir=bundles_dir / "provider") + cluster_bundle = self.add_bundle(source_dir=bundles_dir / "cluster_1") + + self.cluster_1 = self.add_cluster(bundle=cluster_bundle, name="cluster_1") + self.provider = self.add_provider(bundle=self.provider_bundle, name="provider") + self.host_1 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_1", cluster=self.cluster_1 + ) + + def _check_hosts_topology(self, data: Mapping[str, dict], expected: Mapping[str, list[str]]) -> None: + errors = set(data.keys()).symmetric_difference(set(expected.keys())) + self.assertSetEqual(errors, set()) + + for group_name, host_names in expected.items(): + errors = set(data[group_name]["hosts"].keys()).symmetric_difference(set(host_names)) + self.assertSetEqual(errors, set()) + + def _check_data_by_template(self, data: Mapping[str, dict], templates_data: TemplatesData) -> None: + for key_chain, template_data in templates_data.items(): + template_path, kwargs = template_data + + expected_data = loads( + Template(source=template_path.read_text(encoding=settings.ENCODING_UTF_8)).render(kwargs), strict=False + ) + actual_data = reduce(dict.get, key_chain, data) + + self.assertDictEqual(actual_data, expected_data) + + def _prepare_two_services( + self, + ) -> tuple[ClusterObject, ServiceComponent, ServiceComponent, ClusterObject, ServiceComponent, ServiceComponent]: + service_two_components: ClusterObject = bulk_add_services_to_cluster( + cluster=self.cluster_1, + prototypes=Prototype.objects.filter( + type=ObjectType.SERVICE, name="service_two_components", bundle=self.cluster_1.prototype.bundle + ), + ).get() + component_1_s1 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_1") + component_2_s1 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_2") + + another_service_two_components: ClusterObject = bulk_add_services_to_cluster( + cluster=self.cluster_1, + prototypes=Prototype.objects.filter( + type=ObjectType.SERVICE, name="another_service_two_components", bundle=self.cluster_1.prototype.bundle + ), + ).get() + component_1_s2 = ServiceComponent.objects.get( + service=another_service_two_components, prototype__name="component_1" + ) + component_2_s2 = ServiceComponent.objects.get( + service=another_service_two_components, prototype__name="component_2" + ) + + return ( + service_two_components, + component_1_s1, + component_2_s1, + another_service_two_components, + component_1_s2, + component_2_s2, + ) + + def _get_action_on_host_expected_template_data_part(self, host: Host) -> TemplatesData: + return { + ("HOST", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": host.fqdn, + "adcm_hostid": host.pk, + "password": ConfigLog.objects.get(pk=host.config.current).config["password"], + }, + ), + ("HOST", "vars", "provider"): ( + self.templates_dir / "provider.json.j2", + { + "id": host.provider.pk, + "password": ConfigLog.objects.get(pk=host.provider.config.current).config["password"], + "host_prototype_id": host.prototype.pk, + }, + ), + } + + def test_1_component_1_host(self): + service_one_component: ClusterObject = bulk_add_services_to_cluster( + cluster=self.cluster_1, + prototypes=Prototype.objects.filter( + type=ObjectType.SERVICE, name="service_one_component", bundle=self.cluster_1.prototype.bundle + ), + ).get() + component_1 = ServiceComponent.objects.get(service=service_one_component, prototype__name="component_1") + + self.add_hostcomponent_map( + cluster=self.cluster_1, + hc_map=[ + {"service_id": service_one_component.pk, "component_id": component_1.pk, "host_id": self.host_1.pk} + ], + ) + + action_on_cluster = Action.objects.get(name="action_on_cluster", prototype=self.cluster_1.prototype) + action_on_service = Action.objects.get(name="action_on_service", prototype=service_one_component.prototype) + action_on_component = Action.objects.get(name="action_on_component", prototype=component_1.prototype) + action_on_host = Action.objects.get(name="action_on_host", prototype=self.host_1.prototype) + + host_names = [self.host_1.fqdn] + expected_topology = { + "CLUSTER": host_names, + f"{service_one_component.name}.{component_1.name}": host_names, + service_one_component.name: host_names, + } + + expected_data = { + ("CLUSTER", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + "password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster_1.pk, + "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "service_one_component.json.j2", + { + "service_id": service_one_component.pk, + "service_password": ConfigLog.objects.get(pk=service_one_component.config.current).config[ + "password" + ], + "component_id": component_1.pk, + "component_password": ConfigLog.objects.get(pk=component_1.config.current).config["password"], + }, + ), + } + + for obj, action, expected_topology, expected_data in ( + (self.cluster_1, action_on_cluster, expected_topology, expected_data), + (service_one_component, action_on_service, expected_topology, expected_data), + (component_1, action_on_component, expected_topology, expected_data), + ( + self.host_1, + action_on_host, + {**expected_topology, **{"HOST": host_names}}, + {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + ), + ): + with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): + actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] + + self._check_hosts_topology(data=actual_inventory, expected=expected_topology) + self._check_data_by_template(data=actual_inventory, templates_data=expected_data) + + def test_2_components_2_hosts_mapped_all_to_all(self): + self.host_2 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster_1 + ) + + service_two_components: ClusterObject = bulk_add_services_to_cluster( + cluster=self.cluster_1, + prototypes=Prototype.objects.filter( + type=ObjectType.SERVICE, name="service_two_components", bundle=self.cluster_1.prototype.bundle + ), + ).get() + component_1 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_1") + component_2 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_2") + + self.add_hostcomponent_map( + cluster=self.cluster_1, + hc_map=[ + {"service_id": service_two_components.pk, "component_id": component_1.pk, "host_id": self.host_1.pk}, + {"service_id": service_two_components.pk, "component_id": component_1.pk, "host_id": self.host_2.pk}, + {"service_id": service_two_components.pk, "component_id": component_2.pk, "host_id": self.host_1.pk}, + {"service_id": service_two_components.pk, "component_id": component_2.pk, "host_id": self.host_2.pk}, + ], + ) + + action_on_cluster = Action.objects.get(name="action_on_cluster", prototype=self.cluster_1.prototype) + action_on_service = Action.objects.get(name="action_on_service", prototype=service_two_components.prototype) + action_on_component_1 = Action.objects.get(name="action_on_component_1", prototype=component_1.prototype) + action_on_component_2 = Action.objects.get(name="action_on_component_2", prototype=component_2.prototype) + action_on_host_1 = Action.objects.get(name="action_on_host", prototype=self.host_1.prototype) + action_on_host_2 = Action.objects.get(name="action_on_host", prototype=self.host_2.prototype) + + host_names = [self.host_1.fqdn, self.host_2.fqdn] + expected_hosts_topology = { + "CLUSTER": host_names, + f"{service_two_components.name}.{component_1.name}": host_names, + f"{service_two_components.name}.{component_2.name}": host_names, + service_two_components.name: host_names, + } + + expected_data = { + ("CLUSTER", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_1_password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + "host_2_id": self.host_2.pk, + "host_2_password": ConfigLog.objects.get(pk=self.host_2.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster_1.pk, + "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "service_two_components.json.j2", + { + "service_id": service_two_components.pk, + "service_password": ConfigLog.objects.get(pk=service_two_components.config.current).config[ + "password" + ], + "component_1_id": component_1.pk, + "component_1_password": ConfigLog.objects.get(pk=component_1.config.current).config["password"], + "component_2_id": component_2.pk, + "component_2_password": ConfigLog.objects.get(pk=component_2.config.current).config["password"], + }, + ), + } + + for obj, action, expected_topology, expected_data in ( + (self.cluster_1, action_on_cluster, expected_hosts_topology, expected_data), + (service_two_components, action_on_service, expected_hosts_topology, expected_data), + (component_1, action_on_component_1, expected_hosts_topology, expected_data), + (component_2, action_on_component_2, expected_hosts_topology, expected_data), + ( + self.host_1, + action_on_host_1, + {**expected_hosts_topology, **{"HOST": [self.host_1.fqdn]}}, + {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + ), + ( + self.host_2, + action_on_host_2, + {**expected_hosts_topology, **{"HOST": [self.host_2.fqdn]}}, + {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_2)}, + ), + ): + with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): + actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] + + self._check_hosts_topology(data=actual_inventory, expected=expected_topology) + self._check_data_by_template(data=actual_inventory, templates_data=expected_data) + + def test_2_components_2_hosts_mapped_in_pairs(self): + self.host_2 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster_1 + ) + + service_two_components: ClusterObject = bulk_add_services_to_cluster( + cluster=self.cluster_1, + prototypes=Prototype.objects.filter( + type=ObjectType.SERVICE, name="service_two_components", bundle=self.cluster_1.prototype.bundle + ), + ).get() + component_1 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_1") + component_2 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_2") + + self.add_hostcomponent_map( + cluster=self.cluster_1, + hc_map=[ + {"service_id": service_two_components.pk, "component_id": component_1.pk, "host_id": self.host_1.pk}, + {"service_id": service_two_components.pk, "component_id": component_2.pk, "host_id": self.host_2.pk}, + ], + ) + + action_on_cluster = Action.objects.get(name="action_on_cluster", prototype=self.cluster_1.prototype) + action_on_service = Action.objects.get(name="action_on_service", prototype=service_two_components.prototype) + action_on_component_1 = Action.objects.get(name="action_on_component_1", prototype=component_1.prototype) + action_on_component_2 = Action.objects.get(name="action_on_component_2", prototype=component_2.prototype) + action_on_host_1 = Action.objects.get(name="action_on_host", prototype=self.host_1.prototype) + action_on_host_2 = Action.objects.get(name="action_on_host", prototype=self.host_2.prototype) + + host_names = [self.host_1.fqdn, self.host_2.fqdn] + expected_hosts_topology = { + "CLUSTER": host_names, + f"{service_two_components.name}.{component_1.name}": [self.host_1.fqdn], + f"{service_two_components.name}.{component_2.name}": [self.host_2.fqdn], + service_two_components.name: host_names, + } + + expected_data = { + ("CLUSTER", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_1_password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + "host_2_id": self.host_2.pk, + "host_2_password": ConfigLog.objects.get(pk=self.host_2.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster_1.pk, + "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "service_two_components.json.j2", + { + "service_id": service_two_components.pk, + "service_password": ConfigLog.objects.get(pk=service_two_components.config.current).config[ + "password" + ], + "component_1_id": component_1.pk, + "component_1_password": ConfigLog.objects.get(pk=component_1.config.current).config["password"], + "component_2_id": component_2.pk, + "component_2_password": ConfigLog.objects.get(pk=component_2.config.current).config["password"], + }, + ), + } + + for obj, action, expected_topology, expected_data in ( + (self.cluster_1, action_on_cluster, expected_hosts_topology, expected_data), + (service_two_components, action_on_service, expected_hosts_topology, expected_data), + (component_1, action_on_component_1, expected_hosts_topology, expected_data), + (component_2, action_on_component_2, expected_hosts_topology, expected_data), + ( + self.host_1, + action_on_host_1, + {**expected_hosts_topology, **{"HOST": [self.host_1.fqdn]}}, + {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + ), + ( + self.host_2, + action_on_host_2, + {**expected_hosts_topology, **{"HOST": [self.host_2.fqdn]}}, + {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_2)}, + ), + ): + with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): + actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] + + self._check_hosts_topology(data=actual_inventory, expected=expected_topology) + self._check_data_by_template(data=actual_inventory, templates_data=expected_data) + + def test_2_services_2_components_each_on_1_host(self): + ( + service_two_components, + component_1_s1, + component_2_s1, + another_service_two_components, + component_1_s2, + component_2_s2, + ) = self._prepare_two_services() + self.add_hostcomponent_map( + cluster=self.cluster_1, + hc_map=[ + {"service_id": service_two_components.pk, "component_id": component_1_s1.pk, "host_id": self.host_1.pk}, + {"service_id": service_two_components.pk, "component_id": component_2_s1.pk, "host_id": self.host_1.pk}, + { + "service_id": another_service_two_components.pk, + "component_id": component_1_s2.pk, + "host_id": self.host_1.pk, + }, + { + "service_id": another_service_two_components.pk, + "component_id": component_2_s2.pk, + "host_id": self.host_1.pk, + }, + ], + ) + + action_on_cluster = Action.objects.get(name="action_on_cluster", prototype=self.cluster_1.prototype) + action_on_service_1 = Action.objects.get(name="action_on_service", prototype=service_two_components.prototype) + action_on_service_2 = Action.objects.get( + name="action_on_service", prototype=another_service_two_components.prototype + ) + action_on_component_1_s1 = Action.objects.get(name="action_on_component_1", prototype=component_1_s1.prototype) + action_on_component_2_s1 = Action.objects.get(name="action_on_component_2", prototype=component_2_s1.prototype) + action_on_component_1_s2 = Action.objects.get(name="action_on_component_1", prototype=component_1_s2.prototype) + action_on_component_2_s2 = Action.objects.get(name="action_on_component_1", prototype=component_1_s2.prototype) + action_on_host_1 = Action.objects.get(name="action_on_host", prototype=self.host_1.prototype) + + host_names = [self.host_1.fqdn] + expected_hosts_topology = { + "CLUSTER": host_names, + f"{service_two_components.name}.{component_1_s1.name}": host_names, + f"{service_two_components.name}.{component_2_s1.name}": host_names, + f"{another_service_two_components.name}.{component_1_s2.name}": host_names, + f"{another_service_two_components.name}.{component_2_s2.name}": host_names, + service_two_components.name: host_names, + another_service_two_components.name: host_names, + } + + expected_data = { + ("CLUSTER", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + "password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster_1.pk, + "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "two_services_two_components_each.json.j2", + { + "service_1_id": service_two_components.pk, + "service_1_password": ConfigLog.objects.get(pk=service_two_components.config.current).config[ + "password" + ], + "component_1_s1_id": component_1_s1.pk, + "component_1_s1_password": ConfigLog.objects.get(pk=component_1_s1.config.current).config[ + "password" + ], + "component_2_s1_id": component_2_s1.pk, + "component_2_s1_password": ConfigLog.objects.get(pk=component_2_s1.config.current).config[ + "password" + ], + "service_2_id": another_service_two_components.pk, + "service_2_password": ConfigLog.objects.get( + pk=another_service_two_components.config.current + ).config["password"], + "component_1_s2_id": component_1_s2.pk, + "component_1_s2_password": ConfigLog.objects.get(pk=component_1_s2.config.current).config[ + "password" + ], + "component_2_s2_id": component_2_s2.pk, + "component_2_s2_password": ConfigLog.objects.get(pk=component_2_s2.config.current).config[ + "password" + ], + }, + ), + } + + for obj, action, expected_topology, expected_data in ( + (self.cluster_1, action_on_cluster, expected_hosts_topology, expected_data), + (service_two_components, action_on_service_1, expected_hosts_topology, expected_data), + (another_service_two_components, action_on_service_2, expected_hosts_topology, expected_data), + (component_1_s1, action_on_component_1_s1, expected_hosts_topology, expected_data), + (component_2_s1, action_on_component_2_s1, expected_hosts_topology, expected_data), + (component_1_s2, action_on_component_1_s2, expected_hosts_topology, expected_data), + (component_2_s2, action_on_component_2_s2, expected_hosts_topology, expected_data), + ( + self.host_1, + action_on_host_1, + {**expected_hosts_topology, **{"HOST": [self.host_1.fqdn]}}, + {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + ), + ): + with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): + actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] + + self._check_hosts_topology(data=actual_inventory, expected=expected_topology) + self._check_data_by_template(data=actual_inventory, templates_data=expected_data) + + def test_2_services_2_components_each_2_hosts_cross_mapping(self): + self.host_2 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster_1 + ) + ( + service_two_components, + component_1_s1, + component_2_s1, + another_service_two_components, + component_1_s2, + component_2_s2, + ) = self._prepare_two_services() + self.add_hostcomponent_map( + cluster=self.cluster_1, + hc_map=[ + {"service_id": service_two_components.pk, "component_id": component_1_s1.pk, "host_id": self.host_1.pk}, + {"service_id": service_two_components.pk, "component_id": component_2_s1.pk, "host_id": self.host_2.pk}, + { + "service_id": another_service_two_components.pk, + "component_id": component_1_s2.pk, + "host_id": self.host_1.pk, + }, + { + "service_id": another_service_two_components.pk, + "component_id": component_2_s2.pk, + "host_id": self.host_2.pk, + }, + ], + ) + + action_on_cluster = Action.objects.get(name="action_on_cluster", prototype=self.cluster_1.prototype) + action_on_service_1 = Action.objects.get(name="action_on_service", prototype=service_two_components.prototype) + action_on_service_2 = Action.objects.get( + name="action_on_service", prototype=another_service_two_components.prototype + ) + action_on_component_1_s1 = Action.objects.get(name="action_on_component_1", prototype=component_1_s1.prototype) + action_on_component_2_s1 = Action.objects.get(name="action_on_component_2", prototype=component_2_s1.prototype) + action_on_component_1_s2 = Action.objects.get(name="action_on_component_1", prototype=component_1_s2.prototype) + action_on_component_2_s2 = Action.objects.get(name="action_on_component_1", prototype=component_1_s2.prototype) + action_on_host_1 = Action.objects.get(name="action_on_host", prototype=self.host_1.prototype) + action_on_host_2 = Action.objects.get(name="action_on_host", prototype=self.host_2.prototype) + + expected_hosts_topology = { + "CLUSTER": [self.host_1.fqdn, self.host_2.fqdn], + f"{service_two_components.name}.{component_1_s1.name}": [self.host_1.fqdn], + f"{service_two_components.name}.{component_2_s1.name}": [self.host_2.fqdn], + f"{another_service_two_components.name}.{component_1_s2.name}": [self.host_1.fqdn], + f"{another_service_two_components.name}.{component_2_s2.name}": [self.host_2.fqdn], + service_two_components.name: [self.host_1.fqdn, self.host_2.fqdn], + another_service_two_components.name: [self.host_1.fqdn, self.host_2.fqdn], + } + + expected_data = { + ("CLUSTER", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_1_password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + "host_2_id": self.host_2.pk, + "host_2_password": ConfigLog.objects.get(pk=self.host_2.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster_1.pk, + "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "two_services_two_components_each.json.j2", + { + "service_1_id": service_two_components.pk, + "service_1_password": ConfigLog.objects.get(pk=service_two_components.config.current).config[ + "password" + ], + "component_1_s1_id": component_1_s1.pk, + "component_1_s1_password": ConfigLog.objects.get(pk=component_1_s1.config.current).config[ + "password" + ], + "component_2_s1_id": component_2_s1.pk, + "component_2_s1_password": ConfigLog.objects.get(pk=component_2_s1.config.current).config[ + "password" + ], + "service_2_id": another_service_two_components.pk, + "service_2_password": ConfigLog.objects.get( + pk=another_service_two_components.config.current + ).config["password"], + "component_1_s2_id": component_1_s2.pk, + "component_1_s2_password": ConfigLog.objects.get(pk=component_1_s2.config.current).config[ + "password" + ], + "component_2_s2_id": component_2_s2.pk, + "component_2_s2_password": ConfigLog.objects.get(pk=component_2_s2.config.current).config[ + "password" + ], + }, + ), + } + + for obj, action, expected_topology, expected_data in ( + (self.cluster_1, action_on_cluster, expected_hosts_topology, expected_data), + (service_two_components, action_on_service_1, expected_hosts_topology, expected_data), + (another_service_two_components, action_on_service_2, expected_hosts_topology, expected_data), + (component_1_s1, action_on_component_1_s1, expected_hosts_topology, expected_data), + (component_2_s1, action_on_component_2_s1, expected_hosts_topology, expected_data), + (component_1_s2, action_on_component_1_s2, expected_hosts_topology, expected_data), + (component_2_s2, action_on_component_2_s2, expected_hosts_topology, expected_data), + ( + self.host_1, + action_on_host_1, + {**expected_hosts_topology, **{"HOST": [self.host_1.fqdn]}}, + {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + ), + ( + self.host_2, + action_on_host_2, + {**expected_hosts_topology, **{"HOST": [self.host_2.fqdn]}}, + {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_2)}, + ), + ): + with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): + actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] + + self._check_hosts_topology(data=actual_inventory, expected=expected_topology) + self._check_data_by_template(data=actual_inventory, templates_data=expected_data) From 118a41f6fc782c25b9f1dd23047fd6a4803c51a6 Mon Sep 17 00:00:00 2001 From: Igor Kuzmin Date: Mon, 15 Jan 2024 07:54:28 +0000 Subject: [PATCH 027/151] feature/ADCM-5155 extract CompareConfigSlice Task: https://tracker.yandex.ru/ADCM-5155 --- adcm-web/app/src/api/adcm/clusterConfigs.ts | 17 +- .../src/api/adcm/clusterGroupConfigConfigs.ts | 19 ++- .../adcm/clusterServiceComponentsConfigs.ts | 21 ++- .../adcm/clusterServiceGroupConfigConfigs.ts | 21 ++- .../src/api/adcm/clusterServicesConfigs.ts | 19 ++- adcm-web/app/src/api/adcm/hostConfigs.ts | 17 +- .../app/src/api/adcm/hostProviderConfigs.ts | 19 ++- .../adcm/hostProviderGroupConfigConfigs.ts | 19 ++- .../serviceComponentGroupConfigConfigs.ts | 34 ++-- adcm-web/app/src/api/adcm/settings.ts | 8 +- ...roviderConfigGroupConfigurationsCompare.ts | 26 +-- ...ostProviderPrimaryConfigurationsCompare.ts | 26 ++- .../useSettingsConfigurationsCompare.ts | 24 ++- ...ClusterConfigGroupConfigurationsCompare.ts | 20 ++- .../useClusterPrimaryConfigurationsCompare.ts | 26 ++- ...eConfigGroupSingleConfigurationsCompare.ts | 28 ++-- .../useServicesPrimaryConfigurationCompare.ts | 25 ++- ...useComponentPrimaryConfigurationCompare.ts | 26 ++- ...mponentConfigGroupConfigurationsCompare.ts | 36 +++-- .../useHostPrimaryConfigurationCompare.ts | 24 ++- .../clusterConfigGroupConfigurationSlice.ts | 4 +- ...erConfigGroupConfigurationsCompareSlice.ts | 132 ---------------- .../clusterConfigurationSlice.ts | 4 +- .../clusterConfigurationsCompareSlice.ts | 131 ---------------- .../serviceConfigGroupConfigurationSlice.ts | 6 +- ...ceConfigGroupConfigurationsCompareSlice.ts | 133 ---------------- ...eComponentConfigGroupConfigurationSlice.ts | 20 +-- ...ntConfigGroupConfigurationsCompareSlice.ts | 148 ------------------ .../serviceComponentConfigurationSlice.ts | 4 +- ...viceComponentConfigurationsCompareSlice.ts | 132 ---------------- .../servicesConfigurationSlice.ts | 4 +- .../servicesConfigurationsCompareSlice.ts | 132 ---------------- .../compareSlice.constants.ts | 87 ++++++++++ .../compareSlice.ts} | 51 +++--- .../entityConfiguration/compareSlice.types.ts | 136 ++++++++++++++++ .../hostsConfigurationCompareSlice.ts | 131 ---------------- .../configuration/hostsConfigurationSlice.ts | 4 +- .../hostProviderConfigurationSlice.ts | 4 +- .../hostProviderConfigurationsCompareSlice.ts | 131 ---------------- ...stProviderConfigGroupConfigurationSlice.ts | 4 +- .../settingsConfigurationSlice.ts | 5 +- .../settingsConfigurationsCompareSlice.ts | 130 --------------- adcm-web/app/src/store/store.ts | 23 +-- 43 files changed, 591 insertions(+), 1420 deletions(-) delete mode 100644 adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationsCompareSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationsCompareSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationsCompareSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationsCompareSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationsCompareSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationsCompareSlice.ts create mode 100644 adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.constants.ts rename adcm-web/app/src/store/adcm/{hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationsCompareSlice.ts => entityConfiguration/compareSlice.ts} (60%) create mode 100644 adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.types.ts delete mode 100644 adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationCompareSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationsCompareSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationsCompareSlice.ts diff --git a/adcm-web/app/src/api/adcm/clusterConfigs.ts b/adcm-web/app/src/api/adcm/clusterConfigs.ts index 5ceeffe2b0..6814891ad4 100644 --- a/adcm-web/app/src/api/adcm/clusterConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterConfigs.ts @@ -8,6 +8,15 @@ import { ConfigurationAttributes, } from '@models/adcm'; +type GetConfigArgs = { + clusterId: number; + configId: number; +}; + +type GetConfigSchemaArgs = { + clusterId: number; +}; + export class AdcmClusterConfigsApi { public static async getConfigs(clusterId: number) { const response = await httpClient.get>( @@ -16,13 +25,13 @@ export class AdcmClusterConfigsApi { return response.data; } - public static async getConfig(clusterId: number, configId: number) { - const response = await httpClient.get(`/api/v2/clusters/${clusterId}/configs/${configId}/`); + public static async getConfig(args: GetConfigArgs) { + const response = await httpClient.get(`/api/v2/clusters/${args.clusterId}/configs/${args.configId}/`); return response.data; } - public static async getConfigSchema(clusterId: number) { - const response = await httpClient.get(`/api/v2/clusters/${clusterId}/config-schema/`); + public static async getConfigSchema(args: GetConfigSchemaArgs) { + const response = await httpClient.get(`/api/v2/clusters/${args.clusterId}/config-schema/`); return response.data; } diff --git a/adcm-web/app/src/api/adcm/clusterGroupConfigConfigs.ts b/adcm-web/app/src/api/adcm/clusterGroupConfigConfigs.ts index 7c80bcead6..764a2a36f3 100644 --- a/adcm-web/app/src/api/adcm/clusterGroupConfigConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterGroupConfigConfigs.ts @@ -8,6 +8,17 @@ import { ConfigurationAttributes, } from '@models/adcm'; +type GetConfigArgs = { + clusterId: number; + configGroupId: number; + configId: number; +}; + +type GetConfigSchemaArgs = { + clusterId: number; + configGroupId: number; +}; + export class AdcmClusterGroupConfigsConfigsApi { public static async getConfigs(clusterId: number, configGroupId: number) { const response = await httpClient.get>( @@ -16,16 +27,16 @@ export class AdcmClusterGroupConfigsConfigsApi { return response.data; } - public static async getConfig(clusterId: number, configGroupId: number, configId: number) { + public static async getConfig(args: GetConfigArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/config-groups/${configGroupId}/configs/${configId}/`, + `/api/v2/clusters/${args.clusterId}/config-groups/${args.configGroupId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(clusterId: number, configGroupId: number) { + public static async getConfigSchema(args: GetConfigSchemaArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/config-groups/${configGroupId}/config-schema/`, + `/api/v2/clusters/${args.clusterId}/config-groups/${args.configGroupId}/config-schema/`, ); return response.data; } diff --git a/adcm-web/app/src/api/adcm/clusterServiceComponentsConfigs.ts b/adcm-web/app/src/api/adcm/clusterServiceComponentsConfigs.ts index ae09b09109..376db4ae90 100644 --- a/adcm-web/app/src/api/adcm/clusterServiceComponentsConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterServiceComponentsConfigs.ts @@ -8,6 +8,19 @@ import { ConfigurationAttributes, } from '@models/adcm'; +export type GetConfigArgs = { + clusterId: number; + serviceId: number; + componentId: number; + configId: number; +}; + +export type GetConfigSchemaArgs = { + clusterId: number; + serviceId: number; + componentId: number; +}; + export class AdcmClusterServiceComponentsConfigsApi { public static async getConfigs(clusterId: number, serviceId: number, componentId: number) { const response = await httpClient.get>( @@ -16,16 +29,16 @@ export class AdcmClusterServiceComponentsConfigsApi { return response.data; } - public static async getConfig(clusterId: number, serviceId: number, componentId: number, configId: number) { + public static async getConfig(args: GetConfigArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/services/${serviceId}/components/${componentId}/configs/${configId}/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(clusterId: number, serviceId: number, componentId: number) { + public static async getConfigSchema(args: GetConfigSchemaArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/services/${serviceId}/components/${componentId}/config-schema/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/config-schema/`, ); return response.data; } diff --git a/adcm-web/app/src/api/adcm/clusterServiceGroupConfigConfigs.ts b/adcm-web/app/src/api/adcm/clusterServiceGroupConfigConfigs.ts index 991d6ed0d0..44ea3434e8 100644 --- a/adcm-web/app/src/api/adcm/clusterServiceGroupConfigConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterServiceGroupConfigConfigs.ts @@ -8,6 +8,19 @@ import { ConfigurationAttributes, } from '@models/adcm'; +type GetConfigArgs = { + clusterId: number; + serviceId: number; + configGroupId: number; + configId: number; +}; + +type GetConfigSchemaArgs = { + clusterId: number; + serviceId: number; + configGroupId: number; +}; + export class AdcmClusterServiceConfigGroupConfigsApi { public static async getConfigs(clusterId: number, serviceId: number, configGroupId: number) { const response = await httpClient.get>( @@ -16,16 +29,16 @@ export class AdcmClusterServiceConfigGroupConfigsApi { return response.data; } - public static async getConfig(clusterId: number, serviceId: number, configGroupId: number, configId: number) { + public static async getConfig(args: GetConfigArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/services/${serviceId}/config-groups/${configGroupId}/configs/${configId}/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/config-groups/${args.configGroupId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(clusterId: number, serviceId: number, configGroupId: number) { + public static async getConfigSchema(args: GetConfigSchemaArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/services/${serviceId}/config-groups/${configGroupId}/config-schema/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/config-groups/${args.configGroupId}/config-schema/`, ); return response.data; } diff --git a/adcm-web/app/src/api/adcm/clusterServicesConfigs.ts b/adcm-web/app/src/api/adcm/clusterServicesConfigs.ts index cfe917e8e2..615281e223 100644 --- a/adcm-web/app/src/api/adcm/clusterServicesConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterServicesConfigs.ts @@ -8,6 +8,17 @@ import { ConfigurationAttributes, } from '@models/adcm'; +type GetConfigArgs = { + clusterId: number; + serviceId: number; + configId: number; +}; + +type GetConfigSchemaArgs = { + clusterId: number; + serviceId: number; +}; + export class AdcmClusterServicesConfigsApi { public static async getConfigs(clusterId: number, serviceId: number) { const response = await httpClient.get>( @@ -16,16 +27,16 @@ export class AdcmClusterServicesConfigsApi { return response.data; } - public static async getConfig(clusterId: number, serviceId: number, configId: number) { + public static async getConfig(args: GetConfigArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/services/${serviceId}/configs/${configId}`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/configs/${args.configId}`, ); return response.data; } - public static async getConfigSchema(clusterId: number, serviceId: number) { + public static async getConfigSchema(args: GetConfigSchemaArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/services/${serviceId}/config-schema/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/config-schema/`, ); return response.data; } diff --git a/adcm-web/app/src/api/adcm/hostConfigs.ts b/adcm-web/app/src/api/adcm/hostConfigs.ts index 25f3ba0094..b5719444d9 100644 --- a/adcm-web/app/src/api/adcm/hostConfigs.ts +++ b/adcm-web/app/src/api/adcm/hostConfigs.ts @@ -8,6 +8,15 @@ import { ConfigurationAttributes, } from '@models/adcm'; +type GetConfigArgs = { + hostId: number; + configId: number; +}; + +type GetConfigSchemaArgs = { + hostId: number; +}; + export class AdcmHostConfigsApi { public static async getConfigs(hostId: number) { const response = await httpClient.get>( @@ -16,13 +25,13 @@ export class AdcmHostConfigsApi { return response.data; } - public static async getConfig(hostId: number, configId: number) { - const response = await httpClient.get(`/api/v2/hosts/${hostId}/configs/${configId}/`); + public static async getConfig(args: GetConfigArgs) { + const response = await httpClient.get(`/api/v2/hosts/${args.hostId}/configs/${args.configId}/`); return response.data; } - public static async getConfigSchema(hostId: number) { - const response = await httpClient.get(`/api/v2/hosts/${hostId}/config-schema/`); + public static async getConfigSchema(args: GetConfigSchemaArgs) { + const response = await httpClient.get(`/api/v2/hosts/${args.hostId}/config-schema/`); return response.data; } diff --git a/adcm-web/app/src/api/adcm/hostProviderConfigs.ts b/adcm-web/app/src/api/adcm/hostProviderConfigs.ts index 3667979ad3..79ffe0a8e2 100644 --- a/adcm-web/app/src/api/adcm/hostProviderConfigs.ts +++ b/adcm-web/app/src/api/adcm/hostProviderConfigs.ts @@ -8,6 +8,15 @@ import { ConfigurationAttributes, } from '@models/adcm'; +type GetConfigArgs = { + hostProviderId: number; + configId: number; +}; + +type GetConfigSchemaArgs = { + hostProviderId: number; +}; + export class AdcmHostProviderConfigsApi { public static async getConfigs(hostProviderId: number) { const response = await httpClient.get>( @@ -16,14 +25,16 @@ export class AdcmHostProviderConfigsApi { return response.data; } - public static async getConfig(hostProviderId: number, configId: number) { - const response = await httpClient.get(`/api/v2/hostproviders/${hostProviderId}/configs/${configId}/`); + public static async getConfig(args: GetConfigArgs) { + const response = await httpClient.get( + `/api/v2/hostproviders/${args.hostProviderId}/configs/${args.configId}/`, + ); return response.data; } - public static async getConfigSchema(hostProviderId: number) { + public static async getConfigSchema(args: GetConfigSchemaArgs) { const response = await httpClient.get( - `/api/v2/hostproviders/${hostProviderId}/config-schema/`, + `/api/v2/hostproviders/${args.hostProviderId}/config-schema/`, ); return response.data; } diff --git a/adcm-web/app/src/api/adcm/hostProviderGroupConfigConfigs.ts b/adcm-web/app/src/api/adcm/hostProviderGroupConfigConfigs.ts index f629a62768..99cffec706 100644 --- a/adcm-web/app/src/api/adcm/hostProviderGroupConfigConfigs.ts +++ b/adcm-web/app/src/api/adcm/hostProviderGroupConfigConfigs.ts @@ -8,6 +8,17 @@ import { ConfigurationAttributes, } from '@models/adcm'; +type GetConfigArgs = { + hostProviderId: number; + configGroupId: number; + configId: number; +}; + +type GetConfigSchemaArgs = { + hostProviderId: number; + configGroupId: number; +}; + export class AdcmHostProviderGroupConfigsConfigsApi { public static async getConfigs(hostProviderId: number, configGroupId: number) { const response = await httpClient.get>( @@ -16,16 +27,16 @@ export class AdcmHostProviderGroupConfigsConfigsApi { return response.data; } - public static async getConfig(hostProviderId: number, configGroupId: number, configId: number) { + public static async getConfig(args: GetConfigArgs) { const response = await httpClient.get( - `/api/v2/hostproviders/${hostProviderId}/config-groups/${configGroupId}/configs/${configId}/`, + `/api/v2/hostproviders/${args.hostProviderId}/config-groups/${args.configGroupId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(hostProviderId: number, configGroupId: number) { + public static async getConfigSchema(args: GetConfigSchemaArgs) { const response = await httpClient.get( - `/api/v2/hostproviders/${hostProviderId}/config-groups/${configGroupId}/config-schema/`, + `/api/v2/hostproviders/${args.hostProviderId}/config-groups/${args.configGroupId}/config-schema/`, ); return response.data; } diff --git a/adcm-web/app/src/api/adcm/serviceComponentGroupConfigConfigs.ts b/adcm-web/app/src/api/adcm/serviceComponentGroupConfigConfigs.ts index 9763dcd59d..8fdabc3737 100644 --- a/adcm-web/app/src/api/adcm/serviceComponentGroupConfigConfigs.ts +++ b/adcm-web/app/src/api/adcm/serviceComponentGroupConfigConfigs.ts @@ -8,6 +8,21 @@ import { ConfigurationAttributes, } from '@models/adcm'; +type GetConfigArgs = { + clusterId: number; + serviceId: number; + componentId: number; + configGroupId: number; + configId: number; +}; + +type GetConfigSchemaArgs = { + clusterId: number; + serviceId: number; + componentId: number; + configGroupId: number; +}; + export class AdcmClusterServiceComponentGroupConfigConfigsApi { public static async getConfigs(clusterId: number, serviceId: number, componentId: number, configGroupId: number) { const response = await httpClient.get>( @@ -16,27 +31,16 @@ export class AdcmClusterServiceComponentGroupConfigConfigsApi { return response.data; } - public static async getConfig( - clusterId: number, - serviceId: number, - componentId: number, - configGroupId: number, - configId: number, - ) { + public static async getConfig(args: GetConfigArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/services/${serviceId}/components/${componentId}/config-groups/${configGroupId}/configs/${configId}/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/config-groups/${args.configGroupId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema( - clusterId: number, - serviceId: number, - componentId: number, - configGroupId: number, - ) { + public static async getConfigSchema(args: GetConfigSchemaArgs) { const response = await httpClient.get( - `/api/v2/clusters/${clusterId}/services/${serviceId}/components/${componentId}/config-groups/${configGroupId}/config-schema/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/config-groups/${args.configGroupId}/config-schema/`, ); return response.data; } diff --git a/adcm-web/app/src/api/adcm/settings.ts b/adcm-web/app/src/api/adcm/settings.ts index 201f565465..8957542e40 100644 --- a/adcm-web/app/src/api/adcm/settings.ts +++ b/adcm-web/app/src/api/adcm/settings.ts @@ -12,6 +12,10 @@ import { AdcmDynamicActionRunConfig, } from '@models/adcm'; +type GetConfigArgs = { + configId: number; +}; + export class AdcmSettingsApi { public static async getSettings() { const response = await httpClient.get('/api/v2/adcm/'); @@ -23,8 +27,8 @@ export class AdcmSettingsApi { return response.data; } - public static async getConfig(configId: number) { - const response = await httpClient.get(`/api/v2/adcm/configs/${configId}/`); + public static async getConfig(args: GetConfigArgs) { + const response = await httpClient.get(`/api/v2/adcm/configs/${args.configId}/`); return response.data; } diff --git a/adcm-web/app/src/components/pages/HostProviderPage/HostProviderConfigurationGroupSingle/HostProviderConfigGroupConfiguration/useHostProviderConfigGroupConfigurationsCompare.ts b/adcm-web/app/src/components/pages/HostProviderPage/HostProviderConfigurationGroupSingle/HostProviderConfigGroupConfiguration/useHostProviderConfigGroupConfigurationsCompare.ts index 8c9f77a472..693d400f4b 100644 --- a/adcm-web/app/src/components/pages/HostProviderPage/HostProviderConfigurationGroupSingle/HostProviderConfigGroupConfiguration/useHostProviderConfigGroupConfigurationsCompare.ts +++ b/adcm-web/app/src/components/pages/HostProviderPage/HostProviderConfigurationGroupSingle/HostProviderConfigGroupConfiguration/useHostProviderConfigGroupConfigurationsCompare.ts @@ -4,16 +4,14 @@ import { cleanupCompareSlice, getLeftConfiguration, getRightConfiguration, -} from '@store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationsCompareSlice.ts'; +} from '@store/adcm/entityConfiguration/compareSlice'; export const useHostProviderConfigGroupConfigurationsCompare = () => { const dispatch = useDispatch(); const hostProvider = useStore(({ adcm }) => adcm.hostProvider.hostProvider); const hostProviderConfigGroup = useStore((s) => s.adcm.hostProviderConfigGroup.hostProviderConfigGroup); - const leftConfiguration = useStore(({ adcm }) => adcm.hostProviderConfigGroupConfigurationsCompare.leftConfiguration); - const rightConfiguration = useStore( - ({ adcm }) => adcm.hostProviderConfigGroupConfigurationsCompare.rightConfiguration, - ); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { @@ -27,9 +25,12 @@ export const useHostProviderConfigGroupConfigurationsCompare = () => { if (hostProvider && hostProviderConfigGroup) { dispatch( getLeftConfiguration({ - hostProviderId: hostProvider.id, - configGroupId: hostProviderConfigGroup.id, - configId, + entityType: 'host-provider-config-group', + args: { + hostProviderId: hostProvider.id, + configGroupId: hostProviderConfigGroup.id, + configId, + }, }), ); } @@ -42,9 +43,12 @@ export const useHostProviderConfigGroupConfigurationsCompare = () => { if (hostProvider && hostProviderConfigGroup) { dispatch( getRightConfiguration({ - hostProviderId: hostProvider.id, - configGroupId: hostProviderConfigGroup.id, - configId, + entityType: 'host-provider-config-group', + args: { + hostProviderId: hostProvider.id, + configGroupId: hostProviderConfigGroup.id, + configId, + }, }), ); } diff --git a/adcm-web/app/src/components/pages/HostProviderPage/HostProviderPrimaryConfiguration/useHostProviderPrimaryConfigurationsCompare.ts b/adcm-web/app/src/components/pages/HostProviderPage/HostProviderPrimaryConfiguration/useHostProviderPrimaryConfigurationsCompare.ts index d2447ac3ea..d11cce0a3c 100644 --- a/adcm-web/app/src/components/pages/HostProviderPage/HostProviderPrimaryConfiguration/useHostProviderPrimaryConfigurationsCompare.ts +++ b/adcm-web/app/src/components/pages/HostProviderPage/HostProviderPrimaryConfiguration/useHostProviderPrimaryConfigurationsCompare.ts @@ -1,34 +1,46 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { - cleanupHostProviderConfigurationsCompareSlice, + cleanupCompareSlice, getLeftConfiguration, getRightConfiguration, -} from '@store/adcm/hostProvider/configuration/hostProviderConfigurationsCompareSlice'; +} from '@store/adcm/entityConfiguration/compareSlice'; export const useHostProviderPrimaryConfigurationsCompare = () => { const dispatch = useDispatch(); const hostProvider = useStore(({ adcm }) => adcm.hostProvider.hostProvider); - const leftConfiguration = useStore(({ adcm }) => adcm.hostProviderConfigurationsCompare.leftConfiguration); - const rightConfiguration = useStore(({ adcm }) => adcm.hostProviderConfigurationsCompare.rightConfiguration); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { - dispatch(cleanupHostProviderConfigurationsCompareSlice()); + dispatch(cleanupCompareSlice()); }, [hostProvider, dispatch], ); const getLeftConfig = useCallback( (configId: number) => { - hostProvider?.id && dispatch(getLeftConfiguration({ hostProviderId: hostProvider.id, configId })); + hostProvider?.id && + dispatch( + getLeftConfiguration({ + entityType: 'host-provider', + args: { hostProviderId: hostProvider.id, configId }, + }), + ); }, [hostProvider, dispatch], ); const getRightConfig = useCallback( (configId: number) => { - hostProvider?.id && dispatch(getRightConfiguration({ hostProviderId: hostProvider.id, configId })); + hostProvider?.id && + dispatch( + getRightConfiguration({ + entityType: 'host-provider', + args: { hostProviderId: hostProvider.id, configId }, + }), + ); }, [hostProvider, dispatch], ); diff --git a/adcm-web/app/src/components/pages/SettingsPage/SettingsConfiguration/useSettingsConfigurationsCompare.ts b/adcm-web/app/src/components/pages/SettingsPage/SettingsConfiguration/useSettingsConfigurationsCompare.ts index d485760761..05e5ec5492 100644 --- a/adcm-web/app/src/components/pages/SettingsPage/SettingsConfiguration/useSettingsConfigurationsCompare.ts +++ b/adcm-web/app/src/components/pages/SettingsPage/SettingsConfiguration/useSettingsConfigurationsCompare.ts @@ -1,33 +1,43 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { - cleanupSettingsConfigurationsCompareSlice, + cleanupCompareSlice, getLeftConfiguration, getRightConfiguration, -} from '@store/adcm/settings/configuration/settingsConfigurationsCompareSlice'; +} from '@store/adcm/entityConfiguration/compareSlice'; export const useSettingsConfigurationsCompare = () => { const dispatch = useDispatch(); - const leftConfiguration = useStore(({ adcm }) => adcm.settingsConfigurationsCompare.leftConfiguration); - const rightConfiguration = useStore(({ adcm }) => adcm.settingsConfigurationsCompare.rightConfiguration); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { - dispatch(cleanupSettingsConfigurationsCompareSlice()); + dispatch(cleanupCompareSlice()); }, [dispatch], ); const getLeftConfig = useCallback( (configId: number) => { - dispatch(getLeftConfiguration({ configId })); + dispatch( + getLeftConfiguration({ + entityType: 'settings', + args: { configId }, + }), + ); }, [dispatch], ); const getRightConfig = useCallback( (configId: number) => { - dispatch(getRightConfiguration({ configId })); + dispatch( + getRightConfiguration({ + entityType: 'settings', + args: { configId }, + }), + ); }, [dispatch], ); diff --git a/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterConfigGroupSingle/ClusterConfigGroupConfiguration/useClusterConfigGroupConfigurationsCompare.ts b/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterConfigGroupSingle/ClusterConfigGroupConfiguration/useClusterConfigGroupConfigurationsCompare.ts index 0db522a5ca..f016bb5d33 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterConfigGroupSingle/ClusterConfigGroupConfiguration/useClusterConfigGroupConfigurationsCompare.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterConfigGroupSingle/ClusterConfigGroupConfiguration/useClusterConfigGroupConfigurationsCompare.ts @@ -4,14 +4,14 @@ import { cleanupCompareSlice, getLeftConfiguration, getRightConfiguration, -} from '@store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationsCompareSlice'; +} from '@store/adcm/entityConfiguration/compareSlice'; export const useClusterConfigGroupConfigurationsCompare = () => { const dispatch = useDispatch(); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); const clusterConfigGroup = useStore((s) => s.adcm.clusterConfigGroup.clusterConfigGroup); - const leftConfiguration = useStore(({ adcm }) => adcm.clusterConfigGroupConfigurationsCompare.leftConfiguration); - const rightConfiguration = useStore(({ adcm }) => adcm.clusterConfigGroupConfigurationsCompare.rightConfiguration); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { @@ -23,7 +23,12 @@ export const useClusterConfigGroupConfigurationsCompare = () => { const getLeftConfig = useCallback( (configId: number) => { if (cluster && clusterConfigGroup) { - dispatch(getLeftConfiguration({ clusterId: cluster.id, configGroupId: clusterConfigGroup.id, configId })); + dispatch( + getLeftConfiguration({ + entityType: 'cluster-config-group', + args: { clusterId: cluster.id, configGroupId: clusterConfigGroup.id, configId }, + }), + ); } }, [cluster, clusterConfigGroup, dispatch], @@ -32,7 +37,12 @@ export const useClusterConfigGroupConfigurationsCompare = () => { const getRightConfig = useCallback( (configId: number) => { if (cluster && clusterConfigGroup) { - dispatch(getRightConfiguration({ clusterId: cluster.id, configGroupId: clusterConfigGroup.id, configId })); + dispatch( + getRightConfiguration({ + entityType: 'cluster-config-group', + args: { clusterId: cluster.id, configGroupId: clusterConfigGroup.id, configId }, + }), + ); } }, [cluster, clusterConfigGroup, dispatch], diff --git a/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterPrimaryConfiguration/useClusterPrimaryConfigurationsCompare.ts b/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterPrimaryConfiguration/useClusterPrimaryConfigurationsCompare.ts index d42a781ceb..3c9f9aac04 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterPrimaryConfiguration/useClusterPrimaryConfigurationsCompare.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterPrimaryConfiguration/useClusterPrimaryConfigurationsCompare.ts @@ -1,34 +1,46 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { - cleanupClusterConfigurationsCompareSlice, + cleanupCompareSlice, getLeftConfiguration, getRightConfiguration, -} from '@store/adcm/cluster/configuration/clusterConfigurationsCompareSlice'; +} from '@store/adcm/entityConfiguration/compareSlice'; export const useClusterPrimaryConfigurationsCompare = () => { const dispatch = useDispatch(); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); - const leftConfiguration = useStore(({ adcm }) => adcm.clusterConfigurationsCompare.leftConfiguration); - const rightConfiguration = useStore(({ adcm }) => adcm.clusterConfigurationsCompare.rightConfiguration); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { - dispatch(cleanupClusterConfigurationsCompareSlice()); + dispatch(cleanupCompareSlice()); }, [cluster, dispatch], ); const getLeftConfig = useCallback( (configId: number) => { - cluster?.id && dispatch(getLeftConfiguration({ clusterId: cluster.id, configId })); + cluster?.id && + dispatch( + getLeftConfiguration({ + entityType: 'cluster', + args: { clusterId: cluster.id, configId }, + }), + ); }, [cluster, dispatch], ); const getRightConfig = useCallback( (configId: number) => { - cluster?.id && dispatch(getRightConfiguration({ clusterId: cluster.id, configId })); + cluster?.id && + dispatch( + getRightConfiguration({ + entityType: 'cluster', + args: { clusterId: cluster.id, configId }, + }), + ); }, [cluster, dispatch], ); diff --git a/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServiceConfigGroupSingle/ServiceConfigGroupSingleConfiguration/useServiceConfigGroupSingleConfigurationsCompare.ts b/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServiceConfigGroupSingle/ServiceConfigGroupSingleConfiguration/useServiceConfigGroupSingleConfigurationsCompare.ts index 0365ed13ff..b7fd78770c 100644 --- a/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServiceConfigGroupSingle/ServiceConfigGroupSingleConfiguration/useServiceConfigGroupSingleConfigurationsCompare.ts +++ b/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServiceConfigGroupSingle/ServiceConfigGroupSingleConfiguration/useServiceConfigGroupSingleConfigurationsCompare.ts @@ -4,15 +4,15 @@ import { getLeftConfiguration, cleanupCompareSlice, getRightConfiguration, -} from '@store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationsCompareSlice'; +} from '@store/adcm/entityConfiguration/compareSlice'; export const useServiceConfigGroupSingleConfigurationsCompare = () => { const dispatch = useDispatch(); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); const service = useStore(({ adcm }) => adcm.service.service); const serviceConfigGroup = useStore((s) => s.adcm.serviceConfigGroup.serviceConfigGroup); - const leftConfiguration = useStore(({ adcm }) => adcm.serviceConfigGroupConfigurationsCompare.leftConfiguration); - const rightConfiguration = useStore(({ adcm }) => adcm.serviceConfigGroupConfigurationsCompare.rightConfiguration); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { @@ -26,10 +26,13 @@ export const useServiceConfigGroupSingleConfigurationsCompare = () => { if (cluster && service && serviceConfigGroup) { dispatch( getLeftConfiguration({ - clusterId: cluster.id, - serviceId: service.id, - configGroupId: serviceConfigGroup.id, - configId, + entityType: 'service-config-group', + args: { + clusterId: cluster.id, + serviceId: service.id, + configGroupId: serviceConfigGroup.id, + configId, + }, }), ); } @@ -42,10 +45,13 @@ export const useServiceConfigGroupSingleConfigurationsCompare = () => { if (cluster && service && serviceConfigGroup) { dispatch( getRightConfiguration({ - clusterId: cluster.id, - serviceId: service.id, - configGroupId: serviceConfigGroup.id, - configId, + entityType: 'service-config-group', + args: { + clusterId: cluster.id, + serviceId: service.id, + configGroupId: serviceConfigGroup.id, + configId, + }, }), ); } diff --git a/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServicePrimaryConfiguration/useServicesPrimaryConfigurationCompare.ts b/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServicePrimaryConfiguration/useServicesPrimaryConfigurationCompare.ts index f5b0ac477f..4fb441fd60 100644 --- a/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServicePrimaryConfiguration/useServicesPrimaryConfigurationCompare.ts +++ b/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServicePrimaryConfiguration/useServicesPrimaryConfigurationCompare.ts @@ -1,27 +1,33 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { - cleanupClusterServicesConfigurationsCompareSlice, + cleanupCompareSlice, getLeftConfiguration, getRightConfiguration, -} from '@store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationsCompareSlice'; +} from '@store/adcm/entityConfiguration/compareSlice'; export const useServicesPrimaryConfigurationsCompare = () => { const dispatch = useDispatch(); const service = useStore(({ adcm }) => adcm.service.service); - const leftConfiguration = useStore(({ adcm }) => adcm.clusterServicesConfigurationsCompare.leftConfiguration); - const rightConfiguration = useStore(({ adcm }) => adcm.clusterServicesConfigurationsCompare.rightConfiguration); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { - dispatch(cleanupClusterServicesConfigurationsCompareSlice()); + dispatch(cleanupCompareSlice()); }, [service, dispatch], ); const getLeftConfig = useCallback( (configId: number) => { - service?.id && dispatch(getLeftConfiguration({ clusterId: service.cluster.id, serviceId: service.id, configId })); + service?.id && + dispatch( + getLeftConfiguration({ + entityType: 'service', + args: { clusterId: service.cluster.id, serviceId: service.id, configId }, + }), + ); }, [service, dispatch], ); @@ -29,7 +35,12 @@ export const useServicesPrimaryConfigurationsCompare = () => { const getRightConfig = useCallback( (configId: number) => { service?.id && - dispatch(getRightConfiguration({ clusterId: service.cluster.id, serviceId: service.id, configId })); + dispatch( + getRightConfiguration({ + entityType: 'service', + args: { clusterId: service.cluster.id, serviceId: service.id, configId }, + }), + ); }, [service, dispatch], ); diff --git a/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/useComponentPrimaryConfigurationCompare.ts b/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/useComponentPrimaryConfigurationCompare.ts index a22b0a571d..87fb2ed3ce 100644 --- a/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/useComponentPrimaryConfigurationCompare.ts +++ b/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/useComponentPrimaryConfigurationCompare.ts @@ -1,36 +1,48 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { - cleanupServiceComponentConfigurationsCompareSlice, + cleanupCompareSlice, getLeftConfiguration, getRightConfiguration, -} from '@store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationsCompareSlice'; +} from '@store/adcm/entityConfiguration/compareSlice'; import { useServiceComponentParams } from '@pages/cluster/service/component/useServiceComponentParams'; export const useComponentPrimaryConfigurationsCompare = () => { const dispatch = useDispatch(); const { clusterId, serviceId, componentId } = useServiceComponentParams(); - const leftConfiguration = useStore(({ adcm }) => adcm.serviceComponentsConfigurationsCompare.leftConfiguration); - const rightConfiguration = useStore(({ adcm }) => adcm.serviceComponentsConfigurationsCompare.rightConfiguration); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { - dispatch(cleanupServiceComponentConfigurationsCompareSlice()); + dispatch(cleanupCompareSlice()); }, [componentId, dispatch], ); const getLeftConfig = useCallback( (configId: number) => { - componentId && dispatch(getLeftConfiguration({ clusterId, serviceId, componentId, configId })); + componentId && + dispatch( + getLeftConfiguration({ + entityType: 'service-component', + args: { clusterId, serviceId, componentId, configId }, + }), + ); }, [clusterId, componentId, dispatch, serviceId], ); const getRightConfig = useCallback( (configId: number) => { - componentId && dispatch(getRightConfiguration({ clusterId, serviceId, componentId, configId })); + componentId && + dispatch( + getRightConfiguration({ + entityType: 'service-component', + args: { clusterId, serviceId, componentId, configId }, + }), + ); }, [clusterId, componentId, dispatch, serviceId], ); diff --git a/adcm-web/app/src/components/pages/cluster/service/component/ServiceComponentConfiguration/ServiceComponentConfigGroupSingle/ServiceComponentConfigGroupConfiguration/useServiceComponentConfigGroupConfigurationsCompare.ts b/adcm-web/app/src/components/pages/cluster/service/component/ServiceComponentConfiguration/ServiceComponentConfigGroupSingle/ServiceComponentConfigGroupConfiguration/useServiceComponentConfigGroupConfigurationsCompare.ts index 697ae00711..8ee087c63d 100644 --- a/adcm-web/app/src/components/pages/cluster/service/component/ServiceComponentConfiguration/ServiceComponentConfigGroupSingle/ServiceComponentConfigGroupConfiguration/useServiceComponentConfigGroupConfigurationsCompare.ts +++ b/adcm-web/app/src/components/pages/cluster/service/component/ServiceComponentConfiguration/ServiceComponentConfigGroupSingle/ServiceComponentConfigGroupConfiguration/useServiceComponentConfigGroupConfigurationsCompare.ts @@ -4,7 +4,7 @@ import { getLeftConfiguration, getRightConfiguration, cleanupCompareSlice, -} from '@store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationsCompareSlice'; +} from '@store/adcm/entityConfiguration/compareSlice'; export const useServiceComponentConfigGroupConfigurationsCompare = () => { const dispatch = useDispatch(); @@ -14,12 +14,8 @@ export const useServiceComponentConfigGroupConfigurationsCompare = () => { const serviceComponentConfigGroup = useStore( (s) => s.adcm.serviceComponentConfigGroupSingle.serviceComponentConfigGroup, ); - const leftConfiguration = useStore( - ({ adcm }) => adcm.serviceComponentConfigGroupConfigurationsCompare.leftConfiguration, - ); - const rightConfiguration = useStore( - ({ adcm }) => adcm.serviceComponentConfigGroupConfigurationsCompare.rightConfiguration, - ); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { @@ -33,11 +29,14 @@ export const useServiceComponentConfigGroupConfigurationsCompare = () => { if (cluster && service && component && serviceComponentConfigGroup) { dispatch( getLeftConfiguration({ - clusterId: cluster.id, - serviceId: service.id, - componentId: component.id, - configGroupId: serviceComponentConfigGroup.id, - configId, + entityType: 'service-component-config-group', + args: { + clusterId: cluster.id, + serviceId: service.id, + componentId: component.id, + configGroupId: serviceComponentConfigGroup.id, + configId, + }, }), ); } @@ -50,11 +49,14 @@ export const useServiceComponentConfigGroupConfigurationsCompare = () => { if (cluster && service && component && serviceComponentConfigGroup) { dispatch( getRightConfiguration({ - clusterId: cluster.id, - serviceId: service.id, - componentId: component.id, - configGroupId: serviceComponentConfigGroup.id, - configId, + entityType: 'service-component-config-group', + args: { + clusterId: cluster.id, + serviceId: service.id, + componentId: component.id, + configGroupId: serviceComponentConfigGroup.id, + configId, + }, }), ); } diff --git a/adcm-web/app/src/components/pages/host/HostPrimaryConfiguration/useHostPrimaryConfigurationCompare.ts b/adcm-web/app/src/components/pages/host/HostPrimaryConfiguration/useHostPrimaryConfigurationCompare.ts index 06c8a00c86..265877e587 100644 --- a/adcm-web/app/src/components/pages/host/HostPrimaryConfiguration/useHostPrimaryConfigurationCompare.ts +++ b/adcm-web/app/src/components/pages/host/HostPrimaryConfiguration/useHostPrimaryConfigurationCompare.ts @@ -1,36 +1,46 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { - cleanupHostsConfigurationsCompareSlice, + cleanupCompareSlice, getLeftConfiguration, getRightConfiguration, -} from '@store/adcm/host/configuration/hostsConfigurationCompareSlice'; +} from '@store/adcm/entityConfiguration/compareSlice'; import { useParams } from 'react-router-dom'; export const useHostsPrimaryConfigurationsCompare = () => { const dispatch = useDispatch(); const { hostId: hostIdFromUrl } = useParams(); const hostId = Number(hostIdFromUrl); - const leftConfiguration = useStore(({ adcm }) => adcm.hostsConfigurationsCompare.leftConfiguration); - const rightConfiguration = useStore(({ adcm }) => adcm.hostsConfigurationsCompare.rightConfiguration); + const leftConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.leftConfiguration); + const rightConfiguration = useStore(({ adcm }) => adcm.entityConfigurationCompare.rightConfiguration); useEffect( () => () => { - dispatch(cleanupHostsConfigurationsCompareSlice()); + dispatch(cleanupCompareSlice()); }, [dispatch], ); const getLeftConfig = useCallback( (configId: number) => { - dispatch(getLeftConfiguration({ hostId, configId })); + dispatch( + getLeftConfiguration({ + entityType: 'host', + args: { hostId, configId }, + }), + ); }, [hostId, dispatch], ); const getRightConfig = useCallback( (configId: number) => { - dispatch(getRightConfiguration({ hostId, configId })); + dispatch( + getRightConfiguration({ + entityType: 'host', + args: { hostId, configId }, + }), + ); }, [hostId, dispatch], ); diff --git a/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice.ts index df5078b41e..6d13bfcfbd 100644 --- a/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice.ts @@ -79,8 +79,8 @@ const getClusterConfigGroupConfiguration = createAsyncThunk( try { const [config, schema] = await Promise.all([ - AdcmClusterGroupConfigsConfigsApi.getConfig(arg.clusterId, arg.configGroupId, arg.configId), - AdcmClusterGroupConfigsConfigsApi.getConfigSchema(arg.clusterId, arg.configGroupId), + AdcmClusterGroupConfigsConfigsApi.getConfig(arg), + AdcmClusterGroupConfigsConfigsApi.getConfigSchema(arg), ]); return { config, schema }; } catch (error) { diff --git a/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationsCompareSlice.ts b/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationsCompareSlice.ts deleted file mode 100644 index 2f8d9ef950..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationsCompareSlice.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { createAsyncThunk } from '@store/redux'; -import { AdcmFullConfigurationInfo } from '@models/adcm/configuration'; -import { AdcmClusterGroupConfigsConfigsApi, RequestError } from '@api'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; - -type AdcmClusterConfigGroupCompareConfigurationsState = { - leftConfiguration: AdcmFullConfigurationInfo | null; - rightConfiguration: AdcmFullConfigurationInfo | null; - isLeftLoading: boolean; - isRightLoading: boolean; -}; - -type LoadClusterGroupConfigConfigurationPayload = { - clusterId: number; - configGroupId: number; - configId: number; -}; - -const loadClusterGroupConfigConfiguration = createAsyncThunk( - 'adcm/cluster/configGroup/compareConfigurations/loadConfiguration', - async (arg: LoadClusterGroupConfigConfigurationPayload, thunkAPI) => { - try { - const [config, schema] = await Promise.all([ - AdcmClusterGroupConfigsConfigsApi.getConfig(arg.clusterId, arg.configGroupId, arg.configId), - AdcmClusterGroupConfigsConfigsApi.getConfigSchema(arg.clusterId, arg.configGroupId), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const getLeftConfiguration = createAsyncThunk( - 'adcm/cluster/configGroup/compareConfigurations/getLeftConfiguration', - async (arg: LoadClusterGroupConfigConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadClusterGroupConfigConfiguration(arg)).unwrap(); - }, -); - -const getRightConfiguration = createAsyncThunk( - 'adcm/cluster/configGroup/compareConfigurations/getRightConfiguration', - async (arg: LoadClusterGroupConfigConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadClusterGroupConfigConfiguration(arg)).unwrap(); - }, -); - -const createInitialState = (): AdcmClusterConfigGroupCompareConfigurationsState => ({ - leftConfiguration: null, - rightConfiguration: null, - isLeftLoading: false, - isRightLoading: false, -}); - -const clusterConfigGroupConfigurationsCompareSlice = createSlice({ - name: 'adcm/clusters/configGroup/configurationsCompareSlice', - initialState: createInitialState(), - reducers: { - cleanupCompareSlice() { - return createInitialState(); - }, - }, - extraReducers: (builder) => { - builder.addCase(getLeftConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getLeftConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.leftConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isLeftLoading = false; - }); - builder.addCase(getLeftConfiguration.rejected, (state) => { - state.leftConfiguration = null; - state.isLeftLoading = false; - }); - builder.addCase(getRightConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getRightConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.rightConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isRightLoading = false; - }); - builder.addCase(getRightConfiguration.rejected, (state) => { - state.rightConfiguration = null; - state.isRightLoading = false; - }); - }, -}); - -const { cleanupCompareSlice } = clusterConfigGroupConfigurationsCompareSlice.actions; -export { getRightConfiguration, getLeftConfiguration, cleanupCompareSlice }; -export default clusterConfigGroupConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationSlice.ts index b58a0269d0..f21c8ff33d 100644 --- a/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationSlice.ts @@ -65,8 +65,8 @@ const getClusterConfiguration = createAsyncThunk( try { const [config, schema] = await Promise.all([ - AdcmClusterConfigsApi.getConfig(arg.clusterId, arg.configId), - AdcmClusterConfigsApi.getConfigSchema(arg.clusterId), + AdcmClusterConfigsApi.getConfig(arg), + AdcmClusterConfigsApi.getConfigSchema(arg), ]); return { config, schema }; } catch (error) { diff --git a/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationsCompareSlice.ts b/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationsCompareSlice.ts deleted file mode 100644 index ee745d8099..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationsCompareSlice.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { createAsyncThunk } from '@store/redux'; -import { AdcmFullConfigurationInfo } from '@models/adcm/configuration'; -import { AdcmClusterConfigsApi, RequestError } from '@api'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; - -type AdcmClusterCompareConfigurationsState = { - leftConfiguration: AdcmFullConfigurationInfo | null; - rightConfiguration: AdcmFullConfigurationInfo | null; - isLeftLoading: boolean; - isRightLoading: boolean; -}; - -type LoadClusterConfigurationPayload = { - clusterId: number; - configId: number; -}; - -const loadClusterConfiguration = createAsyncThunk( - 'adcm/cluster/compareConfigurations/loadConfiguration', - async (arg: LoadClusterConfigurationPayload, thunkAPI) => { - try { - const [config, schema] = await Promise.all([ - AdcmClusterConfigsApi.getConfig(arg.clusterId, arg.configId), - AdcmClusterConfigsApi.getConfigSchema(arg.clusterId), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const getLeftConfiguration = createAsyncThunk( - 'adcm/cluster/compareConfigurations/getLeftConfiguration', - async (arg: LoadClusterConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadClusterConfiguration(arg)).unwrap(); - }, -); - -const getRightConfiguration = createAsyncThunk( - 'adcm/cluster/compareConfigurations/getRightConfiguration', - async (arg: LoadClusterConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadClusterConfiguration(arg)).unwrap(); - }, -); - -const createInitialState = (): AdcmClusterCompareConfigurationsState => ({ - leftConfiguration: null, - rightConfiguration: null, - isLeftLoading: false, - isRightLoading: false, -}); - -const clusterConfigurationsCompareSlice = createSlice({ - name: 'adcm/clusters/configurationsCompareSlice', - initialState: createInitialState(), - reducers: { - cleanupClusterConfigurationsCompareSlice() { - return createInitialState(); - }, - }, - extraReducers: (builder) => { - builder.addCase(getLeftConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getLeftConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.leftConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isLeftLoading = false; - }); - builder.addCase(getLeftConfiguration.rejected, (state) => { - state.leftConfiguration = null; - state.isLeftLoading = false; - }); - builder.addCase(getRightConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getRightConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.rightConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isRightLoading = false; - }); - builder.addCase(getRightConfiguration.rejected, (state) => { - state.rightConfiguration = null; - state.isRightLoading = false; - }); - }, -}); - -const { cleanupClusterConfigurationsCompareSlice } = clusterConfigurationsCompareSlice.actions; -export { getRightConfiguration, getLeftConfiguration, cleanupClusterConfigurationsCompareSlice }; -export default clusterConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice.ts index 1551a6f428..baf7dfda40 100644 --- a/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice.ts @@ -81,14 +81,14 @@ const createWithUpdateServiceConfigGroupConfigurations = createAsyncThunk( const getServiceConfigGroupConfiguration = createAsyncThunk( 'adcm/service/configGroup/configuration/getServiceConfigGroupConfiguration', - async ({ clusterId, serviceId, configGroupId, configId }: LoadServiceConfigGroupConfigurationPayload, thunkAPI) => { + async (args: LoadServiceConfigGroupConfigurationPayload, thunkAPI) => { const startDate = new Date(); thunkAPI.dispatch(setIsConfigurationLoading(true)); try { const [config, schema] = await Promise.all([ - AdcmClusterServiceConfigGroupConfigsApi.getConfig(clusterId, serviceId, configGroupId, configId), - AdcmClusterServiceConfigGroupConfigsApi.getConfigSchema(clusterId, serviceId, configGroupId), + AdcmClusterServiceConfigGroupConfigsApi.getConfig(args), + AdcmClusterServiceConfigGroupConfigsApi.getConfigSchema(args), ]); return { config, schema }; } catch (error) { diff --git a/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationsCompareSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationsCompareSlice.ts deleted file mode 100644 index 80fac4b531..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationsCompareSlice.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { createAsyncThunk } from '@store/redux'; -import { AdcmFullConfigurationInfo } from '@models/adcm/configuration'; -import { AdcmClusterServiceConfigGroupConfigsApi, RequestError } from '@api'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; - -type AdcmServiceConfigGroupCompareConfigurationsState = { - leftConfiguration: AdcmFullConfigurationInfo | null; - rightConfiguration: AdcmFullConfigurationInfo | null; - isLeftLoading: boolean; - isRightLoading: boolean; -}; - -type LoadServiceGroupConfigConfigurationPayload = { - clusterId: number; - serviceId: number; - configGroupId: number; - configId: number; -}; - -const loadServiceGroupConfigConfiguration = createAsyncThunk( - 'adcm/service/configGroup/compareConfigurations/loadConfiguration', - async ({ clusterId, serviceId, configGroupId, configId }: LoadServiceGroupConfigConfigurationPayload, thunkAPI) => { - try { - const [config, schema] = await Promise.all([ - AdcmClusterServiceConfigGroupConfigsApi.getConfig(clusterId, serviceId, configGroupId, configId), - AdcmClusterServiceConfigGroupConfigsApi.getConfigSchema(clusterId, serviceId, configGroupId), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const getLeftConfiguration = createAsyncThunk( - 'adcm/service/configGroup/compareConfigurations/getLeftConfiguration', - async (arg: LoadServiceGroupConfigConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadServiceGroupConfigConfiguration(arg)).unwrap(); - }, -); - -const getRightConfiguration = createAsyncThunk( - 'adcm/service/configGroup/compareConfigurations/getRightConfiguration', - async (arg: LoadServiceGroupConfigConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadServiceGroupConfigConfiguration(arg)).unwrap(); - }, -); - -const createInitialState = (): AdcmServiceConfigGroupCompareConfigurationsState => ({ - leftConfiguration: null, - rightConfiguration: null, - isLeftLoading: false, - isRightLoading: false, -}); - -const serviceConfigGroupConfigurationsCompareSlice = createSlice({ - name: 'adcm/service/configGroup/configurationsCompareSlice', - initialState: createInitialState(), - reducers: { - cleanupCompareSlice() { - return createInitialState(); - }, - }, - extraReducers: (builder) => { - builder.addCase(getLeftConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getLeftConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.leftConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isLeftLoading = false; - }); - builder.addCase(getLeftConfiguration.rejected, (state) => { - state.leftConfiguration = null; - state.isLeftLoading = false; - }); - builder.addCase(getRightConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getRightConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.rightConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isRightLoading = false; - }); - builder.addCase(getRightConfiguration.rejected, (state) => { - state.rightConfiguration = null; - state.isRightLoading = false; - }); - }, -}); - -const { cleanupCompareSlice } = serviceConfigGroupConfigurationsCompareSlice.actions; -export { getRightConfiguration, getLeftConfiguration, cleanupCompareSlice }; -export default serviceConfigGroupConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice.ts index 9969ec6deb..036ccc10f3 100644 --- a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice.ts @@ -86,28 +86,14 @@ const createWithUpdateServiceComponentConfigGroupConfigurations = createAsyncThu const getServiceComponentConfigGroupConfiguration = createAsyncThunk( 'adcm/serviceComponent/configGroup/configuration/getServiceComponentConfigGroupConfiguration', - async ( - { clusterId, serviceId, componentId, configGroupId, configId }: LoadServiceComponentConfigGroupConfigurationPayload, - thunkAPI, - ) => { + async (args: LoadServiceComponentConfigGroupConfigurationPayload, thunkAPI) => { const startDate = new Date(); thunkAPI.dispatch(setIsConfigurationLoading(true)); try { const [config, schema] = await Promise.all([ - AdcmClusterServiceComponentGroupConfigConfigsApi.getConfig( - clusterId, - serviceId, - componentId, - configGroupId, - configId, - ), - AdcmClusterServiceComponentGroupConfigConfigsApi.getConfigSchema( - clusterId, - serviceId, - componentId, - configGroupId, - ), + AdcmClusterServiceComponentGroupConfigConfigsApi.getConfig(args), + AdcmClusterServiceComponentGroupConfigConfigsApi.getConfigSchema(args), ]); return { config, schema }; } catch (error) { diff --git a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationsCompareSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationsCompareSlice.ts deleted file mode 100644 index 73ccae7072..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationsCompareSlice.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { createAsyncThunk } from '@store/redux'; -import { AdcmFullConfigurationInfo } from '@models/adcm/configuration'; -import { AdcmClusterServiceComponentGroupConfigConfigsApi, RequestError } from '@api'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; - -type AdcmClusterConfigGroupCompareConfigurationsState = { - leftConfiguration: AdcmFullConfigurationInfo | null; - rightConfiguration: AdcmFullConfigurationInfo | null; - isLeftLoading: boolean; - isRightLoading: boolean; -}; - -type LoadClusterGroupConfigConfigurationPayload = { - clusterId: number; - serviceId: number; - componentId: number; - configGroupId: number; - configId: number; -}; - -const loadClusterGroupConfigConfiguration = createAsyncThunk( - 'adcm/serviceComponent/configGroup/compareConfigurations/loadConfiguration', - async ( - { clusterId, serviceId, componentId, configGroupId, configId }: LoadClusterGroupConfigConfigurationPayload, - thunkAPI, - ) => { - try { - const [config, schema] = await Promise.all([ - AdcmClusterServiceComponentGroupConfigConfigsApi.getConfig( - clusterId, - serviceId, - componentId, - configGroupId, - configId, - ), - AdcmClusterServiceComponentGroupConfigConfigsApi.getConfigSchema( - clusterId, - serviceId, - componentId, - configGroupId, - ), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const getLeftConfiguration = createAsyncThunk( - 'adcm/serviceComponent/configGroup/compareConfigurations/getLeftConfiguration', - async (arg: LoadClusterGroupConfigConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadClusterGroupConfigConfiguration(arg)).unwrap(); - }, -); - -const getRightConfiguration = createAsyncThunk( - 'adcm/serviceComponent/configGroup/compareConfigurations/getRightConfiguration', - async (arg: LoadClusterGroupConfigConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadClusterGroupConfigConfiguration(arg)).unwrap(); - }, -); - -const createInitialState = (): AdcmClusterConfigGroupCompareConfigurationsState => ({ - leftConfiguration: null, - rightConfiguration: null, - isLeftLoading: false, - isRightLoading: false, -}); - -const serviceComponentConfigGroupConfigurationsCompareSlice = createSlice({ - name: 'adcm/serviceComponent/configGroup/configurationsCompareSlice', - initialState: createInitialState(), - reducers: { - cleanupCompareSlice() { - return createInitialState(); - }, - }, - extraReducers: (builder) => { - builder.addCase(getLeftConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getLeftConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.leftConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isLeftLoading = false; - }); - builder.addCase(getLeftConfiguration.rejected, (state) => { - state.leftConfiguration = null; - state.isLeftLoading = false; - }); - builder.addCase(getRightConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getRightConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.rightConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isRightLoading = false; - }); - builder.addCase(getRightConfiguration.rejected, (state) => { - state.rightConfiguration = null; - state.isRightLoading = false; - }); - }, -}); - -const { cleanupCompareSlice } = serviceComponentConfigGroupConfigurationsCompareSlice.actions; -export { getRightConfiguration, getLeftConfiguration, cleanupCompareSlice }; -export default serviceComponentConfigGroupConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice.ts index adc3fc5e68..6d119b92a7 100644 --- a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice.ts @@ -87,8 +87,8 @@ const getServiceComponentConfiguration = createAsyncThunk( try { const [config, schema] = await Promise.all([ - AdcmClusterServiceComponentsConfigsApi.getConfig(arg.clusterId, arg.serviceId, arg.componentId, arg.configId), - AdcmClusterServiceComponentsConfigsApi.getConfigSchema(arg.clusterId, arg.serviceId, arg.componentId), + AdcmClusterServiceComponentsConfigsApi.getConfig(arg), + AdcmClusterServiceComponentsConfigsApi.getConfigSchema(arg), ]); return { config, schema }; } catch (error) { diff --git a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationsCompareSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationsCompareSlice.ts deleted file mode 100644 index 6b0f634771..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationsCompareSlice.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; -import { AdcmClusterServiceComponentsConfigsApi, RequestError } from '@api'; -import { getErrorMessage } from '@utils/httpResponseUtils.ts'; -import { showError } from '@store/notificationsSlice.ts'; -import { AdcmFullConfigurationInfo } from '@models/adcm'; - -type AdcmServiceComponentCompareConfigurationsState = { - leftConfiguration: AdcmFullConfigurationInfo | null; - rightConfiguration: AdcmFullConfigurationInfo | null; - isLeftLoading: boolean; - isRightLoading: boolean; -}; - -type LoadServiceComponentConfigurationPayload = { - clusterId: number; - serviceId: number; - componentId: number; - configId: number; -}; - -const loadServiceComponentConfiguration = createAsyncThunk( - 'adcm/component/compareConfigurations/loadConfiguration', - async (arg: LoadServiceComponentConfigurationPayload, thunkAPI) => { - try { - const [config, schema] = await Promise.all([ - AdcmClusterServiceComponentsConfigsApi.getConfig(arg.clusterId, arg.serviceId, arg.componentId, arg.configId), - AdcmClusterServiceComponentsConfigsApi.getConfigSchema(arg.clusterId, arg.serviceId, arg.componentId), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const getLeftConfiguration = createAsyncThunk( - 'adcm/component/compareConfigurations/getLeftConfiguration', - async (arg: LoadServiceComponentConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadServiceComponentConfiguration(arg)).unwrap(); - }, -); - -const getRightConfiguration = createAsyncThunk( - 'adcm/component/compareConfigurations/getRightConfiguration', - async (arg: LoadServiceComponentConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadServiceComponentConfiguration(arg)).unwrap(); - }, -); - -const createInitialState = (): AdcmServiceComponentCompareConfigurationsState => ({ - leftConfiguration: null, - rightConfiguration: null, - isLeftLoading: false, - isRightLoading: false, -}); - -const serviceComponentConfigurationsCompareSlice = createSlice({ - name: 'adcm/component/configurationsCompareSlice', - initialState: createInitialState(), - reducers: { - cleanupServiceComponentConfigurationsCompareSlice() { - return createInitialState(); - }, - }, - extraReducers: (builder) => { - builder.addCase(getLeftConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getLeftConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.leftConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isLeftLoading = false; - }); - builder.addCase(getLeftConfiguration.rejected, (state) => { - state.leftConfiguration = null; - state.isLeftLoading = false; - }); - builder.addCase(getRightConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getRightConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.rightConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isRightLoading = false; - }); - builder.addCase(getRightConfiguration.rejected, (state) => { - state.rightConfiguration = null; - state.isRightLoading = false; - }); - }, -}); - -const { cleanupServiceComponentConfigurationsCompareSlice } = serviceComponentConfigurationsCompareSlice.actions; -export { getRightConfiguration, getLeftConfiguration, cleanupServiceComponentConfigurationsCompareSlice }; -export default serviceComponentConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts index 606c4a7b09..0576d3af89 100644 --- a/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts @@ -73,8 +73,8 @@ const getClusterServicesConfiguration = createAsyncThunk( try { const [config, schema] = await Promise.all([ - AdcmClusterServicesConfigsApi.getConfig(arg.clusterId, arg.serviceId, arg.configId), - AdcmClusterServicesConfigsApi.getConfigSchema(arg.clusterId, arg.serviceId), + AdcmClusterServicesConfigsApi.getConfig(arg), + AdcmClusterServicesConfigsApi.getConfigSchema(arg), ]); return { config, schema }; } catch (error) { diff --git a/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationsCompareSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationsCompareSlice.ts deleted file mode 100644 index a0dbd26bb4..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationsCompareSlice.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { createAsyncThunk } from '@store/redux'; -import { AdcmFullConfigurationInfo } from '@models/adcm/configuration'; -import { AdcmClusterServicesConfigsApi, RequestError } from '@api'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; - -type AdcmClusterServicesCompareConfigurationsState = { - leftConfiguration: AdcmFullConfigurationInfo | null; - rightConfiguration: AdcmFullConfigurationInfo | null; - isLeftLoading: boolean; - isRightLoading: boolean; -}; - -type LoadClusterServicesConfigurationPayload = { - clusterId: number; - serviceId: number; - configId: number; -}; - -const loadClusterServicesConfiguration = createAsyncThunk( - 'adcm/clusterServices/compareConfigurations/loadConfiguration', - async (arg: LoadClusterServicesConfigurationPayload, thunkAPI) => { - try { - const [config, schema] = await Promise.all([ - AdcmClusterServicesConfigsApi.getConfig(arg.clusterId, arg.serviceId, arg.configId), - AdcmClusterServicesConfigsApi.getConfigSchema(arg.clusterId, arg.serviceId), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const getLeftConfiguration = createAsyncThunk( - 'adcm/clusterServices/compareConfigurations/getLeftConfiguration', - async (arg: LoadClusterServicesConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadClusterServicesConfiguration(arg)).unwrap(); - }, -); - -const getRightConfiguration = createAsyncThunk( - 'adcm/clusterServices/compareConfigurations/getRightConfiguration', - async (arg: LoadClusterServicesConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadClusterServicesConfiguration(arg)).unwrap(); - }, -); - -const createInitialState = (): AdcmClusterServicesCompareConfigurationsState => ({ - leftConfiguration: null, - rightConfiguration: null, - isLeftLoading: false, - isRightLoading: false, -}); - -const clusterServicesConfigurationsCompareSlice = createSlice({ - name: 'adcm/clusterServices/configurationsCompareSlice', - initialState: createInitialState(), - reducers: { - cleanupClusterServicesConfigurationsCompareSlice() { - return createInitialState(); - }, - }, - extraReducers: (builder) => { - builder.addCase(getLeftConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getLeftConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.leftConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isLeftLoading = false; - }); - builder.addCase(getLeftConfiguration.rejected, (state) => { - state.leftConfiguration = null; - state.isLeftLoading = false; - }); - builder.addCase(getRightConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getRightConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.rightConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isRightLoading = false; - }); - builder.addCase(getRightConfiguration.rejected, (state) => { - state.rightConfiguration = null; - state.isRightLoading = false; - }); - }, -}); - -const { cleanupClusterServicesConfigurationsCompareSlice } = clusterServicesConfigurationsCompareSlice.actions; -export { getRightConfiguration, getLeftConfiguration, cleanupClusterServicesConfigurationsCompareSlice }; -export default clusterServicesConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.constants.ts b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.constants.ts new file mode 100644 index 0000000000..c24681d2f7 --- /dev/null +++ b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.constants.ts @@ -0,0 +1,87 @@ +import { + AdcmSettingsApi, + AdcmHostProviderConfigsApi, + AdcmHostProviderGroupConfigsConfigsApi, + AdcmClusterConfigsApi, + AdcmClusterGroupConfigsConfigsApi, + AdcmHostConfigsApi, + AdcmClusterServicesConfigsApi, + AdcmClusterServiceConfigGroupConfigsApi, + AdcmClusterServiceComponentsConfigsApi, + AdcmClusterServiceComponentGroupConfigConfigsApi, +} from '@api'; +import { + ApiRequestsDictionary, + LoadConfigurationArgs, + LoadSettingsConfigurationArgs, + LoadHostProviderConfigurationArgs, + LoadHostProviderGroupConfigurationArgs, + LoadClusterConfigurationArgs, + LoadClusterGroupConfigurationArgs, + LoadHostConfigurationArgs, + LoadServiceConfigurationArgs, + LoadServiceGroupConfigurationArgs, + LoadServiceComponentConfigurationArgs, + LoadServiceComponentGroupConfigurationArgs, +} from './compareSlice.types'; + +export const ApiRequests: ApiRequestsDictionary = { + settings: { + getConfig: (args: LoadConfigurationArgs) => AdcmSettingsApi.getConfig(args as LoadSettingsConfigurationArgs), + getConfigSchema: () => AdcmSettingsApi.getConfigSchema(), + }, + 'host-provider': { + getConfig: (args: LoadConfigurationArgs) => + AdcmHostProviderConfigsApi.getConfig(args as LoadHostProviderConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmHostProviderConfigsApi.getConfigSchema(args as LoadHostProviderConfigurationArgs), + }, + 'host-provider-config-group': { + getConfig: (args: LoadConfigurationArgs) => + AdcmHostProviderGroupConfigsConfigsApi.getConfig(args as LoadHostProviderGroupConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmHostProviderGroupConfigsConfigsApi.getConfigSchema(args as LoadHostProviderGroupConfigurationArgs), + }, + cluster: { + getConfig: (args: LoadConfigurationArgs) => AdcmClusterConfigsApi.getConfig(args as LoadClusterConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterConfigsApi.getConfigSchema(args as LoadClusterConfigurationArgs), + }, + 'cluster-config-group': { + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterGroupConfigsConfigsApi.getConfig(args as LoadClusterGroupConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterGroupConfigsConfigsApi.getConfigSchema(args as LoadClusterGroupConfigurationArgs), + }, + host: { + getConfig: (args: LoadConfigurationArgs) => AdcmHostConfigsApi.getConfig(args as LoadHostConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmHostConfigsApi.getConfigSchema(args as LoadHostConfigurationArgs), + }, + service: { + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterServicesConfigsApi.getConfig(args as LoadServiceConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterServicesConfigsApi.getConfigSchema(args as LoadServiceConfigurationArgs), + }, + 'service-config-group': { + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterServiceConfigGroupConfigsApi.getConfig(args as LoadServiceGroupConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterServiceConfigGroupConfigsApi.getConfigSchema(args as LoadServiceGroupConfigurationArgs), + }, + 'service-component': { + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterServiceComponentsConfigsApi.getConfig(args as LoadServiceComponentConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterServiceComponentsConfigsApi.getConfigSchema(args as LoadServiceComponentConfigurationArgs), + }, + 'service-component-config-group': { + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterServiceComponentGroupConfigConfigsApi.getConfig(args as LoadServiceComponentGroupConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterServiceComponentGroupConfigConfigsApi.getConfigSchema( + args as LoadServiceComponentGroupConfigurationArgs, + ), + }, +}; diff --git a/adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationsCompareSlice.ts b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.ts similarity index 60% rename from adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationsCompareSlice.ts rename to adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.ts index c0ab2f770f..9b9a94c621 100644 --- a/adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationsCompareSlice.ts +++ b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.ts @@ -1,31 +1,25 @@ import { AdcmFullConfigurationInfo } from '@models/adcm'; import { createAsyncThunk } from '@store/redux.ts'; -import { AdcmHostProviderGroupConfigsConfigsApi, RequestError } from '@api'; +import { RequestError } from '@api'; import { showError } from '@store/notificationsSlice.ts'; import { getErrorMessage } from '@utils/httpResponseUtils.ts'; import { createSlice } from '@reduxjs/toolkit'; +import { LoadEntityConfigurationArgs } from './compareSlice.types'; +import { ApiRequests } from './compareSlice.constants'; -type AdcmHostProviderConfigGroupCompareConfigurationsState = { +type AdcmEntityCompareConfigurationsState = { leftConfiguration: AdcmFullConfigurationInfo | null; rightConfiguration: AdcmFullConfigurationInfo | null; isLeftLoading: boolean; isRightLoading: boolean; }; -type LoadHostProviderGroupConfigConfigurationPayload = { - hostProviderId: number; - configGroupId: number; - configId: number; -}; - -const loadHostProviderGroupConfigConfiguration = createAsyncThunk( - 'adcm/hostProvider/configGroup/compareConfigurations/loadConfiguration', - async (arg: LoadHostProviderGroupConfigConfigurationPayload, thunkAPI) => { +const loadConfiguration = createAsyncThunk( + 'adcm/entityCompareConfigurations/loadConfiguration', + async ({ entityType, args }: LoadEntityConfigurationArgs, thunkAPI) => { try { - const [config, schema] = await Promise.all([ - AdcmHostProviderGroupConfigsConfigsApi.getConfig(arg.hostProviderId, arg.configGroupId, arg.configId), - AdcmHostProviderGroupConfigsConfigsApi.getConfigSchema(arg.hostProviderId, arg.configGroupId), - ]); + const requests = ApiRequests[entityType]; + const [config, schema] = await Promise.all([requests.getConfig(args), requests.getConfigSchema(args)]); return { config, schema }; } catch (error) { thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); @@ -35,28 +29,28 @@ const loadHostProviderGroupConfigConfiguration = createAsyncThunk( ); const getLeftConfiguration = createAsyncThunk( - 'adcm/hostProvider/configGroup/compareConfigurations/getLeftConfiguration', - async (arg: LoadHostProviderGroupConfigConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadHostProviderGroupConfigConfiguration(arg)).unwrap(); + 'adcm/entityCompareConfigurations/getLeftConfiguration', + async (arg: LoadEntityConfigurationArgs, thunkAPI) => { + return thunkAPI.dispatch(loadConfiguration(arg)).unwrap(); }, ); const getRightConfiguration = createAsyncThunk( - 'adcm/hostProvider/configGroup/compareConfigurations/getRightConfiguration', - async (arg: LoadHostProviderGroupConfigConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadHostProviderGroupConfigConfiguration(arg)).unwrap(); + 'adcm/entityCompareConfigurations/getRightConfiguration', + async (arg: LoadEntityConfigurationArgs, thunkAPI) => { + return thunkAPI.dispatch(loadConfiguration(arg)).unwrap(); }, ); -const createInitialState = (): AdcmHostProviderConfigGroupCompareConfigurationsState => ({ +const createInitialState = (): AdcmEntityCompareConfigurationsState => ({ leftConfiguration: null, rightConfiguration: null, isLeftLoading: false, isRightLoading: false, }); -const hostProviderConfigGroupConfigurationsCompareSlice = createSlice({ - name: 'adcm/hostProviders/configGroup/configurationsCompareSlice', +const entityConfigurationsCompareSlice = createSlice({ + name: 'adcm/entityCompareConfigurations', initialState: createInitialState(), reducers: { cleanupCompareSlice() { @@ -102,10 +96,7 @@ const hostProviderConfigGroupConfigurationsCompareSlice = createSlice({ config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, schema, } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore + state.rightConfiguration = { id, creationTime, @@ -127,6 +118,6 @@ const hostProviderConfigGroupConfigurationsCompareSlice = createSlice({ }, }); -const { cleanupCompareSlice } = hostProviderConfigGroupConfigurationsCompareSlice.actions; +const { cleanupCompareSlice } = entityConfigurationsCompareSlice.actions; export { getRightConfiguration, getLeftConfiguration, cleanupCompareSlice }; -export default hostProviderConfigGroupConfigurationsCompareSlice.reducer; +export default entityConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.types.ts b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.types.ts new file mode 100644 index 0000000000..c508a5e40d --- /dev/null +++ b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.types.ts @@ -0,0 +1,136 @@ +import { AdcmConfig, SchemaDefinition } from '@models/adcm'; + +export type EntityType = + | 'settings' + | 'host-provider' + | 'host-provider-config-group' + | 'cluster' + | 'cluster-config-group' + | 'host' + | 'service' + | 'service-config-group' + | 'service-component' + | 'service-component-config-group'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface LoadConfigurationArgs {} + +/* Settings */ + +export interface LoadSettingsConfigurationArgs extends LoadConfigurationArgs { + configId: number; +} + +/* Host provider */ + +export interface LoadHostProviderConfigurationArgs extends LoadConfigurationArgs { + hostProviderId: number; + configId: number; +} + +export interface LoadHostProviderGroupConfigurationArgs extends LoadConfigurationArgs { + hostProviderId: number; + configGroupId: number; + configId: number; +} + +/* Cluster */ + +export interface LoadClusterConfigurationArgs extends LoadConfigurationArgs { + clusterId: number; + configId: number; +} + +export type LoadClusterGroupConfigurationArgs = { + clusterId: number; + configGroupId: number; + configId: number; +}; + +/* Host */ + +export type LoadHostConfigurationArgs = { + hostId: number; + configId: number; +}; + +/* Service */ + +export type LoadServiceConfigurationArgs = { + clusterId: number; + serviceId: number; + configId: number; +}; + +export type LoadServiceGroupConfigurationArgs = { + clusterId: number; + serviceId: number; + configGroupId: number; + configId: number; +}; + +/* Service component */ + +export type LoadServiceComponentConfigurationArgs = { + clusterId: number; + serviceId: number; + componentId: number; + configId: number; +}; + +export type LoadServiceComponentGroupConfigurationArgs = { + clusterId: number; + serviceId: number; + componentId: number; + configGroupId: number; + configId: number; +}; + +export type LoadEntityConfigurationArgs = + | { + entityType: 'settings'; + args: LoadSettingsConfigurationArgs; + } + | { + entityType: 'host-provider'; + args: LoadHostProviderConfigurationArgs; + } + | { + entityType: 'host-provider-config-group'; + args: LoadHostProviderGroupConfigurationArgs; + } + | { + entityType: 'cluster'; + args: LoadClusterConfigurationArgs; + } + | { + entityType: 'cluster-config-group'; + args: LoadClusterGroupConfigurationArgs; + } + | { + entityType: 'host'; + args: LoadHostConfigurationArgs; + } + | { + entityType: 'service'; + args: LoadServiceConfigurationArgs; + } + | { + entityType: 'service-config-group'; + args: LoadServiceGroupConfigurationArgs; + } + | { + entityType: 'service-component'; + args: LoadServiceComponentConfigurationArgs; + } + | { + entityType: 'service-component-config-group'; + args: LoadServiceComponentGroupConfigurationArgs; + }; + +export type ApiRequestsDictionary = { + [key in EntityType]: { + getConfig: (args: LoadConfigurationArgs) => Promise; + getConfigSchema: (args: LoadConfigurationArgs) => Promise; + }; +}; diff --git a/adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationCompareSlice.ts b/adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationCompareSlice.ts deleted file mode 100644 index 6f4e12341d..0000000000 --- a/adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationCompareSlice.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { createAsyncThunk } from '@store/redux'; -import { AdcmFullConfigurationInfo } from '@models/adcm/configuration'; -import { AdcmHostConfigsApi, RequestError } from '@api'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; - -interface AdcmHostsCompareConfigurationsState { - leftConfiguration: AdcmFullConfigurationInfo | null; - rightConfiguration: AdcmFullConfigurationInfo | null; - isLeftLoading: boolean; - isRightLoading: boolean; -} - -type LoadHostsConfigurationPayload = { - hostId: number; - configId: number; -}; - -const loadHostsConfiguration = createAsyncThunk( - 'adcm/host/compareConfigurations/loadConfiguration', - async (arg: LoadHostsConfigurationPayload, thunkAPI) => { - try { - const [config, schema] = await Promise.all([ - AdcmHostConfigsApi.getConfig(arg.hostId, arg.configId), - AdcmHostConfigsApi.getConfigSchema(arg.hostId), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const getLeftConfiguration = createAsyncThunk( - 'adcm/host/compareConfigurations/getLeftConfiguration', - async (arg: LoadHostsConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadHostsConfiguration(arg)).unwrap(); - }, -); - -const getRightConfiguration = createAsyncThunk( - 'adcm/host/compareConfigurations/getRightConfiguration', - async (arg: LoadHostsConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadHostsConfiguration(arg)).unwrap(); - }, -); - -const createInitialState = (): AdcmHostsCompareConfigurationsState => ({ - leftConfiguration: null, - rightConfiguration: null, - isLeftLoading: false, - isRightLoading: false, -}); - -const hostsConfigurationsCompareSlice = createSlice({ - name: 'adcm/host/configurationsCompareSlice', - initialState: createInitialState(), - reducers: { - cleanupHostsConfigurationsCompareSlice() { - return createInitialState(); - }, - }, - extraReducers: (builder) => { - builder.addCase(getLeftConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getLeftConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.leftConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isLeftLoading = false; - }); - builder.addCase(getLeftConfiguration.rejected, (state) => { - state.leftConfiguration = null; - state.isLeftLoading = false; - }); - builder.addCase(getRightConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getRightConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.rightConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isRightLoading = false; - }); - builder.addCase(getRightConfiguration.rejected, (state) => { - state.rightConfiguration = null; - state.isRightLoading = false; - }); - }, -}); - -const { cleanupHostsConfigurationsCompareSlice } = hostsConfigurationsCompareSlice.actions; -export { getRightConfiguration, getLeftConfiguration, cleanupHostsConfigurationsCompareSlice }; -export default hostsConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationSlice.ts b/adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationSlice.ts index 805354dd25..6c70ae2081 100644 --- a/adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationSlice.ts @@ -65,8 +65,8 @@ const getHostsConfiguration = createAsyncThunk( try { const [config, schema] = await Promise.all([ - AdcmHostConfigsApi.getConfig(arg.hostId, arg.configId), - AdcmHostConfigsApi.getConfigSchema(arg.hostId), + AdcmHostConfigsApi.getConfig(arg), + AdcmHostConfigsApi.getConfigSchema(arg), ]); return { config, schema }; } catch (error) { diff --git a/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationSlice.ts b/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationSlice.ts index 6450c44f99..1d8c8630b7 100644 --- a/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationSlice.ts @@ -68,8 +68,8 @@ const getHostProviderConfiguration = createAsyncThunk( try { const [config, schema] = await Promise.all([ - AdcmHostProviderConfigsApi.getConfig(arg.hostProviderId, arg.configId), - AdcmHostProviderConfigsApi.getConfigSchema(arg.hostProviderId), + AdcmHostProviderConfigsApi.getConfig(arg), + AdcmHostProviderConfigsApi.getConfigSchema(arg), ]); return { config, schema }; } catch (error) { diff --git a/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationsCompareSlice.ts b/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationsCompareSlice.ts deleted file mode 100644 index 05588c18ee..0000000000 --- a/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationsCompareSlice.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { createAsyncThunk } from '@store/redux'; -import { AdcmFullConfigurationInfo } from '@models/adcm/configuration'; -import { AdcmHostProviderConfigsApi, RequestError } from '@api'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; - -type AdcmHostProviderCompareConfigurationsState = { - leftConfiguration: AdcmFullConfigurationInfo | null; - rightConfiguration: AdcmFullConfigurationInfo | null; - isLeftLoading: boolean; - isRightLoading: boolean; -}; - -type LoadHostProviderConfigurationPayload = { - hostProviderId: number; - configId: number; -}; - -const loadHostProviderConfiguration = createAsyncThunk( - 'adcm/hostProvider/compareConfigurations/loadConfiguration', - async (arg: LoadHostProviderConfigurationPayload, thunkAPI) => { - try { - const [config, schema] = await Promise.all([ - AdcmHostProviderConfigsApi.getConfig(arg.hostProviderId, arg.configId), - AdcmHostProviderConfigsApi.getConfigSchema(arg.hostProviderId), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const getLeftConfiguration = createAsyncThunk( - 'adcm/hostProvider/compareConfigurations/getLeftConfiguration', - async (arg: LoadHostProviderConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadHostProviderConfiguration(arg)).unwrap(); - }, -); - -const getRightConfiguration = createAsyncThunk( - 'adcm/hostProvider/compareConfigurations/getRightConfiguration', - async (arg: LoadHostProviderConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadHostProviderConfiguration(arg)).unwrap(); - }, -); - -const createInitialState = (): AdcmHostProviderCompareConfigurationsState => ({ - leftConfiguration: null, - rightConfiguration: null, - isLeftLoading: false, - isRightLoading: false, -}); - -const hostProviderConfigurationsCompareSlice = createSlice({ - name: 'adcm/hostProvider/configurationsCompareSlice', - initialState: createInitialState(), - reducers: { - cleanupHostProviderConfigurationsCompareSlice() { - return createInitialState(); - }, - }, - extraReducers: (builder) => { - builder.addCase(getLeftConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getLeftConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.leftConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isLeftLoading = false; - }); - builder.addCase(getLeftConfiguration.rejected, (state) => { - state.leftConfiguration = null; - state.isLeftLoading = false; - }); - builder.addCase(getRightConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getRightConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.rightConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isRightLoading = false; - }); - builder.addCase(getRightConfiguration.rejected, (state) => { - state.rightConfiguration = null; - state.isRightLoading = false; - }); - }, -}); - -const { cleanupHostProviderConfigurationsCompareSlice } = hostProviderConfigurationsCompareSlice.actions; -export { getRightConfiguration, getLeftConfiguration, cleanupHostProviderConfigurationsCompareSlice }; -export default hostProviderConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice.ts b/adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice.ts index 89fb03caf3..4147722394 100644 --- a/adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice.ts @@ -76,8 +76,8 @@ const getHostProviderConfigGroupConfiguration = createAsyncThunk( try { const [config, schema] = await Promise.all([ - AdcmHostProviderGroupConfigsConfigsApi.getConfig(arg.hostProviderId, arg.configGroupId, arg.configId), - AdcmHostProviderGroupConfigsConfigsApi.getConfigSchema(arg.hostProviderId, arg.configGroupId), + AdcmHostProviderGroupConfigsConfigsApi.getConfig(arg), + AdcmHostProviderGroupConfigsConfigsApi.getConfigSchema(arg), ]); return { config, schema }; } catch (error) { diff --git a/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationSlice.ts b/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationSlice.ts index d0751ab70a..40d104cfa9 100644 --- a/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationSlice.ts @@ -58,7 +58,10 @@ const getSettingsConfiguration = createAsyncThunk( thunkAPI.dispatch(setIsConfigurationLoading(true)); try { - const [config, schema] = await Promise.all([AdcmSettingsApi.getConfig(id), AdcmSettingsApi.getConfigSchema()]); + const [config, schema] = await Promise.all([ + AdcmSettingsApi.getConfig({ configId: id }), + AdcmSettingsApi.getConfigSchema(), + ]); return { config, schema }; } catch (error) { thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); diff --git a/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationsCompareSlice.ts b/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationsCompareSlice.ts deleted file mode 100644 index d87397cdd2..0000000000 --- a/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationsCompareSlice.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { createAsyncThunk } from '@store/redux'; -import { AdcmFullConfigurationInfo } from '@models/adcm/configuration'; -import { AdcmSettingsApi, RequestError } from '@api'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; - -type AdcmSettingsCompareConfigurationsState = { - leftConfiguration: AdcmFullConfigurationInfo | null; - rightConfiguration: AdcmFullConfigurationInfo | null; - isLeftLoading: boolean; - isRightLoading: boolean; -}; - -type LoadSettingsConfigurationPayload = { - configId: number; -}; - -const loadSettingsConfiguration = createAsyncThunk( - 'adcm/settings/compareConfigurations/loadConfiguration', - async (arg: LoadSettingsConfigurationPayload, thunkAPI) => { - try { - const [config, schema] = await Promise.all([ - AdcmSettingsApi.getConfig(arg.configId), - AdcmSettingsApi.getConfigSchema(), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const getLeftConfiguration = createAsyncThunk( - 'adcm/settings/compareConfigurations/getLeftConfiguration', - async (arg: LoadSettingsConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadSettingsConfiguration(arg)).unwrap(); - }, -); - -const getRightConfiguration = createAsyncThunk( - 'adcm/settings/compareConfigurations/getRightConfiguration', - async (arg: LoadSettingsConfigurationPayload, thunkAPI) => { - return thunkAPI.dispatch(loadSettingsConfiguration(arg)).unwrap(); - }, -); - -const createInitialState = (): AdcmSettingsCompareConfigurationsState => ({ - leftConfiguration: null, - rightConfiguration: null, - isLeftLoading: false, - isRightLoading: false, -}); - -const settingsConfigurationsCompareSlice = createSlice({ - name: 'adcm/settings/configurationsCompareSlice', - initialState: createInitialState(), - reducers: { - cleanupSettingsConfigurationsCompareSlice() { - return createInitialState(); - }, - }, - extraReducers: (builder) => { - builder.addCase(getLeftConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getLeftConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.leftConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isLeftLoading = false; - }); - builder.addCase(getLeftConfiguration.rejected, (state) => { - state.leftConfiguration = null; - state.isLeftLoading = false; - }); - builder.addCase(getRightConfiguration.pending, (state) => { - state.isLeftLoading = true; - }); - builder.addCase(getRightConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes, id, creationTime, description, isCurrent }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.rightConfiguration = { - id, - creationTime, - description, - isCurrent, - configuration: { - configurationData, - attributes, - schema, - }, - }; - - state.isRightLoading = false; - }); - builder.addCase(getRightConfiguration.rejected, (state) => { - state.rightConfiguration = null; - state.isRightLoading = false; - }); - }, -}); - -const { cleanupSettingsConfigurationsCompareSlice } = settingsConfigurationsCompareSlice.actions; -export { getRightConfiguration, getLeftConfiguration, cleanupSettingsConfigurationsCompareSlice }; -export default settingsConfigurationsCompareSlice.reducer; diff --git a/adcm-web/app/src/store/store.ts b/adcm-web/app/src/store/store.ts index 13a0b6b68e..2a77a2a4d8 100644 --- a/adcm-web/app/src/store/store.ts +++ b/adcm-web/app/src/store/store.ts @@ -10,16 +10,13 @@ import clusterHostsActionsSlice from '@store/adcm/cluster/hosts/hostsActionsSlic import clusterHostsDynamicActionsSlice from '@store/adcm/cluster/hosts/hostsDynamicActionsSlice'; import hostComponentsDynamicActionsSlice from '@store/adcm/cluster/hosts/host/hostComponentsDynamicActionsSlice'; import clustersTableSlice from '@store/adcm/clusters/clustersTableSlice'; -import clusterConfigurationsCompareSlice from '@store/adcm/cluster/configuration/clusterConfigurationsCompareSlice'; import clusterConfigurationSlice from '@store/adcm/cluster/configuration/clusterConfigurationSlice'; import clusterConfigGroupsSlice from '@store/adcm/cluster/configGroups/clusterConfigGroupsSlice'; import clusterConfigGroupsTableSlice from '@store/adcm/cluster/configGroups/clusterConfigGroupsTableSlice'; import clusterConfigGroupActionsSlice from '@store/adcm/cluster/configGroups/clusterConfigGroupActionsSlice'; import clusterConfigGroupSlice from '@store/adcm/cluster/configGroupSingle/clusterConfigGroup'; import clusterConfigGroupConfigurationSlice from '@store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice'; -import clusterConfigGroupConfigurationsCompareSlice from '@store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationsCompareSlice'; import hostProviderConfigurationSlice from '@store/adcm/hostProvider/configuration/hostProviderConfigurationSlice'; -import hostProviderConfigurationsCompareSlice from '@store/adcm/hostProvider/configuration/hostProviderConfigurationsCompareSlice'; import hostProviderConfigGroupsSlice from '@store/adcm/hostProvider/configurationGroups/hostProviderConfigGroupsSlice'; import hostProviderConfigGroupsTableSlice from '@store/adcm/hostProvider/configurationGroups/hostProviderConfigGroupsTableSlice'; import bundlesSlice from '@store/adcm/bundles/bundlesSlice'; @@ -78,7 +75,6 @@ import serviceComponentConfigGroupsTableSlice from './adcm/cluster/services/serv import serviceComponentConfigGroupsActionsSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configGroups/serviceComponentConfigGroupsActionsSlice'; import serviceComponentConfigGroupSingleSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupSingleSlice'; import serviceComponentConfigGroupConfigurationSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice'; -import serviceComponentConfigGroupConfigurationsCompareSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationsCompareSlice'; import clustersActionsSlice from './adcm/clusters/clustersActionsSlice'; import clusterHostSlice from './adcm/cluster/hosts/host/clusterHostSlice'; @@ -91,29 +87,25 @@ import hostProvidersActionsSlice from './adcm/hostProviders/hostProvidersActions import hostProvidersDynamicActionsSlice from './adcm/hostProviders/hostProvidersDynamicActionsSlice'; import hostProviderUpgradesSlice from './adcm/hostProviders/hostProviderUpgradesSlice'; import serviceComponentsDynamicActionsSlice from './adcm/cluster/services/serviceComponents/serviceComponentsDynamicActionsSlice'; -import serviceComponentConfigurationsCompareSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationsCompareSlice'; import serviceComponentConfigurationSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice'; import hostSlice from './adcm/host/hostSlice'; import clusterServicesConfigurationSlice from './adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts'; -import clusterServicesConfigurationsCompareSlice from './adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationsCompareSlice.ts'; import hostsConfigurationSlice from './adcm/host/configuration/hostsConfigurationSlice.ts'; -import hostsConfigurationCompareSlice from './adcm/host/configuration/hostsConfigurationCompareSlice.ts'; import serviceConfigGroupsSlice from './adcm/cluster/services/configGroups/serviceConfigGroupsSlice.ts'; import serviceConfigGroupsTableSlice from './adcm/cluster/services/configGroups/serviceConfigGroupsTableSlice.ts'; import serviceConfigGroupsActionsSlice from './adcm/cluster/services/configGroups/serviceConfigGroupsActionsSlice.ts'; import serviceConfigGroupSlice from './adcm/cluster/services/configGroupSingle/configGroupSingle.ts'; import serviceConfigGroupConfigurationSlice from './adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice'; -import serviceConfigGroupConfigurationsCompareSlice from './adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationsCompareSlice'; import settingsConfigurationsSlice from './adcm/settings/configuration/settingsConfigurationSlice.ts'; -import settingsConfigurationsCompareSlice from './adcm/settings/configuration/settingsConfigurationsCompareSlice.ts'; import hostProviderConfigGroupActionsSlice from '@store/adcm/hostProvider/configurationGroups/hostProviderConfigGroupActionsSlice'; import hostProviderConfigGroupSlice from '@store/adcm/hostProvider/configurationGroupSingle/hostProviderConfigGroupSlice'; import hostProviderConfigGroupConfigurationSlice from '@store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice'; -import hostProviderConfigGroupConfigurationsCompareSlice from '@store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationsCompareSlice'; import bellSlice from '@store/adcm/bell/bellSlice'; import adcmSettingsSlice from '@store/adcm/settings/settingsSlice'; import adcmSettingsDynamicActionsSlice from '@store/adcm/settings/settingsDynamicActionsSlice'; +import adcmEntityConfigurationCompareSlice from '@store/adcm/entityConfiguration/compareSlice.ts'; + const rootReducer = combineReducers({ auth: authSlice, notifications: notificationsSlice, @@ -131,16 +123,13 @@ const rootReducer = combineReducers({ hostComponentsDynamicActions: hostComponentsDynamicActionsSlice, clusterHostsTable: clusterHostsTableSlice, clusterMapping: clusterMappingSlice, - clusterConfigurationsCompare: clusterConfigurationsCompareSlice, clusterConfiguration: clusterConfigurationSlice, clusterConfigGroups: clusterConfigGroupsSlice, clusterConfigGroupsTable: clusterConfigGroupsTableSlice, clusterConfigGroupActions: clusterConfigGroupActionsSlice, clusterConfigGroup: clusterConfigGroupSlice, clusterConfigGroupConfiguration: clusterConfigGroupConfigurationSlice, - clusterConfigGroupConfigurationsCompare: clusterConfigGroupConfigurationsCompareSlice, clusterServicesConfiguration: clusterServicesConfigurationSlice, - clusterServicesConfigurationsCompare: clusterServicesConfigurationsCompareSlice, bundle: bundleSlice, bundles: bundlesSlice, bundlesTable: bundlesTableSlice, @@ -148,14 +137,12 @@ const rootReducer = combineReducers({ hostComponents: hostComponentsSlice, hostComponentsTable: hostComponentsTableSlice, hostProvider: hostProviderSlice, - hostProviderConfigurationsCompare: hostProviderConfigurationsCompareSlice, hostProviderConfiguration: hostProviderConfigurationSlice, hostProviderConfigGroupActions: hostProviderConfigGroupActionsSlice, hostProviderConfigGroups: hostProviderConfigGroupsSlice, hostProviderConfigGroupsTable: hostProviderConfigGroupsTableSlice, hostProviderConfigGroup: hostProviderConfigGroupSlice, hostProviderConfigGroupConfiguration: hostProviderConfigGroupConfigurationSlice, - hostProviderConfigGroupConfigurationsCompare: hostProviderConfigGroupConfigurationsCompareSlice, hostProviders: hostProvidersSlice, hostProvidersActions: hostProvidersActionsSlice, hostProvidersTable: hostProvidersTableSlice, @@ -168,7 +155,6 @@ const rootReducer = combineReducers({ hostsTable: hostsTableSlice, hostsActions: hostsActionsSlice, hostsConfiguration: hostsConfigurationSlice, - hostsConfigurationsCompare: hostsConfigurationCompareSlice, service: serviceSlice, services: servicesSlice, servicesTable: servicesTableSlice, @@ -179,16 +165,13 @@ const rootReducer = combineReducers({ serviceConfigGroupsActions: serviceConfigGroupsActionsSlice, serviceConfigGroup: serviceConfigGroupSlice, serviceConfigGroupConfiguration: serviceConfigGroupConfigurationSlice, - serviceConfigGroupConfigurationsCompare: serviceConfigGroupConfigurationsCompareSlice, serviceComponents: serviceComponentsSlice, - serviceComponentsConfigurationsCompare: serviceComponentConfigurationsCompareSlice, serviceComponentConfiguration: serviceComponentConfigurationSlice, serviceComponentConfigGroups: serviceComponentConfigGroupsSlice, serviceComponentConfigGroupsTable: serviceComponentConfigGroupsTableSlice, serviceComponentConfigGroupsActions: serviceComponentConfigGroupsActionsSlice, serviceComponentConfigGroupSingle: serviceComponentConfigGroupSingleSlice, serviceComponentConfigGroupConfiguration: serviceComponentConfigGroupConfigurationSlice, - serviceComponentConfigGroupConfigurationsCompare: serviceComponentConfigGroupConfigurationsCompareSlice, serviceComponentsTable: serviceComponentsTableSlice, serviceComponentsActions: serviceComponentsActionsSlice, serviceComponentsDynamicActions: serviceComponentsDynamicActionsSlice, @@ -224,9 +207,9 @@ const rootReducer = combineReducers({ rolesTable: rolesTableSlice, rolesActions: rolesActionsSlice, settingsConfigurations: settingsConfigurationsSlice, - settingsConfigurationsCompare: settingsConfigurationsCompareSlice, adcmSettings: adcmSettingsSlice, adcmSettingsDynamicActions: adcmSettingsDynamicActionsSlice, + entityConfigurationCompare: adcmEntityConfigurationCompareSlice, }), }); From 57e485fb1284fdb7c2f30948f93e37153b1e2efc Mon Sep 17 00:00:00 2001 From: Daniil S Date: Mon, 15 Jan 2024 11:33:42 +0300 Subject: [PATCH 028/151] ADCM-5156: refactor files structure --- python/cm/tests/test_inventory/__init__.py | 11 + .../test_components.py} | 711 +---------------- .../cm/tests/test_inventory/test_inventory.py | 727 ++++++++++++++++++ 3 files changed, 744 insertions(+), 705 deletions(-) create mode 100644 python/cm/tests/test_inventory/__init__.py rename python/cm/tests/{test_inventory.py => test_inventory/test_components.py} (53%) create mode 100644 python/cm/tests/test_inventory/test_inventory.py diff --git a/python/cm/tests/test_inventory/__init__.py b/python/cm/tests/test_inventory/__init__.py new file mode 100644 index 0000000000..824dd6c8fe --- /dev/null +++ b/python/cm/tests/test_inventory/__init__.py @@ -0,0 +1,11 @@ +# Licensed 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. diff --git a/python/cm/tests/test_inventory.py b/python/cm/tests/test_inventory/test_components.py similarity index 53% rename from python/cm/tests/test_inventory.py rename to python/cm/tests/test_inventory/test_components.py index 37209d4e2f..52b066dd8f 100644 --- a/python/cm/tests/test_inventory.py +++ b/python/cm/tests/test_inventory/test_components.py @@ -10,738 +10,39 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-lines, attribute-defined-outside-init, too-many-locals +# pylint: disable=attribute-defined-outside-init,too-many-locals + from functools import reduce from json import loads from pathlib import Path from typing import Any, Mapping, TypeAlias -from unittest.mock import Mock, patch from api_v2.service.utils import bulk_add_services_to_cluster -from cm.api import add_hc, add_service_to_cluster, update_obj_config -from cm.inventory import ( - MAINTENANCE_MODE, - HcAclAction, - get_cluster_config, - get_cluster_hosts, - get_host, - get_host_groups, - get_host_vars, - get_inventory_data, - get_obj_config, - get_provider_config, - get_provider_hosts, - prepare_job_inventory, - process_config_and_attr, -) -from cm.job import re_prepare_job +from cm.inventory import get_inventory_data from cm.models import ( Action, ClusterObject, ConfigLog, Host, - HostComponent, - JobLog, - MaintenanceMode, ObjectType, Prototype, ServiceComponent, - TaskLog, -) -from cm.tests.utils import ( - gen_bundle, - gen_cluster, - gen_component, - gen_config, - gen_group, - gen_host, - gen_host_component, - gen_prototype, - gen_prototype_config, - gen_provider, - gen_service, ) from django.conf import settings -from django.urls import reverse -from django.utils import timezone -from init_db import init as init_adcm from jinja2 import Template -from rest_framework.response import Response -from rest_framework.status import HTTP_201_CREATED -from adcm.tests.base import APPLICATION_JSON, BaseTestCase, BusinessLogicMixin +from adcm.tests.base import BaseTestCase, BusinessLogicMixin TemplatesData: TypeAlias = Mapping[tuple[str, ...], tuple[Path, Mapping[str, Any]]] -class TestInventory(BaseTestCase): - # pylint: disable=too-many-instance-attributes - - def setUp(self): - super().setUp() - - self.cluster_bundle = gen_bundle() - self.cluster_pt = gen_prototype(self.cluster_bundle, "cluster", "cluster") - self.cluster = gen_cluster(prototype=self.cluster_pt, config=gen_config(), name="cluster") - - self.provider_bundle = gen_bundle() - - self.provider_pt = gen_prototype(self.provider_bundle, "provider") - self.host_pt = gen_prototype(self.provider_bundle, "host") - - self.provider = gen_provider(prototype=self.provider_pt) - self.host = gen_host(self.provider, prototype=self.host_pt) - - @patch("cm.inventory.process_config") - @patch("cm.inventory.get_prototype_config") - def test_process_config_and_attr(self, mock_get_prototype_config, mock_process_config): - mock_get_prototype_config.return_value = ({}, {}, {}, {}) - mock_process_config.return_value = {} - obj_mock = Mock(prototype={}) - - attr = {"global": {"active": ""}} - conf = process_config_and_attr(obj_mock, {}, attr) - - self.assertDictEqual(conf, {"global": None}) - - mock_get_prototype_config.assert_called_once_with(prototype={}) - mock_process_config.assert_called_once_with(obj=obj_mock, spec={}, old_conf={}) - - @patch("cm.inventory.process_config_and_attr") - def test_get_obj_config(self, mock_process_config_and_attr): - get_obj_config(self.cluster) - config_log = ConfigLog.objects.get(id=self.cluster.config.current) - mock_process_config_and_attr.assert_called_once_with( - obj=self.cluster, - conf=config_log.config, - attr=config_log.attr, - ) - - @patch("cm.inventory.get_import") - @patch("cm.inventory.get_obj_config") - def test_get_cluster_config(self, mock_get_obj_config, mock_get_import): - mock_get_obj_config.return_value = {} - mock_get_import.return_value = {} - res = get_cluster_config(self.cluster) - test_res = { - "cluster": { - "config": {}, - "edition": "community", - "name": self.cluster.name, - "id": self.cluster.pk, - "version": "1.0.0", - "state": "created", - "multi_state": [], - "before_upgrade": {"state": None}, - }, - "services": {}, - } - self.assertDictEqual(res, test_res) - - mock_get_obj_config.assert_called_once_with(obj=self.cluster) - mock_get_import.assert_called_once_with(cluster=self.cluster) - - @patch("cm.inventory.get_obj_config") - def test_get_provider_config(self, mock_get_obj_config): - mock_get_obj_config.return_value = {} - config = get_provider_config(self.provider.id) - - test_config = { - "provider": { - "config": {}, - "name": self.provider.name, - "id": self.provider.pk, - "host_prototype_id": self.host_pt.pk, - "state": "created", - "multi_state": [], - "before_upgrade": {"state": None}, - }, - } - - self.assertDictEqual(config, test_config) - mock_get_obj_config.assert_called_once_with(obj=self.provider) - - @patch("cm.inventory.get_obj_config") - def test_get_host_groups(self, mock_get_obj_config): - mock_get_obj_config.return_value = {} - - groups = get_host_groups(cluster=self.cluster) - - self.assertDictEqual(groups, {}) - mock_get_obj_config.assert_not_called() - - @patch("cm.inventory.get_hosts") - @patch("cm.inventory.get_cluster_config") - def test_get_cluster_hosts(self, mock_get_cluster_config, mock_get_hosts): - mock_get_cluster_config.return_value = [] - mock_get_hosts.return_value = [] - - test_cluster_hosts = {"CLUSTER": {"hosts": [], "vars": []}} - - cluster_hosts = get_cluster_hosts(self.cluster) - - self.assertDictEqual(cluster_hosts, test_cluster_hosts) - mock_get_hosts.assert_called_once() - mock_get_cluster_config.assert_called_once_with(cluster=self.cluster) - - @patch("cm.inventory.get_hosts") - def test_get_provider_hosts(self, mock_get_hosts): - mock_get_hosts.return_value = [] - - provider_hosts = get_provider_hosts(self.provider) - - test_provider_hosts = {"PROVIDER": {"hosts": []}} - - self.assertDictEqual(provider_hosts, test_provider_hosts) - mock_get_hosts.assert_called_once() - - @patch("cm.inventory.get_provider_hosts") - @patch("cm.inventory.get_hosts") - def test_get_host(self, mock_get_hosts, mock_get_provider_hosts): - mock_get_hosts.return_value = [] - mock_get_provider_hosts.return_value = {"PROVIDER": {"hosts": [], "vars": []}} - - groups = get_host(self.host.id) - test_groups = { - "HOST": { - "hosts": [], - "vars": { - "provider": { - "config": {}, - "name": self.provider.name, - "id": self.provider.pk, - "host_prototype_id": self.host_pt.pk, - "state": "created", - "multi_state": [], - "before_upgrade": {"state": None}, - }, - }, - }, - } - self.assertDictEqual(groups, test_groups) - mock_get_hosts.assert_called_once_with(host_list=[self.host], obj=self.host) - - @patch("json.dump") - @patch("cm.inventory.open") - def test_prepare_job_inventory(self, mock_open, mock_dump): - host2 = Host.objects.create(prototype=self.host_pt, fqdn="h2", cluster=self.cluster, provider=self.provider) - action = Action.objects.create(prototype=self.cluster_pt) - job = JobLog.objects.create(action=action, start_date=timezone.now(), finish_date=timezone.now()) - - file_mock = Mock() - file_mock.__enter__ = Mock(return_value=(Mock(), None)) - file_mock.__exit__ = Mock(return_value=None) - mock_open.return_value = file_mock - cluster_inv = { - "all": { - "children": { - "CLUSTER": { - "hosts": { - host2.fqdn: { - "adcm_hostid": host2.pk, - "state": "created", - "multi_state": [], - }, - }, - "vars": { - "cluster": { - "config": {}, - "name": "cluster", - "id": self.cluster.pk, - "version": "1.0.0", - "edition": "community", - "state": "created", - "multi_state": [], - "before_upgrade": {"state": None}, - }, - "services": {}, - }, - }, - }, - }, - } - host_inv = { - "all": { - "children": { - "HOST": { - "hosts": { - self.host.fqdn: { - "adcm_hostid": self.host.pk, - "state": "created", - "multi_state": [], - }, - }, - "vars": { - "provider": { - "config": {}, - "name": self.provider.name, - "id": self.provider.pk, - "host_prototype_id": self.host_pt.pk, - "state": "created", - "multi_state": [], - "before_upgrade": {"state": None}, - }, - }, - }, - }, - }, - } - provider_inv = { - "all": { - "children": { - "PROVIDER": { - "hosts": { - self.host.fqdn: { - "adcm_hostid": self.host.pk, - "state": "created", - "multi_state": [], - }, - "h2": {"adcm_hostid": host2.pk, "state": "created", "multi_state": []}, - }, - }, - }, - "vars": { - "provider": { - "config": {}, - "name": self.provider.name, - "id": self.provider.pk, - "host_prototype_id": self.host_pt.pk, - "state": "created", - "multi_state": [], - "before_upgrade": {"state": None}, - }, - }, - }, - } - - data = [ - (self.host, host_inv), - (self.provider, provider_inv), - (self.cluster, cluster_inv), - ] - - for obj, inv in data: - with self.subTest(obj=obj, inv=inv): - prepare_job_inventory(obj=obj, job_id=job.id, action=action) - mock_dump.assert_called_once_with(obj=inv, fp=file_mock.__enter__.return_value, separators=(",", ":")) - mock_dump.reset_mock() - - def test_host_vars(self): - # pylint: disable=too-many-locals - - service_pt_1 = gen_prototype(self.cluster_bundle, "service", "service_1") - service_pt_2 = gen_prototype(self.cluster_bundle, "service", "service_2") - component_pt_11 = gen_prototype(self.cluster_bundle, "component", "component_11") - component_pt_12 = gen_prototype(self.cluster_bundle, "component", "component_12") - component_pt_21 = gen_prototype(self.cluster_bundle, "component", "component_21") - - prototypes = [ - self.cluster_pt, - service_pt_1, - service_pt_2, - component_pt_11, - component_pt_12, - component_pt_21, - ] - for proto in prototypes: - gen_prototype_config( - prototype=proto, - name="some_string", - field_type="string", - group_customization=True, - ) - update_obj_config(self.cluster.config, config={"some_string": "some_string"}, attr={}) - service_1 = gen_service( - self.cluster, - prototype=service_pt_1, - config=gen_config({"some_string": "some_string"}), - ) - service_2 = gen_service( - self.cluster, - prototype=service_pt_2, - config=gen_config({"some_string": "some_string"}), - ) - component_11 = gen_component( - service_1, - prototype=component_pt_11, - config=gen_config({"some_string": "some_string"}), - ) - component_12 = gen_component( - service_1, - prototype=component_pt_12, - config=gen_config({"some_string": "some_string"}), - ) - component_21 = gen_component( - service_2, - prototype=component_pt_21, - config=gen_config({"some_string": "some_string"}), - ) - - self.host.cluster = self.cluster - self.host.save() - gen_host_component(component_11, self.host) - gen_host_component(component_12, self.host) - gen_host_component(component_21, self.host) - - groups = [ - gen_group("cluster", self.cluster.id, "cluster"), - gen_group("service_1", service_1.id, "clusterobject"), - gen_group("service_2", service_2.id, "clusterobject"), - gen_group("component_1", component_11.id, "servicecomponent"), - ] - for group in groups: - group.hosts.add(self.host) - update_obj_config(group.config, {"some_string": group.name}, {"group_keys": {"some_string": True}}) - - self.assertDictEqual(get_host_vars(self.host, self.cluster)["cluster"]["config"], {"some_string": "cluster"}) - - service_1_host_vars = get_host_vars(self.host, service_1) - - self.assertDictEqual(service_1_host_vars["services"]["service_1"]["config"], {"some_string": "service_1"}) - self.assertDictEqual(service_1_host_vars["services"]["service_2"]["config"], {"some_string": "service_2"}) - self.assertDictEqual( - service_1_host_vars["services"]["service_1"]["component_11"]["config"], - {"some_string": "component_1"}, - ) - self.assertDictEqual( - service_1_host_vars["services"]["service_1"]["component_12"]["config"], - {"some_string": "some_string"}, - ) - self.assertDictEqual( - service_1_host_vars["services"]["service_2"]["component_21"]["config"], - {"some_string": "some_string"}, - ) - - component_11_host_vars = get_host_vars(self.host, component_11) - - self.assertDictEqual(component_11_host_vars["services"]["service_1"]["config"], {"some_string": "service_1"}) - self.assertDictEqual( - component_11_host_vars["services"]["service_1"]["component_11"]["config"], - {"some_string": "component_1"}, - ) - self.assertDictEqual( - component_11_host_vars["services"]["service_1"]["component_12"]["config"], - {"some_string": "some_string"}, - ) - self.assertIn("service_2", component_11_host_vars["services"].keys()) - - component_12_host_vars = get_host_vars(self.host, component_12) - - self.assertDictEqual( - component_12_host_vars["services"]["service_1"]["component_12"]["config"], - {"some_string": "some_string"}, - ) - - -class TestInventoryAndMaintenanceMode(BaseTestCase): - # pylint: disable=too-many-instance-attributes - - def setUp(self): - super().setUp() - init_adcm() - - self.test_files_dir = self.base_dir / "python" / "cm" / "tests" / "files" - - _, self.cluster_hc_acl, _ = self.upload_bundle_create_cluster_config_log( - bundle_path=Path(self.test_files_dir, "test_inventory_remove_group_mm_hosts.tar"), - cluster_name="cluster_hc_acl", - ) - - self.provider = gen_provider(name="test_provider") - host_prototype = gen_prototype(bundle=self.provider.prototype.bundle, proto_type="host") - self.host_hc_acl_1 = gen_host( - provider=self.provider, cluster=self.cluster_hc_acl, fqdn="hc_acl_host_1", prototype=host_prototype - ) - self.host_hc_acl_2 = gen_host( - provider=self.provider, cluster=self.cluster_hc_acl, fqdn="hc_acl_host_2", prototype=host_prototype - ) - self.host_hc_acl_3 = gen_host( - provider=self.provider, cluster=self.cluster_hc_acl, fqdn="hc_acl_host_3", prototype=host_prototype - ) - - self.service_hc_acl = add_service_to_cluster( - cluster=self.cluster_hc_acl, - proto=Prototype.objects.get(name="service_1", type="service"), - ) - - self.component_hc_acl_1 = ServiceComponent.objects.get( - cluster=self.cluster_hc_acl, prototype__name="component_1" - ) - self.component_hc_acl_2 = ServiceComponent.objects.get( - cluster=self.cluster_hc_acl, prototype__name="component_2" - ) - - self.hc_c1_h1 = { - "host_id": self.host_hc_acl_1.pk, - "service_id": self.service_hc_acl.pk, - "component_id": self.component_hc_acl_1.pk, - } - self.hc_c1_h2 = { - "host_id": self.host_hc_acl_2.pk, - "service_id": self.service_hc_acl.pk, - "component_id": self.component_hc_acl_1.pk, - } - self.hc_c1_h3 = { - "host_id": self.host_hc_acl_3.pk, - "service_id": self.service_hc_acl.pk, - "component_id": self.component_hc_acl_1.pk, - } - self.hc_c2_h1 = { - "host_id": self.host_hc_acl_1.pk, - "service_id": self.service_hc_acl.pk, - "component_id": self.component_hc_acl_2.pk, - } - self.hc_c2_h2 = { - "host_id": self.host_hc_acl_2.pk, - "service_id": self.service_hc_acl.pk, - "component_id": self.component_hc_acl_2.pk, - } - - add_hc( - cluster=self.cluster_hc_acl, - hc_in=[self.hc_c1_h1, self.hc_c1_h2, self.hc_c1_h3, self.hc_c2_h1, self.hc_c2_h2], - ) - - self.action_hc_acl = Action.objects.get(name="cluster_action_hc_acl", allow_in_maintenance_mode=True) - - _, self.cluster_target_group, _ = self.upload_bundle_create_cluster_config_log( - bundle_path=Path(self.test_files_dir, "cluster_mm_host_target_group.tar"), - cluster_name="cluster_target_group", - ) - - self.host_target_group_1 = gen_host( - provider=self.provider, - cluster=self.cluster_target_group, - fqdn="host_target_group_1", - prototype=host_prototype, - ) - self.host_target_group_2 = gen_host( - provider=self.provider, - cluster=self.cluster_target_group, - fqdn="host_target_group_2", - prototype=host_prototype, - ) - - self.service_target_group = add_service_to_cluster( - cluster=self.cluster_target_group, - proto=Prototype.objects.get(name="service_1_target_group", type="service"), - ) - self.component_target_group = ServiceComponent.objects.get( - cluster=self.cluster_target_group, prototype__name="component_1_target_group" - ) - - add_hc( - cluster=self.cluster_target_group, - hc_in=[ - { - "host_id": self.host_target_group_1.pk, - "service_id": self.service_target_group.pk, - "component_id": self.component_target_group.pk, - }, - { - "host_id": self.host_target_group_2.pk, - "service_id": self.service_target_group.pk, - "component_id": self.component_target_group.pk, - }, - ], - ) - - self.action_target_group = Action.objects.get(name="host_action_target_group", allow_in_maintenance_mode=True) - - @staticmethod - def _get_hc_request_data(*new_hc_items: dict) -> list[dict]: - hc_fields = ("id", "service_id", "component_id", "host_id") - hc_request_data = [] - - for host_component in new_hc_items: - hc_values = HostComponent.objects.filter(**host_component).values_list(*hc_fields).first() - hc_request_data.append(dict(zip(hc_fields, hc_values))) - - return hc_request_data - - def get_inventory_data(self, data: dict, kwargs: dict) -> dict: - self.assertEqual(TaskLog.objects.count(), 0) - self.assertEqual(JobLog.objects.count(), 0) - - response: Response = self.client.post( - path=reverse(viewname="v1:run-task", kwargs=kwargs), - data=data, - content_type=APPLICATION_JSON, - ) - self.assertEqual(response.status_code, HTTP_201_CREATED) - - task = TaskLog.objects.last() - job = JobLog.objects.last() - - re_prepare_job(task=task, job=job) - - inventory_file = settings.RUN_DIR / str(job.pk) / "inventory.json" - with open(file=inventory_file, encoding=settings.ENCODING_UTF_8) as f: - inventory_data = loads(s=f.read())["all"]["children"] - - return inventory_data - - def test_groups_remove_host_not_in_mm_success(self): - self.host_hc_acl_3.maintenance_mode = MaintenanceMode.ON - self.host_hc_acl_3.save() - - # remove: hc_c1_h2 - hc_request_data = self._get_hc_request_data(self.hc_c1_h1, self.hc_c1_h3, self.hc_c2_h1, self.hc_c2_h2) - - inventory_data = self.get_inventory_data( - data={"hc": hc_request_data, "verbose": False}, - kwargs={ - "cluster_id": self.cluster_hc_acl.pk, - "object_type": "cluster", - "action_id": self.action_hc_acl.pk, - }, - ) - - target_key_remove = ( - f"{ClusterObject.objects.get(pk=self.hc_c1_h2['service_id']).prototype.name}" - f".{ServiceComponent.objects.get(pk=self.hc_c1_h2['component_id']).prototype.name}" - f".{HcAclAction.REMOVE}" - ) - target_key_mm_service = ( - f"{ClusterObject.objects.get(pk=self.hc_c1_h3['service_id']).prototype.name}.{MAINTENANCE_MODE}" - ) - target_key_mm_service_component = ( - f"{ClusterObject.objects.get(pk=self.hc_c1_h3['service_id']).prototype.name}" - f".{ServiceComponent.objects.get(pk=self.hc_c1_h3['component_id']).prototype.name}" - f".{MAINTENANCE_MODE}" - ) - - self.assertIn(target_key_remove, inventory_data) - self.assertIn(self.host_hc_acl_2.fqdn, inventory_data[target_key_remove]["hosts"]) - - self.assertIn(target_key_mm_service, inventory_data) - self.assertIn(self.host_hc_acl_3.fqdn, inventory_data[target_key_mm_service]["hosts"]) - - self.assertIn(target_key_mm_service_component, inventory_data) - self.assertIn(self.host_hc_acl_3.fqdn, inventory_data[target_key_mm_service_component]["hosts"]) - - remove_keys = [key for key in inventory_data if key.endswith(f".{HcAclAction.REMOVE}")] - self.assertEqual(len(remove_keys), 1) - - mm_keys = [key for key in inventory_data if key.endswith(f".{MAINTENANCE_MODE}")] - self.assertEqual(len(mm_keys), 2) - - def test_groups_remove_host_in_mm_success(self): - self.host_hc_acl_3.maintenance_mode = MaintenanceMode.ON - self.host_hc_acl_3.save() - - # remove: hc_c1_h3 - hc_request_data = self._get_hc_request_data(self.hc_c1_h1, self.hc_c1_h2, self.hc_c2_h1, self.hc_c2_h2) - - inventory_data = self.get_inventory_data( - data={"hc": hc_request_data, "verbose": False}, - kwargs={ - "cluster_id": self.cluster_hc_acl.pk, - "object_type": "cluster", - "action_id": self.action_hc_acl.pk, - }, - ) - - target_key_remove = ( - f"{ClusterObject.objects.get(pk=self.hc_c1_h3['service_id']).prototype.name}" - f".{ServiceComponent.objects.get(pk=self.hc_c1_h3['component_id']).prototype.name}" - f".{HcAclAction.REMOVE}" - ) - - self.assertIn(target_key_remove, inventory_data) - self.assertNotIn(self.host_hc_acl_3.fqdn, inventory_data[target_key_remove]["hosts"]) - - remove_keys = [key for key in inventory_data if key.endswith(f".{HcAclAction.REMOVE}")] - self.assertEqual(len(remove_keys), 1) - - mm_keys = [key for key in inventory_data if key.endswith(f".{HcAclAction.REMOVE}.{MAINTENANCE_MODE}")] - self.assertEqual(len(mm_keys), 1) - - def test_vars_in_mm_group(self): - self.host_target_group_1.maintenance_mode = MaintenanceMode.ON - self.host_target_group_1.save() - - groups = [ - gen_group(name="cluster", object_id=self.cluster_target_group.id, model_name="cluster"), - gen_group(name="service_1", object_id=self.service_target_group.id, model_name="clusterobject"), - ] - - for group in groups: - group.hosts.add(self.host_target_group_1) - update_obj_config( - obj_conf=group.config, - config={"some_string": group.name, "float": 0.1}, - attr={"group_keys": {"some_string": True, "float": False}}, - ) - - inventory_data = self.get_inventory_data( - data={"verbose": False}, - kwargs={ - "cluster_id": self.cluster_target_group.pk, - "object_type": "cluster", - "action_id": Action.objects.get(name="not_host_action").id, - }, - ) - - self.assertDictEqual( - inventory_data["service_1_target_group.component_1_target_group.maintenance_mode"]["hosts"][ - "host_target_group_1" - ]["cluster"]["config"], - {"some_string": "cluster", "float": 0.1}, - ) - self.assertDictEqual( - inventory_data["service_1_target_group.component_1_target_group.maintenance_mode"]["hosts"][ - "host_target_group_1" - ]["services"]["service_1_target_group"]["config"], - {"some_string": "service_1", "float": 0.1}, - ) - self.assertDictEqual( - inventory_data["service_1_target_group.component_1_target_group.maintenance_mode"]["hosts"][ - "host_target_group_1" - ]["services"]["service_1_target_group"]["component_1_target_group"]["config"], - {"some_string": "some_string", "float": 0.1}, - ) - - def test_host_in_target_group_hostaction_on_host_in_mm_success(self): - self.host_target_group_1.maintenance_mode = MaintenanceMode.ON - self.host_target_group_1.save() - - target_hosts_data = self.get_inventory_data( - data={"verbose": False}, - kwargs={ - "cluster_id": self.cluster_target_group.pk, - "host_id": self.host_target_group_1.pk, - "object_type": "host", - "action_id": self.action_target_group.pk, - }, - )["target"]["hosts"] - - self.assertIn(self.host_target_group_1.fqdn, target_hosts_data) - - def test_host_in_target_group_hostaction_on_host_not_in_mm_success(self): - self.host_target_group_2.maintenance_mode = MaintenanceMode.OFF - self.host_target_group_2.save() - - target_hosts_data = self.get_inventory_data( - data={"verbose": False}, - kwargs={ - "cluster_id": self.cluster_target_group.pk, - "host_id": self.host_target_group_2.pk, - "object_type": "host", - "action_id": self.action_target_group.pk, - }, - )["target"]["hosts"] - - self.assertIn(self.host_target_group_2.fqdn, target_hosts_data) - - class TestInventoryComponents(BusinessLogicMixin, BaseTestCase): def setUp(self) -> None: self.maxDiff = None # pylint: disable=invalid-name - bundles_dir = Path(__file__).parent / "bundles" - self.templates_dir = Path(__file__).parent / "files/response_templates" + bundles_dir = Path(__file__).parent.parent / "bundles" + self.templates_dir = Path(__file__).parent.parent / "files/response_templates" self.provider_bundle = self.add_bundle(source_dir=bundles_dir / "provider") cluster_bundle = self.add_bundle(source_dir=bundles_dir / "cluster_1") diff --git a/python/cm/tests/test_inventory/test_inventory.py b/python/cm/tests/test_inventory/test_inventory.py new file mode 100644 index 0000000000..5dad327348 --- /dev/null +++ b/python/cm/tests/test_inventory/test_inventory.py @@ -0,0 +1,727 @@ +# Licensed 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. + + +from json import loads +from pathlib import Path +from unittest.mock import Mock, patch + +from cm.api import add_hc, add_service_to_cluster, update_obj_config +from cm.inventory import ( + MAINTENANCE_MODE, + HcAclAction, + get_cluster_config, + get_cluster_hosts, + get_host, + get_host_groups, + get_host_vars, + get_obj_config, + get_provider_config, + get_provider_hosts, + prepare_job_inventory, + process_config_and_attr, +) +from cm.job import re_prepare_job +from cm.models import ( + Action, + ClusterObject, + ConfigLog, + Host, + HostComponent, + JobLog, + MaintenanceMode, + Prototype, + ServiceComponent, + TaskLog, +) +from cm.tests.utils import ( + gen_bundle, + gen_cluster, + gen_component, + gen_config, + gen_group, + gen_host, + gen_host_component, + gen_prototype, + gen_prototype_config, + gen_provider, + gen_service, +) +from django.conf import settings +from django.urls import reverse +from django.utils import timezone +from init_db import init as init_adcm +from rest_framework.response import Response +from rest_framework.status import HTTP_201_CREATED + +from adcm.tests.base import APPLICATION_JSON, BaseTestCase + + +class TestInventory(BaseTestCase): + # pylint: disable=too-many-instance-attributes + + def setUp(self): + super().setUp() + + self.cluster_bundle = gen_bundle() + self.cluster_pt = gen_prototype(self.cluster_bundle, "cluster", "cluster") + self.cluster = gen_cluster(prototype=self.cluster_pt, config=gen_config(), name="cluster") + + self.provider_bundle = gen_bundle() + + self.provider_pt = gen_prototype(self.provider_bundle, "provider") + self.host_pt = gen_prototype(self.provider_bundle, "host") + + self.provider = gen_provider(prototype=self.provider_pt) + self.host = gen_host(self.provider, prototype=self.host_pt) + + @patch("cm.inventory.process_config") + @patch("cm.inventory.get_prototype_config") + def test_process_config_and_attr(self, mock_get_prototype_config, mock_process_config): + mock_get_prototype_config.return_value = ({}, {}, {}, {}) + mock_process_config.return_value = {} + obj_mock = Mock(prototype={}) + + attr = {"global": {"active": ""}} + conf = process_config_and_attr(obj_mock, {}, attr) + + self.assertDictEqual(conf, {"global": None}) + + mock_get_prototype_config.assert_called_once_with(prototype={}) + mock_process_config.assert_called_once_with(obj=obj_mock, spec={}, old_conf={}) + + @patch("cm.inventory.process_config_and_attr") + def test_get_obj_config(self, mock_process_config_and_attr): + get_obj_config(self.cluster) + config_log = ConfigLog.objects.get(id=self.cluster.config.current) + mock_process_config_and_attr.assert_called_once_with( + obj=self.cluster, + conf=config_log.config, + attr=config_log.attr, + ) + + @patch("cm.inventory.get_import") + @patch("cm.inventory.get_obj_config") + def test_get_cluster_config(self, mock_get_obj_config, mock_get_import): + mock_get_obj_config.return_value = {} + mock_get_import.return_value = {} + res = get_cluster_config(self.cluster) + test_res = { + "cluster": { + "config": {}, + "edition": "community", + "name": self.cluster.name, + "id": self.cluster.pk, + "version": "1.0.0", + "state": "created", + "multi_state": [], + "before_upgrade": {"state": None}, + }, + "services": {}, + } + self.assertDictEqual(res, test_res) + + mock_get_obj_config.assert_called_once_with(obj=self.cluster) + mock_get_import.assert_called_once_with(cluster=self.cluster) + + @patch("cm.inventory.get_obj_config") + def test_get_provider_config(self, mock_get_obj_config): + mock_get_obj_config.return_value = {} + config = get_provider_config(self.provider.id) + + test_config = { + "provider": { + "config": {}, + "name": self.provider.name, + "id": self.provider.pk, + "host_prototype_id": self.host_pt.pk, + "state": "created", + "multi_state": [], + "before_upgrade": {"state": None}, + }, + } + + self.assertDictEqual(config, test_config) + mock_get_obj_config.assert_called_once_with(obj=self.provider) + + @patch("cm.inventory.get_obj_config") + def test_get_host_groups(self, mock_get_obj_config): + mock_get_obj_config.return_value = {} + + groups = get_host_groups(cluster=self.cluster) + + self.assertDictEqual(groups, {}) + mock_get_obj_config.assert_not_called() + + @patch("cm.inventory.get_hosts") + @patch("cm.inventory.get_cluster_config") + def test_get_cluster_hosts(self, mock_get_cluster_config, mock_get_hosts): + mock_get_cluster_config.return_value = [] + mock_get_hosts.return_value = [] + + test_cluster_hosts = {"CLUSTER": {"hosts": [], "vars": []}} + + cluster_hosts = get_cluster_hosts(self.cluster) + + self.assertDictEqual(cluster_hosts, test_cluster_hosts) + mock_get_hosts.assert_called_once() + mock_get_cluster_config.assert_called_once_with(cluster=self.cluster) + + @patch("cm.inventory.get_hosts") + def test_get_provider_hosts(self, mock_get_hosts): + mock_get_hosts.return_value = [] + + provider_hosts = get_provider_hosts(self.provider) + + test_provider_hosts = {"PROVIDER": {"hosts": []}} + + self.assertDictEqual(provider_hosts, test_provider_hosts) + mock_get_hosts.assert_called_once() + + @patch("cm.inventory.get_provider_hosts") + @patch("cm.inventory.get_hosts") + def test_get_host(self, mock_get_hosts, mock_get_provider_hosts): + mock_get_hosts.return_value = [] + mock_get_provider_hosts.return_value = {"PROVIDER": {"hosts": [], "vars": []}} + + groups = get_host(self.host.id) + test_groups = { + "HOST": { + "hosts": [], + "vars": { + "provider": { + "config": {}, + "name": self.provider.name, + "id": self.provider.pk, + "host_prototype_id": self.host_pt.pk, + "state": "created", + "multi_state": [], + "before_upgrade": {"state": None}, + }, + }, + }, + } + self.assertDictEqual(groups, test_groups) + mock_get_hosts.assert_called_once_with(host_list=[self.host], obj=self.host) + + @patch("json.dump") + @patch("cm.inventory.open") + def test_prepare_job_inventory(self, mock_open, mock_dump): + host2 = Host.objects.create(prototype=self.host_pt, fqdn="h2", cluster=self.cluster, provider=self.provider) + action = Action.objects.create(prototype=self.cluster_pt) + job = JobLog.objects.create(action=action, start_date=timezone.now(), finish_date=timezone.now()) + + file_mock = Mock() + file_mock.__enter__ = Mock(return_value=(Mock(), None)) + file_mock.__exit__ = Mock(return_value=None) + mock_open.return_value = file_mock + cluster_inv = { + "all": { + "children": { + "CLUSTER": { + "hosts": { + host2.fqdn: { + "adcm_hostid": host2.pk, + "state": "created", + "multi_state": [], + }, + }, + "vars": { + "cluster": { + "config": {}, + "name": "cluster", + "id": self.cluster.pk, + "version": "1.0.0", + "edition": "community", + "state": "created", + "multi_state": [], + "before_upgrade": {"state": None}, + }, + "services": {}, + }, + }, + }, + }, + } + host_inv = { + "all": { + "children": { + "HOST": { + "hosts": { + self.host.fqdn: { + "adcm_hostid": self.host.pk, + "state": "created", + "multi_state": [], + }, + }, + "vars": { + "provider": { + "config": {}, + "name": self.provider.name, + "id": self.provider.pk, + "host_prototype_id": self.host_pt.pk, + "state": "created", + "multi_state": [], + "before_upgrade": {"state": None}, + }, + }, + }, + }, + }, + } + provider_inv = { + "all": { + "children": { + "PROVIDER": { + "hosts": { + self.host.fqdn: { + "adcm_hostid": self.host.pk, + "state": "created", + "multi_state": [], + }, + "h2": {"adcm_hostid": host2.pk, "state": "created", "multi_state": []}, + }, + }, + }, + "vars": { + "provider": { + "config": {}, + "name": self.provider.name, + "id": self.provider.pk, + "host_prototype_id": self.host_pt.pk, + "state": "created", + "multi_state": [], + "before_upgrade": {"state": None}, + }, + }, + }, + } + + data = [ + (self.host, host_inv), + (self.provider, provider_inv), + (self.cluster, cluster_inv), + ] + + for obj, inv in data: + with self.subTest(obj=obj, inv=inv): + prepare_job_inventory(obj=obj, job_id=job.id, action=action) + mock_dump.assert_called_once_with(obj=inv, fp=file_mock.__enter__.return_value, separators=(",", ":")) + mock_dump.reset_mock() + + def test_host_vars(self): + # pylint: disable=too-many-locals + + service_pt_1 = gen_prototype(self.cluster_bundle, "service", "service_1") + service_pt_2 = gen_prototype(self.cluster_bundle, "service", "service_2") + component_pt_11 = gen_prototype(self.cluster_bundle, "component", "component_11") + component_pt_12 = gen_prototype(self.cluster_bundle, "component", "component_12") + component_pt_21 = gen_prototype(self.cluster_bundle, "component", "component_21") + + prototypes = [ + self.cluster_pt, + service_pt_1, + service_pt_2, + component_pt_11, + component_pt_12, + component_pt_21, + ] + for proto in prototypes: + gen_prototype_config( + prototype=proto, + name="some_string", + field_type="string", + group_customization=True, + ) + update_obj_config(self.cluster.config, config={"some_string": "some_string"}, attr={}) + service_1 = gen_service( + self.cluster, + prototype=service_pt_1, + config=gen_config({"some_string": "some_string"}), + ) + service_2 = gen_service( + self.cluster, + prototype=service_pt_2, + config=gen_config({"some_string": "some_string"}), + ) + component_11 = gen_component( + service_1, + prototype=component_pt_11, + config=gen_config({"some_string": "some_string"}), + ) + component_12 = gen_component( + service_1, + prototype=component_pt_12, + config=gen_config({"some_string": "some_string"}), + ) + component_21 = gen_component( + service_2, + prototype=component_pt_21, + config=gen_config({"some_string": "some_string"}), + ) + + self.host.cluster = self.cluster + self.host.save() + gen_host_component(component_11, self.host) + gen_host_component(component_12, self.host) + gen_host_component(component_21, self.host) + + groups = [ + gen_group("cluster", self.cluster.id, "cluster"), + gen_group("service_1", service_1.id, "clusterobject"), + gen_group("service_2", service_2.id, "clusterobject"), + gen_group("component_1", component_11.id, "servicecomponent"), + ] + for group in groups: + group.hosts.add(self.host) + update_obj_config(group.config, {"some_string": group.name}, {"group_keys": {"some_string": True}}) + + self.assertDictEqual(get_host_vars(self.host, self.cluster)["cluster"]["config"], {"some_string": "cluster"}) + + service_1_host_vars = get_host_vars(self.host, service_1) + + self.assertDictEqual(service_1_host_vars["services"]["service_1"]["config"], {"some_string": "service_1"}) + self.assertDictEqual(service_1_host_vars["services"]["service_2"]["config"], {"some_string": "service_2"}) + self.assertDictEqual( + service_1_host_vars["services"]["service_1"]["component_11"]["config"], + {"some_string": "component_1"}, + ) + self.assertDictEqual( + service_1_host_vars["services"]["service_1"]["component_12"]["config"], + {"some_string": "some_string"}, + ) + self.assertDictEqual( + service_1_host_vars["services"]["service_2"]["component_21"]["config"], + {"some_string": "some_string"}, + ) + + component_11_host_vars = get_host_vars(self.host, component_11) + + self.assertDictEqual(component_11_host_vars["services"]["service_1"]["config"], {"some_string": "service_1"}) + self.assertDictEqual( + component_11_host_vars["services"]["service_1"]["component_11"]["config"], + {"some_string": "component_1"}, + ) + self.assertDictEqual( + component_11_host_vars["services"]["service_1"]["component_12"]["config"], + {"some_string": "some_string"}, + ) + self.assertIn("service_2", component_11_host_vars["services"].keys()) + + component_12_host_vars = get_host_vars(self.host, component_12) + + self.assertDictEqual( + component_12_host_vars["services"]["service_1"]["component_12"]["config"], + {"some_string": "some_string"}, + ) + + +class TestInventoryAndMaintenanceMode(BaseTestCase): + # pylint: disable=too-many-instance-attributes + + def setUp(self): + super().setUp() + init_adcm() + + self.test_files_dir = self.base_dir / "python" / "cm" / "tests" / "files" + + _, self.cluster_hc_acl, _ = self.upload_bundle_create_cluster_config_log( + bundle_path=Path(self.test_files_dir, "test_inventory_remove_group_mm_hosts.tar"), + cluster_name="cluster_hc_acl", + ) + + self.provider = gen_provider(name="test_provider") + host_prototype = gen_prototype(bundle=self.provider.prototype.bundle, proto_type="host") + self.host_hc_acl_1 = gen_host( + provider=self.provider, cluster=self.cluster_hc_acl, fqdn="hc_acl_host_1", prototype=host_prototype + ) + self.host_hc_acl_2 = gen_host( + provider=self.provider, cluster=self.cluster_hc_acl, fqdn="hc_acl_host_2", prototype=host_prototype + ) + self.host_hc_acl_3 = gen_host( + provider=self.provider, cluster=self.cluster_hc_acl, fqdn="hc_acl_host_3", prototype=host_prototype + ) + + self.service_hc_acl = add_service_to_cluster( + cluster=self.cluster_hc_acl, + proto=Prototype.objects.get(name="service_1", type="service"), + ) + + self.component_hc_acl_1 = ServiceComponent.objects.get( + cluster=self.cluster_hc_acl, prototype__name="component_1" + ) + self.component_hc_acl_2 = ServiceComponent.objects.get( + cluster=self.cluster_hc_acl, prototype__name="component_2" + ) + + self.hc_c1_h1 = { + "host_id": self.host_hc_acl_1.pk, + "service_id": self.service_hc_acl.pk, + "component_id": self.component_hc_acl_1.pk, + } + self.hc_c1_h2 = { + "host_id": self.host_hc_acl_2.pk, + "service_id": self.service_hc_acl.pk, + "component_id": self.component_hc_acl_1.pk, + } + self.hc_c1_h3 = { + "host_id": self.host_hc_acl_3.pk, + "service_id": self.service_hc_acl.pk, + "component_id": self.component_hc_acl_1.pk, + } + self.hc_c2_h1 = { + "host_id": self.host_hc_acl_1.pk, + "service_id": self.service_hc_acl.pk, + "component_id": self.component_hc_acl_2.pk, + } + self.hc_c2_h2 = { + "host_id": self.host_hc_acl_2.pk, + "service_id": self.service_hc_acl.pk, + "component_id": self.component_hc_acl_2.pk, + } + + add_hc( + cluster=self.cluster_hc_acl, + hc_in=[self.hc_c1_h1, self.hc_c1_h2, self.hc_c1_h3, self.hc_c2_h1, self.hc_c2_h2], + ) + + self.action_hc_acl = Action.objects.get(name="cluster_action_hc_acl", allow_in_maintenance_mode=True) + + _, self.cluster_target_group, _ = self.upload_bundle_create_cluster_config_log( + bundle_path=Path(self.test_files_dir, "cluster_mm_host_target_group.tar"), + cluster_name="cluster_target_group", + ) + + self.host_target_group_1 = gen_host( + provider=self.provider, + cluster=self.cluster_target_group, + fqdn="host_target_group_1", + prototype=host_prototype, + ) + self.host_target_group_2 = gen_host( + provider=self.provider, + cluster=self.cluster_target_group, + fqdn="host_target_group_2", + prototype=host_prototype, + ) + + self.service_target_group = add_service_to_cluster( + cluster=self.cluster_target_group, + proto=Prototype.objects.get(name="service_1_target_group", type="service"), + ) + self.component_target_group = ServiceComponent.objects.get( + cluster=self.cluster_target_group, prototype__name="component_1_target_group" + ) + + add_hc( + cluster=self.cluster_target_group, + hc_in=[ + { + "host_id": self.host_target_group_1.pk, + "service_id": self.service_target_group.pk, + "component_id": self.component_target_group.pk, + }, + { + "host_id": self.host_target_group_2.pk, + "service_id": self.service_target_group.pk, + "component_id": self.component_target_group.pk, + }, + ], + ) + + self.action_target_group = Action.objects.get(name="host_action_target_group", allow_in_maintenance_mode=True) + + @staticmethod + def _get_hc_request_data(*new_hc_items: dict) -> list[dict]: + hc_fields = ("id", "service_id", "component_id", "host_id") + hc_request_data = [] + + for host_component in new_hc_items: + hc_values = HostComponent.objects.filter(**host_component).values_list(*hc_fields).first() + hc_request_data.append(dict(zip(hc_fields, hc_values))) + + return hc_request_data + + def get_inventory_data(self, data: dict, kwargs: dict) -> dict: + self.assertEqual(TaskLog.objects.count(), 0) + self.assertEqual(JobLog.objects.count(), 0) + + response: Response = self.client.post( + path=reverse(viewname="v1:run-task", kwargs=kwargs), + data=data, + content_type=APPLICATION_JSON, + ) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + task = TaskLog.objects.last() + job = JobLog.objects.last() + + re_prepare_job(task=task, job=job) + + inventory_file = settings.RUN_DIR / str(job.pk) / "inventory.json" + with open(file=inventory_file, encoding=settings.ENCODING_UTF_8) as f: + inventory_data = loads(s=f.read())["all"]["children"] + + return inventory_data + + def test_groups_remove_host_not_in_mm_success(self): + self.host_hc_acl_3.maintenance_mode = MaintenanceMode.ON + self.host_hc_acl_3.save() + + # remove: hc_c1_h2 + hc_request_data = self._get_hc_request_data(self.hc_c1_h1, self.hc_c1_h3, self.hc_c2_h1, self.hc_c2_h2) + + inventory_data = self.get_inventory_data( + data={"hc": hc_request_data, "verbose": False}, + kwargs={ + "cluster_id": self.cluster_hc_acl.pk, + "object_type": "cluster", + "action_id": self.action_hc_acl.pk, + }, + ) + + target_key_remove = ( + f"{ClusterObject.objects.get(pk=self.hc_c1_h2['service_id']).prototype.name}" + f".{ServiceComponent.objects.get(pk=self.hc_c1_h2['component_id']).prototype.name}" + f".{HcAclAction.REMOVE}" + ) + target_key_mm_service = ( + f"{ClusterObject.objects.get(pk=self.hc_c1_h3['service_id']).prototype.name}.{MAINTENANCE_MODE}" + ) + target_key_mm_service_component = ( + f"{ClusterObject.objects.get(pk=self.hc_c1_h3['service_id']).prototype.name}" + f".{ServiceComponent.objects.get(pk=self.hc_c1_h3['component_id']).prototype.name}" + f".{MAINTENANCE_MODE}" + ) + + self.assertIn(target_key_remove, inventory_data) + self.assertIn(self.host_hc_acl_2.fqdn, inventory_data[target_key_remove]["hosts"]) + + self.assertIn(target_key_mm_service, inventory_data) + self.assertIn(self.host_hc_acl_3.fqdn, inventory_data[target_key_mm_service]["hosts"]) + + self.assertIn(target_key_mm_service_component, inventory_data) + self.assertIn(self.host_hc_acl_3.fqdn, inventory_data[target_key_mm_service_component]["hosts"]) + + remove_keys = [key for key in inventory_data if key.endswith(f".{HcAclAction.REMOVE}")] + self.assertEqual(len(remove_keys), 1) + + mm_keys = [key for key in inventory_data if key.endswith(f".{MAINTENANCE_MODE}")] + self.assertEqual(len(mm_keys), 2) + + def test_groups_remove_host_in_mm_success(self): + self.host_hc_acl_3.maintenance_mode = MaintenanceMode.ON + self.host_hc_acl_3.save() + + # remove: hc_c1_h3 + hc_request_data = self._get_hc_request_data(self.hc_c1_h1, self.hc_c1_h2, self.hc_c2_h1, self.hc_c2_h2) + + inventory_data = self.get_inventory_data( + data={"hc": hc_request_data, "verbose": False}, + kwargs={ + "cluster_id": self.cluster_hc_acl.pk, + "object_type": "cluster", + "action_id": self.action_hc_acl.pk, + }, + ) + + target_key_remove = ( + f"{ClusterObject.objects.get(pk=self.hc_c1_h3['service_id']).prototype.name}" + f".{ServiceComponent.objects.get(pk=self.hc_c1_h3['component_id']).prototype.name}" + f".{HcAclAction.REMOVE}" + ) + + self.assertIn(target_key_remove, inventory_data) + self.assertNotIn(self.host_hc_acl_3.fqdn, inventory_data[target_key_remove]["hosts"]) + + remove_keys = [key for key in inventory_data if key.endswith(f".{HcAclAction.REMOVE}")] + self.assertEqual(len(remove_keys), 1) + + mm_keys = [key for key in inventory_data if key.endswith(f".{HcAclAction.REMOVE}.{MAINTENANCE_MODE}")] + self.assertEqual(len(mm_keys), 1) + + def test_vars_in_mm_group(self): + self.host_target_group_1.maintenance_mode = MaintenanceMode.ON + self.host_target_group_1.save() + + groups = [ + gen_group(name="cluster", object_id=self.cluster_target_group.id, model_name="cluster"), + gen_group(name="service_1", object_id=self.service_target_group.id, model_name="clusterobject"), + ] + + for group in groups: + group.hosts.add(self.host_target_group_1) + update_obj_config( + obj_conf=group.config, + config={"some_string": group.name, "float": 0.1}, + attr={"group_keys": {"some_string": True, "float": False}}, + ) + + inventory_data = self.get_inventory_data( + data={"verbose": False}, + kwargs={ + "cluster_id": self.cluster_target_group.pk, + "object_type": "cluster", + "action_id": Action.objects.get(name="not_host_action").id, + }, + ) + + self.assertDictEqual( + inventory_data["service_1_target_group.component_1_target_group.maintenance_mode"]["hosts"][ + "host_target_group_1" + ]["cluster"]["config"], + {"some_string": "cluster", "float": 0.1}, + ) + self.assertDictEqual( + inventory_data["service_1_target_group.component_1_target_group.maintenance_mode"]["hosts"][ + "host_target_group_1" + ]["services"]["service_1_target_group"]["config"], + {"some_string": "service_1", "float": 0.1}, + ) + self.assertDictEqual( + inventory_data["service_1_target_group.component_1_target_group.maintenance_mode"]["hosts"][ + "host_target_group_1" + ]["services"]["service_1_target_group"]["component_1_target_group"]["config"], + {"some_string": "some_string", "float": 0.1}, + ) + + def test_host_in_target_group_hostaction_on_host_in_mm_success(self): + self.host_target_group_1.maintenance_mode = MaintenanceMode.ON + self.host_target_group_1.save() + + target_hosts_data = self.get_inventory_data( + data={"verbose": False}, + kwargs={ + "cluster_id": self.cluster_target_group.pk, + "host_id": self.host_target_group_1.pk, + "object_type": "host", + "action_id": self.action_target_group.pk, + }, + )["target"]["hosts"] + + self.assertIn(self.host_target_group_1.fqdn, target_hosts_data) + + def test_host_in_target_group_hostaction_on_host_not_in_mm_success(self): + self.host_target_group_2.maintenance_mode = MaintenanceMode.OFF + self.host_target_group_2.save() + + target_hosts_data = self.get_inventory_data( + data={"verbose": False}, + kwargs={ + "cluster_id": self.cluster_target_group.pk, + "host_id": self.host_target_group_2.pk, + "object_type": "host", + "action_id": self.action_target_group.pk, + }, + )["target"]["hosts"] + + self.assertIn(self.host_target_group_2.fqdn, target_hosts_data) From eae23d876758a896c1e9c8e34b0d565fec008ec8 Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Tue, 16 Jan 2024 06:25:40 +0000 Subject: [PATCH 029/151] ADCM-5179 Implement bulk mapping of hosts to cluster --- python/api_v2/host/serializers.py | 4 +- python/api_v2/host/views.py | 56 +++++++++--- python/api_v2/tests/test_host.py | 141 +++++++++++++++++++++++++++++- python/audit/cases/cluster.py | 4 + python/cm/services/__init__.py | 13 +++ python/cm/services/cluster.py | 53 +++++++++++ python/core/__init__.py | 14 +++ python/core/cluster/__init__.py | 17 ++++ python/core/cluster/errors.py | 25 ++++++ python/core/cluster/operations.py | 39 +++++++++ python/core/cluster/rules.py | 37 ++++++++ python/core/cluster/types.py | 18 ++++ python/core/types.py | 25 ++++++ 13 files changed, 427 insertions(+), 19 deletions(-) create mode 100644 python/cm/services/__init__.py create mode 100644 python/cm/services/cluster.py create mode 100644 python/core/__init__.py create mode 100644 python/core/cluster/__init__.py create mode 100644 python/core/cluster/errors.py create mode 100644 python/core/cluster/operations.py create mode 100644 python/core/cluster/rules.py create mode 100644 python/core/cluster/types.py create mode 100644 python/core/types.py diff --git a/python/api_v2/host/serializers.py b/python/api_v2/host/serializers.py index 9522d25ec8..2a0e9551b1 100644 --- a/python/api_v2/host/serializers.py +++ b/python/api_v2/host/serializers.py @@ -144,8 +144,8 @@ class HostCreateSerializer(EmptySerializer): cluster_id = IntegerField(required=False) -class HostCreateRelatedSerializer(EmptySerializer): - host_id = PrimaryKeyRelatedField(queryset=Host.objects.all()) +class HostAddSerializer(EmptySerializer): + host_id = IntegerField() class HostMappingSerializer(ModelSerializer): diff --git a/python/api_v2/host/views.py b/python/api_v2/host/views.py index ccb7cc9c7a..2819b30ace 100644 --- a/python/api_v2/host/views.py +++ b/python/api_v2/host/views.py @@ -9,6 +9,9 @@ # 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. + +from typing import Collection + from api_v2.config.utils import ConfigSchemaMixin from api_v2.host.filters import HostClusterFilter, HostFilter from api_v2.host.permissions import ( @@ -18,8 +21,8 @@ ) from api_v2.host.serializers import ( ClusterHostStatusSerializer, + HostAddSerializer, HostChangeMaintenanceModeSerializer, - HostCreateRelatedSerializer, HostCreateSerializer, HostGroupConfigSerializer, HostSerializer, @@ -28,9 +31,15 @@ from api_v2.host.utils import add_new_host_and_map_it, maintenance_mode from api_v2.views import CamelCaseModelViewSet, CamelCaseReadOnlyModelViewSet from audit.utils import audit -from cm.api import add_host_to_cluster, delete_host, remove_host_from_cluster +from cm.api import delete_host, remove_host_from_cluster from cm.errors import AdcmEx from cm.models import Cluster, GroupConfig, Host, HostProvider +from cm.services.cluster import perform_host_to_cluster_map +from core.cluster import ( + HostAlreadyBoundError, + HostBelongsToAnotherClusterError, + HostDoesNotExistError, +) from django_filters.rest_framework.backends import DjangoFilterBackend from guardian.mixins import PermissionListMixin from rest_framework.decorators import action @@ -145,8 +154,9 @@ class HostClusterViewSet(PermissionListMixin, CamelCaseReadOnlyModelViewSet): # def get_serializer_class(self): if self.action == "maintenance_mode": return HostChangeMaintenanceModeSerializer - elif self.action == "create": - return HostCreateRelatedSerializer + + if self.action == "create": + return HostAddSerializer return HostSerializer @@ -158,21 +168,40 @@ def get_queryset(self, *args, **kwargs): return Host.objects.filter(cluster=cluster).select_related("cluster").prefetch_related("hostcomponent_set") @audit - def create(self, request, *args, **kwargs): # pylint:disable=unused-argument + def create(self, request, *_, **kwargs): cluster = get_object_for_user( user=request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=kwargs["cluster_pk"] ) - if not cluster: return Response(data=f'Cluster with pk "{kwargs["cluster_pk"]}" not found', status=HTTP_404_NOT_FOUND) check_custom_perm(request.user, "map_host_to", "cluster", cluster) - serializer = self.get_serializer(data=request.data) + multiple_hosts = isinstance(request.data, list) + + serializer = self.get_serializer(data=request.data, many=multiple_hosts) serializer.is_valid(raise_exception=True) - host = add_host_to_cluster(cluster=cluster, host=serializer.validated_data["host_id"]) - return Response(status=HTTP_201_CREATED, data=HostSerializer(instance=host).data) + try: + added_hosts: Collection[int] = perform_host_to_cluster_map( + cluster_id=cluster.pk, + hosts=[ + entry["host_id"] + for entry in (serializer.validated_data if multiple_hosts else [serializer.validated_data]) + ], + ) + except HostDoesNotExistError: + raise AdcmEx("BAD_REQUEST", "At least one host does not exist.") from None + except HostAlreadyBoundError: + raise AdcmEx("HOST_CONFLICT", "At least one host is already associated with this cluster.") from None + except HostBelongsToAnotherClusterError: + raise AdcmEx("FOREIGN_HOST", "At least one host is already linked to another cluster.") from None + + qs_for_added_hosts = self.get_queryset().filter(id__in=added_hosts) + if multiple_hosts: + return Response(status=HTTP_201_CREATED, data=HostSerializer(instance=qs_for_added_hosts, many=True).data) + + return Response(status=HTTP_201_CREATED, data=HostSerializer(instance=qs_for_added_hosts.first()).data) @audit def destroy(self, request, *args, **kwargs): # pylint:disable=unused-argument @@ -210,9 +239,9 @@ class HostGroupConfigViewSet(PermissionListMixin, GetParentObjectMixin, CamelCas filter_backends = (DjangoFilterBackend,) pagination_class = None - def get_serializer_class(self) -> type[HostGroupConfigSerializer | HostCreateRelatedSerializer]: + def get_serializer_class(self) -> type[HostGroupConfigSerializer | HostAddSerializer]: if self.action == "create": - return HostCreateRelatedSerializer + return HostAddSerializer return HostGroupConfigSerializer @@ -246,8 +275,9 @@ def create(self, request, *_, **__): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) - host = serializer.validated_data["host_id"] - group_config.check_host_candidate(host_ids=[host.pk]) + host_id = serializer.validated_data["host_id"] + group_config.check_host_candidate(host_ids=[host_id]) + host = Host.objects.get(pk=host_id) group_config.hosts.add(host) return Response(status=HTTP_201_CREATED, data=HostGroupConfigSerializer(instance=host).data) diff --git a/python/api_v2/tests/test_host.py b/python/api_v2/tests/test_host.py index 33f3dbb54a..eb4d390960 100644 --- a/python/api_v2/tests/test_host.py +++ b/python/api_v2/tests/test_host.py @@ -216,6 +216,28 @@ def setUp(self) -> None: super().setUp() self.host = self.add_host(bundle=self.provider_bundle, provider=self.provider, fqdn="test_host") + self.host_2 = self.add_host(bundle=self.provider_bundle, provider=self.provider, fqdn="second-host") + self.control_free_host = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="not-bound-host" + ) + self.control_host_same_cluster = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="bound-to-same-host" + ) + self.add_host_to_cluster(cluster=self.cluster_1, host=self.control_host_same_cluster) + self.control_host_another_cluster = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="bound-to-another-host" + ) + self.add_host_to_cluster(cluster=self.cluster_2, host=self.control_host_another_cluster) + + def check_control_hosts(self) -> None: + self.control_free_host.refresh_from_db() + self.assertIsNone(self.control_free_host.cluster) + + self.control_host_same_cluster.refresh_from_db() + self.assertEqual(self.control_host_same_cluster.cluster, self.cluster_1) + + self.control_host_another_cluster.refresh_from_db() + self.assertEqual(self.control_host_another_cluster.cluster, self.cluster_2) def test_list_success(self): self.add_host_to_cluster(cluster=self.cluster_1, host=self.host) @@ -224,7 +246,7 @@ def test_list_success(self): ) self.assertEqual(response.status_code, HTTP_200_OK) - self.assertEqual(response.json()["count"], 1) + self.assertEqual(response.json()["count"], 2) def test_retrieve_success(self): self.add_host_to_cluster(cluster=self.cluster_1, host=self.host) @@ -247,6 +269,8 @@ def test_create_success(self): self.host.refresh_from_db() self.assertEqual(self.host.cluster, self.cluster_1) + self.check_control_hosts() + def test_create_belonging_to_another_cluster_fail(self): self.add_host_to_cluster(cluster=self.cluster_2, host=self.host) @@ -258,9 +282,15 @@ def test_create_belonging_to_another_cluster_fail(self): self.assertEqual(response.status_code, HTTP_409_CONFLICT) self.assertDictEqual( response.json(), - {"code": "FOREIGN_HOST", "desc": "Host already linked to another cluster.", "level": "error"}, + { + "code": "FOREIGN_HOST", + "desc": "At least one host is already linked to another cluster.", + "level": "error", + }, ) + self.check_control_hosts() + def test_create_already_added_fail(self) -> None: self.add_host_to_cluster(cluster=self.cluster_1, host=self.host) @@ -272,9 +302,15 @@ def test_create_already_added_fail(self) -> None: self.assertEqual(response.status_code, HTTP_409_CONFLICT) self.assertDictEqual( response.json(), - {"code": "HOST_CONFLICT", "desc": "The host is already associated with this cluster.", "level": "error"}, + { + "code": "HOST_CONFLICT", + "desc": "At least one host is already associated with this cluster.", + "level": "error", + }, ) + self.check_control_hosts() + def test_create_not_found_fail(self): response = self.client.post( path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), @@ -284,9 +320,106 @@ def test_create_not_found_fail(self): self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) self.assertDictEqual( response.json(), - {"code": "BAD_REQUEST", "desc": 'host_id - Invalid pk "2" - object does not exist.;', "level": "error"}, + {"code": "BAD_REQUEST", "desc": "At least one host does not exist.", "level": "error"}, ) + self.check_control_hosts() + + def test_add_many_success(self): + response = self.client.post( + path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data=[{"hostId": self.host.pk}, {"hostId": self.host_2.pk}], + ) + + self.assertEqual(response.status_code, HTTP_201_CREATED) + data = response.json() + + self.assertEqual(len(data), 2) + + self.host.refresh_from_db() + self.assertEqual(self.host.cluster, self.cluster_1) + + self.host_2.refresh_from_db() + self.assertEqual(self.host_2.cluster, self.cluster_1) + + self.check_control_hosts() + + def test_add_many_when_one_belongs_to_another_cluster_fail(self): + self.add_host_to_cluster(cluster=self.cluster_2, host=self.host) + + response = self.client.post( + path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data=[{"hostId": self.host_2.pk}, {"hostId": self.host.pk}], + ) + + self.assertEqual(response.status_code, HTTP_409_CONFLICT) + self.assertDictEqual( + response.json(), + { + "code": "FOREIGN_HOST", + "desc": "At least one host is already linked to another cluster.", + "level": "error", + }, + ) + + self.host.refresh_from_db() + self.assertEqual(self.host.cluster, self.cluster_2) + + self.host_2.refresh_from_db() + self.assertIsNone(self.host_2.cluster) + + self.check_control_hosts() + + def test_add_many_when_one_is_already_added_fail(self) -> None: + self.add_host_to_cluster(cluster=self.cluster_1, host=self.host) + + response = self.client.post( + path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data=[{"hostId": self.host_2.pk}, {"hostId": self.host.pk}], + ) + + self.assertEqual(response.status_code, HTTP_409_CONFLICT) + self.assertDictEqual( + response.json(), + { + "code": "HOST_CONFLICT", + "desc": "At least one host is already associated with this cluster.", + "level": "error", + }, + ) + + self.host.refresh_from_db() + self.assertEqual(self.host.cluster, self.cluster_1) + + self.host_2.refresh_from_db() + self.assertIsNone(self.host_2.cluster) + + self.check_control_hosts() + + def test_add_many_when_one_is_not_found_fail(self): + response = self.client.post( + path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data=[ + {"hostId": self.host_2.pk}, + {"hostId": self.host.pk}, + {"hostId": self.get_non_existent_pk(model=Host)}, + ], + ) + + self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) + self.assertDictEqual( + response.json(), + {"code": "BAD_REQUEST", "desc": "At least one host does not exist.", "level": "error"}, + ) + + self.host.refresh_from_db() + self.assertIsNone(self.host.cluster) + + self.host_2.refresh_from_db() + self.assertIsNone(self.host_2.cluster) + + self.check_control_hosts() + def test_maintenance_mode(self): self.add_host_to_cluster(cluster=self.cluster_1, host=self.host) response = self.client.post( diff --git a/python/audit/cases/cluster.py b/python/audit/cases/cluster.py index 0bdb03d5dd..75970cb4df 100644 --- a/python/audit/cases/cluster.py +++ b/python/audit/cases/cluster.py @@ -9,6 +9,8 @@ # 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. +from operator import itemgetter + from audit.cases.common import ( get_obj_name, get_or_create_audit_obj, @@ -113,6 +115,8 @@ def cluster_case( if response and response.data: if api_version == 1: host_fqdn = response.data["fqdn"] + elif isinstance(response.data, list): + host_fqdn = ", ".join(map(itemgetter("name"), response.data)) else: host_fqdn = response.data["name"] diff --git a/python/cm/services/__init__.py b/python/cm/services/__init__.py new file mode 100644 index 0000000000..b006242508 --- /dev/null +++ b/python/cm/services/__init__.py @@ -0,0 +1,13 @@ +# Licensed 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. + +from . import cluster # noqa diff --git a/python/cm/services/cluster.py b/python/cm/services/cluster.py new file mode 100644 index 0000000000..cb6a8c037d --- /dev/null +++ b/python/cm/services/cluster.py @@ -0,0 +1,53 @@ +# Licensed 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. + +from typing import Collection, Iterable + +from cm.api import load_service_map +from cm.api_context import CTX +from cm.issue import add_concern_to_object, update_hierarchy_issues +from cm.models import Cluster, Host +from core.cluster import HostClusterPair +from core.cluster.operations import add_hosts_to_cluster +from core.types import ClusterID, HostID +from django.db.transaction import atomic +from rbac.models import re_apply_object_policy + + +class HostClusterDB: + __slots__ = () + + @staticmethod + def get_host_cluster_pairs_for_hosts(hosts: Iterable[HostID]) -> Iterable[HostClusterPair]: + return ( + HostClusterPair(host_id=host, cluster_id=cluster_) + for host, cluster_ in Host.objects.filter(pk__in=hosts).values_list("id", "cluster_id").all() + ) + + @staticmethod + def set_cluster_id_for_hosts(cluster_id: ClusterID, hosts: Iterable[HostID]) -> None: + Host.objects.filter(pk__in=hosts).update(cluster_id=cluster_id) + + +def perform_host_to_cluster_map(cluster_id: int, hosts: Collection[int]) -> Collection[int]: + with atomic(): + add_hosts_to_cluster(cluster_id=cluster_id, hosts=hosts, db=HostClusterDB) + + for host in Host.objects.filter(id__in=hosts): + add_concern_to_object(object_=host, concern=CTX.lock) + update_hierarchy_issues(host) + + re_apply_object_policy(Cluster.objects.get(id=cluster_id)) + + load_service_map() + + return hosts diff --git a/python/core/__init__.py b/python/core/__init__.py new file mode 100644 index 0000000000..5c5e5f6fba --- /dev/null +++ b/python/core/__init__.py @@ -0,0 +1,14 @@ +# Licensed 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. + + +from . import cluster # isort: skip diff --git a/python/core/cluster/__init__.py b/python/core/cluster/__init__.py new file mode 100644 index 0000000000..cfee91894b --- /dev/null +++ b/python/core/cluster/__init__.py @@ -0,0 +1,17 @@ +# Licensed 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. + +# pylint: disable=cyclic-import + +from .errors import * # isort: skip +from .types import * # isort: skip +from . import operations, rules # isort: skip diff --git a/python/core/cluster/errors.py b/python/core/cluster/errors.py new file mode 100644 index 0000000000..ecd3ccb316 --- /dev/null +++ b/python/core/cluster/errors.py @@ -0,0 +1,25 @@ +# Licensed 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. + +from core.types import ADCMCoreError + + +class HostDoesNotExistError(ADCMCoreError): + ... + + +class HostAlreadyBoundError(ADCMCoreError): + ... + + +class HostBelongsToAnotherClusterError(ADCMCoreError): + ... diff --git a/python/core/cluster/operations.py b/python/core/cluster/operations.py new file mode 100644 index 0000000000..d715aecb27 --- /dev/null +++ b/python/core/cluster/operations.py @@ -0,0 +1,39 @@ +# Licensed 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. + +from typing import Any, Collection, Iterable, Protocol + +from core.cluster import HostClusterPair +from core.cluster.rules import ( + check_all_hosts_exist, + check_hosts_can_be_added_to_cluster, +) +from core.types import ClusterID, HostID + + +class HostClusterDBProtocol(Protocol): + def get_host_cluster_pairs_for_hosts(self, hosts: Iterable[HostID]) -> Iterable[HostClusterPair]: + """Extract pairs of ids host-component for given hosts""" + + def set_cluster_id_for_hosts(self, cluster_id: ClusterID, hosts: Iterable[HostID]) -> Any: + """Set `cluster_id` to all given hosts""" + + +def add_hosts_to_cluster(cluster_id: int, hosts: Collection[int], db: HostClusterDBProtocol) -> Collection[int]: + existing_hosts: tuple[HostClusterPair, ...] = tuple(db.get_host_cluster_pairs_for_hosts(hosts)) + + check_all_hosts_exist(host_candidates=hosts, existing_hosts=existing_hosts) + check_hosts_can_be_added_to_cluster(cluster_id=cluster_id, hosts=existing_hosts) + + db.set_cluster_id_for_hosts(cluster_id, hosts) + + return hosts diff --git a/python/core/cluster/rules.py b/python/core/cluster/rules.py new file mode 100644 index 0000000000..f4cbf4adfb --- /dev/null +++ b/python/core/cluster/rules.py @@ -0,0 +1,37 @@ +# Licensed 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. + +from operator import attrgetter +from typing import Collection + +from core.cluster import ( + HostAlreadyBoundError, + HostBelongsToAnotherClusterError, + HostClusterPair, + HostDoesNotExistError, +) + + +def check_all_hosts_exist(host_candidates: Collection[int], existing_hosts: Collection[HostClusterPair]) -> None: + if not set(host_candidates).issubset(map(attrgetter("host_id"), existing_hosts)): + raise HostDoesNotExistError() + + +def check_hosts_can_be_added_to_cluster(cluster_id: int, hosts: Collection[HostClusterPair]) -> None: + bound_hosts = set(entry for entry in hosts if entry.cluster_id) + if not bound_hosts: + return + + if any(entry.cluster_id == cluster_id for entry in bound_hosts): + raise HostAlreadyBoundError() + + raise HostBelongsToAnotherClusterError() diff --git a/python/core/cluster/types.py b/python/core/cluster/types.py new file mode 100644 index 0000000000..e8cf60d552 --- /dev/null +++ b/python/core/cluster/types.py @@ -0,0 +1,18 @@ +# Licensed 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. + +from typing import NamedTuple + + +class HostClusterPair(NamedTuple): + host_id: int + cluster_id: int | None diff --git a/python/core/types.py b/python/core/types.py new file mode 100644 index 0000000000..e69f958fa1 --- /dev/null +++ b/python/core/types.py @@ -0,0 +1,25 @@ +# Licensed 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. + +from typing import TypeAlias + +# pylint: disable=invalid-name + +ObjectID: TypeAlias = int +ClusterID: TypeAlias = ObjectID +HostID: TypeAlias = ObjectID + +# pylint: enable=invalid-name + + +class ADCMCoreError(Exception): + ... From 581f7bcae5921729141bcafa2f48046b4cfafe40 Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Tue, 16 Jan 2024 07:29:51 +0000 Subject: [PATCH 030/151] ADCM-5179 Added tests on audit cases Changed: 1. Message for audit record for mapping hosts to cluster Added: 1. Audit tests on mapping multiple hosts to cluster 1. Audit tests on mapping single service to cluster --- .../api_v2/tests/test_audit/test_cluster.py | 148 +++++++++++++++++- python/audit/cases/cluster.py | 25 ++- python/audit/tests/test_cluster.py | 6 +- 3 files changed, 161 insertions(+), 18 deletions(-) diff --git a/python/api_v2/tests/test_audit/test_cluster.py b/python/api_v2/tests/test_audit/test_cluster.py index 2215d7a98c..56d3d85852 100644 --- a/python/api_v2/tests/test_audit/test_cluster.py +++ b/python/api_v2/tests/test_audit/test_cluster.py @@ -534,6 +534,8 @@ def test_delete_host_fail(self): user__username="admin", ) + # add single host + def test_add_host_success(self): response = self.client.post( path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), @@ -542,7 +544,7 @@ def test_add_host_success(self): self.assertEqual(response.status_code, HTTP_201_CREATED) self.check_last_audit_record( - operation_name=f"{self.host_2.name} host added", + operation_name=f"[{self.host_2.name}] host(s) added", operation_type="update", operation_result="success", **self.prepare_audit_object_arguments(expected_object=self.cluster_1), @@ -559,7 +561,7 @@ def test_add_host_no_perms_denied(self): self.assertEqual(response.status_code, HTTP_404_NOT_FOUND) self.check_last_audit_record( - operation_name=f"{self.host_2.name} host added", + operation_name=f"[{self.host_2.name}] host(s) added", operation_type="update", operation_result="denied", **self.prepare_audit_object_arguments(expected_object=self.cluster_1), @@ -574,7 +576,7 @@ def test_add_host_incorrect_body_fail(self): self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) self.check_last_audit_record( - operation_name="host added", + operation_name="[] host(s) added", operation_type="update", operation_result="fail", **self.prepare_audit_object_arguments(expected_object=self.cluster_1), @@ -589,7 +591,7 @@ def test_add_non_existing_host_fail(self): self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) self.check_last_audit_record( - operation_name="host added", + operation_name="[] host(s) added", operation_type="update", operation_result="fail", **self.prepare_audit_object_arguments(expected_object=self.cluster_1), @@ -606,7 +608,7 @@ def test_add_host_fail(self): self.assertEqual(response.status_code, HTTP_404_NOT_FOUND) self.check_last_audit_record( - operation_name=f"{self.host_2.name} host added", + operation_name=f"[{self.host_2.name}] host(s) added", operation_type="update", operation_result="fail", **self.prepare_audit_object_arguments(expected_object=None), @@ -621,7 +623,71 @@ def test_add_host_wrong_data_fail(self): self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) self.check_last_audit_record( - operation_name="host added", + operation_name="[] host(s) added", + operation_type="update", + operation_result="fail", + **self.prepare_audit_object_arguments(expected_object=self.cluster_1), + user__username="admin", + ) + + # add multiple hosts + + def test_add_many_hosts_success(self): + response = self.client.post( + path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data=[{"hostId": self.host_2.pk}, {"hostId": self.host_3.pk}], + ) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + self.check_last_audit_record( + operation_name=f"[{self.host_2.name}, {self.host_3.name}] host(s) added", + operation_type="update", + operation_result="success", + **self.prepare_audit_object_arguments(expected_object=self.cluster_1), + user__username="admin", + ) + + def test_add_many_hosts_no_perms_denied(self): + self.client.login(**self.test_user_credentials) + + response = self.client.post( + path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data=[{"hostId": self.host_2.pk}, {"hostId": self.host_3.pk}], + ) + self.assertEqual(response.status_code, HTTP_404_NOT_FOUND) + + self.check_last_audit_record( + operation_name=f"[{self.host_2.name}, {self.host_3.name}] host(s) added", + operation_type="update", + operation_result="denied", + **self.prepare_audit_object_arguments(expected_object=self.cluster_1), + user__username=self.test_user.username, + ) + + def test_add_many_hosts_incorrect_body_fail(self): + response = self.client.post( + path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data=[{"hey": "you"}, {"hostId": self.host_2.pk}], + ) + self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) + + self.check_last_audit_record( + operation_name=f"[{self.host_2.name}] host(s) added", + operation_type="update", + operation_result="fail", + **self.prepare_audit_object_arguments(expected_object=self.cluster_1), + user__username="admin", + ) + + def test_add_many_non_existing_host_fail(self): + response = self.client.post( + path=reverse(viewname="v2:host-cluster-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data=[{"hostId": self.get_non_existent_pk(Host)}], + ) + self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) + + self.check_last_audit_record( + operation_name="[] host(s) added", operation_type="update", operation_result="fail", **self.prepare_audit_object_arguments(expected_object=self.cluster_1), @@ -689,6 +755,8 @@ def test_change_host_mm_fail(self): user__username="admin", ) + # add multiple services + def test_add_service_success(self): response = self.client.post( path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), @@ -714,13 +782,13 @@ def test_add_service_wrong_data_fail(self): path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), data=[ {"id_of_prototype": self.service_add_prototypes[0].pk}, - {"id_of_prototype": self.service_add_prototypes[1].pk}, + {"prototypeId": self.service_add_prototypes[1].pk}, ], ) self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) self.check_last_audit_record( - operation_name="[] service(s) added", + operation_name=f"[{self.service_add_prototypes[1].display_name}] service(s) added", operation_type="update", operation_result="fail", **self.prepare_audit_object_arguments(expected_object=self.cluster_1), @@ -769,6 +837,70 @@ def test_add_service_fail(self): user__username="admin", ) + # add single service + + def test_add_one_service_success(self): + response = self.client.post( + path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data={"prototypeId": self.service_add_prototypes[0].pk}, + ) + self.assertEqual(response.status_code, HTTP_201_CREATED) + + self.check_last_audit_record( + operation_name=(f"[{self.service_add_prototypes[0].display_name}] service(s) added"), + operation_type="update", + operation_result="success", + **self.prepare_audit_object_arguments(expected_object=self.cluster_1), + user__username="admin", + ) + + def test_add_one_service_wrong_data_fail(self): + response = self.client.post( + path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data={"id_of_prototype": self.service_add_prototypes[0].pk}, + ) + self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) + + self.check_last_audit_record( + operation_name="[] service(s) added", + operation_type="update", + operation_result="fail", + **self.prepare_audit_object_arguments(expected_object=self.cluster_1), + user__username="admin", + ) + + def test_add_one_service_denied(self): + self.client.login(**self.test_user_credentials) + + response = self.client.post( + path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), + data={"prototypeId": self.service_add_prototypes[1].pk}, + ) + self.assertEqual(response.status_code, HTTP_404_NOT_FOUND) + + self.check_last_audit_record( + operation_name=f"[{self.service_add_prototypes[1].display_name}] service(s) added", + operation_type="update", + operation_result="denied", + **self.prepare_audit_object_arguments(expected_object=self.cluster_1), + user__username=self.test_user.username, + ) + + def test_add_one_service_fail(self): + response = self.client.post( + path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.get_non_existent_pk(model=Cluster)}), + data={"prototypeId": self.service_add_prototypes[0].pk}, + ) + self.assertEqual(response.status_code, HTTP_404_NOT_FOUND) + + self.check_last_audit_record( + operation_name=f"[{self.service_add_prototypes[0].display_name}] service(s) added", + operation_type="update", + operation_result="fail", + **self.prepare_audit_object_arguments(expected_object=None), + user__username="admin", + ) + def test_delete_service_success(self): response = self.client.delete( path=reverse( diff --git a/python/audit/cases/cluster.py b/python/audit/cases/cluster.py index 75970cb4df..eef9d7a87a 100644 --- a/python/audit/cases/cluster.py +++ b/python/audit/cases/cluster.py @@ -120,12 +120,16 @@ def cluster_case( else: host_fqdn = response.data["name"] - if "host_id" in view.request.data: - host = Host.objects.filter(pk=view.request.data["host_id"]).first() - if host: - host_fqdn = host.fqdn + else: + if isinstance(view.request.data, list): + ids = (entry.get("host_id", None) for entry in view.request.data if isinstance(entry, dict)) + host_fqdn = ", ".join(sorted(Host.objects.filter(pk__in=ids).values_list("fqdn", flat=True))) + elif isinstance(view.request.data, dict) and "host_id" in view.request.data: + host = Host.objects.filter(pk=view.request.data["host_id"]).first() + if host: + host_fqdn = host.fqdn - operation_name = f"{host_fqdn} host added".strip() + operation_name = f"[{host_fqdn}] host(s) added".strip() audit_operation = AuditOperation( name=operation_name, @@ -223,12 +227,19 @@ def cluster_case( data["display_name"] for data in (response.data if isinstance(response.data, list) else [response.data]) ] - elif isinstance(view.request.data, list) and all("prototype_id" in data for data in view.request.data): + elif isinstance(view.request.data, list): service_display_name = ( - Prototype.objects.filter(pk__in=[data["prototype_id"] for data in view.request.data]) + Prototype.objects.filter(pk__in=(data.get("prototype_id", None) for data in view.request.data)) .order_by("pk") .values_list("display_name", flat=True) ) + elif isinstance(view.request.data, dict): + service_display_name = [ + Prototype.objects.filter(pk=view.request.data.get("prototype_id")) + .values_list("display_name", flat=True) + .first() + or "" + ] service_display_name = f"[{', '.join(service_display_name)}]" operation_name = f"{service_display_name} service(s) added" diff --git a/python/audit/tests/test_cluster.py b/python/audit/tests/test_cluster.py index 702c05be0b..08304ec189 100644 --- a/python/audit/tests/test_cluster.py +++ b/python/audit/tests/test_cluster.py @@ -691,7 +691,7 @@ def test_add_host_success_and_fail(self): obj=self.cluster, obj_name=self.cluster.name, obj_type=AuditObjectType.CLUSTER, - operation_name=f"{self.host.fqdn} host added", + operation_name=f"[{self.host.fqdn}] host(s) added", operation_type=AuditLogOperationType.UPDATE, ) @@ -708,7 +708,7 @@ def test_add_host_success_and_fail(self): obj=self.cluster, obj_name=self.cluster.name, obj_type=AuditObjectType.CLUSTER, - operation_name="host added", + operation_name="[] host(s) added", operation_type=AuditLogOperationType.UPDATE, operation_result=AuditLogOperationResult.FAIL, ) @@ -726,7 +726,7 @@ def test_add_host_denied(self): self.assertEqual(response.status_code, HTTP_404_NOT_FOUND) self.check_log_denied( log=log, - operation_name=f"{self.host.fqdn} host added", + operation_name=f"[{self.host.fqdn}] host(s) added", operation_type=AuditLogOperationType.UPDATE, ) From d05e67ed8a63cb73ca8dfaccde1e52dc6fe6121e Mon Sep 17 00:00:00 2001 From: Dmitriy Bardin Date: Tue, 16 Jan 2024 08:35:49 +0000 Subject: [PATCH 031/151] ADCM-5187 - [UI 2.0] No 'Import service' page reload on change from selected service to 'none' https://tracker.yandex.ru/ADCM-5187 --- .../ClusterImportServices/useClusterImportsService.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportServices/useClusterImportsService.ts b/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportServices/useClusterImportsService.ts index 15d0ab8a75..0b7b7f453c 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportServices/useClusterImportsService.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterImport/ClusterImportServices/useClusterImportsService.ts @@ -70,7 +70,11 @@ export const useClusterImportsService = () => { }, [clusterId, dispatch]); useEffect(() => { - if (serviceId) dispatch(getClusterServiceImports({ clusterId })); + if (serviceId) { + dispatch(getClusterServiceImports({ clusterId })); + } else { + dispatch(cleanupClusterServiceImports()); + } }, [serviceId, paginationParams, clusterId, dispatch]); useEffect(() => { From 40b8bf96eee917cd925c6f32ec40dfcf7a18cdaa Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Tue, 16 Jan 2024 09:56:53 +0000 Subject: [PATCH 032/151] ADCM-5179 Optimization of host to cluster mapping Changed: 1. `load_service_map` optimized to use less queries 2. `HostSerializer` in means of concerns retrieval 3. Querysets improved for a part of Host views to solve N+1 problem Removed: 1. Concerns re-evaluation on mapping host to cluster (seems redundant, because concerns aren't hazardous to cluster-host without HC-mapping) --- python/api_v2/host/views.py | 26 ++++++++--- python/cm/api.py | 60 +++++++++++-------------- python/cm/services/__init__.py | 2 - python/cm/services/cluster.py | 8 +--- python/cm/tests/test_issue.py | 74 ++++++++++++++++++++++++++++++- python/cm/tests/utils.py | 7 +-- python/core/__init__.py | 3 -- python/core/cluster/__init__.py | 6 --- python/core/cluster/operations.py | 2 +- python/core/cluster/rules.py | 4 +- 10 files changed, 126 insertions(+), 66 deletions(-) diff --git a/python/api_v2/host/views.py b/python/api_v2/host/views.py index 2819b30ace..8a30bd265a 100644 --- a/python/api_v2/host/views.py +++ b/python/api_v2/host/views.py @@ -35,7 +35,7 @@ from cm.errors import AdcmEx from cm.models import Cluster, GroupConfig, Host, HostProvider from cm.services.cluster import perform_host_to_cluster_map -from core.cluster import ( +from core.cluster.errors import ( HostAlreadyBoundError, HostBelongsToAnotherClusterError, HostDoesNotExistError, @@ -68,7 +68,7 @@ # pylint:disable-next=too-many-ancestors class HostViewSet(PermissionListMixin, ConfigSchemaMixin, CamelCaseModelViewSet): queryset = ( - Host.objects.select_related("provider", "cluster") + Host.objects.select_related("provider", "cluster", "cluster__prototype", "prototype") .prefetch_related("concerns", "hostcomponent_set") .order_by("fqdn") ) @@ -108,7 +108,10 @@ def create(self, request, *args, **kwargs): provider=request_hostprovider, fqdn=serializer.validated_data["fqdn"], cluster=request_cluster ) - return Response(data=HostSerializer(instance=host).data, status=HTTP_201_CREATED) + return Response( + data=HostSerializer(instance=host).data, + status=HTTP_201_CREATED, + ) @audit def destroy(self, request, *args, **kwargs): @@ -165,7 +168,11 @@ def get_queryset(self, *args, **kwargs): user=self.request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=self.kwargs["cluster_pk"] ) - return Host.objects.filter(cluster=cluster).select_related("cluster").prefetch_related("hostcomponent_set") + return ( + Host.objects.filter(cluster=cluster) + .select_related("cluster", "cluster__prototype", "provider", "prototype") + .prefetch_related("hostcomponent_set", "concerns") + ) @audit def create(self, request, *_, **kwargs): @@ -198,10 +205,17 @@ def create(self, request, *_, **kwargs): raise AdcmEx("FOREIGN_HOST", "At least one host is already linked to another cluster.") from None qs_for_added_hosts = self.get_queryset().filter(id__in=added_hosts) + if multiple_hosts: - return Response(status=HTTP_201_CREATED, data=HostSerializer(instance=qs_for_added_hosts, many=True).data) + return Response( + status=HTTP_201_CREATED, + data=HostSerializer(instance=qs_for_added_hosts, many=True).data, + ) - return Response(status=HTTP_201_CREATED, data=HostSerializer(instance=qs_for_added_hosts.first()).data) + return Response( + status=HTTP_201_CREATED, + data=HostSerializer(instance=qs_for_added_hosts.first()).data, + ) @audit def destroy(self, request, *args, **kwargs): # pylint:disable=unused-argument diff --git a/python/cm/api.py b/python/cm/api.py index 2b9f43a1df..f3adfabcb1 100644 --- a/python/cm/api.py +++ b/python/cm/api.py @@ -12,6 +12,7 @@ # pylint: disable=too-many-lines import json +from collections import defaultdict from functools import partial, wraps from typing import Literal @@ -98,45 +99,35 @@ def is_version_suitable(version: str, prototype_import: PrototypeImport) -> bool return True -def load_service_map(): - comps = {} - hosts = {} +def load_service_map() -> None: + comps = defaultdict(lambda: defaultdict(list)) + hosts = defaultdict(list) hc_map = {} - services = {} - passive = {} - for service_component in ServiceComponent.objects.filter(prototype__monitoring="passive"): - passive[service_component.pk] = True + services = defaultdict(list) - for hostcomponent in HostComponent.objects.order_by("id"): - if hostcomponent.component.pk in passive: - continue - - key = f"{hostcomponent.host.pk}.{hostcomponent.component.pk}" - hc_map[key] = {"cluster": hostcomponent.cluster.pk, "service": hostcomponent.service.pk} - if str(hostcomponent.cluster.pk) not in comps: - comps[str(hostcomponent.cluster.pk)] = {} - - if str(hostcomponent.service.pk) not in comps[str(hostcomponent.cluster.pk)]: - comps[str(hostcomponent.cluster.pk)][str(hostcomponent.service.pk)] = [] - - comps[str(hostcomponent.cluster.pk)][str(hostcomponent.service.pk)].append(key) - - for host in Host.objects.filter(prototype__monitoring="active"): - if host.cluster: - cluster_pk = host.cluster.pk - else: - cluster_pk = 0 - - if cluster_pk not in hosts: - hosts[cluster_pk] = [] + passive = { + component_id: True + for component_id in ServiceComponent.objects.values_list("id", flat=True).filter( + prototype__monitoring="passive" + ) + } - hosts[cluster_pk].append(host.pk) + for cluster_id, service_id, component_id, host_id in ( + HostComponent.objects.values_list("cluster_id", "service_id", "component_id", "host_id") + .exclude(component_id__in=passive.keys()) + .order_by("id") + ): + key = f"{host_id}.{component_id}" + hc_map[key] = {"cluster": cluster_id, "service": service_id} + comps[str(cluster_id)][str(service_id)].append(key) - for service in ClusterObject.objects.filter(prototype__monitoring="active"): - if service.cluster.pk not in services: - services[service.cluster.pk] = [] + for host_id, cluster_id in Host.objects.values_list("id", "cluster_id").filter(prototype__monitoring="active"): + hosts[cluster_id or 0].append(host_id) - services[service.cluster.pk].append(service.pk) + for service_id, cluster_id in ClusterObject.objects.values_list("id", "cluster_id").filter( + prototype__monitoring="active" + ): + services[cluster_id].append(service_id) data = { "hostservice": hc_map, @@ -145,6 +136,7 @@ def load_service_map(): "host": hosts, } api_request(method="post", url="servicemap/", data=data) + load_mm_objects() diff --git a/python/cm/services/__init__.py b/python/cm/services/__init__.py index b006242508..824dd6c8fe 100644 --- a/python/cm/services/__init__.py +++ b/python/cm/services/__init__.py @@ -9,5 +9,3 @@ # 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. - -from . import cluster # noqa diff --git a/python/cm/services/cluster.py b/python/cm/services/cluster.py index cb6a8c037d..fb02b2203d 100644 --- a/python/cm/services/cluster.py +++ b/python/cm/services/cluster.py @@ -13,11 +13,9 @@ from typing import Collection, Iterable from cm.api import load_service_map -from cm.api_context import CTX -from cm.issue import add_concern_to_object, update_hierarchy_issues from cm.models import Cluster, Host -from core.cluster import HostClusterPair from core.cluster.operations import add_hosts_to_cluster +from core.cluster.types import HostClusterPair from core.types import ClusterID, HostID from django.db.transaction import atomic from rbac.models import re_apply_object_policy @@ -42,10 +40,6 @@ def perform_host_to_cluster_map(cluster_id: int, hosts: Collection[int]) -> Coll with atomic(): add_hosts_to_cluster(cluster_id=cluster_id, hosts=hosts, db=HostClusterDB) - for host in Host.objects.filter(id__in=hosts): - add_concern_to_object(object_=host, concern=CTX.lock) - update_hierarchy_issues(host) - re_apply_object_policy(Cluster.objects.get(id=cluster_id)) load_service_map() diff --git a/python/cm/tests/test_issue.py b/python/cm/tests/test_issue.py index 4334e30c0a..0c2ebfde1b 100644 --- a/python/cm/tests/test_issue.py +++ b/python/cm/tests/test_issue.py @@ -9,19 +9,31 @@ # 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. - +from operator import attrgetter +from typing import Iterable from unittest.mock import patch from cm.api import add_cluster, add_service_to_cluster from cm.hierarchy import Tree from cm.issue import ( + add_concern_to_object, create_issue, do_check_import, recheck_issues, remove_issue, update_hierarchy_issues, ) -from cm.models import Bundle, ClusterBind, ConcernCause, Prototype, PrototypeImport +from cm.models import ( + ADCMEntity, + Bundle, + ClusterBind, + ConcernCause, + ConcernItem, + ConcernType, + Prototype, + PrototypeImport, +) +from cm.services.cluster import perform_host_to_cluster_map from cm.tests.utils import gen_service, generate_hierarchy from adcm.tests.base import BaseTestCase @@ -297,3 +309,61 @@ def test_issue_service_imported(self): issue = service.get_own_issue(ConcernCause.IMPORT) self.assertIsNone(issue) + + +class TestConcernsRedistribution(BaseTestCase): + MOCK_ISSUE_CHECK_MAP_ALL_FALSE = { + ConcernCause.CONFIG: lambda x: False, + ConcernCause.IMPORT: lambda x: False, + ConcernCause.SERVICE: lambda x: False, + ConcernCause.HOSTCOMPONENT: lambda x: False, + ConcernCause.REQUIREMENT: lambda x: False, + } + + def setUp(self) -> None: + super().setUp() + + self.hierarchy = generate_hierarchy(bind_to_cluster=False) + self.cluster = self.hierarchy["cluster"] + self.service = self.hierarchy["service"] + self.component = self.hierarchy["component"] + self.hostprovider = self.hierarchy["provider"] + self.host = self.hierarchy["host"] + + for object_ in self.hierarchy.values(): + create_issue(object_, ConcernCause.CONFIG) + tree = Tree(object_) + self.add_lock( + owner=object_, affected_objects=map(attrgetter("value"), tree.get_all_affected(node=tree.built_from)) + ) + + def add_lock(self, owner: ADCMEntity, affected_objects: Iterable[ADCMEntity]): + """Check out lock_affected_objects""" + lock = ConcernItem.objects.create( + type=ConcernType.LOCK.value, + name=None, + reason=f"Lock from {owner.__class__.__name__} {owner.id}", + blocking=True, + owner=owner, + cause=ConcernCause.JOB.value, + ) + for obj in affected_objects: + add_concern_to_object(object_=obj, concern=lock) + + def test_map_host_to_cluster(self) -> None: + concerns_before = self.host.concerns.all() + self.assertEqual(len(concerns_before), 4) + self.assertEqual( + set(map(attrgetter("owner_type"), concerns_before)), + {self.hostprovider.content_type, self.host.content_type}, + ) + + with patch("cm.issue._issue_check_map", self.MOCK_ISSUE_CHECK_MAP_ALL_FALSE): + perform_host_to_cluster_map(self.cluster.id, [self.host.id]) + + self.host.refresh_from_db() + concerns_after = self.host.concerns.all() + self.assertEqual(len(concerns_after), 4) + self.assertEqual( + set(map(attrgetter("owner_type"), concerns_after)), {self.hostprovider.content_type, self.host.content_type} + ) diff --git a/python/cm/tests/utils.py b/python/cm/tests/utils.py index b36b567383..c962e74cca 100644 --- a/python/cm/tests/utils.py +++ b/python/cm/tests/utils.py @@ -206,7 +206,7 @@ def gen_job_log(task: TaskLog) -> JobLog: ) -def generate_hierarchy(): +def generate_hierarchy(bind_to_cluster: bool = True): """ Generates hierarchy: cluster - service - component - host - provider @@ -240,11 +240,12 @@ def generate_hierarchy(): provider.save() host_pt = gen_prototype(provider_bundle, "host") - host = gen_host(provider, cluster, prototype=host_pt) + host = gen_host(provider, cluster if bind_to_cluster else None, prototype=host_pt) host.config = gen_config() host.save() - gen_host_component(component, host) + if bind_to_cluster: + gen_host_component(component, host) return { "cluster": cluster, diff --git a/python/core/__init__.py b/python/core/__init__.py index 5c5e5f6fba..824dd6c8fe 100644 --- a/python/core/__init__.py +++ b/python/core/__init__.py @@ -9,6 +9,3 @@ # 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. - - -from . import cluster # isort: skip diff --git a/python/core/cluster/__init__.py b/python/core/cluster/__init__.py index cfee91894b..824dd6c8fe 100644 --- a/python/core/cluster/__init__.py +++ b/python/core/cluster/__init__.py @@ -9,9 +9,3 @@ # 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. - -# pylint: disable=cyclic-import - -from .errors import * # isort: skip -from .types import * # isort: skip -from . import operations, rules # isort: skip diff --git a/python/core/cluster/operations.py b/python/core/cluster/operations.py index d715aecb27..d2dbbe6635 100644 --- a/python/core/cluster/operations.py +++ b/python/core/cluster/operations.py @@ -12,11 +12,11 @@ from typing import Any, Collection, Iterable, Protocol -from core.cluster import HostClusterPair from core.cluster.rules import ( check_all_hosts_exist, check_hosts_can_be_added_to_cluster, ) +from core.cluster.types import HostClusterPair from core.types import ClusterID, HostID diff --git a/python/core/cluster/rules.py b/python/core/cluster/rules.py index f4cbf4adfb..4dbc6e1ddf 100644 --- a/python/core/cluster/rules.py +++ b/python/core/cluster/rules.py @@ -13,12 +13,12 @@ from operator import attrgetter from typing import Collection -from core.cluster import ( +from core.cluster.errors import ( HostAlreadyBoundError, HostBelongsToAnotherClusterError, - HostClusterPair, HostDoesNotExistError, ) +from core.cluster.types import HostClusterPair def check_all_hosts_exist(host_candidates: Collection[int], existing_hosts: Collection[HostClusterPair]) -> None: From 621fe2d5d95610e2c7e65d54e680d40757eadec5 Mon Sep 17 00:00:00 2001 From: Igor Kuzmin Date: Tue, 16 Jan 2024 10:55:25 +0000 Subject: [PATCH 033/151] bugfix/ADCM-5164 add own mappings state to clusterDynamicActionsSlice Task: https://tracker.yandex.ru/ADCM-5164 --- .../DynamicActionHostMapping.tsx | 50 +++++++------ .../ComponentContainer/ComponentContainer.tsx | 6 +- .../ComponentsMapping/ComponentsMapping.tsx | 39 +++++++--- .../HostsMapping/HostsMapping.tsx | 11 ++- .../ClusterMapping/useClusterMapping.ts | 53 ++++++-------- .../clusters/clustersDynamicActionsSlice.ts | 71 +++++++++++++++++-- 6 files changed, 160 insertions(+), 70 deletions(-) diff --git a/adcm-web/app/src/components/common/DynamicActionDialog/DynamicActionHostMapping/DynamicActionHostMapping.tsx b/adcm-web/app/src/components/common/DynamicActionDialog/DynamicActionHostMapping/DynamicActionHostMapping.tsx index a9da50a02d..627f8b5296 100644 --- a/adcm-web/app/src/components/common/DynamicActionDialog/DynamicActionHostMapping/DynamicActionHostMapping.tsx +++ b/adcm-web/app/src/components/common/DynamicActionDialog/DynamicActionHostMapping/DynamicActionHostMapping.tsx @@ -1,13 +1,14 @@ -import React, { useEffect } from 'react'; -import { useDispatch } from '@hooks'; +import React, { useCallback, useEffect } from 'react'; +import { useDispatch, useStore } from '@hooks'; import { Button, ButtonGroup, SearchInput, SpinnerPanel, ToolbarPanel } from '@uikit'; import { DynamicActionCommonOptions } from '@commonComponents/DynamicActionDialog/DynamicAction.types'; import s from '@commonComponents/DynamicActionDialog/DynamicActionDialog.module.scss'; import { useClusterMapping } from '@pages/cluster/ClusterMapping/useClusterMapping'; import ComponentContainer from '@pages/cluster/ClusterMapping/ComponentsMapping/ComponentContainer/ComponentContainer'; -import { AdcmMappingComponent, AdcmMappingComponentService } from '@models/adcm'; -import { getMappings, cleanupMappings } from '@store/adcm/cluster/mapping/mappingSlice'; +import { AdcmMapping, AdcmMappingComponent, AdcmMappingComponentService } from '@models/adcm'; +import { getMappings, setLocalMapping, revertChanges } from '@store/adcm/clusters/clustersDynamicActionsSlice'; import { Link } from 'react-router-dom'; +import { LoadState } from '@models/loadState'; interface DynamicActionHostMappingProps extends DynamicActionCommonOptions { submitLabel?: string; @@ -27,26 +28,30 @@ const DynamicActionHostMapping: React.FC = ({ if (!Number.isNaN(clusterId)) { dispatch(getMappings({ clusterId })); } - - return () => { - dispatch(cleanupMappings()); - }; }, [clusterId, dispatch]); + const { + dialog: { hosts, components, localMapping, loadState }, + } = useStore(({ adcm }) => adcm.clustersDynamicActions); + + const notAddedServicesDictionary = useStore(({ adcm }) => adcm.clusterMapping.relatedData.notAddedServicesDictionary); + + const handleSetMapping = useCallback( + (newMapping: AdcmMapping[]) => { + dispatch(setLocalMapping(newMapping)); + }, + [dispatch], + ); + const { hostComponentMapping, - hosts, servicesMapping, servicesMappingFilter, handleServicesMappingFilterChange, mappingValidation, - hasSaveError, - handleMapHostsToComponent, + handleMap, handleUnmap, - handleRevert, - isLoading, - isLoaded, - } = useClusterMapping(); + } = useClusterMapping(localMapping, hosts, components, notAddedServicesDictionary, true, handleSetMapping); const isServicesMappingEmpty = servicesMapping.length === 0; @@ -64,28 +69,32 @@ const DynamicActionHostMapping: React.FC = ({ handleServicesMappingFilterChange({ hostName: event.target.value }); }; + const handleRevertMappingChanges = () => { + dispatch(revertChanges()); + }; + return (
- - {isLoading && } + {loadState === LoadState.Loading && } - {isLoaded && ( + {loadState === LoadState.Loaded && (
{isServicesMappingEmpty && (
@@ -106,8 +115,9 @@ const DynamicActionHostMapping: React.FC = ({ componentMapping={componentMapping} filter={servicesMappingFilter} allHosts={hosts} + notAddedServicesDictionary={notAddedServicesDictionary} componentMappingValidation={mappingValidation.byComponents[componentMapping.component.id]} - onMap={handleMapHostsToComponent} + onMap={handleMap} onUnmap={handleUnmap} allowActions={allowActions} denyAddHostReason="Add host do not allow in config of action" diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentContainer/ComponentContainer.tsx b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentContainer/ComponentContainer.tsx index 9e98c2c9e0..5d64fd99e8 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentContainer/ComponentContainer.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentContainer/ComponentContainer.tsx @@ -9,12 +9,13 @@ import { AdcmHostShortView, AdcmMaintenanceMode, AdcmMappingComponent, + AdcmServicePrototype, } from '@models/adcm'; import { ComponentMapping, ComponentMappingValidation, ServiceMappingFilter } from '../../ClusterMapping.types'; import { getConstraintsLimit, isComponentDependOnNotAddedServices } from '../../ClusterMapping.utils'; import s from './ComponentContainer.module.scss'; import cn from 'classnames'; -import { useDispatch, useStore } from '@hooks'; +import { useDispatch } from '@hooks'; import { openRequiredServicesDialog } from '@store/adcm/cluster/mapping/mappingSlice'; export interface ComponentContainerProps { @@ -22,6 +23,7 @@ export interface ComponentContainerProps { componentMappingValidation: ComponentMappingValidation; filter: ServiceMappingFilter; allHosts: AdcmHostShortView[]; + notAddedServicesDictionary: Record; onMap: (hosts: AdcmHostShortView[], component: AdcmMappingComponent) => void; onUnmap: (hostId: number, componentId: number) => void; allowActions?: AdcmHostComponentMapRuleAction[]; @@ -36,6 +38,7 @@ const ComponentContainer = ({ componentMappingValidation, filter, allHosts, + notAddedServicesDictionary, onUnmap, onMap, denyAddHostReason = , @@ -43,7 +46,6 @@ const ComponentContainer = ({ allowActions = defaultAllowActions, }: ComponentContainerProps) => { const dispatch = useDispatch(); - const notAddedServicesDictionary = useStore(({ adcm }) => adcm.clusterMapping.relatedData.notAddedServicesDictionary); const [isSelectOpen, setIsSelectOpen] = useState(false); const addIconRef = useRef(null); const { component, hosts } = componentMapping; diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.tsx b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.tsx index e839d67d12..77f78191b4 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo } from 'react'; import { AnchorBar, AnchorBarItem, AnchorList, Button, MarkerIcon, SearchInput, Switch, Text } from '@uikit'; import { useClusterMapping } from '../useClusterMapping'; import ComponentContainer from './ComponentContainer/ComponentContainer'; @@ -6,11 +6,11 @@ import ClusterMappingToolbar from '../ClusterMappingToolbar/ClusterMappingToolba import s from './ComponentsMapping.module.scss'; import cn from 'classnames'; import { Link, useParams } from 'react-router-dom'; -import { saveMapping } from '@store/adcm/cluster/mapping/mappingSlice'; +import { setLocalMapping, saveMapping, revertChanges } from '@store/adcm/cluster/mapping/mappingSlice'; import { useDispatch, useStore } from '@hooks'; import { setBreadcrumbs } from '@store/adcm/breadcrumbs/breadcrumbsSlice'; import RequiredServicesDialog from '@pages/cluster/ClusterMapping/ComponentsMapping/RequiredServicesDialog/RequiredServicesDialog'; -import { AdcmEntitySystemState, AdcmMaintenanceMode } from '@models/adcm'; +import { AdcmEntitySystemState, AdcmMaintenanceMode, AdcmMapping } from '@models/adcm'; const buildServiceAnchorId = (id: number) => `anchor_${id}`; @@ -21,6 +21,7 @@ const ComponentsMapping = () => { const clusterId = Number(clusterIdFromUrl); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); + useEffect(() => { if (cluster) { dispatch( @@ -34,19 +35,32 @@ const ComponentsMapping = () => { } }, [cluster, dispatch]); + const handleSetMapping = useCallback( + (newMapping: AdcmMapping[]) => { + dispatch(setLocalMapping(newMapping)); + }, + [dispatch], + ); + const { - hostComponentMapping, hosts, + components, + localMapping, + isLoaded, + hasSaveError, + state: mappingState, + } = useStore(({ adcm }) => adcm.clusterMapping); + const notAddedServicesDictionary = useStore(({ adcm }) => adcm.clusterMapping.relatedData.notAddedServicesDictionary); + + const { + hostComponentMapping, servicesMapping, servicesMappingFilter, handleServicesMappingFilterChange, - mappingState, mappingValidation, - hasSaveError, - handleMapHostsToComponent, + handleMap, handleUnmap, - handleRevert, - } = useClusterMapping(); + } = useClusterMapping(localMapping, hosts, components, notAddedServicesDictionary, isLoaded, handleSetMapping); const anchorItems: AnchorBarItem[] = useMemo( () => @@ -69,6 +83,10 @@ const ComponentsMapping = () => { dispatch(saveMapping({ clusterId, mapping: hostComponentMapping })); }; + const handleRevert = () => { + dispatch(revertChanges()); + }; + const isButtonsDisabledByState = mappingState === 'saving' || mappingState === 'no-changes'; return ( @@ -126,7 +144,8 @@ const ComponentsMapping = () => { componentMappingValidation={mappingValidation.byComponents[componentMapping.component.id]} filter={servicesMappingFilter} allHosts={hosts} - onMap={handleMapHostsToComponent} + notAddedServicesDictionary={notAddedServicesDictionary} + onMap={handleMap} onUnmap={handleUnmap} allowActions={isEditableComponent ? undefined : []} /> diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.tsx b/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.tsx index 5a7bb41274..5403d21c6c 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.tsx @@ -10,7 +10,16 @@ import { setBreadcrumbs } from '@store/adcm/breadcrumbs/breadcrumbsSlice'; const HostsMapping = () => { const dispatch = useDispatch(); - const { hostsMapping, hostsMappingFilter, handleHostsMappingFilterChange, mappingValidation } = useClusterMapping(); + const { hosts, components, localMapping, isLoaded } = useStore(({ adcm }) => adcm.clusterMapping); + const notAddedServicesDictionary = useStore(({ adcm }) => adcm.clusterMapping.relatedData.notAddedServicesDictionary); + + const { hostsMapping, hostsMappingFilter, handleHostsMappingFilterChange, mappingValidation } = useClusterMapping( + localMapping, + hosts, + components, + notAddedServicesDictionary, + isLoaded, + ); const handleFilterChange = (event: React.ChangeEvent) => { handleHostsMappingFilterChange({ componentDisplayName: event.target.value }); diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts b/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts index 1a97de3b58..7fd8f00cfd 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts @@ -1,7 +1,5 @@ import { useCallback, useMemo, useState } from 'react'; -import { useDispatch, useStore } from '@hooks'; -import { setLocalMapping, revertChanges } from '@store/adcm/cluster/mapping/mappingSlice'; -import { AdcmMappingComponent, AdcmHostShortView } from '@models/adcm'; +import { AdcmMappingComponent, AdcmHostShortView, AdcmMapping, AdcmServicePrototype } from '@models/adcm'; import { arrayToHash } from '@utils/arrayUtils'; import { getComponentsMapping, @@ -20,14 +18,14 @@ import { ComponentsDictionary, } from './ClusterMapping.types'; -export const useClusterMapping = () => { - const dispatch = useDispatch(); - - const { hosts, components, localMapping, isLoaded, isLoading, hasSaveError, state } = useStore( - ({ adcm }) => adcm.clusterMapping, - ); - const notAddedServicesDictionary = useStore(({ adcm }) => adcm.clusterMapping.relatedData.notAddedServicesDictionary); - +export const useClusterMapping = ( + mapping: AdcmMapping[], + hosts: AdcmHostShortView[], + components: AdcmMappingComponent[], + notAddedServicesDictionary: Record, + isLoaded: boolean, + handleSetMapping?: (newMapping: AdcmMapping[]) => void, +) => { const hostsDictionary: HostsDictionary = useMemo(() => arrayToHash(hosts, (h) => h.id), [hosts]); const componentsDictionary: ComponentsDictionary = useMemo(() => arrayToHash(components, (c) => c.id), [components]); @@ -41,13 +39,13 @@ export const useClusterMapping = () => { }); const componentsMapping: ComponentMapping[] = useMemo( - () => (isLoaded ? getComponentsMapping(localMapping, components, hostsDictionary) : []), - [components, hostsDictionary, isLoaded, localMapping], + () => (isLoaded ? getComponentsMapping(mapping, components, hostsDictionary) : []), + [components, hostsDictionary, isLoaded, mapping], ); const hostsMapping: HostMapping[] = useMemo( - () => (isLoaded ? getHostsMapping(localMapping, hosts, componentsDictionary) : []), - [isLoaded, localMapping, hosts, componentsDictionary], + () => (isLoaded ? getHostsMapping(mapping, hosts, componentsDictionary) : []), + [isLoaded, mapping, hosts, componentsDictionary], ); const servicesMapping: ServiceMapping[] = useMemo( @@ -68,20 +66,20 @@ export const useClusterMapping = () => { }); }, [componentsMapping, servicesMappingDictionary, notAddedServicesDictionary, hosts.length]); - const handleMapHostsToComponent = useCallback( + const handleMap = useCallback( (hosts: AdcmHostShortView[], component: AdcmMappingComponent) => { const newLocalMapping = mapHostsToComponent(servicesMapping, hosts, component); - dispatch(setLocalMapping(newLocalMapping)); + handleSetMapping?.(newLocalMapping); }, - [dispatch, servicesMapping], + [servicesMapping, handleSetMapping], ); const handleUnmap = useCallback( (hostId: number, componentId: number) => { - const newLocalMapping = localMapping.filter((m) => !(m.hostId === hostId && m.componentId === componentId)); - dispatch(setLocalMapping(newLocalMapping)); + const newMapping = mapping.filter((m) => !(m.hostId === hostId && m.componentId === componentId)); + handleSetMapping?.(newMapping); }, - [dispatch, localMapping], + [mapping, handleSetMapping], ); const handleServicesMappingFilterChange = (changes: Partial) => { @@ -98,14 +96,8 @@ export const useClusterMapping = () => { }); }; - const handleRevert = useCallback(() => { - dispatch(revertChanges()); - }, [dispatch]); - return { - hostComponentMapping: localMapping, - isLoading, - isLoaded, + hostComponentMapping: mapping, hosts, hostsMapping, hostsMappingFilter, @@ -114,11 +106,8 @@ export const useClusterMapping = () => { servicesMapping, servicesMappingFilter, handleServicesMappingFilterChange, - mappingState: state, mappingValidation, - hasSaveError, - handleMapHostsToComponent, + handleMap, handleUnmap, - handleRevert, }; }; diff --git a/adcm-web/app/src/store/adcm/clusters/clustersDynamicActionsSlice.ts b/adcm-web/app/src/store/adcm/clusters/clustersDynamicActionsSlice.ts index 3f53a365d5..5b03a3b933 100644 --- a/adcm-web/app/src/store/adcm/clusters/clustersDynamicActionsSlice.ts +++ b/adcm-web/app/src/store/adcm/clusters/clustersDynamicActionsSlice.ts @@ -1,12 +1,19 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { AdcmCluster } from '@models/adcm'; +import { PayloadAction, createSlice } from '@reduxjs/toolkit'; +import { AdcmCluster, AdcmHostShortView, AdcmMapping, AdcmMappingComponent, AdcmServicePrototype } from '@models/adcm'; import { createAsyncThunk } from '@store/redux'; -import { AdcmClustersApi, RequestError } from '@api'; +import { AdcmClusterMappingApi, AdcmClustersApi, RequestError } from '@api'; import { fulfilledFilter } from '@utils/promiseUtils'; import { showError, showInfo } from '@store/notificationsSlice'; import { AdcmDynamicAction, AdcmDynamicActionDetails, AdcmDynamicActionRunConfig } from '@models/adcm/dynamicAction'; import { getErrorMessage } from '@utils/httpResponseUtils'; import { ActionStatuses } from '@constants'; +import { LoadState } from '@models/loadState'; +import { AdcmClusterServicesApi } from '@api/adcm/clusterServices'; +import { arrayToHash } from '@utils/arrayUtils'; + +type GetClusterMappingArg = { + clusterId: number; +}; const loadClustersDynamicActions = createAsyncThunk( 'adcm/clustersDynamicActions/loadClustersDynamicActions', @@ -60,6 +67,28 @@ const openClusterDynamicActionDialog = createAsyncThunk( }, ); +const loadMappings = createAsyncThunk( + 'adcm/clustersDynamicActions/loadMappings', + async ({ clusterId }: GetClusterMappingArg, thunkAPI) => { + try { + const mapping = await AdcmClusterMappingApi.getMapping(clusterId); + const hosts = await AdcmClusterMappingApi.getMappingHosts(clusterId); + const components = await AdcmClusterMappingApi.getMappingComponents(clusterId); + const notAddedServices = await AdcmClusterServicesApi.getClusterServiceCandidates(clusterId); + return { mapping, components, hosts, notAddedServices }; + } catch (error) { + return thunkAPI.rejectWithValue(error); + } + }, +); + +const getMappings = createAsyncThunk( + 'adcm/clustersDynamicActions/getMappings', + async (arg: GetClusterMappingArg, thunkAPI) => { + await thunkAPI.dispatch(loadMappings(arg)); + }, +); + interface RunClusterDynamicActionPayload { cluster: AdcmCluster; actionId: number; @@ -87,6 +116,12 @@ type AdcmClustersDynamicActionsState = { dialog: { actionDetails: AdcmDynamicActionDetails | null; cluster: AdcmCluster | null; + mapping: AdcmMapping[]; + localMapping: AdcmMapping[]; + hosts: AdcmHostShortView[]; + components: AdcmMappingComponent[]; + notAddedServicesDictionary: Record; + loadState: LoadState; }; clusterDynamicActions: Record; }; @@ -95,6 +130,12 @@ const createInitialState = (): AdcmClustersDynamicActionsState => ({ dialog: { actionDetails: null, cluster: null, + mapping: [], + localMapping: [], + hosts: [], + components: [], + notAddedServicesDictionary: {}, + loadState: LoadState.NotLoaded, }, clusterDynamicActions: {}, }); @@ -103,6 +144,12 @@ const clustersDynamicActionsSlice = createSlice({ name: 'adcm/clustersDynamicActions', initialState: createInitialState(), reducers: { + setLocalMapping(state, action: PayloadAction) { + state.dialog.localMapping = action.payload; + }, + revertChanges(state) { + state.dialog.localMapping = state.dialog.mapping; + }, cleanupClusterDynamicActions() { return createInitialState(); }, @@ -113,6 +160,19 @@ const clustersDynamicActionsSlice = createSlice({ }, }, extraReducers: (builder) => { + builder.addCase(loadMappings.fulfilled, (state, action) => { + state.dialog.localMapping = action.payload.mapping; + state.dialog.mapping = action.payload.mapping; + state.dialog.hosts = action.payload.hosts; + state.dialog.components = action.payload.components; + state.dialog.notAddedServicesDictionary = arrayToHash(action.payload.notAddedServices, (s) => s.id); + }); + builder.addCase(getMappings.pending, (state) => { + state.dialog.loadState = LoadState.Loading; + }); + builder.addCase(getMappings.fulfilled, (state) => { + state.dialog.loadState = LoadState.Loaded; + }); builder.addCase(loadClustersDynamicActions.fulfilled, (state, action) => { state.clusterDynamicActions = action.payload; }); @@ -132,7 +192,8 @@ const clustersDynamicActionsSlice = createSlice({ }, }); -export const { cleanupClusterDynamicActions, closeClusterDynamicActionDialog } = clustersDynamicActionsSlice.actions; -export { loadClustersDynamicActions, openClusterDynamicActionDialog, runClusterDynamicAction }; +export const { setLocalMapping, revertChanges, cleanupClusterDynamicActions, closeClusterDynamicActionDialog } = + clustersDynamicActionsSlice.actions; +export { loadClustersDynamicActions, openClusterDynamicActionDialog, getMappings, runClusterDynamicAction }; export default clustersDynamicActionsSlice.reducer; From 81523e3196bb8c62c71f889f724929f686ed0fe6 Mon Sep 17 00:00:00 2001 From: Artem Starovoitov Date: Tue, 16 Jan 2024 13:15:01 +0000 Subject: [PATCH 034/151] ADCM-5180: Add tests for link hosts with a cluster --- python/cm/tests/test_inventory/base.py | 72 +++++++++ .../test_inventory/test_cluster_hosts.py | 148 ++++++++++++++++++ .../tests/test_inventory/test_components.py | 92 ++--------- 3 files changed, 236 insertions(+), 76 deletions(-) create mode 100644 python/cm/tests/test_inventory/base.py create mode 100644 python/cm/tests/test_inventory/test_cluster_hosts.py diff --git a/python/cm/tests/test_inventory/base.py b/python/cm/tests/test_inventory/base.py new file mode 100644 index 0000000000..e9f2361284 --- /dev/null +++ b/python/cm/tests/test_inventory/base.py @@ -0,0 +1,72 @@ +# Licensed 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. + +from functools import reduce +from json import loads +from pathlib import Path +from typing import Any, Mapping, TypeAlias + +from cm.inventory import get_inventory_data +from cm.models import Action, ADCMEntity, ConfigLog, Host +from django.conf import settings +from jinja2 import Template + +from adcm.tests.base import BaseTestCase, BusinessLogicMixin + +TemplatesData: TypeAlias = Mapping[tuple[str, ...], tuple[Path, Mapping[str, Any]]] + + +class BaseInventoryTestCase(BusinessLogicMixin, BaseTestCase): + def check_hosts_topology(self, data: Mapping[str, dict], expected: Mapping[str, list[str]]) -> None: + errors = set(data.keys()).symmetric_difference(set(expected.keys())) + self.assertSetEqual(errors, set()) + + for group_name, host_names in expected.items(): + errors = set(data[group_name]["hosts"].keys()).symmetric_difference(set(host_names)) + self.assertSetEqual(errors, set()) + + def check_data_by_template(self, data: Mapping[str, dict], templates_data: TemplatesData) -> None: + for key_chain, template_data in templates_data.items(): + template_path, kwargs = template_data + + expected_data = loads( + Template(source=template_path.read_text(encoding=settings.ENCODING_UTF_8)).render(kwargs), strict=False + ) + actual_data = reduce(dict.get, key_chain, data) + + self.assertDictEqual(actual_data, expected_data) + + def get_action_on_host_expected_template_data_part(self, host: Host) -> TemplatesData: + return { + ("HOST", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": host.fqdn, + "adcm_hostid": host.pk, + "password": ConfigLog.objects.get(pk=host.config.current).config["password"], + }, + ), + ("HOST", "vars", "provider"): ( + self.templates_dir / "provider.json.j2", + { + "id": host.provider.pk, + "password": ConfigLog.objects.get(pk=host.provider.config.current).config["password"], + "host_prototype_id": host.prototype.pk, + }, + ), + } + + def assert_inventory(self, obj: ADCMEntity, action: Action, expected_topology: dict, expected_data: dict): + actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] + + self.check_hosts_topology(data=actual_inventory, expected=expected_topology) + self.check_data_by_template(data=actual_inventory, templates_data=expected_data) diff --git a/python/cm/tests/test_inventory/test_cluster_hosts.py b/python/cm/tests/test_inventory/test_cluster_hosts.py new file mode 100644 index 0000000000..322d900fe1 --- /dev/null +++ b/python/cm/tests/test_inventory/test_cluster_hosts.py @@ -0,0 +1,148 @@ +# Licensed 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. + + +from pathlib import Path + +from cm.models import Action, ConfigLog +from cm.tests.test_inventory.base import BaseInventoryTestCase + + +class TestClusterHosts(BaseInventoryTestCase): + def setUp(self) -> None: + self.maxDiff = None # pylint: disable=invalid-name + + bundles_dir = Path(__file__).parent.parent / "bundles" + self.templates_dir = Path(__file__).parent.parent / "files/response_templates" + + self.provider_bundle = self.add_bundle(source_dir=bundles_dir / "provider") + cluster_bundle = self.add_bundle(source_dir=bundles_dir / "cluster_1") + + self.cluster_1 = self.add_cluster(bundle=cluster_bundle, name="cluster_1") + self.provider = self.add_provider(bundle=self.provider_bundle, name="provider") + + def test_cluster_action_on_cluster(self): + action_on_cluster = Action.objects.get(name="action_on_cluster", prototype=self.cluster_1.prototype) + expected_topology = { + "CLUSTER": [], + } + expected_data = { + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster_1.pk, + "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], + }, + ), + } + with self.subTest( + msg=f"Object: {self.cluster_1.prototype.type} #{self.cluster_1.pk} " + f"{self.cluster_1.name}, action: {action_on_cluster.name}" + ): + self.assert_inventory(self.cluster_1, action_on_cluster, expected_topology, expected_data) + + def test_add_1_host_on_cluster_actions(self): + host_1 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_1", cluster=self.cluster_1 + ) + + action_on_cluster = Action.objects.get(name="action_on_cluster", prototype=self.cluster_1.prototype) + action_on_host = Action.objects.get(name="action_on_host", prototype=host_1.prototype) + + host_names = [host_1.fqdn] + expected_topology = { + "CLUSTER": host_names, + } + + expected_data = { + ("CLUSTER", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": host_1.fqdn, + "adcm_hostid": host_1.pk, + "password": ConfigLog.objects.get(pk=host_1.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster_1.pk, + "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], + }, + ), + } + + for obj, action, expected_topology, expected_data in ( + (self.cluster_1, action_on_cluster, expected_topology, expected_data), + ( + host_1, + action_on_host, + {**expected_topology, **{"HOST": host_names}}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=host_1)}, + ), + ): + with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): + self.assert_inventory(obj, action, expected_topology, expected_data) + + def test_add_2_hosts_on_cluster_actions(self): + host_1 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_1", cluster=self.cluster_1 + ) + host_2 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster_1 + ) + + action_on_cluster = Action.objects.get(name="action_on_cluster", prototype=self.cluster_1.prototype) + action_on_host_1 = Action.objects.get(name="action_on_host", prototype=host_1.prototype) + action_on_host_2 = Action.objects.get(name="action_on_host", prototype=host_2.prototype) + + host_names = [host_1.fqdn, host_2.fqdn] + expected_topology = { + "CLUSTER": host_names, + } + + expected_data = { + ("CLUSTER", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": host_1.pk, + "host_1_password": ConfigLog.objects.get(pk=host_1.config.current).config["password"], + "host_2_id": host_2.pk, + "host_2_password": ConfigLog.objects.get(pk=host_2.config.current).config["password"], + }, + ), + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster_1.pk, + "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], + }, + ), + } + + for obj, action, expected_topology, expected_data in ( + (self.cluster_1, action_on_cluster, expected_topology, expected_data), + ( + host_1, + action_on_host_1, + {**expected_topology, **{"HOST": [host_1.fqdn]}}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=host_1)}, + ), + ( + host_2, + action_on_host_2, + {**expected_topology, **{"HOST": [host_2.fqdn]}}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=host_2)}, + ), + ): + with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): + self.assert_inventory(obj, action, expected_topology, expected_data) diff --git a/python/cm/tests/test_inventory/test_components.py b/python/cm/tests/test_inventory/test_components.py index 52b066dd8f..ce303135c6 100644 --- a/python/cm/tests/test_inventory/test_components.py +++ b/python/cm/tests/test_inventory/test_components.py @@ -13,10 +13,7 @@ # pylint: disable=attribute-defined-outside-init,too-many-locals -from functools import reduce -from json import loads from pathlib import Path -from typing import Any, Mapping, TypeAlias from api_v2.service.utils import bulk_add_services_to_cluster from cm.inventory import get_inventory_data @@ -24,20 +21,14 @@ Action, ClusterObject, ConfigLog, - Host, ObjectType, Prototype, ServiceComponent, ) -from django.conf import settings -from jinja2 import Template +from cm.tests.test_inventory.base import BaseInventoryTestCase -from adcm.tests.base import BaseTestCase, BusinessLogicMixin -TemplatesData: TypeAlias = Mapping[tuple[str, ...], tuple[Path, Mapping[str, Any]]] - - -class TestInventoryComponents(BusinessLogicMixin, BaseTestCase): +class TestInventoryComponents(BaseInventoryTestCase): def setUp(self) -> None: self.maxDiff = None # pylint: disable=invalid-name @@ -53,25 +44,6 @@ def setUp(self) -> None: bundle=self.provider_bundle, provider=self.provider, fqdn="host_1", cluster=self.cluster_1 ) - def _check_hosts_topology(self, data: Mapping[str, dict], expected: Mapping[str, list[str]]) -> None: - errors = set(data.keys()).symmetric_difference(set(expected.keys())) - self.assertSetEqual(errors, set()) - - for group_name, host_names in expected.items(): - errors = set(data[group_name]["hosts"].keys()).symmetric_difference(set(host_names)) - self.assertSetEqual(errors, set()) - - def _check_data_by_template(self, data: Mapping[str, dict], templates_data: TemplatesData) -> None: - for key_chain, template_data in templates_data.items(): - template_path, kwargs = template_data - - expected_data = loads( - Template(source=template_path.read_text(encoding=settings.ENCODING_UTF_8)).render(kwargs), strict=False - ) - actual_data = reduce(dict.get, key_chain, data) - - self.assertDictEqual(actual_data, expected_data) - def _prepare_two_services( self, ) -> tuple[ClusterObject, ServiceComponent, ServiceComponent, ClusterObject, ServiceComponent, ServiceComponent]: @@ -106,26 +78,6 @@ def _prepare_two_services( component_2_s2, ) - def _get_action_on_host_expected_template_data_part(self, host: Host) -> TemplatesData: - return { - ("HOST", "hosts"): ( - self.templates_dir / "one_host.json.j2", - { - "host_fqdn": host.fqdn, - "adcm_hostid": host.pk, - "password": ConfigLog.objects.get(pk=host.config.current).config["password"], - }, - ), - ("HOST", "vars", "provider"): ( - self.templates_dir / "provider.json.j2", - { - "id": host.provider.pk, - "password": ConfigLog.objects.get(pk=host.provider.config.current).config["password"], - "host_prototype_id": host.prototype.pk, - }, - ), - } - def test_1_component_1_host(self): service_one_component: ClusterObject = bulk_add_services_to_cluster( cluster=self.cluster_1, @@ -191,14 +143,11 @@ def test_1_component_1_host(self): self.host_1, action_on_host, {**expected_topology, **{"HOST": host_names}}, - {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=self.host_1)}, ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] - - self._check_hosts_topology(data=actual_inventory, expected=expected_topology) - self._check_data_by_template(data=actual_inventory, templates_data=expected_data) + self.assert_inventory(obj, action, expected_topology, expected_data) def test_2_components_2_hosts_mapped_all_to_all(self): self.host_2 = self.add_host( @@ -280,20 +229,20 @@ def test_2_components_2_hosts_mapped_all_to_all(self): self.host_1, action_on_host_1, {**expected_hosts_topology, **{"HOST": [self.host_1.fqdn]}}, - {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=self.host_1)}, ), ( self.host_2, action_on_host_2, {**expected_hosts_topology, **{"HOST": [self.host_2.fqdn]}}, - {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_2)}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=self.host_2)}, ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] - self._check_hosts_topology(data=actual_inventory, expected=expected_topology) - self._check_data_by_template(data=actual_inventory, templates_data=expected_data) + self.check_hosts_topology(data=actual_inventory, expected=expected_topology) + self.check_data_by_template(data=actual_inventory, templates_data=expected_data) def test_2_components_2_hosts_mapped_in_pairs(self): self.host_2 = self.add_host( @@ -373,20 +322,17 @@ def test_2_components_2_hosts_mapped_in_pairs(self): self.host_1, action_on_host_1, {**expected_hosts_topology, **{"HOST": [self.host_1.fqdn]}}, - {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=self.host_1)}, ), ( self.host_2, action_on_host_2, {**expected_hosts_topology, **{"HOST": [self.host_2.fqdn]}}, - {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_2)}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=self.host_2)}, ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] - - self._check_hosts_topology(data=actual_inventory, expected=expected_topology) - self._check_data_by_template(data=actual_inventory, templates_data=expected_data) + self.assert_inventory(obj, action, expected_topology, expected_data) def test_2_services_2_components_each_on_1_host(self): ( @@ -496,14 +442,11 @@ def test_2_services_2_components_each_on_1_host(self): self.host_1, action_on_host_1, {**expected_hosts_topology, **{"HOST": [self.host_1.fqdn]}}, - {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=self.host_1)}, ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] - - self._check_hosts_topology(data=actual_inventory, expected=expected_topology) - self._check_data_by_template(data=actual_inventory, templates_data=expected_data) + self.assert_inventory(obj, action, expected_topology, expected_data) def test_2_services_2_components_each_2_hosts_cross_mapping(self): self.host_2 = self.add_host( @@ -617,17 +560,14 @@ def test_2_services_2_components_each_2_hosts_cross_mapping(self): self.host_1, action_on_host_1, {**expected_hosts_topology, **{"HOST": [self.host_1.fqdn]}}, - {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_1)}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=self.host_1)}, ), ( self.host_2, action_on_host_2, {**expected_hosts_topology, **{"HOST": [self.host_2.fqdn]}}, - {**expected_data, **self._get_action_on_host_expected_template_data_part(host=self.host_2)}, + {**expected_data, **self.get_action_on_host_expected_template_data_part(host=self.host_2)}, ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] - - self._check_hosts_topology(data=actual_inventory, expected=expected_topology) - self._check_data_by_template(data=actual_inventory, templates_data=expected_data) + self.assert_inventory(obj, action, expected_topology, expected_data) From 162fd4f3e644c318af0581f322f241535c74c1fc Mon Sep 17 00:00:00 2001 From: Artem Starovoitov Date: Tue, 16 Jan 2024 15:50:31 +0000 Subject: [PATCH 035/151] ADCM-5158: [API] LDAP-related tasks can see all users, not only superuser --- python/api_v2/job/views.py | 8 +++++++- python/api_v2/task/views.py | 8 +++++++- python/api_v2/tests/test_mapping.py | 2 +- python/api_v2/tests/test_tasks.py | 32 +++++++++++++++++++++++++++-- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/python/api_v2/job/views.py b/python/api_v2/job/views.py index cbad1845dc..266d572ed1 100644 --- a/python/api_v2/job/views.py +++ b/python/api_v2/job/views.py @@ -9,13 +9,13 @@ # 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. - from api_v2.job.permissions import JobPermissions from api_v2.job.serializers import JobRetrieveSerializer from api_v2.task.serializers import JobListSerializer from api_v2.views import CamelCaseGenericViewSet from audit.utils import audit from cm.models import JobLog +from django.contrib.contenttypes.models import ContentType from guardian.mixins import PermissionListMixin from rest_framework.decorators import action from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin @@ -35,6 +35,12 @@ class JobViewSet( permission_classes = [JobPermissions] permission_required = [VIEW_JOBLOG_PERMISSION] + def get_queryset(self, *args, **kwargs): + queryset = super().get_queryset(*args, **kwargs) + if not self.request.user.is_superuser: + queryset = queryset.exclude(task__object_type=ContentType.objects.get(app_label="cm", model="adcm")) + return queryset + def get_serializer_class(self): if self.action == "retrieve": return JobRetrieveSerializer diff --git a/python/api_v2/task/views.py b/python/api_v2/task/views.py index 58631b3064..8003f76a46 100644 --- a/python/api_v2/task/views.py +++ b/python/api_v2/task/views.py @@ -9,7 +9,6 @@ # 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. - from api_v2.log_storage.utils import ( get_task_download_archive_file_handler, get_task_download_archive_name, @@ -20,6 +19,7 @@ from api_v2.views import CamelCaseGenericViewSet from audit.utils import audit from cm.models import TaskLog +from django.contrib.contenttypes.models import ContentType from django.http import HttpResponse from django_filters.rest_framework.backends import DjangoFilterBackend from guardian.mixins import PermissionListMixin @@ -42,6 +42,12 @@ class TaskViewSet( permission_classes = [TaskPermissions] permission_required = [VIEW_TASKLOG_PERMISSION] + def get_queryset(self, *args, **kwargs): + queryset = super().get_queryset(*args, **kwargs) + if not self.request.user.is_superuser: + queryset = queryset.exclude(object_type=ContentType.objects.get(app_label="cm", model="adcm")) + return queryset + @audit @action(methods=["post"], detail=True) def terminate(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument diff --git a/python/api_v2/tests/test_mapping.py b/python/api_v2/tests/test_mapping.py index 90ba60c3dd..824b8455cd 100644 --- a/python/api_v2/tests/test_mapping.py +++ b/python/api_v2/tests/test_mapping.py @@ -1152,7 +1152,7 @@ def _prepare_config_group_via_api( "cluster_pk": obj.pk, } case _: - raise NotImplemented(str(obj)) + raise NotImplementedError(str(obj)) response = self.client.post( path=reverse(viewname=viewname_create, kwargs=kwargs), diff --git a/python/api_v2/tests/test_tasks.py b/python/api_v2/tests/test_tasks.py index 4398faabbc..7d809d5bcb 100644 --- a/python/api_v2/tests/test_tasks.py +++ b/python/api_v2/tests/test_tasks.py @@ -27,14 +27,21 @@ ServiceComponent, TaskLog, ) +from django.contrib.contenttypes.models import ContentType from django.urls import reverse +from django.utils import timezone +from rbac.services.user import create_user from rest_framework.status import HTTP_200_OK, HTTP_404_NOT_FOUND -class TestTask(BaseAPITestCase): +class TestTask(BaseAPITestCase): # pylint: disable=too-many-instance-attributes def setUp(self) -> None: super().setUp() + self.test_user_credentials = {"username": "test_user_username", "password": "test_user_password"} + self.test_user = create_user(**self.test_user_credentials) + + self.adcm = ADCM.objects.first() service_1 = self.add_services_to_cluster(service_names=["service_1"], cluster=self.cluster_1).get() component_1 = ServiceComponent.objects.filter(service=service_1, prototype__name="component_1").first() self.cluster_action = Action.objects.filter(name="action", prototype=self.cluster_1.prototype).first() @@ -70,12 +77,18 @@ def setUp(self) -> None: verbose=False, post_upgrade_hc=[], ) + self.adcm_task = TaskLog.objects.create( + object_id=self.adcm.pk, + object_type=ContentType.objects.get(app_label="cm", model="adcm"), + start_date=timezone.now(), + finish_date=timezone.now(), + ) def test_task_list_success(self): response = self.client.get(path=reverse(viewname="v2:tasklog-list")) self.assertEqual(response.status_code, HTTP_200_OK) - self.assertEqual(len(response.data["results"]), 3) + self.assertEqual(len(response.data["results"]), 4) def test_task_filter_by_job_name(self): response = self.client.get(path=reverse(viewname="v2:tasklog-list"), data={"jobName": "comp"}) @@ -136,6 +149,21 @@ def test_task_log_download_success(self): self.assertEqual(response.status_code, HTTP_200_OK) + def test_adcm_5158_adcm_task_view_for_not_superuser_fail(self): + self.client.login(username="admin", password="admin") + response = self.client.get(path=reverse(viewname="v2:tasklog-detail", kwargs={"pk": self.adcm_task.pk})) + self.assertEqual(response.status_code, HTTP_200_OK) + + response = self.client.get(path=reverse(viewname="v2:tasklog-list")) + self.assertIn(self.adcm_task.pk, [task["id"] for task in response.json()["results"]]) + + self.client.login(**self.test_user_credentials) + response = self.client.get(path=reverse(viewname="v2:tasklog-detail", kwargs={"pk": self.adcm_task.pk})) + self.assertEqual(response.status_code, HTTP_404_NOT_FOUND) + + response = self.client.get(path=reverse(viewname="v2:tasklog-list")) + self.assertNotIn(self.adcm_task.pk, [task["id"] for task in response.json()["results"]]) + class TestTaskObjects(BaseAPITestCase): # pylint: disable=too-many-instance-attributes def setUp(self) -> None: From e0b53c29c046312dc6310fc19abf5517ce7c9f23 Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Wed, 17 Jan 2024 07:32:42 +0000 Subject: [PATCH 036/151] ADCM-5205 Add test on group configs effect on inventories --- python/adcm/tests/base.py | 4 +- .../bundles/cluster_group_config/config.yaml | 174 +++++++ .../bundles/cluster_group_config/dol.yaml | 16 + .../bundles/cluster_group_config/lod.yaml | 13 + .../cluster_group_config/secret-group.txt | 3 + .../bundles/cluster_group_config/secret.txt | 2 + .../host_1_cluster_config.json.j2 | 57 +++ .../group_config/host_1_services.json.j2 | 406 +++++++++++++++++ .../host_2_cluster_config.json.j2 | 58 +++ .../group_config/host_2_services.json.j2 | 425 ++++++++++++++++++ .../host_3_cluster_config.json.j2 | 57 +++ .../group_config/host_3_services.json.j2 | 416 +++++++++++++++++ python/cm/tests/test_inventory/base.py | 47 +- .../test_inventory/test_cluster_hosts.py | 4 +- .../tests/test_inventory/test_components.py | 11 +- .../tests/test_inventory/test_group_config.py | 238 ++++++++++ 16 files changed, 1918 insertions(+), 13 deletions(-) create mode 100644 python/cm/tests/bundles/cluster_group_config/config.yaml create mode 100644 python/cm/tests/bundles/cluster_group_config/dol.yaml create mode 100644 python/cm/tests/bundles/cluster_group_config/lod.yaml create mode 100644 python/cm/tests/bundles/cluster_group_config/secret-group.txt create mode 100644 python/cm/tests/bundles/cluster_group_config/secret.txt create mode 100644 python/cm/tests/files/response_templates/group_config/host_1_cluster_config.json.j2 create mode 100644 python/cm/tests/files/response_templates/group_config/host_1_services.json.j2 create mode 100644 python/cm/tests/files/response_templates/group_config/host_2_cluster_config.json.j2 create mode 100644 python/cm/tests/files/response_templates/group_config/host_2_services.json.j2 create mode 100644 python/cm/tests/files/response_templates/group_config/host_3_cluster_config.json.j2 create mode 100644 python/cm/tests/files/response_templates/group_config/host_3_services.json.j2 create mode 100644 python/cm/tests/test_inventory/test_group_config.py diff --git a/python/adcm/tests/base.py b/python/adcm/tests/base.py index 90f136f0c4..13bb901976 100644 --- a/python/adcm/tests/base.py +++ b/python/adcm/tests/base.py @@ -65,8 +65,8 @@ class ParallelReadyTestCase: def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) - directories = cls._prepare_temporal_directories_for_adcm() - override_settings(**directories)(cls) + cls.directories = cls._prepare_temporal_directories_for_adcm() + override_settings(**cls.directories)(cls) @staticmethod def _prepare_temporal_directories_for_adcm() -> dict: diff --git a/python/cm/tests/bundles/cluster_group_config/config.yaml b/python/cm/tests/bundles/cluster_group_config/config.yaml new file mode 100644 index 0000000000..04b8877297 --- /dev/null +++ b/python/cm/tests/bundles/cluster_group_config/config.yaml @@ -0,0 +1,174 @@ +- type: cluster + name: very_complex + version: 2.3 + config_group_customization: true + + config: &config + - name: just_bool + type: boolean + required: false + - name: just_integer + type: integer + default: 4 + - name: just_float + type: float + default: 2.3 + - name: just_string + type: string + default: "outofgroup" + - name: just_text + type: text + default: | + lineone + second line + - name: just_map + type: map + required: false + - name: just_list + type: list + required: false + default: ["1"] + - name: just_json + type: json + required: false + - name: variant_config + required: false + type: variant + source: + type: config + name: just_list + - name: variant_inline + type: variant + required: false + source: + type: inline + value: + - f + - c + - name: variant_builtin + type: variant + required: false + source: + type: builtin + name: host_in_cluster + # secrets + - name: password + type: password + default: "defaultpass" + - name: secrettext + type: secrettext + default: | + default + password + - name: secretmap + type: secretmap + default: + k1: v1 + k2: v2 + - name: secretfile + type: secretfile + default: ./secret.txt + - name: nullist + type: list + required: false + # plain group + - name: plain_group + type: group + subs: + - name: simple + type: string + default: "ingroup" + - name: secretmap + type: secretmap + default: + gk1: gv1 + gk2: gv2 + - name: secretfile + type: secretfile + default: ./secret-group.txt + - &list_of_dicts + name: list_of_dicts + display_name: List of Dicts + type: structure + yspec: ./lod.yaml + required: false + - name: listofstuff + type: list + default: ["x", "y"] + # activatable group + - name: activatable_group + type: group + activatable: true + active: false + subs: + - name: simple + type: string + default: "inactgroup" + - name: secretmap + type: secretmap + default: + agk1: agv1 + agk2: agv2 + - name: secretfile + type: secretfile + default: ./secret-group.txt + # structures + - <<: *list_of_dicts + default: + - integer: 3 + string: "three" + - integer: 12 + string: "twelve" + - name: dict_of_lists + display_name: Dict of Lists + type: structure + yspec: ./dol.yaml + default: + integers: + - 1 + - 103 + strings: + - "over" + - "and" + - "over" + actions: &actions + dummy: + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any + + +- type: service + name: not_simple + version: 4.3 + config_group_customization: true + + config: *config + actions: *actions + + components: + not_simple_component: + config: *config + actions: *actions + + another_not_simple_component: + config: *config + actions: *actions + +- type: service + name: thesame + version: 2.1 + + config: *config + actions: *actions + + components: + thesame_component: + config: *config + actions: *actions + + another_thesame_component: + config: *config + actions: *actions diff --git a/python/cm/tests/bundles/cluster_group_config/dol.yaml b/python/cm/tests/bundles/cluster_group_config/dol.yaml new file mode 100644 index 0000000000..9f83139ed6 --- /dev/null +++ b/python/cm/tests/bundles/cluster_group_config/dol.yaml @@ -0,0 +1,16 @@ +--- +root: + match: dict + items: + integers: integers + strings: strings +integers: + match: list + item: integer +strings: + match: list + item: string +integer: + match: int +string: + match: string diff --git a/python/cm/tests/bundles/cluster_group_config/lod.yaml b/python/cm/tests/bundles/cluster_group_config/lod.yaml new file mode 100644 index 0000000000..b04767dd83 --- /dev/null +++ b/python/cm/tests/bundles/cluster_group_config/lod.yaml @@ -0,0 +1,13 @@ +--- +root: + match: list + item: variable +variable: + match: dict + items: + integer: integer + string: string +integer: + match: int +string: + match: string diff --git a/python/cm/tests/bundles/cluster_group_config/secret-group.txt b/python/cm/tests/bundles/cluster_group_config/secret-group.txt new file mode 100644 index 0000000000..4dab48b2c8 --- /dev/null +++ b/python/cm/tests/bundles/cluster_group_config/secret-group.txt @@ -0,0 +1,3 @@ +something +iknow +aboutthegroup diff --git a/python/cm/tests/bundles/cluster_group_config/secret.txt b/python/cm/tests/bundles/cluster_group_config/secret.txt new file mode 100644 index 0000000000..9307251818 --- /dev/null +++ b/python/cm/tests/bundles/cluster_group_config/secret.txt @@ -0,0 +1,2 @@ +something +good diff --git a/python/cm/tests/files/response_templates/group_config/host_1_cluster_config.json.j2 b/python/cm/tests/files/response_templates/group_config/host_1_cluster_config.json.j2 new file mode 100644 index 0000000000..2f7bac0fef --- /dev/null +++ b/python/cm/tests/files/response_templates/group_config/host_1_cluster_config.json.j2 @@ -0,0 +1,57 @@ +{ + "just_bool": true, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": "1", + "variant_inline": "f", + "variant_builtin": "host_1", + "password": "defaultpass", + "secrettext": "imsecrett\nextforu\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/cluster.1.group.1.secretfile.", + "nullist": [], + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/cluster.1.group.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "hello" + ] + }, + "activatable_group": null, + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/group_config/host_1_services.json.j2 b/python/cm/tests/files/response_templates/group_config/host_1_services.json.j2 new file mode 100644 index 0000000000..8e1c13f760 --- /dev/null +++ b/python/cm/tests/files/response_templates/group_config/host_1_services.json.j2 @@ -0,0 +1,406 @@ +{ + "not_simple": { + "id": {{ not_simple.id }}, + "version": "4.3", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/service.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/service.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "maintenance_mode": false, + "display_name": "not_simple", + "before_upgrade": { + "state": null + }, + "not_simple_component": { + "component_id": {{ not_simple_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "not_simple_component", + "before_upgrade": { + "state": null + } + }, + "another_not_simple_component": { + "component_id": {{ another_not_simple_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.2.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.2.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "another_not_simple_component", + "before_upgrade": { + "state": null + } + } + }, + "thesame": { + "id": {{ thesame.id }}, + "version": "2.1", + "state": "created", + "multi_state": [], + "config": { + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": { + "key": "val" + }, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/service.2.group.2.secretfile.", + "nullist": [], + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/service.2.group.2.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "list_of_dicts": [], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "maintenance_mode": false, + "display_name": "thesame", + "before_upgrade": { + "state": null + }, + "thesame_component": { + "component_id": {{ thesame_component.id }}, + "config": { + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.3.group.4.secretfile.", + "nullist": [], + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.3.group.4.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "thesame_component", + "before_upgrade": { + "state": null + } + }, + "another_thesame_component": { + "component_id": {{ another_thesame_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.4.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "wind", + "vs", + "oak" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 1000.304, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.4.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "another_thesame_component", + "before_upgrade": { + "state": null + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/group_config/host_2_cluster_config.json.j2 b/python/cm/tests/files/response_templates/group_config/host_2_cluster_config.json.j2 new file mode 100644 index 0000000000..ef8a7c987b --- /dev/null +++ b/python/cm/tests/files/response_templates/group_config/host_2_cluster_config.json.j2 @@ -0,0 +1,58 @@ +{ + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/cluster.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/cluster.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/group_config/host_2_services.json.j2 b/python/cm/tests/files/response_templates/group_config/host_2_services.json.j2 new file mode 100644 index 0000000000..521b9d0d22 --- /dev/null +++ b/python/cm/tests/files/response_templates/group_config/host_2_services.json.j2 @@ -0,0 +1,425 @@ +{ + "not_simple": { + "id": {{ not_simple.id }}, + "version": "4.3", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/service.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/service.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "maintenance_mode": false, + "display_name": "not_simple", + "before_upgrade": { + "state": null + }, + "not_simple_component": { + "component_id": {{ not_simple_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "not_simple_component", + "before_upgrade": { + "state": null + } + }, + "another_not_simple_component": { + "component_id": {{ another_not_simple_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.2.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.2.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "another_not_simple_component", + "before_upgrade": { + "state": null + } + } + }, + "thesame": { + "id": {{ thesame.id }}, + "version": "2.1", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/service.2.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": { + "simple": "bestgroupever", + "secretmap": { + "agk1": "agv1", + "agk2": "agv2" + }, + "secretfile": "{{ filedir }}/service.2.activatable_group.secretfile" + }, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/service.2.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 400, + "string": "woo" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "maintenance_mode": false, + "display_name": "thesame", + "before_upgrade": { + "state": null + }, + "thesame_component": { + "component_id": {{ thesame_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.3.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.3.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "thesame_component", + "before_upgrade": { + "state": null + } + }, + "another_thesame_component": { + "component_id": {{ another_thesame_component.id }}, + "config": { + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.4.group.3.secretfile.", + "nullist": [], + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2", + "donot": "know", + "m": "e" + }, + "secretfile": "{{ filedir }}/component.4.group.3.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "wind", + "vs", + "oak" + ] + }, + "activatable_group": { + "simple": "inactgroup", + "secretmap": { + "agk1": "agv1", + "agk2": "agv2" + }, + "secretfile": "{{ filedir }}/component.4.group.3.activatable_group.secretfile" + }, + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "another_thesame_component", + "before_upgrade": { + "state": null + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/group_config/host_3_cluster_config.json.j2 b/python/cm/tests/files/response_templates/group_config/host_3_cluster_config.json.j2 new file mode 100644 index 0000000000..2f7bac0fef --- /dev/null +++ b/python/cm/tests/files/response_templates/group_config/host_3_cluster_config.json.j2 @@ -0,0 +1,57 @@ +{ + "just_bool": true, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": "1", + "variant_inline": "f", + "variant_builtin": "host_1", + "password": "defaultpass", + "secrettext": "imsecrett\nextforu\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/cluster.1.group.1.secretfile.", + "nullist": [], + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/cluster.1.group.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "hello" + ] + }, + "activatable_group": null, + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/group_config/host_3_services.json.j2 b/python/cm/tests/files/response_templates/group_config/host_3_services.json.j2 new file mode 100644 index 0000000000..e7e835171c --- /dev/null +++ b/python/cm/tests/files/response_templates/group_config/host_3_services.json.j2 @@ -0,0 +1,416 @@ +{ + "not_simple": { + "id": {{ not_simple.id }}, + "version": "4.3", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/service.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/service.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "maintenance_mode": false, + "display_name": "not_simple", + "before_upgrade": { + "state": null + }, + "not_simple_component": { + "component_id": {{ not_simple_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "not_simple_component", + "before_upgrade": { + "state": null + } + }, + "another_not_simple_component": { + "component_id": {{ another_not_simple_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.2.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.2.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "another_not_simple_component", + "before_upgrade": { + "state": null + } + } + }, + "thesame": { + "id": {{ thesame.id }}, + "version": "2.1", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/service.2.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": { + "simple": "bestgroupever", + "secretmap": { + "agk1": "agv1", + "agk2": "agv2" + }, + "secretfile": "{{ filedir }}/service.2.activatable_group.secretfile" + }, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/service.2.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 400, + "string": "woo" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "maintenance_mode": false, + "display_name": "thesame", + "before_upgrade": { + "state": null + }, + "thesame_component": { + "component_id": {{ thesame_component.id }}, + "config": { + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.3.group.4.secretfile.", + "nullist": [], + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.3.group.4.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "thesame_component", + "before_upgrade": { + "state": null + } + }, + "another_thesame_component": { + "component_id": {{ another_thesame_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.4.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "wind", + "vs", + "oak" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 1000.304, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.4.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "another_thesame_component", + "before_upgrade": { + "state": null + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/test_inventory/base.py b/python/cm/tests/test_inventory/base.py index e9f2361284..29c23ed3de 100644 --- a/python/cm/tests/test_inventory/base.py +++ b/python/cm/tests/test_inventory/base.py @@ -13,10 +13,20 @@ from functools import reduce from json import loads from pathlib import Path -from typing import Any, Mapping, TypeAlias +from typing import Any, Iterable, Mapping, TypeAlias +from cm.adcm_config.ansible import ansible_decrypt +from cm.api import add_hc from cm.inventory import get_inventory_data -from cm.models import Action, ADCMEntity, ConfigLog, Host +from cm.models import ( + Action, + ADCMEntity, + Cluster, + ConfigLog, + Host, + HostComponent, + ServiceComponent, +) from django.conf import settings from jinja2 import Template @@ -25,7 +35,30 @@ TemplatesData: TypeAlias = Mapping[tuple[str, ...], tuple[Path, Mapping[str, Any]]] +def decrypt_secrets(source: dict) -> dict: + result = {} + for key, value in source.items(): + if not isinstance(value, dict): + result[key] = value + continue + + if "__ansible_vault" in value: + result[key] = ansible_decrypt(value["__ansible_vault"]) + else: + result[key] = decrypt_secrets(value) + + return result + + class BaseInventoryTestCase(BusinessLogicMixin, BaseTestCase): + def setUp(self): + super().setUp() + + self.maxDiff = None # pylint: disable=invalid-name + + self.bundles_dir = Path(__file__).parent.parent / "bundles" + self.templates_dir = Path(__file__).parent.parent / "files" / "response_templates" + def check_hosts_topology(self, data: Mapping[str, dict], expected: Mapping[str, list[str]]) -> None: errors = set(data.keys()).symmetric_difference(set(expected.keys())) self.assertSetEqual(errors, set()) @@ -34,6 +67,16 @@ def check_hosts_topology(self, data: Mapping[str, dict], expected: Mapping[str, errors = set(data[group_name]["hosts"].keys()).symmetric_difference(set(host_names)) self.assertSetEqual(errors, set()) + @staticmethod + def set_hostcomponent(cluster: Cluster, entries: Iterable[tuple[Host, ServiceComponent]]) -> list[HostComponent]: + return add_hc( + cluster=cluster, + hc_in=[ + {"host_id": host.pk, "component_id": component.pk, "service_id": component.service_id} + for host, component in entries + ], + ) + def check_data_by_template(self, data: Mapping[str, dict], templates_data: TemplatesData) -> None: for key_chain, template_data in templates_data.items(): template_path, kwargs = template_data diff --git a/python/cm/tests/test_inventory/test_cluster_hosts.py b/python/cm/tests/test_inventory/test_cluster_hosts.py index 322d900fe1..fd91fdab8f 100644 --- a/python/cm/tests/test_inventory/test_cluster_hosts.py +++ b/python/cm/tests/test_inventory/test_cluster_hosts.py @@ -19,7 +19,9 @@ class TestClusterHosts(BaseInventoryTestCase): def setUp(self) -> None: - self.maxDiff = None # pylint: disable=invalid-name + super().setUp() + + self.maxDiff = None bundles_dir = Path(__file__).parent.parent / "bundles" self.templates_dir = Path(__file__).parent.parent / "files/response_templates" diff --git a/python/cm/tests/test_inventory/test_components.py b/python/cm/tests/test_inventory/test_components.py index ce303135c6..c32322083c 100644 --- a/python/cm/tests/test_inventory/test_components.py +++ b/python/cm/tests/test_inventory/test_components.py @@ -13,8 +13,6 @@ # pylint: disable=attribute-defined-outside-init,too-many-locals -from pathlib import Path - from api_v2.service.utils import bulk_add_services_to_cluster from cm.inventory import get_inventory_data from cm.models import ( @@ -30,13 +28,10 @@ class TestInventoryComponents(BaseInventoryTestCase): def setUp(self) -> None: - self.maxDiff = None # pylint: disable=invalid-name - - bundles_dir = Path(__file__).parent.parent / "bundles" - self.templates_dir = Path(__file__).parent.parent / "files/response_templates" + super().setUp() - self.provider_bundle = self.add_bundle(source_dir=bundles_dir / "provider") - cluster_bundle = self.add_bundle(source_dir=bundles_dir / "cluster_1") + self.provider_bundle = self.add_bundle(source_dir=self.bundles_dir / "provider") + cluster_bundle = self.add_bundle(source_dir=self.bundles_dir / "cluster_1") self.cluster_1 = self.add_cluster(bundle=cluster_bundle, name="cluster_1") self.provider = self.add_provider(bundle=self.provider_bundle, name="provider") diff --git a/python/cm/tests/test_inventory/test_group_config.py b/python/cm/tests/test_inventory/test_group_config.py new file mode 100644 index 0000000000..474796f6b9 --- /dev/null +++ b/python/cm/tests/test_inventory/test_group_config.py @@ -0,0 +1,238 @@ +# Licensed 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 json +from typing import Callable, Iterable + +from api_v2.config.utils import convert_adcm_meta_to_attr, convert_attr_to_adcm_meta +from api_v2.service.utils import bulk_add_services_to_cluster +from cm.api import update_obj_config +from cm.inventory import get_inventory_data +from cm.models import ( + Action, + ADCMModel, + ConfigLog, + GroupConfig, + Host, + ObjectType, + Prototype, + ServiceComponent, +) +from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets +from cm.utils import deep_merge +from django.contrib.contenttypes.models import ContentType +from jinja2 import Template + + +class TestGroupConfigsInInventory(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes + def setUp(self) -> None: + super().setUp() + + self.cluster = self.add_cluster( + bundle=self.add_bundle(source_dir=self.bundles_dir / "cluster_group_config"), name="Target Cluster" + ) + + self.provider = self.add_provider( + bundle=self.add_bundle(source_dir=self.bundles_dir / "provider"), name="provider" + ) + self.host_1 = self.add_host( + bundle=self.provider.prototype.bundle, provider=self.provider, fqdn="host_1", cluster=self.cluster + ) + self.host_2 = self.add_host( + bundle=self.provider.prototype.bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster + ) + self.host_3 = self.add_host( + bundle=self.provider.prototype.bundle, provider=self.provider, fqdn="host_3", cluster=self.cluster + ) + + self.service_not_simple, self.service_thesame = bulk_add_services_to_cluster( + cluster=self.cluster, + prototypes=Prototype.objects.filter(type=ObjectType.SERVICE, name__in=["not_simple", "thesame"]), + ) + self.component_not_simple = ServiceComponent.objects.get( + service=self.service_not_simple, prototype__name="not_simple_component" + ) + self.component_another_not_simple = ServiceComponent.objects.get( + service=self.service_not_simple, prototype__name="another_not_simple_component" + ) + self.component_thesame = ServiceComponent.objects.get( + service=self.service_thesame, prototype__name="thesame_component" + ) + self.component_another_thesame = ServiceComponent.objects.get( + service=self.service_thesame, prototype__name="another_thesame_component" + ) + + @staticmethod + def add_group_config(parent: ADCMModel, hosts: Iterable[Host]) -> GroupConfig: + group_config = GroupConfig.objects.create( + object_type=ContentType.objects.get_for_model(model=parent), + object_id=parent.pk, + name=f"Group for {parent.__class__.__name__} {parent.pk}", + ) + group_config.hosts.set(hosts) + return group_config + + @staticmethod + def change_configuration( + target: ADCMModel | GroupConfig, + config_diff: dict, + meta_diff: dict | None = None, + preprocess_config: Callable[[dict], dict] = lambda x: x, + ) -> ConfigLog: + meta = meta_diff or {} + + target.refresh_from_db() + current_config = ConfigLog.objects.get(id=target.config.current) + + new_config = update_obj_config( + obj_conf=target.config, + config=deep_merge(origin=preprocess_config(current_config.config), renovator=config_diff), + attr=convert_adcm_meta_to_attr( + deep_merge(origin=convert_attr_to_adcm_meta(current_config.attr), renovator=meta) + ), + description="", + ) + + return new_config + + def test_group_config_in_inventory(self) -> None: + self.set_hostcomponent( + cluster=self.cluster, + entries=( + (self.host_1, self.component_not_simple), + (self.host_1, self.component_another_not_simple), + (self.host_1, self.component_thesame), + (self.host_1, self.component_another_thesame), + (self.host_2, self.component_not_simple), + (self.host_2, self.component_another_not_simple), + (self.host_3, self.component_not_simple), + (self.host_3, self.component_thesame), + ), + ) + + host_names = [self.host_1.name, self.host_2.name, self.host_3.name] + expected_topology = { + "CLUSTER": host_names, + self.service_not_simple.name: host_names, + f"{self.service_not_simple.name}.{self.component_another_not_simple.name}": [host_names[0], host_names[1]], + f"{self.service_not_simple.name}.{self.component_not_simple.name}": host_names, + self.service_thesame.name: [host_names[0], host_names[2]], + f"{self.service_thesame.name}.{self.component_thesame.name}": [host_names[0], host_names[2]], + f"{self.service_thesame.name}.{self.component_another_thesame.name}": [host_names[0]], + } + + context = { + **{ + obj_.name: obj_ + for obj_ in ( + self.service_thesame, + self.service_not_simple, + self.component_thesame, + self.component_another_thesame, + self.component_not_simple, + self.component_another_not_simple, + ) + }, + "filedir": self.directories["FILE_DIR"], + } + expected_parts = { + file.stem.replace(".json", ""): json.loads( + Template(source=file.read_text(encoding="utf-8")).render(**context), strict=False + ) + for file in (self.templates_dir / "group_config").iterdir() + } + + cluster_group = self.add_group_config(parent=self.cluster, hosts=(self.host_1, self.host_3)) + service_group = self.add_group_config(parent=self.service_thesame, hosts=(self.host_1,)) + component_group_1 = self.add_group_config(parent=self.component_another_thesame, hosts=(self.host_2,)) + self.add_group_config(parent=self.component_thesame, hosts=(self.host_1, self.host_3)) + + self.change_configuration( + target=cluster_group, + config_diff={ + "plain_group": {"listofstuff": ["hello"]}, + "just_bool": True, + "secrettext": "imsecrett\nextforu\n", + "variant_inline": "f", + "variant_config": "1", + "variant_builtin": self.host_1.name, + }, + meta_diff={ + key: {"isSynchronized": False} + for key in ( + "/plain_group/listofstuff", + "/just_bool", + "/secrettext", + "/variant_inline", + "/variant_config", + "/variant_builtin", + ) + }, + ) + + self.change_configuration( + target=self.service_thesame, + config_diff={ + "activatable_group": {"simple": "bestgroupever"}, + "list_of_dicts": [{"integer": 400, "string": "woo"}], + }, + meta_diff={"/activatable_group": {"isActive": True}}, + ) + self.change_configuration( + target=service_group, + config_diff={"list_of_dicts": [], "just_map": {"key": "val"}}, + meta_diff={ + "/activatable_group": {"isActive": False, "isSynchronized": False}, + "/just_map": {"isSynchronized": False}, + "/list_of_dicts": {"isSynchronized": False}, + }, + # because `just_map` is None and it'll fail `deep_merge` + preprocess_config=lambda d: {**d, "just_map": {}}, + ) + + self.change_configuration( + target=component_group_1, + config_diff={"plain_group": {"secretmap": {"donot": "know", "m": "e"}}}, + meta_diff={ + "/activatable_group": {"isActive": True, "isSynchronized": False}, + "/plain_group/secretmap": {"isSynchronized": False}, + "/just_float": {"isSynchronized": False}, + }, + ) + self.change_configuration( + target=self.component_another_thesame, + config_diff={ + "plain_group": {"secretmap": {}, "listofstuff": ["wind", "vs", "oak"]}, + "just_float": 1000.304, + }, + ) + + for object_ in ( + self.cluster, + self.service_not_simple, + self.service_thesame, + self.component_not_simple, + self.component_another_not_simple, + self.component_thesame, + self.component_another_thesame, + ): + actual_inventory = decrypt_secrets( + get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ + "all" + ]["children"] + ) + self.check_hosts_topology(actual_inventory, expected_topology) + for group in actual_inventory.values(): + for host_name, actual_data in group["hosts"].items(): + self.assertDictEqual( + actual_data["cluster"]["config"], expected_parts[f"{host_name}_cluster_config"] + ) + self.assertDictEqual(actual_data["services"], expected_parts[f"{host_name}_services"]) From 9fc8ec4c5e235de27ca9e8db46f650507dd4fd9d Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Wed, 17 Jan 2024 09:36:17 +0000 Subject: [PATCH 037/151] [UI] ADCM-5202: Fix Component config version compare https://tracker.yandex.ru/ADCM-5202 --- .../ComponentPrimaryConfiguration.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/ComponentPrimaryConfiguration.tsx b/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/ComponentPrimaryConfiguration.tsx index 490be179e1..f727a43c84 100644 --- a/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/ComponentPrimaryConfiguration.tsx +++ b/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/ComponentPrimaryConfiguration.tsx @@ -1,12 +1,12 @@ import React, { useEffect } from 'react'; import { useDispatch } from '@hooks'; import { useComponentPrimaryConfiguration } from '@pages/cluster/service/component/ComponentPrimaryConfiguration/useComponentPrimaryConfiguration'; -import { useHostProviderPrimaryConfigurationsCompare } from '@pages/HostProviderPage/HostProviderPrimaryConfiguration/useHostProviderPrimaryConfigurationsCompare'; import { setBreadcrumbs } from '@store/adcm/breadcrumbs/breadcrumbsSlice'; import ConfigurationHeader from '@commonComponents/configuration/ConfigurationHeader/ConfigurationHeader'; import ConfigurationFormContextProvider from '@commonComponents/configuration/ConfigurationFormContext/ConfigurationFormContextProvider'; import ConfigurationSubHeader from '@commonComponents/configuration/ConfigurationSubHeader/ConfigurationSubHeader'; import ConfigurationMain from '@commonComponents/configuration/ConfigurationMain/ConfigurationMain'; +import { useComponentPrimaryConfigurationsCompare } from './useComponentPrimaryConfigurationCompare'; const ComponentPrimaryConfiguration: React.FC = () => { const dispatch = useDispatch(); @@ -23,7 +23,7 @@ const ComponentPrimaryConfiguration: React.FC = () => { isConfigurationLoading, } = useComponentPrimaryConfiguration(); - const compareOptions = useHostProviderPrimaryConfigurationsCompare(); + const compareOptions = useComponentPrimaryConfigurationsCompare(); useEffect(() => { if (component) { From 7aa3a98aecef51c139c3088aa79e2a1d4e5e3f32 Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Wed, 17 Jan 2024 10:41:08 +0000 Subject: [PATCH 038/151] ADCM-5212 Change long log truncation Added: 1. Truncation message at the end of truncated log as well as at the start 2. Added test on checking content of downloaded log --- python/api_v2/log_storage/serializers.py | 21 +++++++---- python/api_v2/tests/test_jobs.py | 44 ++++++++++++++++++++++-- python/cm/log.py | 29 ++++++++++++++++ 3 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 python/cm/log.py diff --git a/python/api_v2/log_storage/serializers.py b/python/api_v2/log_storage/serializers.py index d100faece2..0eb4febfba 100644 --- a/python/api_v2/log_storage/serializers.py +++ b/python/api_v2/log_storage/serializers.py @@ -15,6 +15,7 @@ from contextlib import suppress from cm.ansible_plugin import get_checklogs_data_by_job_id +from cm.log import extract_log_content_from_fs from cm.models import LogStorage from django.conf import settings from rest_framework.fields import SerializerMethodField @@ -41,15 +42,17 @@ def get_content(self, obj: LogStorage) -> str: # retrieve if empty if content is None: if log_type in {"stdout", "stderr"}: - logfile = settings.RUN_DIR / f"{obj.job_id}" / f"{obj.name}-{obj.type}.{obj.format}" - if logfile.exists(): - content = logfile.read_text(encoding="utf-8") + content = extract_log_content_from_fs(jobs_dir=settings.RUN_DIR, log_info=obj) if log_type == "check": content = get_checklogs_data_by_job_id(obj.job_id) # postprocessing - if log_type in {"stdout", "stderr"} and len(content or "") >= settings.STDOUT_STDERR_LOG_MAX_UNCUT_LENGTH: + if ( + log_type in {"stdout", "stderr"} + and content is not None + and len(content) >= settings.STDOUT_STDERR_LOG_MAX_UNCUT_LENGTH + ): cut_lines = "\n".join( ( line @@ -58,12 +61,16 @@ def get_content(self, obj: LogStorage) -> str: line[: settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH] + settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE ) - for line in obj.body.splitlines()[-1500:] + for line in content.splitlines()[-1500:] ) ) - content = f"{settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE}\n{cut_lines}\n" + content = ( + f"{settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE}\n" + f"{cut_lines}\n" + f"{settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE}\n" + ) elif log_type == "check" and isinstance(content, str): - content = json.loads(obj.body) + content = json.loads(content) elif log_type == "custom" and obj.format == "json" and isinstance(content, str): with suppress(json.JSONDecodeError): custom_content = json.loads(content) diff --git a/python/api_v2/tests/test_jobs.py b/python/api_v2/tests/test_jobs.py index 01f60ff0b9..5fe0dd321e 100644 --- a/python/api_v2/tests/test_jobs.py +++ b/python/api_v2/tests/test_jobs.py @@ -25,6 +25,7 @@ ) from django.conf import settings from django.contrib.contenttypes.models import ContentType +from django.http import HttpResponse from django.urls import reverse from django.utils import timezone from rest_framework.response import Response @@ -170,7 +171,8 @@ def test_job_log_detail_success(self): self.assertEqual(response.status_code, HTTP_200_OK) log = response.json()["content"].splitlines() self.assertEqual(log[0], self.TRUNCATED_LOG_MESSAGE) - log_itself = log[1:] + self.assertEqual(log[-1], self.TRUNCATED_LOG_MESSAGE) + log_itself = log[1:-1] self.assertEqual(len(log_itself), settings.STDOUT_STDERR_LOG_CUT_LENGTH) self.assertTrue(all(line == self.word_10_symbols for line in log_itself)) @@ -216,6 +218,7 @@ def test_job_log_detail_success(self): self.assertEqual(response.status_code, HTTP_200_OK) log = response.json()["content"].splitlines() self.assertEqual(log[0], self.TRUNCATED_LOG_MESSAGE) + self.assertEqual(log[-1], self.TRUNCATED_LOG_MESSAGE) expected_last_lines = [ "", expected_truncated_line, @@ -223,8 +226,8 @@ def test_job_log_detail_success(self): expected_truncated_line, "logline", ] - self.assertEqual(log[-5:], expected_last_lines) - main_log = log[1:-5] + self.assertEqual(log[-6:-1], expected_last_lines) + main_log = log[1:-6] self.assertEqual(len(main_log), settings.STDOUT_STDERR_LOG_CUT_LENGTH - 5) self.assertTrue(all(line == self.word_10_symbols for line in main_log)) @@ -241,15 +244,50 @@ def test_job_log_detail_success(self): log, f"{self.TRUNCATED_LOG_MESSAGE}\n" f"{self.long_one_liner_log.body[: settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH]}" + f"{self.TRUNCATED_LOG_MESSAGE}\n" f"{self.TRUNCATED_LOG_MESSAGE}\n", ) + def test_adcm_5212_retrieve_log_null_body_cut_success(self) -> None: + log_content = self.ansible_stdout_many_lines.body + self.ansible_stdout_many_lines.body = None + self.ansible_stdout_many_lines.save(update_fields=["body"]) + + with patch("api_v2.log_storage.serializers.extract_log_content_from_fs", return_value=log_content): + response = self.client.get( + path=reverse( + viewname="v2:log-detail", + kwargs={"job_pk": self.job_with_logs.pk, "pk": self.ansible_stdout_many_lines.pk}, + ) + ) + + self.assertEqual(response.status_code, HTTP_200_OK) + log = response.json()["content"].splitlines() + self.assertEqual(log[0], self.TRUNCATED_LOG_MESSAGE) + self.assertEqual(log[-1], self.TRUNCATED_LOG_MESSAGE) + log_itself = log[1:-1] + self.assertEqual(len(log_itself), settings.STDOUT_STDERR_LOG_CUT_LENGTH) + self.assertTrue(all(line == self.word_10_symbols for line in log_itself)) + def test_job_log_download_success(self): response: Response = self.client.get( path=reverse(viewname="v2:log-download", kwargs={"job_pk": self.job_1.pk, "pk": self.log_1.pk}) ) self.assertEqual(response.status_code, HTTP_200_OK) + def test_adcm_5212_job_log_download_full_success(self) -> None: + response: HttpResponse = self.client.get( + path=reverse( + viewname="v2:log-download", + kwargs={"job_pk": self.job_with_logs.pk, "pk": self.ansible_stdout_many_lines.pk}, + ) + ) + self.assertEqual(response.status_code, HTTP_200_OK) + + log = response.content.decode("utf-8") + self.assertNotIn(self.TRUNCATED_LOG_MESSAGE, log) + self.assertEqual(self.ansible_stdout_many_lines.body, log) + def test_job_log_not_found_download_fail(self): response: Response = self.client.get( path=reverse(viewname="v2:log-download", kwargs={"job_pk": self.job_1.pk, "pk": self.log_1.pk + 10}) diff --git a/python/cm/log.py b/python/cm/log.py new file mode 100644 index 0000000000..d3a41c2b04 --- /dev/null +++ b/python/cm/log.py @@ -0,0 +1,29 @@ +# Licensed 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. + +from pathlib import Path +from typing import Protocol + + +class BasicLogInfo(Protocol): + job_id: int + name: str + type: str + format: str + + +def extract_log_content_from_fs(jobs_dir: Path, log_info: BasicLogInfo) -> str | None: + logfile = jobs_dir / f"{log_info.job_id}" / f"{log_info.name}-{log_info.type}.{log_info.format}" + if logfile.exists(): + return logfile.read_text(encoding="utf-8") + + return None From f1e302a70effa7e717ed8098cd59cc51a2ef412d Mon Sep 17 00:00:00 2001 From: Dmitriy Bardin Date: Wed, 17 Jan 2024 11:45:36 +0000 Subject: [PATCH 039/151] ADCM-5214 - [UI] Update Storybook version https://tracker.yandex.ru/ADCM-5214 --- adcm-web/app/package.json | 18 +- adcm-web/app/yarn.lock | 7516 +++++++++++++++++++++---------------- 2 files changed, 4320 insertions(+), 3214 deletions(-) diff --git a/adcm-web/app/package.json b/adcm-web/app/package.json index 796837fa57..17bcc48067 100644 --- a/adcm-web/app/package.json +++ b/adcm-web/app/package.json @@ -42,14 +42,14 @@ "@babel/preset-env": "7.21.5", "@babel/preset-react": "7.18.6", "@babel/preset-typescript": "7.21.5", - "@storybook/addon-essentials": "7.0.12", - "@storybook/addon-interactions": "7.0.12", - "@storybook/addon-links": "7.0.12", - "@storybook/blocks": "7.0.12", - "@storybook/builder-vite": "7.0.12", - "@storybook/react": "7.0.12", - "@storybook/react-vite": "7.0.12", - "@storybook/testing-library": "0.0.14-next.2", + "@storybook/addon-essentials": "7.6.7", + "@storybook/addon-interactions": "7.6.7", + "@storybook/addon-links": "7.6.7", + "@storybook/blocks": "7.6.7", + "@storybook/builder-vite": "7.6.7", + "@storybook/react": "7.6.7", + "@storybook/react-vite": "7.6.7", + "@storybook/testing-library": "0.2.2", "@testing-library/dom": "9.3.0", "@testing-library/jest-dom": "5.16.5", "@testing-library/react": "14.0.0", @@ -82,7 +82,7 @@ "prettier": "2.8.8", "prop-types": "15.8.1", "sass": "1.62.1", - "storybook": "7.0.12", + "storybook": "7.6.7", "typescript": "5.0.2", "vite": "4.4.1", "vite-plugin-eslint": "1.8.1", diff --git a/adcm-web/app/yarn.lock b/adcm-web/app/yarn.lock index 45a6a4c12b..dd545331db 100644 --- a/adcm-web/app/yarn.lock +++ b/adcm-web/app/yarn.lock @@ -2,20 +2,20 @@ # Manual changes might be lost - proceed with caution! __metadata: - version: 8 - cacheKey: 10c0 + version: 6 + cacheKey: 8 "@aashutoshrathi/word-wrap@npm:^1.2.3": version: 1.2.6 resolution: "@aashutoshrathi/word-wrap@npm:1.2.6" - checksum: 53c2b231a61a46792b39a0d43bc4f4f776bb4542aa57ee04930676802e5501282c2fc8aac14e4cd1f1120ff8b52616b6ff5ab539ad30aa2277d726444b71619f + checksum: ada901b9e7c680d190f1d012c84217ce0063d8f5c5a7725bb91ec3c5ed99bb7572680eb2d2938a531ccbaec39a95422fcd8a6b4a13110c7d98dd75402f66a0cd languageName: node linkType: hard "@adobe/css-tools@npm:^4.0.1": version: 4.2.0 resolution: "@adobe/css-tools@npm:4.2.0" - checksum: b8dbfd9c54df73a398e9b20c922abe26c67732e16afc50668402af0e3d101409e0c944baf69bf814343eb8639014637b96f209426088b06943cea288c1ef1486 + checksum: dc5cc92ba3d562e7ffddb79d6d222c7e00b65f255fd2725b3d71490ff268844be322f917415d8c4ab39eca646343b632058db8bd5b1d646193fcc94d1d3e420b languageName: node linkType: hard @@ -25,18 +25,18 @@ __metadata: dependencies: "@jridgewell/gen-mapping": "npm:^0.3.0" "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 92ce5915f8901d8c7cd4f4e6e2fe7b9fd335a29955b400caa52e0e5b12ca3796ada7c2f10e78c9c5b0f9c2539dff0ffea7b19850a56e1487aa083531e1e46d43 + checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079 languageName: node linkType: hard -"@aw-web-design/x-default-browser@npm:1.4.88": - version: 1.4.88 - resolution: "@aw-web-design/x-default-browser@npm:1.4.88" +"@aw-web-design/x-default-browser@npm:1.4.126": + version: 1.4.126 + resolution: "@aw-web-design/x-default-browser@npm:1.4.126" dependencies: - default-browser-id: "npm:3.0.0" + default-browser-id: 3.0.0 bin: x-default-browser: bin/x-default-browser.js - checksum: ae604e01aeb226b48cad226bfce55a88a12d759d139ede20aa71ee9ed94fefe912659678ae663bb277d9c02f281f62a965bdc0adf43817b0f95d397cbf97d8b2 + checksum: f63b68a0ff41c8fe478b1b4822e169cac0d26c61b123c0400d5e16a8a5987732b85795aff16d6b21936f9c955f0d32bffbfc166890d3446f74a72a7a2c9633ea languageName: node linkType: hard @@ -45,18 +45,35 @@ __metadata: resolution: "@babel/code-frame@npm:7.22.5" dependencies: "@babel/highlight": "npm:^7.22.5" - checksum: 0b6c5eaf9e58be7140ac790b7bdf8148e8a24e26502dcaa50f157259c083b0584285748fd90d342ae311a5bb1eaad7835aec625296d2b46853464f9bd8991e28 + checksum: cfe804f518f53faaf9a1d3e0f9f74127ab9a004912c3a16fda07fb6a633393ecb9918a053cb71804204c1b7ec3d49e1699604715e2cfb0c9f7bc4933d324ebb6 languageName: node linkType: hard -"@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.21.5, @babel/compat-data@npm:^7.22.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9": +"@babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/code-frame@npm:7.23.5" + dependencies: + "@babel/highlight": ^7.23.4 + chalk: ^2.4.2 + checksum: d90981fdf56a2824a9b14d19a4c0e8db93633fd488c772624b4e83e0ceac6039a27cd298a247c3214faa952bf803ba23696172ae7e7235f3b97f43ba278c569a + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.21.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9": version: 7.22.9 resolution: "@babel/compat-data@npm:7.22.9" - checksum: 1334264b041f8ad4e33036326970c9c26754eb5c04b3af6c223fe6da988cbb8a8542b5526f49ec1ac488210d2f710484a0e4bcd30256294ae3f261d0141febad + checksum: bed77d9044ce948b4327b30dd0de0779fa9f3a7ed1f2d31638714ed00229fa71fc4d1617ae0eb1fad419338d3658d0e9a5a083297451e09e73e078d0347ff808 languageName: node linkType: hard -"@babel/core@npm:7.21.8, @babel/core@npm:~7.21.0": +"@babel/compat-data@npm:^7.23.3, @babel/compat-data@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/compat-data@npm:7.23.5" + checksum: 06ce244cda5763295a0ea924728c09bae57d35713b675175227278896946f922a63edf803c322f855a3878323d48d0255a2a3023409d2a123483c8a69ebb4744 + languageName: node + linkType: hard + +"@babel/core@npm:7.21.8": version: 7.21.8 resolution: "@babel/core@npm:7.21.8" dependencies: @@ -75,11 +92,11 @@ __metadata: gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.2" semver: "npm:^6.3.0" - checksum: bf6bb92bd78fb8b6628bb0612ac0915407b996b179e1404108f92ed32972978340b4457b08f2abf86390a58fb51815cab419edb2dbbc8846efc39eaa61b8cde3 + checksum: f28118447355af2a90bd340e2e60699f94c8020517eba9b71bf8ebff62fa9e00d63f076e033f9dfb97548053ad62ada45fafb0d96584b1a90e8aef5a3b8241b1 languageName: node linkType: hard -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.10, @babel/core@npm:^7.12.3, @babel/core@npm:^7.13.16, @babel/core@npm:^7.20.12, @babel/core@npm:^7.20.2, @babel/core@npm:^7.21.3, @babel/core@npm:^7.21.4, @babel/core@npm:^7.7.5": +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.20.12, @babel/core@npm:^7.21.3, @babel/core@npm:^7.21.4": version: 7.22.9 resolution: "@babel/core@npm:7.22.9" dependencies: @@ -98,11 +115,34 @@ __metadata: gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.2" semver: "npm:^6.3.1" - checksum: 4dffc8844bd8ab5c292e795f3eb0e636246177d28b75ec99f3349a29fe08a9f3e089fe68b857ed160f3312c035c8fb73fdc83b0c781f4629164e548a7d62a8c7 + checksum: 7bf069aeceb417902c4efdaefab1f7b94adb7dea694a9aed1bda2edf4135348a080820529b1a300c6f8605740a00ca00c19b2d5e74b5dd489d99d8c11d5e56d1 + languageName: node + linkType: hard + +"@babel/core@npm:^7.18.9, @babel/core@npm:^7.23.0, @babel/core@npm:^7.23.2": + version: 7.23.7 + resolution: "@babel/core@npm:7.23.7" + dependencies: + "@ampproject/remapping": ^2.2.0 + "@babel/code-frame": ^7.23.5 + "@babel/generator": ^7.23.6 + "@babel/helper-compilation-targets": ^7.23.6 + "@babel/helper-module-transforms": ^7.23.3 + "@babel/helpers": ^7.23.7 + "@babel/parser": ^7.23.6 + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.23.7 + "@babel/types": ^7.23.6 + convert-source-map: ^2.0.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.3 + semver: ^6.3.1 + checksum: 32d5bf73372a47429afaae9adb0af39e47bcea6a831c4b5dcbb4791380cda6949cb8cb1a2fea8b60bb1ebe189209c80e333903df1fa8e9dcb04798c0ce5bf59e languageName: node linkType: hard -"@babel/generator@npm:^7.12.11, @babel/generator@npm:^7.21.5, @babel/generator@npm:^7.22.7, @babel/generator@npm:^7.22.9, @babel/generator@npm:^7.7.2": +"@babel/generator@npm:^7.21.5, @babel/generator@npm:^7.22.7, @babel/generator@npm:^7.22.9, @babel/generator@npm:^7.7.2": version: 7.22.9 resolution: "@babel/generator@npm:7.22.9" dependencies: @@ -110,19 +150,19 @@ __metadata: "@jridgewell/gen-mapping": "npm:^0.3.2" "@jridgewell/trace-mapping": "npm:^0.3.17" jsesc: "npm:^2.5.1" - checksum: 6ef82c7f6dc8f749c0eb3a04fe35acab032a9221d82984e67cbbada449ca857dd981e08c129f9cf5d2f342ba00efcc683a99e46a470f233b0948edf197e35d26 + checksum: 7c9d2c58b8d5ac5e047421a6ab03ec2ff5d9a5ff2c2212130a0055e063ac349e0b19d435537d6886c999771aef394832e4f54cd9fc810100a7f23d982f6af06b languageName: node linkType: hard -"@babel/generator@npm:~7.21.1": - version: 7.21.9 - resolution: "@babel/generator@npm:7.21.9" +"@babel/generator@npm:^7.23.0, @babel/generator@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/generator@npm:7.23.6" dependencies: - "@babel/types": "npm:^7.21.5" - "@jridgewell/gen-mapping": "npm:^0.3.2" - "@jridgewell/trace-mapping": "npm:^0.3.17" - jsesc: "npm:^2.5.1" - checksum: cba1e31004c7ee1a94cbcf48215a99f802a4bf52f690865ac7efce54984e8896dbeb0365788ff61da849d222d1abdbbff72ce13ab7f4ab9f6702001b0b72eddd + "@babel/types": ^7.23.6 + "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 + jsesc: ^2.5.1 + checksum: 1a1a1c4eac210f174cd108d479464d053930a812798e09fee069377de39a893422df5b5b146199ead7239ae6d3a04697b45fc9ac6e38e0f6b76374390f91fc6c languageName: node linkType: hard @@ -131,7 +171,16 @@ __metadata: resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: 5a80dc364ddda26b334bbbc0f6426cab647381555ef7d0cd32eb284e35b867c012ce6ce7d52a64672ed71383099c99d32765b3d260626527bb0e3470b0f58e45 + checksum: 53da330f1835c46f26b7bf4da31f7a496dee9fd8696cca12366b94ba19d97421ce519a74a837f687749318f94d1a37f8d1abcbf35e8ed22c32d16373b2f6198d + languageName: node + linkType: hard + +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.15" + dependencies: + "@babel/types": ^7.22.15 + checksum: 639c697a1c729f9fafa2dd4c9af2e18568190299b5907bd4c2d0bc818fcbd1e83ffeecc2af24327a7faa7ac4c34edd9d7940510a5e66296c19bad17001cf5c7a languageName: node linkType: hard @@ -140,7 +189,7 @@ __metadata: resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: 73a61a56364849770d5569264ba0a5f06035387cafd219d1ae26077f80a1dfb75f240e6abcd991c655641ad8fe066b964261942b4086ba2efc946c807c9d1698 + checksum: d753acac62399fc6dd354cf1b9441bde0c331c2fe792a4c14904c5e5eafc3cac79478f6aa038e8a51c1148b0af6710a2e619855e4b5d54497ac972eaffed5884 languageName: node linkType: hard @@ -155,7 +204,20 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 543b9a45800c1db2f91cc53462ed1799834a1259e498d3d91f45816ae79d19719ef957fa00b0f015d8b768eac09fd1f4f5f42f868c5a10f4389e3883a3f050f1 + checksum: ea0006c6a93759025f4a35a25228ae260538c9f15023e8aac2a6d45ca68aef4cf86cfc429b19af9a402cbdd54d5de74ad3fbcf6baa7e48184dc079f1a791e178 + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/helper-compilation-targets@npm:7.23.6" + dependencies: + "@babel/compat-data": ^7.23.5 + "@babel/helper-validator-option": ^7.23.5 + browserslist: ^4.22.2 + lru-cache: ^5.1.1 + semver: ^6.3.1 + checksum: c630b98d4527ac8fe2c58d9a06e785dfb2b73ec71b7c4f2ddf90f814b5f75b547f3c015f110a010fd31f76e3864daaf09f3adcd2f6acdbfb18a8de3a48717590 languageName: node linkType: hard @@ -174,7 +236,26 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: f383152992996b0b936e555aaef35264852908720216c298f677f4b53ba3c4325b700c6a62ff08a8e1377d76ed6538e1bd5232557266eae777cc06b7eb3dd4ad + checksum: 6c2436d1a5a3f1ff24628d78fa8c6d3120c40285aa3eda7815b1adbf8c5951e0dd73d368cf845825888fa3dc2f207dadce53309825598d7c67953e5ed9dd51d2 + languageName: node + linkType: hard + +"@babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.23.6": + version: 7.23.7 + resolution: "@babel/helper-create-class-features-plugin@npm:7.23.7" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-member-expression-to-functions": ^7.23.0 + "@babel/helper-optimise-call-expression": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.20 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 33e60714b856c3816a7965d4c76278cc8f430644a2dfc4eeafad2f7167c4fbd2becdb74cbfeb04b02efd6bbd07176ef53c6683262b588e65d378438e9c55c26b languageName: node linkType: hard @@ -187,7 +268,20 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 056c9913299ba399194d9aef5f4281a81806f66979c3c9c6da19b2e29bc92abad6d6d6be0cd4b3ed5945abbdf2d4c45362ee26a012f75f16de7d26859dfde11d + checksum: 87cb48a7ee898ab205374274364c3adc70b87b08c7bd07f51019ae4562c0170d7148e654d591f825dee14b5fe11666a0e7966872dfdbfa0d1b94b861ecf0e4e1 + languageName: node + linkType: hard + +"@babel/helper-create-regexp-features-plugin@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + regexpu-core: ^5.3.1 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 0243b8d4854f1dc8861b1029a46d3f6393ad72f366a5a08e36a4648aa682044f06da4c6e87a456260e1e1b33c999f898ba591a0760842c1387bcc93fbf2151a6 languageName: node linkType: hard @@ -203,48 +297,74 @@ __metadata: semver: "npm:^6.1.2" peerDependencies: "@babel/core": ^7.4.0-0 - checksum: c3668f9ee2b76bfc08398756c504a8823e18bad05d0c2ee039b821c839e2b70f3b6ad8b7a3d3a6be434d981ed2af845a490aafecc50eaefb9b5099f2da156527 + checksum: 8e3fe75513302e34f6d92bd67b53890e8545e6c5bca8fe757b9979f09d68d7e259f6daea90dc9e01e332c4f8781bda31c5fe551c82a277f9bc0bec007aed497c languageName: node linkType: hard -"@babel/helper-define-polyfill-provider@npm:^0.4.1": - version: 0.4.1 - resolution: "@babel/helper-define-polyfill-provider@npm:0.4.1" +"@babel/helper-define-polyfill-provider@npm:^0.4.4": + version: 0.4.4 + resolution: "@babel/helper-define-polyfill-provider@npm:0.4.4" dependencies: - "@babel/helper-compilation-targets": "npm:^7.22.6" - "@babel/helper-plugin-utils": "npm:^7.22.5" - debug: "npm:^4.1.1" - lodash.debounce: "npm:^4.0.8" - resolve: "npm:^1.14.2" + "@babel/helper-compilation-targets": ^7.22.6 + "@babel/helper-plugin-utils": ^7.22.5 + debug: ^4.1.1 + lodash.debounce: ^4.0.8 + resolve: ^1.14.2 peerDependencies: - "@babel/core": ^7.4.0-0 - checksum: 402a8ca29354f01640d7226587576479507093437239ec1ba283c190986442a8759e5043859df9795c07c43d9b99d0685ee36ff77974c5be9a0cbec36a8283af + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 2453cdd79f18a4cb8653d8a7e06b2eb0d8e31bae0d35070fc5abadbddca246a36d82b758064b421cca49b48d0e696d331d54520ba8582c1d61fb706d6d831817 languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.18.9, @babel/helper-environment-visitor@npm:^7.21.5, @babel/helper-environment-visitor@npm:^7.22.5": +"@babel/helper-environment-visitor@npm:^7.18.9, @babel/helper-environment-visitor@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-environment-visitor@npm:7.22.5" - checksum: c9377464c1839741a0a77bbad56de94c896f4313eb034c988fc2ab01293e7c4027244c93b4256606c5f4e34c68cf599a7d31a548d537577c7da836bbca40551b + checksum: 248532077d732a34cd0844eb7b078ff917c3a8ec81a7f133593f71a860a582f05b60f818dc5049c2212e5baa12289c27889a4b81d56ef409b4863db49646c4b1 + languageName: node + linkType: hard + +"@babel/helper-environment-visitor@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.21.0, @babel/helper-function-name@npm:^7.22.5": +"@babel/helper-function-name@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-function-name@npm:7.22.5" dependencies: "@babel/template": "npm:^7.22.5" "@babel/types": "npm:^7.22.5" - checksum: 3ce2e87967fe54aa463d279150ddda0dae3b5bc3f8c2773b90670b553b61e8fe62da7edcd7b1e1891c5b25af4924a6700dad2e9d8249b910a5bf7caa2eaf4c13 + checksum: 6b1f6ce1b1f4e513bf2c8385a557ea0dd7fa37971b9002ad19268ca4384bbe90c09681fe4c076013f33deabc63a53b341ed91e792de741b4b35e01c00238177a + languageName: node + linkType: hard + +"@babel/helper-function-name@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-function-name@npm:7.23.0" + dependencies: + "@babel/template": ^7.22.15 + "@babel/types": ^7.23.0 + checksum: e44542257b2d4634a1f979244eb2a4ad8e6d75eb6761b4cfceb56b562f7db150d134bc538c8e6adca3783e3bc31be949071527aa8e3aab7867d1ad2d84a26e10 languageName: node linkType: hard -"@babel/helper-hoist-variables@npm:^7.18.6, @babel/helper-hoist-variables@npm:^7.22.5": +"@babel/helper-hoist-variables@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-hoist-variables@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: 60a3077f756a1cd9f14eb89f0037f487d81ede2b7cfe652ea6869cd4ec4c782b0fb1de01b8494b9a2d2050e3d154d7d5ad3be24806790acfb8cbe2073bf1e208 + checksum: 394ca191b4ac908a76e7c50ab52102669efe3a1c277033e49467913c7ed6f7c64d7eacbeabf3bed39ea1f41731e22993f763b1edce0f74ff8563fd1f380d92cc + languageName: node + linkType: hard + +"@babel/helper-member-expression-to-functions@npm:^7.22.15, @babel/helper-member-expression-to-functions@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" + dependencies: + "@babel/types": ^7.23.0 + checksum: 494659361370c979ada711ca685e2efe9460683c36db1b283b446122596602c901e291e09f2f980ecedfe6e0f2bd5386cb59768285446530df10c14df1024e75 languageName: node linkType: hard @@ -253,7 +373,16 @@ __metadata: resolution: "@babel/helper-member-expression-to-functions@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: c04a71976b2508c6f1fa46562439b74970cea37958e450bcd59363b9c62ac49fb8e3cef544b08264b1d710b3f36214486cb7e1102e4f1ee8e1c2878b5eebcc75 + checksum: 4bd5791529c280c00743e8bdc669ef0d4cd1620d6e3d35e0d42b862f8262bc2364973e5968007f960780344c539a4b9cf92ab41f5b4f94560a9620f536de2a39 + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-module-imports@npm:7.22.15" + dependencies: + "@babel/types": ^7.22.15 + checksum: ecd7e457df0a46f889228f943ef9b4a47d485d82e030676767e6a2fdcbdaa63594d8124d4b55fd160b41c201025aec01fc27580352b1c87a37c9c6f33d116702 languageName: node linkType: hard @@ -262,7 +391,7 @@ __metadata: resolution: "@babel/helper-module-imports@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: 04f8c0586c485c33017c63e0fc5fc16bd33b883cef3c88e4b3a8bf7bc807b3f9a7bcb9372fbcc01c0a539a5d1cdb477e7bdec77e250669edab00f796683b6b07 + checksum: 9ac2b0404fa38b80bdf2653fbeaf8e8a43ccb41bd505f9741d820ed95d3c4e037c62a1bcdcb6c9527d7798d2e595924c4d025daed73283badc180ada2c9c49ad languageName: node linkType: hard @@ -277,7 +406,22 @@ __metadata: "@babel/helper-validator-identifier": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: 1844dc2c9049552d13d40385cb196704a754feab60ef8c370a5e1c431a4f64b0ddd7bb1dddaa5c98288cafd5c08cd4d8e6d5aba9a11e1133b8b999ab7c9defd1 + checksum: 2751f77660518cf4ff027514d6f4794f04598c6393be7b04b8e46c6e21606e11c19f3f57ab6129a9c21bacdf8b3ffe3af87bb401d972f34af2d0ffde02ac3001 + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/helper-module-transforms@npm:7.23.3" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-simple-access": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/helper-validator-identifier": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 5d0895cfba0e16ae16f3aa92fee108517023ad89a855289c4eb1d46f7aef4519adf8e6f971e1d55ac20c5461610e17213f1144097a8f932e768a9132e2278d71 languageName: node linkType: hard @@ -286,14 +430,14 @@ __metadata: resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: 31b41a764fc3c585196cf5b776b70cf4705c132e4ce9723f39871f215f2ddbfb2e28a62f9917610f67c8216c1080482b9b05f65dd195dae2a52cef461f2ac7b8 + checksum: c70ef6cc6b6ed32eeeec4482127e8be5451d0e5282d5495d5d569d39eb04d7f1d66ec99b327f45d1d5842a9ad8c22d48567e93fc502003a47de78d122e355f7c languageName: node linkType: hard "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.16.7, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.18.9, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.21.5, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": version: 7.22.5 resolution: "@babel/helper-plugin-utils@npm:7.22.5" - checksum: d2c4bfe2fa91058bcdee4f4e57a3f4933aed7af843acfd169cd6179fab8d13c1d636474ecabb2af107dc77462c7e893199aa26632bac1c6d7e025a17cbb9d20d + checksum: c0fc7227076b6041acd2f0e818145d2e8c41968cc52fb5ca70eed48e21b8fe6dd88a0a91cbddf4951e33647336eb5ae184747ca706817ca3bef5e9e905151ff5 languageName: node linkType: hard @@ -306,7 +450,33 @@ __metadata: "@babel/helper-wrap-function": "npm:^7.22.9" peerDependencies: "@babel/core": ^7.0.0 - checksum: e753f19726846df26a13a304632aff2bc6e437201f27eecc7ba12db04b9175062da307e72512cf4761e659ec82cb71016352acd83fbe5e527f4b881ce1e633e8 + checksum: 05538079447829b13512157491cc77f9cf1ea7e1680e15cff0682c3ed9ee162de0c4862ece20a6d6b2df28177a1520bcfe45993fbeccf2747a81795a7c3f6290 + languageName: node + linkType: hard + +"@babel/helper-remap-async-to-generator@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-wrap-function": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 2fe6300a6f1b58211dffa0aed1b45d4958506d096543663dba83bd9251fe8d670fa909143a65b45e72acb49e7e20fbdb73eae315d9ddaced467948c3329986e7 + languageName: node + linkType: hard + +"@babel/helper-replace-supers@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-replace-supers@npm:7.22.20" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-member-expression-to-functions": ^7.22.15 + "@babel/helper-optimise-call-expression": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a0008332e24daedea2e9498733e3c39b389d6d4512637e000f96f62b797e702ee24a407ccbcd7a236a551590a38f31282829a8ef35c50a3c0457d88218cae639 languageName: node linkType: hard @@ -319,7 +489,7 @@ __metadata: "@babel/helper-optimise-call-expression": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: 9ef42e0d1f81d3377c96449c82666d54daea86db9f352915d2aff7540008cd65f23574bc97a74308b6203f7a8c6bf886d1cc1fa24917337d3d12ea93cb2a53a8 + checksum: d41471f56ff2616459d35a5df1900d5f0756ae78b1027040365325ef332d66e08e3be02a9489756d870887585ff222403a228546e93dd7019e19e59c0c0fe586 languageName: node linkType: hard @@ -328,7 +498,7 @@ __metadata: resolution: "@babel/helper-simple-access@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: f0cf81a30ba3d09a625fd50e5a9069e575c5b6719234e04ee74247057f8104beca89ed03e9217b6e9b0493434cedc18c5ecca4cea6244990836f1f893e140369 + checksum: fe9686714caf7d70aedb46c3cce090f8b915b206e09225f1e4dbc416786c2fdbbee40b38b23c268b7ccef749dd2db35f255338fb4f2444429874d900dede5ad2 languageName: node linkType: hard @@ -337,37 +507,69 @@ __metadata: resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: ab7fa2aa709ab49bb8cd86515a1e715a3108c4bb9a616965ba76b43dc346dee66d1004ccf4d222b596b6224e43e04cbc5c3a34459501b388451f8c589fbc3691 + checksum: 1012ef2295eb12dc073f2b9edf3425661e9b8432a3387e62a8bc27c42963f1f216ab3124228015c748770b2257b4f1fda882ca8fa34c0bf485e929ae5bc45244 languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:^7.18.6, @babel/helper-split-export-declaration@npm:^7.22.6": +"@babel/helper-split-export-declaration@npm:^7.22.6": version: 7.22.6 resolution: "@babel/helper-split-export-declaration@npm:7.22.6" dependencies: "@babel/types": "npm:^7.22.5" - checksum: d83e4b623eaa9622c267d3c83583b72f3aac567dc393dda18e559d79187961cb29ae9c57b2664137fc3d19508370b12ec6a81d28af73a50e0846819cb21c6e44 + checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.21.5, @babel/helper-string-parser@npm:^7.22.5": +"@babel/helper-string-parser@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-string-parser@npm:7.22.5" - checksum: 6b0ff8af724377ec41e5587fffa7605198da74cb8e7d8d48a36826df0c0ba210eb9fedb3d9bef4d541156e0bd11040f021945a6cbb731ccec4aefb4affa17aa4 + checksum: 836851ca5ec813077bbb303acc992d75a360267aa3b5de7134d220411c852a6f17de7c0d0b8c8dcc0f567f67874c00f4528672b2a4f1bc978a3ada64c8c78467 + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/helper-string-parser@npm:7.23.4" + checksum: c0641144cf1a7e7dc93f3d5f16d5327465b6cf5d036b48be61ecba41e1eece161b48f46b7f960951b67f8c3533ce506b16dece576baef4d8b3b49f8c65410f90 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.19.1, @babel/helper-validator-identifier@npm:^7.22.5": +"@babel/helper-validator-identifier@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-validator-identifier@npm:7.22.5" - checksum: 2ff1d3833154d17ccf773b8a71fdc0cd0e7356aa8033179d0e3133787dfb33d97796cbff8b92a97c56268205337dfc720227aeddc677c1bc08ae1b67a95252d7 + checksum: 7f0f30113474a28298c12161763b49de5018732290ca4de13cdaefd4fd0d635a6fe3f6686c37a02905fb1e64f21a5ee2b55140cf7b070e729f1bd66866506aea languageName: node linkType: hard "@babel/helper-validator-option@npm:^7.18.6, @babel/helper-validator-option@npm:^7.21.0, @babel/helper-validator-option@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-validator-option@npm:7.22.5" - checksum: 23e310bf1b90d085b1ae250f31d423fb6cc004da882f0d3409266e5e4c7fd41ed0a172283a6a9a16083c5f2e11f987b32c815c80c60d9a948e23dd6dcf2e0437 + checksum: bbeca8a85ee86990215c0424997438b388b8d642d69b9f86c375a174d3cdeb270efafd1ff128bc7a1d370923d13b6e45829ba8581c027620e83e3a80c5c414b3 + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.22.15, @babel/helper-validator-option@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/helper-validator-option@npm:7.23.5" + checksum: 537cde2330a8aede223552510e8a13e9c1c8798afee3757995a7d4acae564124fe2bf7e7c3d90d62d3657434a74340a274b3b3b1c6f17e9a2be1f48af29cb09e + languageName: node + linkType: hard + +"@babel/helper-wrap-function@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-wrap-function@npm:7.22.20" + dependencies: + "@babel/helper-function-name": ^7.22.5 + "@babel/template": ^7.22.15 + "@babel/types": ^7.22.19 + checksum: 221ed9b5572612aeb571e4ce6a256f2dee85b3c9536f1dd5e611b0255e5f59a3d0ec392d8d46d4152149156a8109f92f20379b1d6d36abb613176e0e33f05fca languageName: node linkType: hard @@ -378,7 +580,7 @@ __metadata: "@babel/helper-function-name": "npm:^7.22.5" "@babel/template": "npm:^7.22.5" "@babel/types": "npm:^7.22.5" - checksum: 233c10fe3b38efbf8fcf9bcda8b45b998e963d352beb1966012f4b0be8c221776546a999190c77f0a43524b35c0271691453baf71fe2772fcf7f7938d3621b0d + checksum: 037317dc06dac6593e388738ae1d3e43193bc1d31698f067c0ef3d4dc6f074dbed860ed42aa137b48a67aa7cb87336826c4bdc13189260481bcf67eb7256c789 languageName: node linkType: hard @@ -389,7 +591,18 @@ __metadata: "@babel/template": "npm:^7.22.5" "@babel/traverse": "npm:^7.22.6" "@babel/types": "npm:^7.22.5" - checksum: 8c03c19802d0fcc78d00d1eaa9ddab28f97f0c78a5d570762800e86f08c6f41750ad61e20cdede977a56173edf85e7175f1fd804eb6ef817280f064d3a3ca514 + checksum: 5c1f33241fe7bf7709868c2105134a0a86dca26a0fbd508af10a89312b1f77ca38ebae43e50be3b208613c5eacca1559618af4ca236f0abc55d294800faeff30 + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.23.7": + version: 7.23.8 + resolution: "@babel/helpers@npm:7.23.8" + dependencies: + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.23.7 + "@babel/types": ^7.23.6 + checksum: 8b522d527921f8df45a983dc7b8e790c021250addf81ba7900ba016e165442a527348f6f877aa55e1debb3eef9e860a334b4e8d834e6c9b438ed61a63d9a7ad4 languageName: node linkType: hard @@ -400,40 +613,62 @@ __metadata: "@babel/helper-validator-identifier": "npm:^7.22.5" chalk: "npm:^2.0.0" js-tokens: "npm:^4.0.0" - checksum: e8cc07b5de76a9bf779982096ccbbe5a867c36d3786b26151eb570d9344a68af8aa065ed97d431e0d18ba55fe792c7c4301e0d62afff7a52ee0d20678443be54 + checksum: f61ae6de6ee0ea8d9b5bcf2a532faec5ab0a1dc0f7c640e5047fc61630a0edb88b18d8c92eb06566d30da7a27db841aca11820ecd3ebe9ce514c9350fbed39c4 + languageName: node + linkType: hard + +"@babel/highlight@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/highlight@npm:7.23.4" + dependencies: + "@babel/helper-validator-identifier": ^7.22.20 + chalk: ^2.4.2 + js-tokens: ^4.0.0 + checksum: 643acecdc235f87d925979a979b539a5d7d1f31ae7db8d89047269082694122d11aa85351304c9c978ceeb6d250591ccadb06c366f358ccee08bb9c122476b89 languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.5, @babel/parser@npm:^7.21.8, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.22.7": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.8, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.22.7": version: 7.22.7 resolution: "@babel/parser@npm:7.22.7" bin: parser: ./bin/babel-parser.js - checksum: d2bdf212644c39de58f1216540ec5aca4a05ffbec07c904eaaef8575dd9546b55345b91dcc0d306be4adbb717401ce321027bac7e2f7babfd66794c96243bb79 + checksum: 02209ddbd445831ee8bf966fdf7c29d189ed4b14343a68eb2479d940e7e3846340d7cc6bd654a5f3d87d19dc84f49f50a58cf9363bee249dc5409ff3ba3dab54 languageName: node linkType: hard -"@babel/parser@npm:~7.21.2": - version: 7.21.9 - resolution: "@babel/parser@npm:7.21.9" +"@babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/parser@npm:7.23.6" bin: parser: ./bin/babel-parser.js - checksum: 1a1895932eeec199ac80acca6f63ac2221843156c9cb8b870e4ecabb0d5d61ee60f109bb49d391d1be7e877042df912c2d51619d728f80f658a4d5bf41ecb364 + checksum: 140801c43731a6c41fd193f5c02bc71fd647a0360ca616b23d2db8be4b9739b9f951a03fc7c2db4f9b9214f4b27c1074db0f18bc3fa653783082d5af7c8860d5 languageName: node linkType: hard -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6, @babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.22.5": +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6": version: 7.22.5 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: 573bd9b1984d74e3663cb7f5f317646223020107681e8dcffe68b041bd620ebbb35c0cc05f4ee20f2da502d02a9633e2b477596e71f4f7802f72c02e948f38af + checksum: 1e353a060fb2cd8f1256d28cd768f16fb02513f905b9b6d656fb0242c96c341a196fa188b27c2701506a6e27515359fbcc1a5ca7fa8b9b530cf88fbd137baefc + languageName: node + linkType: hard + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: ddbaf2c396b7780f15e80ee01d6dd790db076985f3dfeb6527d1a8d4cacf370e49250396a3aa005b2c40233cac214a106232f83703d5e8491848bde273938232 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.20.7, @babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.22.5": +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.20.7": version: 7.22.5 resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.22.5" dependencies: @@ -442,7 +677,32 @@ __metadata: "@babel/plugin-transform-optional-chaining": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.13.0 - checksum: 1e38dcd28d2dc5012f96550a3fa1330d71fc923607ceccc91e83c0b7dd3eaeb4d8c632946909c389964acb3e35c888f81653e2d24f7cc02a83fe39a64ca59e89 + checksum: 16e7a5f3bf2f2ac0ca032a70bf0ebd7e886d84dbb712b55c0643c04c495f0f221fbcbca14b5f8f8027fa6c87a3dafae0934022ad2b409384af6c5c356495b7bd + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/plugin-transform-optional-chaining": ^7.23.3 + peerDependencies: + "@babel/core": ^7.13.0 + checksum: 434b9d710ae856fa1a456678cc304fbc93915af86d581ee316e077af746a709a741ea39d7e1d4f5b98861b629cc7e87f002d3138f5e836775632466d4c74aef2 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.23.7": + version: 7.23.7 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.23.7" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: f88e400b548202a6f8c5dfd25bc4949a13ea1ccb64a170d7dea4deaa655a0fcb001d3fd61c35e1ad9c09a3d5f0d43f783400425471fe6d660ccaf33dabea9aba languageName: node linkType: hard @@ -456,11 +716,11 @@ __metadata: "@babel/plugin-syntax-async-generators": "npm:^7.8.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 0f4bc01805704ae4840536acc9888c50a32250e9188d025063bd17fe77ed171a12361c3dc83ce99664dcd73aec612accb8da95b0d8b825c854931b2860c0bfb5 + checksum: 111109ee118c9e69982f08d5e119eab04190b36a0f40e22e873802d941956eee66d2aa5a15f5321e51e3f9aa70a91136451b987fe15185ef8cc547ac88937723 languageName: node linkType: hard -"@babel/plugin-proposal-class-properties@npm:^7.13.0, @babel/plugin-proposal-class-properties@npm:^7.18.6": +"@babel/plugin-proposal-class-properties@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" dependencies: @@ -468,7 +728,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.18.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d5172ac6c9948cdfc387e94f3493ad86cb04035cf7433f86b5d358270b1b9752dc25e176db0c5d65892a246aca7bdb4636672e15626d7a7de4bc0bd0040168d9 + checksum: 49a78a2773ec0db56e915d9797e44fd079ab8a9b2e1716e0df07c92532f2c65d76aeda9543883916b8e0ff13606afeffa67c5b93d05b607bc87653ad18a91422 languageName: node linkType: hard @@ -481,7 +741,7 @@ __metadata: "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.12.0 - checksum: b46eb08badd7943c7bdf06fa6f1bb171e00f26d3c25e912205f735ccc321d1dbe8d023d97491320017e0e5d083b7aab3104f5a661535597d278a6c833c97eb79 + checksum: 236c0ad089e7a7acab776cc1d355330193314bfcd62e94e78f2df35817c6144d7e0e0368976778afd6b7c13e70b5068fa84d7abbf967d4f182e60d03f9ef802b languageName: node linkType: hard @@ -493,7 +753,7 @@ __metadata: "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 99be9865edfd65a46afb97d877ea247a8e881b4d0246a1ea0adf6db04c92f4f0959bd2f6f706d73248a2a7167c34f2464c4863137ddb94deadc5c7cc8bfc3e72 + checksum: 96b1c8a8ad8171d39e9ab106be33bde37ae09b22fb2c449afee9a5edf3c537933d79d963dcdc2694d10677cb96da739cdf1b53454e6a5deab9801f28a818bb2f languageName: node linkType: hard @@ -505,7 +765,7 @@ __metadata: "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b90346bd3628ebd44138d0628a5aba1e6b11748893fb48e87008cac30f3bc7cd3161362e49433156737350318174164436357a66fbbfdbe952606b460bd8a0e4 + checksum: 84ff22bacc5d30918a849bfb7e0e90ae4c5b8d8b65f2ac881803d1cf9068dffbe53bd657b0e4bc4c20b4db301b1c85f1e74183cf29a0dd31e964bd4e97c363ef languageName: node linkType: hard @@ -517,7 +777,7 @@ __metadata: "@babel/plugin-syntax-json-strings": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 83f2ce41262a538ee43450044b9b0de320002473e4849421a7318c0500f9b0385c03d228f1be777ad71fd358aef13392e3551f0be52b5c423b0c34f7c9e5a06d + checksum: 25ba0e6b9d6115174f51f7c6787e96214c90dd4026e266976b248a2ed417fe50fddae72843ffb3cbe324014a18632ce5648dfac77f089da858022b49fd608cb3 languageName: node linkType: hard @@ -529,11 +789,11 @@ __metadata: "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 436c1ee9f983813fc52788980a7231414351bd34d80b16b83bddb09115386292fe4912cc6d172304eabbaf0c4813625331b9b5bc798acb0e8925cf0d2b394d4d + checksum: cdd7b8136cc4db3f47714d5266f9e7b592a2ac5a94a5878787ce08890e97c8ab1ca8e94b27bfeba7b0f2b1549a026d9fc414ca2196de603df36fb32633bbdc19 languageName: node linkType: hard -"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.13.8, @babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6": +"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" dependencies: @@ -541,7 +801,7 @@ __metadata: "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f6629158196ee9f16295d16db75825092ef543f8b98f4dfdd516e642a0430c7b1d69319ee676d35485d9b86a53ade6de0b883490d44de6d4336d38cdeccbe0bf + checksum: 949c9ddcdecdaec766ee610ef98f965f928ccc0361dd87cf9f88cf4896a6ccd62fce063d4494778e50da99dea63d270a1be574a62d6ab81cbe9d85884bf55a7d languageName: node linkType: hard @@ -553,7 +813,7 @@ __metadata: "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: a83a65c6ec0d2293d830e9db61406d246f22d8ea03583d68460cb1b6330c6699320acce1b45f66ba3c357830720e49267e3d99f95088be457c66e6450fbfe3fa + checksum: f370ea584c55bf4040e1f78c80b4eeb1ce2e6aaa74f87d1a48266493c33931d0b6222d8cee3a082383d6bb648ab8d6b7147a06f974d3296ef3bc39c7851683ec languageName: node linkType: hard @@ -568,7 +828,7 @@ __metadata: "@babel/plugin-transform-parameters": "npm:^7.20.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b9818749bb49d8095df64c45db682448d04743d96722984cbfd375733b2585c26d807f84b4fdb28474f2d614be6a6ffe3d96ffb121840e9e5345b2ccc0438bd8 + checksum: 1329db17009964bc644484c660eab717cb3ca63ac0ab0f67c651a028d1bc2ead51dc4064caea283e46994f1b7221670a35cbc0b4beb6273f55e915494b5aa0b2 languageName: node linkType: hard @@ -580,11 +840,11 @@ __metadata: "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ab20153d9e95e0b73004fdf86b6a2d219be2a0ace9ca76cd9eccddb680c913fec173bca54d761b1bc6044edde0a53811f3e515908c3b16d2d81cfec1e2e17391 + checksum: 7b5b39fb5d8d6d14faad6cb68ece5eeb2fd550fb66b5af7d7582402f974f5bc3684641f7c192a5a57e0f59acfae4aada6786be1eba030881ddc590666eff4d1e languageName: node linkType: hard -"@babel/plugin-proposal-optional-chaining@npm:^7.13.12, @babel/plugin-proposal-optional-chaining@npm:^7.21.0": +"@babel/plugin-proposal-optional-chaining@npm:^7.21.0": version: 7.21.0 resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" dependencies: @@ -593,7 +853,7 @@ __metadata: "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b524a61b1de3f3ad287cd1e98c2a7f662178d21cd02205b0d615512e475f0159fa1b569fa7e34c8ed67baef689c0136fa20ba7d1bf058d186d30736a581a723f + checksum: 11c5449e01b18bb8881e8e005a577fa7be2fe5688e2382c8822d51f8f7005342a301a46af7b273b1f5645f9a7b894c428eee8526342038a275ef6ba4c8d8d746 languageName: node linkType: hard @@ -605,7 +865,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.18.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1c273d0ec3d49d0fe80bd754ec0191016e5b3ab4fb1e162ac0c014e9d3c1517a5d973afbf8b6dc9f9c98a8605c79e5f9e8b5ee158a4313fa68d1ff7b02084b6a + checksum: 22d8502ee96bca99ad2c8393e8493e2b8d4507576dd054490fd8201a36824373440106f5b098b6d821b026c7e72b0424ff4aeca69ed5f42e48f029d3a156d5ad languageName: node linkType: hard @@ -614,7 +874,7 @@ __metadata: resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e605e0070da087f6c35579499e65801179a521b6842c15181a1e305c04fded2393f11c1efd09b087be7f8b083d1b75e8f3efcbc1292b4f60d3369e14812cff63 + checksum: d97745d098b835d55033ff3a7fb2b895b9c5295b08a5759e4f20df325aa385a3e0bc9bd5ad8f2ec554a44d4e6525acfc257b8c5848a1345cb40f26a30e277e91 languageName: node linkType: hard @@ -628,7 +888,7 @@ __metadata: "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 3c8c9ea175101b1cbb2b0e8fee20fcbdd03eb0700d3581aa826ac3573c9b002f39b1512c2af9fd1903ff921bcc864da95ad3cdeba53c9fbcfb3dc23916eacf47 + checksum: 1b880543bc5f525b360b53d97dd30807302bb82615cd42bf931968f59003cac75629563d6b104868db50abd22235b3271fdf679fea5db59a267181a99cc0c265 languageName: node linkType: hard @@ -640,7 +900,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.18.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c68feae57d9b1f4d98ecc2da63bda1993980deb509ccb08f6eace712ece8081032eb6532c304524b544c2dd577e2f9c2fe5c5bfd73d1955c946300def6fc7493 + checksum: a8575ecb7ff24bf6c6e94808d5c84bb5a0c6dd7892b54f09f4646711ba0ee1e1668032b3c43e3e1dfec2c5716c302e851ac756c1645e15882d73df6ad21ae951 languageName: node linkType: hard @@ -651,7 +911,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.8.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d13efb282838481348c71073b6be6245b35d4f2f964a8f71e4174f235009f929ef7613df25f8d2338e2d3e44bc4265a9f8638c6aaa136d7a61fe95985f9725c8 + checksum: 7ed1c1d9b9e5b64ef028ea5e755c0be2d4e5e4e3d6cf7df757b9a8c4cfa4193d268176d0f1f7fbecdda6fe722885c7fda681f480f3741d8a2d26854736f05367 languageName: node linkType: hard @@ -662,7 +922,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.8.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 686891b81af2bc74c39013655da368a480f17dd237bf9fbc32048e5865cb706d5a8f65438030da535b332b1d6b22feba336da8fa931f663b6b34e13147d12dde + checksum: 3a10849d83e47aec50f367a9e56a6b22d662ddce643334b087f9828f4c3dd73bdc5909aaeabe123fed78515767f9ca43498a0e621c438d1cd2802d7fae3c9648 languageName: node linkType: hard @@ -673,7 +933,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.12.13" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 95168fa186416195280b1264fb18afcdcdcea780b3515537b766cb90de6ce042d42dd6a204a39002f794ae5845b02afb0fd4861a3308a861204a55e68310a120 + checksum: 24f34b196d6342f28d4bad303612d7ff566ab0a013ce89e775d98d6f832969462e7235f3e7eaf17678a533d4be0ba45d3ae34ab4e5a9dcbda5d98d49e5efa2fc languageName: node linkType: hard @@ -684,7 +944,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 4464bf9115f4a2d02ce1454411baf9cfb665af1da53709c5c56953e5e2913745b0fcce82982a00463d6facbdd93445c691024e310b91431a1e2f024b158f6371 + checksum: 3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 languageName: node linkType: hard @@ -695,7 +955,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.8.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9c50927bf71adf63f60c75370e2335879402648f468d0172bc912e303c6a3876927d8eb35807331b57f415392732ed05ab9b42c68ac30a936813ab549e0246c5 + checksum: ce307af83cf433d4ec42932329fad25fa73138ab39c7436882ea28742e1c0066626d224e0ad2988724c82644e41601cef607b36194f695cb78a1fcdc959637bd languageName: node linkType: hard @@ -706,40 +966,51 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 5100d658ba563829700cd8d001ddc09f4c0187b1a13de300d729c5b3e87503f75a6d6c99c1794182f7f1a9f546ee009df4f15a0ce36376e206ed0012fa7cdc24 + checksum: 85740478be5b0de185228e7814451d74ab8ce0a26fcca7613955262a26e99e8e15e9da58f60c754b84515d4c679b590dbd3f2148f0f58025f4ae706f1c5a5d4a languageName: node linkType: hard -"@babel/plugin-syntax-flow@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-flow@npm:7.22.5" +"@babel/plugin-syntax-flow@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-syntax-flow@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 07afc7df02141597968532bfbfa3f6c0ad21a2bdd885d0e5e035dcf60fdf35f0995631c9750b464e1a6f2feea14160a82787f914e88e8f7115dc99f09853e43e + checksum: c6e6f355d6ace5f4a9e7bb19f1fed2398aeb9b62c4c671a189d81b124f9f5bb77c4225b6e85e19339268c60a021c1e49104e450375de5e6bb70612190d9678af languageName: node linkType: hard -"@babel/plugin-syntax-import-assertions@npm:^7.20.0, @babel/plugin-syntax-import-assertions@npm:^7.22.5": +"@babel/plugin-syntax-import-assertions@npm:^7.20.0": version: 7.22.5 resolution: "@babel/plugin-syntax-import-assertions@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b297d7c757c746ed0ef3496ad749ae2ce648ec73dae5184120b191c280e62da7dc104ee126bc0053dfece3ce198a5ee7dc1cbf4768860f666afef5dee84a7146 + checksum: 2b8b5572db04a7bef1e6cd20debf447e4eef7cb012616f5eceb8fa3e23ce469b8f76ee74fd6d1e158ba17a8f58b0aec579d092fb67c5a30e83ccfbc5754916c1 languageName: node linkType: hard -"@babel/plugin-syntax-import-attributes@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.22.5" +"@babel/plugin-syntax-import-assertions@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 883e6b35b2da205138caab832d54505271a3fee3fc1e8dc0894502434fc2b5d517cbe93bbfbfef8068a0fb6ec48ebc9eef3f605200a489065ba43d8cddc1c9a7 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-attributes@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: de0b104a82cb8ffdc29472177210936609b973665a2ad8ef26c078251d7c728fbd521119de4c417285408a8bae345b5da09cd4a4a3311619f71b9b2c64cce3fa + checksum: 9aed7661ffb920ca75df9f494757466ca92744e43072e0848d87fa4aa61a3f2ee5a22198ac1959856c036434b5614a8f46f1fb70298835dbe28220cdd1d4c11e languageName: node linkType: hard @@ -750,7 +1021,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 0b08b5e4c3128523d8e346f8cfc86824f0da2697b1be12d71af50a31aff7a56ceb873ed28779121051475010c28d6146a6bfea8518b150b71eeb4e46190172ee + checksum: 166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b languageName: node linkType: hard @@ -761,7 +1032,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.8.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e98f31b2ec406c57757d115aac81d0336e8434101c224edd9a5c93cefa53faf63eacc69f3138960c8b25401315af03df37f68d316c151c4b933136716ed6906e + checksum: bf5aea1f3188c9a507e16efe030efb996853ca3cadd6512c51db7233cc58f3ac89ff8c6bdfb01d30843b161cfe7d321e1bf28da82f7ab8d7e6bc5464666f354a languageName: node linkType: hard @@ -772,7 +1043,18 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b56ceaa9c6adc17fadfb48e1c801d07797195df2a581489e33c8034950e12e7778de6e1e70d6bcf7c5c7ada6222fe6bad5746187ab280df435f5a2799c8dd0d8 + checksum: 8829d30c2617ab31393d99cec2978e41f014f4ac6f01a1cecf4c4dd8320c3ec12fdc3ce121126b2d8d32f6887e99ca1a0bad53dedb1e6ad165640b92b24980ce + languageName: node + linkType: hard + +"@babel/plugin-syntax-jsx@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-syntax-jsx@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 89037694314a74e7f0e7a9c8d3793af5bf6b23d80950c29b360db1c66859d67f60711ea437e70ad6b5b4b29affe17eababda841b6c01107c2b638e0493bafb4e languageName: node linkType: hard @@ -783,7 +1065,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2594cfbe29411ad5bc2ad4058de7b2f6a8c5b86eda525a993959438615479e59c012c14aec979e538d60a584a1a799b60d1b8942c3b18468cb9d99b8fd34cd0b + checksum: aff33577037e34e515911255cdbb1fd39efee33658aa00b8a5fd3a4b903585112d037cce1cc9e4632f0487dc554486106b79ccd5ea63a2e00df4363f6d4ff886 languageName: node linkType: hard @@ -794,7 +1076,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.8.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2024fbb1162899094cfc81152449b12bd0cc7053c6d4bda8ac2852545c87d0a851b1b72ed9560673cbf3ef6248257262c3c04aabf73117215c1b9cc7dd2542ce + checksum: 87aca4918916020d1fedba54c0e232de408df2644a425d153be368313fdde40d96088feed6c4e5ab72aac89be5d07fef2ddf329a15109c5eb65df006bf2580d1 languageName: node linkType: hard @@ -805,7 +1087,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c55a82b3113480942c6aa2fcbe976ff9caa74b7b1109ff4369641dfbc88d1da348aceb3c31b6ed311c84d1e7c479440b961906c735d0ab494f688bf2fd5b9bb9 + checksum: 01ec5547bd0497f76cc903ff4d6b02abc8c05f301c88d2622b6d834e33a5651aa7c7a3d80d8d57656a4588f7276eba357f6b7e006482f5b564b7a6488de493a1 languageName: node linkType: hard @@ -816,7 +1098,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.8.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ee1eab52ea6437e3101a0a7018b0da698545230015fc8ab129d292980ec6dff94d265e9e90070e8ae5fed42f08f1622c14c94552c77bcac784b37f503a82ff26 + checksum: fddcf581a57f77e80eb6b981b10658421bc321ba5f0a5b754118c6a92a5448f12a0c336f77b8abf734841e102e5126d69110a306eadb03ca3e1547cab31f5cbf languageName: node linkType: hard @@ -827,7 +1109,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.8.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 27e2493ab67a8ea6d693af1287f7e9acec206d1213ff107a928e85e173741e1d594196f99fec50e9dde404b09164f39dec5864c767212154ffe1caa6af0bc5af + checksum: 910d90e72bc90ea1ce698e89c1027fed8845212d5ab588e35ef91f13b93143845f94e2539d831dc8d8ededc14ec02f04f7bd6a8179edd43a326c784e7ed7f0b9 languageName: node linkType: hard @@ -838,7 +1120,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.8.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 46edddf2faa6ebf94147b8e8540dfc60a5ab718e2de4d01b2c0bdf250a4d642c2bd47cbcbb739febcb2bf75514dbcefad3c52208787994b8d0f8822490f55e81 + checksum: eef94d53a1453361553c1f98b68d17782861a04a392840341bc91780838dd4e695209c783631cf0de14c635758beafb6a3a65399846ffa4386bff90639347f30 languageName: node linkType: hard @@ -849,7 +1131,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 69822772561706c87f0a65bc92d0772cea74d6bc0911537904a676d5ff496a6d3ac4e05a166d8125fce4a16605bace141afc3611074e170a994e66e5397787f3 + checksum: b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda languageName: node linkType: hard @@ -860,7 +1142,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 14bf6e65d5bc1231ffa9def5f0ef30b19b51c218fcecaa78cd1bdf7939dfdf23f90336080b7f5196916368e399934ce5d581492d8292b46a2fb569d8b2da106f + checksum: bbd1a56b095be7820029b209677b194db9b1d26691fe999856462e66b25b281f031f3dfd91b1619e9dcf95bebe336211833b854d0fb8780d618e35667c2d0d7e languageName: node linkType: hard @@ -871,7 +1153,18 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 523a76627f17e67dc1999f4d7c7a71ed79e9f77f55a61cf05051101967ac23ec378ff0c93787b2cbd5d53720ad799658d796a649fa351682b2bf636f63b665a1 + checksum: 8ab7718fbb026d64da93681a57797d60326097fd7cb930380c8bffd9eb101689e90142c760a14b51e8e69c88a73ba3da956cb4520a3b0c65743aee5c71ef360a + languageName: node + linkType: hard + +"@babel/plugin-syntax-typescript@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-syntax-typescript@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: abfad3a19290d258b028e285a1f34c9b8a0cbe46ef79eafed4ed7ffce11b5d0720b5e536c82f91cbd8442cde35a3dd8e861fa70366d87ff06fdc0d4756e30876 languageName: node linkType: hard @@ -883,36 +1176,47 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.18.6" peerDependencies: "@babel/core": ^7.0.0 - checksum: 9144e5b02a211a4fb9a0ce91063f94fbe1004e80bde3485a0910c9f14897cf83fabd8c21267907cff25db8e224858178df0517f14333cfcf3380ad9a4139cb50 + checksum: a651d700fe63ff0ddfd7186f4ebc24447ca734f114433139e3c027bc94a900d013cf1ef2e2db8430425ba542e39ae160c3b05f06b59fd4656273a3df97679e9c languageName: node linkType: hard -"@babel/plugin-transform-arrow-functions@npm:^7.21.5, @babel/plugin-transform-arrow-functions@npm:^7.22.5": +"@babel/plugin-transform-arrow-functions@npm:^7.21.5": version: 7.22.5 resolution: "@babel/plugin-transform-arrow-functions@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1b24d47ddac6ae2fe8c7fab9a020fdb6a556d17d8c5f189bb470ff2958a5437fe6441521fd3d850f4283a1131d7a0acf3e8ebe789f9077f54bab4e2e8c6df176 + checksum: 35abb6c57062802c7ce8bd96b2ef2883e3124370c688bbd67609f7d2453802fb73944df8808f893b6c67de978eb2bcf87bbfe325e46d6f39b5fcb09ece11d01a languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.22.7": - version: 7.22.7 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.7" +"@babel/plugin-transform-arrow-functions@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.23.3" dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-remap-async-to-generator": "npm:^7.22.5" - "@babel/plugin-syntax-async-generators": "npm:^7.8.4" + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1e99118176e5366c2636064d09477016ab5272b2a92e78b8edb571d20bc3eaa881789a905b20042942c3c2d04efc530726cf703f937226db5ebc495f5d067e66 + languageName: node + linkType: hard + +"@babel/plugin-transform-async-generator-functions@npm:^7.23.7": + version: 7.23.7 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.7" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-remap-async-to-generator": ^7.22.20 + "@babel/plugin-syntax-async-generators": ^7.8.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b9712f47de65d8409625de5cfa4bda6984f9e7065f6170c34b3d11974879276ffa61675c8118de5de7746f5de378c5dfc21efc706664c6f0c652fb58949b53f0 + checksum: b1f66b23423933c27336b1161ac92efef46683321caea97e2255a666f992979376f47a5559f64188d3831fa66a4b24c2a7a40838cc0e9737e90eebe20e8e6372 languageName: node linkType: hard -"@babel/plugin-transform-async-to-generator@npm:^7.20.7, @babel/plugin-transform-async-to-generator@npm:^7.22.5": +"@babel/plugin-transform-async-to-generator@npm:^7.20.7": version: 7.22.5 resolution: "@babel/plugin-transform-async-to-generator@npm:7.22.5" dependencies: @@ -921,29 +1225,64 @@ __metadata: "@babel/helper-remap-async-to-generator": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2972f22c3a5a56a8b225f4fa1bbdbcf6e989e0da460d5f4e2280652b1433d7c68b6ddc0cc2affc4b59905835133a253a31c24c7ca1bebe1a2f28377d27b4ca1c + checksum: b95f23f99dcb379a9f0a1c2a3bbea3f8dc0e1b16dc1ac8b484fe378370169290a7a63d520959a9ba1232837cf74a80e23f6facbe14fd42a3cda6d3c2d7168e62 + languageName: node + linkType: hard + +"@babel/plugin-transform-async-to-generator@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.23.3" + dependencies: + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-remap-async-to-generator": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2e9d9795d4b3b3d8090332104e37061c677f29a1ce65bcbda4099a32d243e5d9520270a44bbabf0fb1fb40d463bd937685b1a1042e646979086c546d55319c3c languageName: node linkType: hard -"@babel/plugin-transform-block-scoped-functions@npm:^7.18.6, @babel/plugin-transform-block-scoped-functions@npm:^7.22.5": +"@babel/plugin-transform-block-scoped-functions@npm:^7.18.6": version: 7.22.5 resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 21878d4f0040f5001c4a14e17759e80bf699cb883a497552fa882dbc05230b100e8572345654b091021d5c4227555ed2bf40c8d6ba16a54d81145abfe0022cf8 + checksum: 416b1341858e8ca4e524dee66044735956ced5f478b2c3b9bc11ec2285b0c25d7dbb96d79887169eb938084c95d0a89338c8b2fe70d473bd9dc92e5d9db1732c + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoped-functions@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e63b16d94ee5f4d917e669da3db5ea53d1e7e79141a2ec873c1e644678cdafe98daa556d0d359963c827863d6b3665d23d4938a94a4c5053a1619c4ebd01d020 languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.21.0, @babel/plugin-transform-block-scoping@npm:^7.22.5": +"@babel/plugin-transform-block-scoping@npm:^7.21.0": version: 7.22.5 resolution: "@babel/plugin-transform-block-scoping@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 68f663d349345b522e1dece9641ee304d8f7db1d4b11998f47ebc5d678d281f76a143fb8603a1c12596962d7a63ffe044cd205a4910c8d74906eae17a605f96f + checksum: 26987002cfe6e24544e60fa35f07052b6557f590c1a1cc5cf35d6dc341d7fea163c1222a2d70d5d2692f0b9860d942fd3ba979848b2995d4debffa387b9b19ae + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoping@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-block-scoping@npm:7.23.4" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: fc4b2100dd9f2c47d694b4b35ae8153214ccb4e24ef545c259a9db17211b18b6a430f22799b56db8f6844deaeaa201af45a03331d0c80cc28b0c4e3c814570e4 languageName: node linkType: hard @@ -955,24 +1294,36 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 707f976d3aea2b52dad36a5695a71af8956f9b1d5dec02c2b8cce7ff3b5e60df4cbe059c71ae0b7983034dc639de654a2c928b97e4e01ebf436d58ea43639e7d + checksum: b830152dfc2ff2f647f0abe76e6251babdfbef54d18c4b2c73a6bf76b1a00050a5d998dac80dc901a48514e95604324943a9dd39317073fe0928b559e0e0c579 languageName: node linkType: hard -"@babel/plugin-transform-class-static-block@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-class-static-block@npm:7.22.5" +"@babel/plugin-transform-class-properties@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-class-properties@npm:7.23.3" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" + "@babel/helper-create-class-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 9c6f8366f667897541d360246de176dd29efc7a13d80a5b48361882f7173d9173be4646c3b7d9b003ccc0e01e25df122330308f33db921fa553aa17ad544b3fc + languageName: node + linkType: hard + +"@babel/plugin-transform-class-static-block@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-class-static-block@npm:7.23.4" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-class-static-block": ^7.14.5 peerDependencies: "@babel/core": ^7.12.0 - checksum: 23814d00b2966e8dab7a60934622853698b2cb861a8667c006e000d8e5a50aba4d221c52852552562e7f38e32ad5c7778125ef602c2d2f1c4f9d8f790a9f27e9 + checksum: c8bfaba19a674fc2eb54edad71e958647360474e3163e8226f1acd63e4e2dbec32a171a0af596c1dc5359aee402cc120fea7abd1fb0e0354b6527f0fc9e8aa1e languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.21.0, @babel/plugin-transform-classes@npm:^7.22.6": +"@babel/plugin-transform-classes@npm:^7.21.0": version: 7.22.6 resolution: "@babel/plugin-transform-classes@npm:7.22.6" dependencies: @@ -987,11 +1338,29 @@ __metadata: globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 915f1c0d3a0446a3ebfb099c4a5e714896f773322432b91572e6739d7af82e9743ae2874eb596ef1d26ed94472385eb814e1f33b033fc708155576d566e1f5ff + checksum: 8380e855c01033dbc7460d9acfbc1fc37c880350fa798c2de8c594ef818ade0e4c96173ec72f05f2a4549d8d37135e18cb62548352d51557b45a0fb4388d2f3f languageName: node linkType: hard -"@babel/plugin-transform-computed-properties@npm:^7.21.5, @babel/plugin-transform-computed-properties@npm:^7.22.5": +"@babel/plugin-transform-classes@npm:^7.23.8": + version: 7.23.8 + resolution: "@babel/plugin-transform-classes@npm:7.23.8" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-compilation-targets": ^7.23.6 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.20 + "@babel/helper-split-export-declaration": ^7.22.6 + globals: ^11.1.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7dee6cebe52131d2d16944f36e1fdb9d4b24f44d0e7e450f93a44435d001f17cc0789a4cb6b15ec67c8e484581b8a730b5c3ec374470f29ff0133086955b8c58 + languageName: node + linkType: hard + +"@babel/plugin-transform-computed-properties@npm:^7.21.5": version: 7.22.5 resolution: "@babel/plugin-transform-computed-properties@npm:7.22.5" dependencies: @@ -999,300 +1368,479 @@ __metadata: "@babel/template": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 22ecea23c1635083f5473092c5fbca62cbf7a85764bcf3e704c850446d68fe946097f6001c4cbfc92b4aee27ed30b375773ee479f749293e41fdb8f1fb8fcb67 + checksum: c2a77a0f94ec71efbc569109ec14ea2aa925b333289272ced8b33c6108bdbb02caf01830ffc7e49486b62dec51911924d13f3a76f1149f40daace1898009e131 languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.21.3, @babel/plugin-transform-destructuring@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-destructuring@npm:7.22.5" +"@babel/plugin-transform-computed-properties@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-computed-properties@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/template": ^7.22.15 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: bffd0069f44165e101368f34ab34d4bb810ef3dc16a5bf5e55e633a60b0c3aca948dccc15d04e6d6996a2a467f4a52d7224a82efc4be175836cc6e3a3702efa5 + checksum: 80452661dc25a0956f89fe98cb562e8637a9556fb6c00d312c57653ce7df8798f58d138603c7e1aad96614ee9ccd10c47e50ab9ded6b6eded5adeb230d2a982e languageName: node linkType: hard -"@babel/plugin-transform-dotall-regex@npm:^7.18.6, @babel/plugin-transform-dotall-regex@npm:^7.22.5, @babel/plugin-transform-dotall-regex@npm:^7.4.4": +"@babel/plugin-transform-destructuring@npm:^7.21.3": version: 7.22.5 - resolution: "@babel/plugin-transform-dotall-regex@npm:7.22.5" + resolution: "@babel/plugin-transform-destructuring@npm:7.22.5" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.5" "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e0d7b95380483ef563c13f7c0a2122f575c58708cfb56494d6265ebb31753cf46ee0b3f5126fa6bbea5af392b3a2da05bf1e028d0b2b4d1dc279edd67cf3c3d9 + checksum: 76f6ea2aee1fcfa1c3791eb7a5b89703c6472650b993e8666fff0f1d6e9d737a84134edf89f63c92297f3e75064c1263219463b02dd9bc7434b6e5b9935e3f20 languageName: node linkType: hard -"@babel/plugin-transform-duplicate-keys@npm:^7.18.9, @babel/plugin-transform-duplicate-keys@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-duplicate-keys@npm:7.22.5" +"@babel/plugin-transform-destructuring@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-destructuring@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 82772fdcc1301358bc722c1316bea071ad0cd5893ca95b08e183748e044277a93ee90f9c641ac7873a00e4b31a8df7cf8c0981ca98d01becb4864a11b22c09d1 + checksum: 9e015099877272501162419bfe781689aec5c462cd2aec752ee22288f209eec65969ff11b8fdadca2eaddea71d705d3bba5b9c60752fcc1be67874fcec687105 languageName: node linkType: hard -"@babel/plugin-transform-dynamic-import@npm:^7.22.5": +"@babel/plugin-transform-dotall-regex@npm:^7.18.6, @babel/plugin-transform-dotall-regex@npm:^7.4.4": version: 7.22.5 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.22.5" + resolution: "@babel/plugin-transform-dotall-regex@npm:7.22.5" dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.5" "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 82fb6fa0b6f7c7760ac21ebcb856a01579c9e64a325d5bb8841591b58b2d92024169f10f4ca2b34b45376999b352974138c94fc1d5cc330e00beeeb1bda51425 + checksum: 409b658d11e3082c8f69e9cdef2d96e4d6d11256f005772425fb230cc48fd05945edbfbcb709dab293a1a2f01f9c8a5bb7b4131e632b23264039d9f95864b453 languageName: node linkType: hard -"@babel/plugin-transform-exponentiation-operator@npm:^7.18.6, @babel/plugin-transform-exponentiation-operator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.22.5" +"@babel/plugin-transform-dotall-regex@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.23.3" dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-create-regexp-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e8832460cfc9e087561fa42a796bb4eb181e6983d6db85c6dcec15f98af4ae3d13fcab18a262252a43b075d79ac93aaa38d33022bc5a870d2760c6888ba5d211 + checksum: a2dbbf7f1ea16a97948c37df925cb364337668c41a3948b8d91453f140507bd8a3429030c7ce66d09c299987b27746c19a2dd18b6f17dcb474854b14fd9159a3 languageName: node linkType: hard -"@babel/plugin-transform-export-namespace-from@npm:^7.22.5": +"@babel/plugin-transform-duplicate-keys@npm:^7.18.9": version: 7.22.5 - resolution: "@babel/plugin-transform-export-namespace-from@npm:7.22.5" + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d5d301dde2d6e7f9e4db12ac70e19153f0e8d17406ad733a8f7d01de77d123588fe90c7f5b8cc086420594ec1e7d20abc5e08323f9ad9704a19c6c87ca03eb59 + checksum: bb1280fbabaab6fab2ede585df34900712698210a3bd413f4df5bae6d8c24be36b496c92722ae676a7a67d060a4624f4d6c23b923485f906bfba8773c69f55b4 languageName: node linkType: hard -"@babel/plugin-transform-flow-strip-types@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-flow-strip-types@npm:7.22.5" +"@babel/plugin-transform-duplicate-keys@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-flow": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 5949a8e5214e3fc65d31dab0551423cea9d9eef35faa5d0004707ba7347baf96166aa400907ce7498f754db4e1e9d039ca434a508546b0dc9fdae9a42e814c1a + checksum: c2a21c34dc0839590cd945192cbc46fde541a27e140c48fe1808315934664cdbf18db64889e23c4eeb6bad9d3e049482efdca91d29de5734ffc887c4fbabaa16 languageName: node linkType: hard -"@babel/plugin-transform-for-of@npm:^7.21.5, @babel/plugin-transform-for-of@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-for-of@npm:7.22.5" +"@babel/plugin-transform-dynamic-import@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 08bd2d14f10b8ae421e61b55c28232547044149b8ef62c99c54561ce93a5067f9654d701d798871e733543359748e1b093f5c450b69705ec1db674175ee9fcdb + checksum: 57a722604c430d9f3dacff22001a5f31250e34785d4969527a2ae9160fa86858d0892c5b9ff7a06a04076f8c76c9e6862e0541aadca9c057849961343aab0845 languageName: node linkType: hard -"@babel/plugin-transform-function-name@npm:^7.18.9, @babel/plugin-transform-function-name@npm:^7.22.5": +"@babel/plugin-transform-exponentiation-operator@npm:^7.18.6": version: 7.22.5 - resolution: "@babel/plugin-transform-function-name@npm:7.22.5" + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.22.5" dependencies: - "@babel/helper-compilation-targets": "npm:^7.22.5" - "@babel/helper-function-name": "npm:^7.22.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.22.5" "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 206bdef2ff91c29a7d94c77778ad79f18bdb2cd6a30179449f2b95af04637cb68d96625dc673d9a0961b6b7088bd325bbed7540caf9aa8f69e5b003d6ba20456 + checksum: f2d660c1b1d51ad5fec1cd5ad426a52187204068c4158f8c4aa977b31535c61b66898d532603eef21c15756827be8277f724c869b888d560f26d7fe848bb5eae languageName: node linkType: hard -"@babel/plugin-transform-json-strings@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-json-strings@npm:7.22.5" +"@babel/plugin-transform-exponentiation-operator@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-json-strings": "npm:^7.8.3" + "@babel/helper-builder-binary-assignment-operator-visitor": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 64ee0f3497822d312b609d3b8a5a2617337d1624292e89f5e90fd25b5bc91a20beadfa91730b5b199b5a027284ced5d59748d99e8ab81ee7bdac38236e6b61ca + checksum: 00d05ab14ad0f299160fcf9d8f55a1cc1b740e012ab0b5ce30207d2365f091665115557af7d989cd6260d075a252d9e4283de5f2b247dfbbe0e42ae586e6bf66 languageName: node linkType: hard -"@babel/plugin-transform-literals@npm:^7.18.9, @babel/plugin-transform-literals@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-literals@npm:7.22.5" +"@babel/plugin-transform-export-namespace-from@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1003d0cf98e9ae432889bcf5f3d5f7d463f777fc2c74b0d4a1a93b51e83606c263a16146e34f0a06b291300aa5f2001d6e8bf65ed1bf478ab071b714bf158aa5 + checksum: 9f770a81bfd03b48d6ba155d452946fd56d6ffe5b7d871e9ec2a0b15e0f424273b632f3ed61838b90015b25bbda988896b7a46c7d964fbf8f6feb5820b309f93 languageName: node linkType: hard -"@babel/plugin-transform-logical-assignment-operators@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.22.5" +"@babel/plugin-transform-flow-strip-types@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-flow-strip-types@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-flow": ^7.23.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: bfacdafa8018d1607897015e1ea0f98edbefee16b4409d5f37c37df0d2058dde2e55586dd79f8479a0cd603ff06272216de077f071bc49c96014edfe1629bd26 + checksum: de38cc5cf948bc19405ea041292181527a36f59f08d787a590415fac36e9b0c7992f0d3e2fd3b9402089bafdaa1a893291a0edf15beebfd29bdedbbe582fee9b languageName: node linkType: hard -"@babel/plugin-transform-member-expression-literals@npm:^7.18.6, @babel/plugin-transform-member-expression-literals@npm:^7.22.5": +"@babel/plugin-transform-for-of@npm:^7.21.5": version: 7.22.5 - resolution: "@babel/plugin-transform-member-expression-literals@npm:7.22.5" + resolution: "@babel/plugin-transform-for-of@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 731a341b17511809ae435b64822d4d093e86fd928b572028e6742bdfba271c57070860b0f3da080a76c5574d58c4f369fac3f7bf0f450b37920c0fc6fe27bb4e + checksum: d7b8d4db010bce7273674caa95c4e6abd909362866ce297e86a2ecaa9ae636e05d525415811db9b3c942155df7f3651d19b91dd6c41f142f7308a97c7cb06023 languageName: node linkType: hard -"@babel/plugin-transform-modules-amd@npm:^7.20.11, @babel/plugin-transform-modules-amd@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-amd@npm:7.22.5" +"@babel/plugin-transform-for-of@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/plugin-transform-for-of@npm:7.23.6" dependencies: - "@babel/helper-module-transforms": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 157ae3b58a50ca52e361860ecab2b608bc9228ea6c760112a35302990976f8936b8d75a2b21925797eed7b3bab4930a3f447193127afef9a21b7b6463ff0b422 + checksum: 228c060aa61f6aa89dc447170075f8214863b94f830624e74ade99c1a09316897c12d76e848460b0b506593e58dbc42739af6dc4cb0fe9b84dffe4a596050a36 languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.13.8, @babel/plugin-transform-modules-commonjs@npm:^7.21.5, @babel/plugin-transform-modules-commonjs@npm:^7.22.5": +"@babel/plugin-transform-function-name@npm:^7.18.9": version: 7.22.5 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.22.5" + resolution: "@babel/plugin-transform-function-name@npm:7.22.5" dependencies: - "@babel/helper-module-transforms": "npm:^7.22.5" + "@babel/helper-compilation-targets": "npm:^7.22.5" + "@babel/helper-function-name": "npm:^7.22.5" "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-simple-access": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 818317363cc96a1ab28cd0691bdb86fe06f452d210e2cef7ef4708f2c2c80cbe3c76bca23c2ab4b1bb200d44e508eae71f627c7cb27299a41be56fc7e3aaced0 + checksum: cff3b876357999cb8ae30e439c3ec6b0491a53b0aa6f722920a4675a6dd5b53af97a833051df4b34791fe5b3dd326ccf769d5c8e45b322aa50ee11a660b17845 languageName: node linkType: hard -"@babel/plugin-transform-modules-systemjs@npm:^7.20.11, @babel/plugin-transform-modules-systemjs@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.22.5" +"@babel/plugin-transform-function-name@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-function-name@npm:7.23.3" dependencies: - "@babel/helper-hoist-variables": "npm:^7.22.5" - "@babel/helper-module-transforms": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-validator-identifier": "npm:^7.22.5" + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 25d7ada275039523541cfc3efd91cd3d9cfc77e7b9dd6a51e7d9ad842d2cb3e0f26aee29426aa56ac72f61247268369680f2bdc1171bb00a16cfd00bbb325a6c + checksum: 355c6dbe07c919575ad42b2f7e020f320866d72f8b79181a16f8e0cd424a2c761d979f03f47d583d9471b55dcd68a8a9d829b58e1eebcd572145b934b48975a6 languageName: node linkType: hard -"@babel/plugin-transform-modules-umd@npm:^7.18.6, @babel/plugin-transform-modules-umd@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-umd@npm:7.22.5" +"@babel/plugin-transform-json-strings@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-json-strings@npm:7.23.4" dependencies: - "@babel/helper-module-transforms": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-json-strings": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f4a40e18986182a2b1be6af949aaff67a7d112af3d26bbd4319d05b50f323a62a10b32b5584148e4630bdffbd4d85b31c0d571fe4f601354898b837b87afca4c + checksum: f9019820233cf8955d8ba346df709a0683c120fe86a24ed1c9f003f2db51197b979efc88f010d558a12e1491210fc195a43cd1c7fee5e23b92da38f793a875de languageName: node linkType: hard -"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.20.5, @babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5": +"@babel/plugin-transform-literals@npm:^7.18.9": version: 7.22.5 - resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5" + resolution: "@babel/plugin-transform-literals@npm:7.22.5" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.5" "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: - "@babel/core": ^7.0.0 - checksum: b0b072bef303670b5a98307bc37d1ac326cb7ad40ea162b89a03c2ffc465451be7ef05be95cb81ed28bfeb29670dc98fe911f793a67bceab18b4cb4c81ef48f3 + "@babel/core": ^7.0.0-0 + checksum: ec37cc2ffb32667af935ab32fe28f00920ec8a1eb999aa6dc6602f2bebd8ba205a558aeedcdccdebf334381d5c57106c61f52332045730393e73410892a9735b languageName: node linkType: hard -"@babel/plugin-transform-new-target@npm:^7.18.6, @babel/plugin-transform-new-target@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-new-target@npm:7.22.5" +"@babel/plugin-transform-literals@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-literals@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 22ead0668bfd8db9166a4a47579d9f44726b59f21104561a6dd851156336741abdc5c576558e042c58c4b4fd577d3e29e4bd836021007f3381c33fe3c88dca19 + checksum: 519a544cd58586b9001c4c9b18da25a62f17d23c48600ff7a685d75ca9eb18d2c5e8f5476f067f0a8f1fea2a31107eff950b9864833061e6076dcc4bdc3e71ed languageName: node linkType: hard -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.22.5" +"@babel/plugin-transform-logical-assignment-operators@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 66f7237d59060954fc0ba0c5d9e7081580421014b446080b3efedb3d4be9a4346f50974c5886a4ec7962db9992e5e1c5e26cb76801728b4d9626ac2eb09c26f7 + checksum: 2ae1dc9b4ff3bf61a990ff3accdecb2afe3a0ca649b3e74c010078d1cdf29ea490f50ac0a905306a2bcf9ac177889a39ac79bdcc3a0fdf220b3b75fac18d39b5 languageName: node linkType: hard -"@babel/plugin-transform-numeric-separator@npm:^7.22.5": +"@babel/plugin-transform-member-expression-literals@npm:^7.18.6": version: 7.22.5 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.22.5" + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 921d6ff2165eb782c28a6c06e9eb0dc17400c9476b000a7f8b8dfa95c122c22be4adee7bc15f035a1e4269842b3a68b0a2f20e4437025a6e0fbe16e479a879b8 + checksum: ec4b0e07915ddd4fda0142fd104ee61015c208608a84cfa13643a95d18760b1dc1ceb6c6e0548898b8c49e5959a994e46367260176dbabc4467f729b21868504 languageName: node linkType: hard -"@babel/plugin-transform-object-rest-spread@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.22.5" +"@babel/plugin-transform-member-expression-literals@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.23.3" dependencies: - "@babel/compat-data": "npm:^7.22.5" - "@babel/helper-compilation-targets": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 95cec13c36d447c5aa6b8e4c778b897eeba66dcb675edef01e0d2afcec9e8cb9726baf4f81b4bbae7a782595aed72e6a0d44ffb773272c3ca180fada99bf92db + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-amd@npm:^7.20.11": + version: 7.22.5 + resolution: "@babel/plugin-transform-modules-amd@npm:7.22.5" + dependencies: + "@babel/helper-module-transforms": "npm:^7.22.5" "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" - "@babel/plugin-transform-parameters": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ab93b8f84e4ed6629ea258d94b597976598a1990035b4d5178c8d117908a48a36f0f03dd2f4a3375393a23a588ecc7817c099ac88a80f8307475b9a25e4d08e0 + checksum: 7da4c4ebbbcf7d182abb59b2046b22d86eee340caf8a22a39ef6a727da2d8acfec1f714fcdcd5054110b280e4934f735e80a6848d192b6834c5d4459a014f04d + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-amd@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-modules-amd@npm:7.23.3" + dependencies: + "@babel/helper-module-transforms": ^7.23.3 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d163737b6a3d67ea579c9aa3b83d4df4b5c34d9dcdf25f415f027c0aa8cded7bac2750d2de5464081f67a042ad9e1c03930c2fab42acd79f9e57c00cf969ddff languageName: node linkType: hard -"@babel/plugin-transform-object-super@npm:^7.18.6, @babel/plugin-transform-object-super@npm:^7.22.5": +"@babel/plugin-transform-modules-commonjs@npm:^7.21.5": version: 7.22.5 - resolution: "@babel/plugin-transform-object-super@npm:7.22.5" + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.22.5" dependencies: + "@babel/helper-module-transforms": "npm:^7.22.5" "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-replace-supers": "npm:^7.22.5" + "@babel/helper-simple-access": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2067aca8f6454d54ffcce69b02c457cfa61428e11372f6a1d99ff4fcfbb55c396ed2ca6ca886bf06c852e38c1a205b8095921b2364fd0243f3e66bc1dda61caa + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-commonjs@npm:^7.23.0, @babel/plugin-transform-modules-commonjs@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.23.3" + dependencies: + "@babel/helper-module-transforms": ^7.23.3 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-simple-access": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 062a78ff897c095a71f0db577bd4e4654659d542cb9ef79ec0fda7873ee6fefe31a0cb8a6c2e307e16dacaae1f50d48572184a59e1235b8d9d9cb2f38c4259ce + checksum: 720a231ceade4ae4d2632478db4e7fecf21987d444942b72d523487ac8d715ca97de6c8f415c71e939595e1a4776403e7dc24ed68fe9125ad4acf57753c9bff7 languageName: node linkType: hard -"@babel/plugin-transform-optional-catch-binding@npm:^7.22.5": +"@babel/plugin-transform-modules-systemjs@npm:^7.20.11": version: 7.22.5 - resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.22.5" + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.22.5" dependencies: + "@babel/helper-hoist-variables": "npm:^7.22.5" + "@babel/helper-module-transforms": "npm:^7.22.5" "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" + "@babel/helper-validator-identifier": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 04f4178589543396b3c24330a67a59c5e69af5e96119c9adda730c0f20122deaff54671ebbc72ad2df6495a5db8a758bd96942de95fba7ad427de9c80b1b38c8 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-systemjs@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.23.3" + dependencies: + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-module-transforms": ^7.23.3 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0d2fdd993c785aecac9e0850cd5ed7f7d448f0fbb42992a950cc0590167144df25d82af5aac9a5c99ef913d2286782afa44e577af30c10901c5ee8984910fa1f + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-umd@npm:^7.18.6": + version: 7.22.5 + resolution: "@babel/plugin-transform-modules-umd@npm:7.22.5" + dependencies: + "@babel/helper-module-transforms": "npm:^7.22.5" + "@babel/helper-plugin-utils": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 46622834c54c551b231963b867adbc80854881b3e516ff29984a8da989bd81665bd70e8cba6710345248e97166689310f544aee1a5773e262845a8f1b3e5b8b4 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-umd@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-modules-umd@npm:7.23.3" + dependencies: + "@babel/helper-module-transforms": ^7.23.3 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 586a7a2241e8b4e753a37af9466a9ffa8a67b4ba9aa756ad7500712c05d8fa9a8c1ed4f7bd25fae2a8265e6cf8fe781ec85a8ee885dd34cf50d8955ee65f12dc + languageName: node + linkType: hard + +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.20.5, @babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.5" + "@babel/helper-plugin-utils": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 3ee564ddee620c035b928fdc942c5d17e9c4b98329b76f9cefac65c111135d925eb94ed324064cd7556d4f5123beec79abea1d4b97d1c8a2a5c748887a2eb623 + languageName: node + linkType: hard + +"@babel/plugin-transform-new-target@npm:^7.18.6": + version: 7.22.5 + resolution: "@babel/plugin-transform-new-target@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6b72112773487a881a1d6ffa680afde08bad699252020e86122180ee7a88854d5da3f15d9bca3331cf2e025df045604494a8208a2e63b486266b07c14e2ffbf3 + languageName: node + linkType: hard + +"@babel/plugin-transform-new-target@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-new-target@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e5053389316fce73ad5201b7777437164f333e24787fbcda4ae489cd2580dbbbdfb5694a7237bad91fabb46b591d771975d69beb1c740b82cb4761625379f00b + languageName: node + linkType: hard + +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.11, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.23.4" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a27d73ea134d3d9560a6b2e26ab60012fba15f1db95865aa0153c18f5ec82cfef6a7b3d8df74e3c2fca81534fa5efeb6cacaf7b08bdb7d123e3dafdd079886a3 + languageName: node + linkType: hard + +"@babel/plugin-transform-numeric-separator@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.23.4" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6ba0e5db3c620a3ec81f9e94507c821f483c15f196868df13fa454cbac719a5449baf73840f5b6eb7d77311b24a2cf8e45db53700d41727f693d46f7caf3eec3 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-rest-spread@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.23.4" + dependencies: + "@babel/compat-data": ^7.23.3 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-transform-parameters": ^7.23.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 73fec495e327ca3959c1c03d07a621be09df00036c69fff0455af9a008291677ee9d368eec48adacdc6feac703269a649747568b4af4c4e9f134aa71cc5b378d + languageName: node + linkType: hard + +"@babel/plugin-transform-object-super@npm:^7.18.6": + version: 7.22.5 + resolution: "@babel/plugin-transform-object-super@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-replace-supers": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b71887877d74cb64dbccb5c0324fa67e31171e6a5311991f626650e44a4083e5436a1eaa89da78c0474fb095d4ec322d63ee778b202d33aa2e4194e1ed8e62d7 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-super@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-object-super@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e495497186f621fa79026e183b4f1fbb172fd9df812cbd2d7f02c05b08adbe58012b1a6eb6dd58d11a30343f6ec80d0f4074f9b501d70aa1c94df76d59164c53 + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-catch-binding@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.23.4" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: a15bfa5b36f5f1f61521cc1c73e1e394fbd08aef82a416e2e43f5fc7b43830f17d4c9a5605f1b69ed2bbbacd6f49f5e4f9a3e8e0b7a83841bc95e8ef2116f0a9 + checksum: d50b5ee142cdb088d8b5de1ccf7cea85b18b85d85b52f86618f6e45226372f01ad4cdb29abd4fd35ea99a71fefb37009e0107db7a787dcc21d4d402f97470faf languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.22.5, @babel/plugin-transform-optional-chaining@npm:^7.22.6": +"@babel/plugin-transform-optional-chaining@npm:^7.22.5": version: 7.22.6 resolution: "@babel/plugin-transform-optional-chaining@npm:7.22.6" dependencies: @@ -1301,18 +1849,42 @@ __metadata: "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: bb8188df57ab46c4c708eea17eddd20238ef9106c0e82016b1eb9565f073746e385e0be0b6ee25148507f3dc849311147a43323109c97106f15e0e7ff3220fdf + checksum: 9713f7920ed04090c149fc5ec024dd1638e8b97aa4ae3753b93072d84103b8de380afb96d6cf03e53b285420db4f705f3ac13149c6fd54f322b61dc19e33c54f + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-chaining@npm:^7.23.0, @babel/plugin-transform-optional-chaining@npm:^7.23.3, @babel/plugin-transform-optional-chaining@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.23.4" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e7a4c08038288057b7a08d68c4d55396ada9278095509ca51ed8dfb72a7f13f26bdd7c5185de21079fe0a9d60d22c227cb32e300d266c1bda40f70eee9f4bc1e languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.20.7, @babel/plugin-transform-parameters@npm:^7.21.3, @babel/plugin-transform-parameters@npm:^7.22.5": +"@babel/plugin-transform-parameters@npm:^7.20.7, @babel/plugin-transform-parameters@npm:^7.21.3": version: 7.22.5 resolution: "@babel/plugin-transform-parameters@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7d6a76dd1ac02373bc5542076c97fadcb18a9ebbcd4047e15f7a83d64efcff2baef1060a4bcfb9372d8ea18e5b1970f09514c58cece4145beb31d8b8d45d2e5f + checksum: b44f89cf97daf23903776ba27c2ab13b439d80d8c8a95be5c476ab65023b1e0c0e94c28d3745f3b60a58edc4e590fa0cd4287a0293e51401ca7d29a2ddb13b8e + languageName: node + linkType: hard + +"@babel/plugin-transform-parameters@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-parameters@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a735b3e85316d17ec102e3d3d1b6993b429bdb3b494651c9d754e3b7d270462ee1f1a126ccd5e3d871af5e683727e9ef98c9d34d4a42204fffaabff91052ed16 languageName: node linkType: hard @@ -1324,32 +1896,55 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: a62f2e47ca30f6b8043201483c5a505e3d54416e6ddfbe7cb696a1db853a4281b1fffee9f883fe26ac72ba02bba0db5832d69e02f2eb4746e9811b8779287cc1 + checksum: 321479b4fcb6d3b3ef622ab22fd24001e43d46e680e8e41324c033d5810c84646e470f81b44cbcbef5c22e99030784f7cac92f1829974da7a47a60a7139082c3 languageName: node linkType: hard -"@babel/plugin-transform-private-property-in-object@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.22.5" +"@babel/plugin-transform-private-methods@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-private-methods@npm:7.23.3" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-create-class-features-plugin": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" + "@babel/helper-create-class-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: cedc1285c49b5a6d9a3d0e5e413b756ac40b3ac2f8f68bdfc3ae268bc8d27b00abd8bb0861c72756ff5dd8bf1eb77211b7feb5baf4fdae2ebbaabe49b9adc1d0 + languageName: node + linkType: hard + +"@babel/plugin-transform-private-property-in-object@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.23.4" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f178191da005d986fdeb30ef74ea0d28878e6225d305d931ce925d87b7df432f5bb29e32173cff2a5c408cee7abc9f25fab09530d4f419ce5cc29a44a89f7a55 + checksum: fb7adfe94ea97542f250a70de32bddbc3e0b802381c92be947fec83ebffda57e68533c4d0697152719a3496fdd3ebf3798d451c024cd4ac848fc15ac26b70aa7 languageName: node linkType: hard -"@babel/plugin-transform-property-literals@npm:^7.18.6, @babel/plugin-transform-property-literals@npm:^7.22.5": +"@babel/plugin-transform-property-literals@npm:^7.18.6": version: 7.22.5 resolution: "@babel/plugin-transform-property-literals@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8d25b7b01b5f487cfc1a296555273c1ddad45276f01039130f57eb9ab0fafa0560d10d972323071042e73ac3b8bab596543c9d1a877229624a52e6535084ea51 + checksum: 796176a3176106f77fcb8cd04eb34a8475ce82d6d03a88db089531b8f0453a2fb8b0c6ec9a52c27948bc0ea478becec449893741fc546dfc3930ab927e3f9f2e + languageName: node + linkType: hard + +"@babel/plugin-transform-property-literals@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-property-literals@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 16b048c8e87f25095f6d53634ab7912992f78e6997a6ff549edc3cf519db4fca01c7b4e0798530d7f6a05228ceee479251245cdd850a5531c6e6f404104d6cc9 languageName: node linkType: hard @@ -1360,7 +1955,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 41e0167ecd8e5281e427556146b1d3bee8652bcd0664be013f16ffeeb4d61b7ab0b1e59bcc2c923774f0d265f78012628d5277880f758f3675893226f9be012e + checksum: a12bfd1e4e93055efca3ace3c34722571bda59d9740dca364d225d9c6e3ca874f134694d21715c42cc63d79efd46db9665bd4a022998767f9245f1e29d5d204d languageName: node linkType: hard @@ -1371,7 +1966,7 @@ __metadata: "@babel/plugin-transform-react-jsx": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 4d2e9e68383238feb873f6111df972df4a2ebf6256d6f787a8772241867efa975b3980f7d75ab7d750e7eaad4bd454e8cc6e106301fd7572dd389e553f5f69d2 + checksum: 36bc3ff0b96bb0ef4723070a50cfdf2e72cfd903a59eba448f9fe92fea47574d6f22efd99364413719e1f3fb3c51b6c9b2990b87af088f8486a84b2a5f9e4560 languageName: node linkType: hard @@ -1382,7 +1977,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 263091bdede1f448cb2c59b84eb69972c15d3f022c929a75337bd20d8b65551ac38cd26dad1946eaa93289643506b10ddaea3445a28cb8fca5a773a22a0df90b + checksum: 671eebfabd14a0c7d6ae805fff7e289dfdb7ba984bb100ea2ef6dad1d6a665ebbb09199ab2e64fca7bc78bd0fdc80ca897b07996cf215fafc32c67bc564309af languageName: node linkType: hard @@ -1393,11 +1988,11 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: defc9debb76b4295e3617ef7795a0533dbbecef6f51bf5ba4bfc162df892a84fd39e14d5f1b9a5aad7b09b97074fef4c6756f9d2036eef5a9874acabe198f75a + checksum: 4ca2bd62ca14f8bbdcda9139f3f799e1c1c1bae504b67c1ca9bca142c53d81926d1a2b811f66a625f20999b2d352131053d886601f1ba3c1e9378c104d884277 languageName: node linkType: hard -"@babel/plugin-transform-react-jsx@npm:^7.18.6, @babel/plugin-transform-react-jsx@npm:^7.19.0, @babel/plugin-transform-react-jsx@npm:^7.22.5": +"@babel/plugin-transform-react-jsx@npm:^7.18.6, @babel/plugin-transform-react-jsx@npm:^7.22.5": version: 7.22.5 resolution: "@babel/plugin-transform-react-jsx@npm:7.22.5" dependencies: @@ -1408,7 +2003,7 @@ __metadata: "@babel/types": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: fa4e5b32233c41686a420ad97b07a8a8b6cec7d484e93d5917db460887ded5179a8a20867a5d56d962b5452535830c0c0f8bfdc7d55853369be1e51b6a79a14a + checksum: c8f93f29f32cf79683ca2b8958fd62f38155674846ef27a7d4b6fbeb8713c37257418391731b58ff8024ec37b888bed5960e615a3f552e28245d2082e7f2a2df languageName: node linkType: hard @@ -1420,11 +2015,11 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 18db2e2346d79ebe4a3f85f51fa7757a63a09bc6da7f339e6ce9e7534de68b5165fe7d49ac363dee6ba3f81eb904d44bf9c13653331805f9b236a1d9fec7e018 + checksum: 092021c4f404e267002099ec20b3f12dd730cb90b0d83c5feed3dc00dbe43b9c42c795a18e7c6c7d7bddea20c7dd56221b146aec81b37f2e7eb5137331c61120 languageName: node linkType: hard -"@babel/plugin-transform-regenerator@npm:^7.21.5, @babel/plugin-transform-regenerator@npm:^7.22.5": +"@babel/plugin-transform-regenerator@npm:^7.21.5": version: 7.22.5 resolution: "@babel/plugin-transform-regenerator@npm:7.22.5" dependencies: @@ -1432,33 +2027,67 @@ __metadata: regenerator-transform: "npm:^0.15.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 5d9f42f831323db7e148cd9c47f61f3f667d283dba95f3221715871f52dec39868be1aa81dd834c27a2993602e5e396bb44bdfa563573a0d86b3883a58660004 + checksum: f7c5ca5151321963df777cc02725d10d1ccc3b3b8323da0423aecd9ac6144cbdd2274af5281a5580db2fc2f8b234e318517b5d76b85669118906533a559f2b6a + languageName: node + linkType: hard + +"@babel/plugin-transform-regenerator@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-regenerator@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + regenerator-transform: ^0.15.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7fdacc7b40008883871b519c9e5cdea493f75495118ccc56ac104b874983569a24edd024f0f5894ba1875c54ee2b442f295d6241c3280e61c725d0dd3317c8e6 languageName: node linkType: hard -"@babel/plugin-transform-reserved-words@npm:^7.18.6, @babel/plugin-transform-reserved-words@npm:^7.22.5": +"@babel/plugin-transform-reserved-words@npm:^7.18.6": version: 7.22.5 resolution: "@babel/plugin-transform-reserved-words@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 3ee861941b1d3f9e50f1bb97a2067f33c868b8cd5fd3419a610b2ad5f3afef5f9e4b3740d26a617dc1a9e169a33477821d96b6917c774ea87cac6790d341abbd + checksum: 3ffd7dbc425fe8132bfec118b9817572799cab1473113a635d25ab606c1f5a2341a636c04cf6b22df3813320365ed5a965b5eeb3192320a10e4cc2c137bd8bfc + languageName: node + linkType: hard + +"@babel/plugin-transform-reserved-words@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-reserved-words@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 298c4440ddc136784ff920127cea137168e068404e635dc946ddb5d7b2a27b66f1dd4c4acb01f7184478ff7d5c3e7177a127279479926519042948fb7fa0fa48 languageName: node linkType: hard -"@babel/plugin-transform-shorthand-properties@npm:^7.18.6, @babel/plugin-transform-shorthand-properties@npm:^7.22.5": +"@babel/plugin-transform-shorthand-properties@npm:^7.18.6": version: 7.22.5 resolution: "@babel/plugin-transform-shorthand-properties@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d2dd6b7033f536dd74569d7343bf3ca88c4bc12575e572a2c5446f42a1ebc8e69cec5e38fc0e63ac7c4a48b944a3225e4317d5db94287b9a5b381a5045c0cdb2 + checksum: a5ac902c56ea8effa99f681340ee61bac21094588f7aef0bc01dff98246651702e677552fa6d10e548c4ac22a3ffad047dd2f8c8f0540b68316c2c203e56818b + languageName: node + linkType: hard + +"@babel/plugin-transform-shorthand-properties@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 5d677a03676f9fff969b0246c423d64d77502e90a832665dc872a5a5e05e5708161ce1effd56bb3c0f2c20a1112fca874be57c8a759d8b08152755519281f326 languageName: node linkType: hard -"@babel/plugin-transform-spread@npm:^7.20.7, @babel/plugin-transform-spread@npm:^7.22.5": +"@babel/plugin-transform-spread@npm:^7.20.7": version: 7.22.5 resolution: "@babel/plugin-transform-spread@npm:7.22.5" dependencies: @@ -1466,44 +2095,89 @@ __metadata: "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f8896b00d69557a4aafb3f48b7db6fbaa8462588e733afc4eabfdf79b12a6aed7d20341d160d704205591f0a43d04971d391fa80328f61240d1edc918079a1b0 + checksum: 5587f0deb60b3dfc9b274e269031cc45ec75facccf1933ea2ea71ced9fd3ce98ed91bb36d6cd26817c14474b90ed998c5078415f0eab531caf301496ce24c95c languageName: node linkType: hard -"@babel/plugin-transform-sticky-regex@npm:^7.18.6, @babel/plugin-transform-sticky-regex@npm:^7.22.5": +"@babel/plugin-transform-spread@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-spread@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8fd5cac201e77a0b4825745f4e07a25f923842f282f006b3a79223c00f61075c8868d12eafec86b2642cd0b32077cdd32314e27bcb75ee5e6a68c0144140dcf2 + languageName: node + linkType: hard + +"@babel/plugin-transform-sticky-regex@npm:^7.18.6": version: 7.22.5 resolution: "@babel/plugin-transform-sticky-regex@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 42d9295d357415b55c04967ff1cd124cdcbabf2635614f9ad4f8b372d9ae35f6c02bf7473a5418b91e75235960cb1e61493e2c0581cb55bf9719b0986bcd22a5 + checksum: 63b2c575e3e7f96c32d52ed45ee098fb7d354b35c2223b8c8e76840b32cc529ee0c0ceb5742fd082e56e91e3d82842a367ce177e82b05039af3d602c9627a729 + languageName: node + linkType: hard + +"@babel/plugin-transform-sticky-regex@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 53e55eb2575b7abfdb4af7e503a2bf7ef5faf8bf6b92d2cd2de0700bdd19e934e5517b23e6dfed94ba50ae516b62f3f916773ef7d9bc81f01503f585051e2949 languageName: node linkType: hard -"@babel/plugin-transform-template-literals@npm:^7.18.9, @babel/plugin-transform-template-literals@npm:^7.22.5": +"@babel/plugin-transform-template-literals@npm:^7.18.9": version: 7.22.5 resolution: "@babel/plugin-transform-template-literals@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1fc597716edf9f5c7bc74e2fead4d7751467500486dd17092af90ccbd65c5fc4a1db2e9c86e9ed1a9f206f6a3403bbc07eab50b0c2b8e50f819b4118f2cf71ef + checksum: 27e9bb030654cb425381c69754be4abe6a7c75b45cd7f962cd8d604b841b2f0fb7b024f2efc1c25cc53f5b16d79d5e8cfc47cacbdaa983895b3aeefa3e7e24ff + languageName: node + linkType: hard + +"@babel/plugin-transform-template-literals@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-template-literals@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b16c5cb0b8796be0118e9c144d15bdc0d20a7f3f59009c6303a6e9a8b74c146eceb3f05186f5b97afcba7cfa87e34c1585a22186e3d5b22f2fd3d27d959d92b2 languageName: node linkType: hard -"@babel/plugin-transform-typeof-symbol@npm:^7.18.9, @babel/plugin-transform-typeof-symbol@npm:^7.22.5": +"@babel/plugin-transform-typeof-symbol@npm:^7.18.9": version: 7.22.5 resolution: "@babel/plugin-transform-typeof-symbol@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 277084dd3e873d62541f683173c7cf33b8317f7714335b7e861cc5b4b76f09acbf532a4c9dfbcf7756d29bc07b94b48bd9356af478f424865a86c7d5798be7c0 + checksum: 82a53a63ffc3010b689ca9a54e5f53b2718b9f4b4a9818f36f9b7dba234f38a01876680553d2716a645a61920b5e6e4aaf8d4a0064add379b27ca0b403049512 + languageName: node + linkType: hard + +"@babel/plugin-transform-typeof-symbol@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.23.3" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0af7184379d43afac7614fc89b1bdecce4e174d52f4efaeee8ec1a4f2c764356c6dba3525c0685231f1cbf435b6dd4ee9e738d7417f3b10ce8bbe869c32f4384 languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.21.3, @babel/plugin-transform-typescript@npm:^7.22.5": +"@babel/plugin-transform-typescript@npm:^7.21.3": version: 7.22.9 resolution: "@babel/plugin-transform-typescript@npm:7.22.9" dependencies: @@ -1513,34 +2187,59 @@ __metadata: "@babel/plugin-syntax-typescript": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: dc0623bbb21bffdc3c64bf5f50677ba06c6bd9f17edae08fd40f3e639632a716efce91100a46aeaad064e082ee71dfd35941cb605bf27f5d32363912a86ba07f + checksum: 6d1317a54d093b302599a4bee8ba9865d0de8b7b6ac1a0746c4316231d632f75b7f086e6e78acb9ac95ba12ba3b9da462dc9ca69370abb4603c4cc987f62e67e languageName: node linkType: hard -"@babel/plugin-transform-unicode-escapes@npm:^7.21.5, @babel/plugin-transform-unicode-escapes@npm:^7.22.5": +"@babel/plugin-transform-typescript@npm:^7.23.3": + version: 7.23.6 + resolution: "@babel/plugin-transform-typescript@npm:7.23.6" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.23.6 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-typescript": ^7.23.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0462241843d14dff9f1a4c49ab182a6f01a5f7679957c786b08165dac3e8d49184011f05ca204183d164c54b9d3496d1b3005f904fa8708e394e6f15bf5548e6 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-escapes@npm:^7.21.5": version: 7.22.5 resolution: "@babel/plugin-transform-unicode-escapes@npm:7.22.5" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e9005b2ca102d75e77154a9a7aa2a716d27f5fede04d98fc5f5bfc63390922da9e0112dac0e3c4df9145d30421131a8a79eeb3c6d51435cb7a6595bb692976f7 + checksum: da5e85ab3bb33a75cbf6181bfd236b208dc934702fd304db127232f17b4e0f42c6d3f238de8589470b4190906967eea8ca27adf3ae9d8ee4de2a2eae906ed186 languageName: node linkType: hard -"@babel/plugin-transform-unicode-property-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.22.5" +"@babel/plugin-transform-unicode-escapes@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.23.3" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 561c429183a54b9e4751519a3dfba6014431e9cdc1484fad03bdaf96582dfc72c76a4f8661df2aeeae7c34efd0fa4d02d3b83a2f63763ecf71ecc925f9cc1f60 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-property-regex@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.23.3" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: da424c1e99af0e920d21f7f121fb9503d0771597a4bd14130fb5f116407be29e9340c049d04733b3d8a132effe4f4585fe3cc9630ae3294a2df9199c8dfd7075 + checksum: 2298461a194758086d17c23c26c7de37aa533af910f9ebf31ebd0893d4aa317468043d23f73edc782ec21151d3c46cf0ff8098a83b725c49a59de28a1d4d6225 languageName: node linkType: hard -"@babel/plugin-transform-unicode-regex@npm:^7.18.6, @babel/plugin-transform-unicode-regex@npm:^7.22.5": +"@babel/plugin-transform-unicode-regex@npm:^7.18.6": version: 7.22.5 resolution: "@babel/plugin-transform-unicode-regex@npm:7.22.5" dependencies: @@ -1548,23 +2247,35 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 4cfaf4bb724a5c55a6fb5b0ee6ebbeba78dc700b9bc0043715d4b37409d90b43c888735c613690a1ec0d8d8e41a500b9d3f0395aa9f55b174449c8407663684b + checksum: 6b5d1404c8c623b0ec9bd436c00d885a17d6a34f3f2597996343ddb9d94f6379705b21582dfd4cec2c47fd34068872e74ab6b9580116c0566b3f9447e2a7fa06 languageName: node linkType: hard -"@babel/plugin-transform-unicode-sets-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.22.5" +"@babel/plugin-transform-unicode-regex@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.23.3" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-create-regexp-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c5f835d17483ba899787f92e313dfa5b0055e3deab332f1d254078a2bba27ede47574b6599fcf34d3763f0c048ae0779dc21d2d8db09295edb4057478dc80a9a + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-sets-regex@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.23.3" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0 - checksum: af37b468332db051f0aaa144adbfab39574e570f613e121b58a551e3cbb7083c9f8c32a83ba2641172a4065128052643468438c19ad098cd62b2d97140dc483e + checksum: 79d0b4c951955ca68235c87b91ab2b393c96285f8aeaa34d6db416d2ddac90000c9bd6e8c4d82b60a2b484da69930507245035f28ba63c6cae341cf3ba68fdef languageName: node linkType: hard -"@babel/preset-env@npm:7.21.5, @babel/preset-env@npm:~7.21.0": +"@babel/preset-env@npm:7.21.5": version: 7.21.5 resolution: "@babel/preset-env@npm:7.21.5" dependencies: @@ -1646,110 +2357,123 @@ __metadata: semver: "npm:^6.3.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6072eb19dee48dbfeaf1b5c79fbd0a28eea486c6e9d06a1793f1aa8769110adbe4ab6e14954ce6753f5dc9baf546e9fe62414c405caab0f7aecb2b0e5d94a950 + checksum: 86e167f3a351c89f8cd1409262481ece6ddc085b76147e801530ce29d60b1cfda8b264b1efd1ae27b8181b073a923c7161f21e2ebc0a41d652d717b10cf1c829 + languageName: node + linkType: hard + +"@babel/preset-env@npm:^7.23.2": + version: 7.23.8 + resolution: "@babel/preset-env@npm:7.23.8" + dependencies: + "@babel/compat-data": ^7.23.5 + "@babel/helper-compilation-targets": ^7.23.6 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.23.5 + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.23.3 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.23.3 + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.23.7 + "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 + "@babel/plugin-syntax-async-generators": ^7.8.4 + "@babel/plugin-syntax-class-properties": ^7.12.13 + "@babel/plugin-syntax-class-static-block": ^7.14.5 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + "@babel/plugin-syntax-import-assertions": ^7.23.3 + "@babel/plugin-syntax-import-attributes": ^7.23.3 + "@babel/plugin-syntax-import-meta": ^7.10.4 + "@babel/plugin-syntax-json-strings": ^7.8.3 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + "@babel/plugin-syntax-top-level-await": ^7.14.5 + "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 + "@babel/plugin-transform-arrow-functions": ^7.23.3 + "@babel/plugin-transform-async-generator-functions": ^7.23.7 + "@babel/plugin-transform-async-to-generator": ^7.23.3 + "@babel/plugin-transform-block-scoped-functions": ^7.23.3 + "@babel/plugin-transform-block-scoping": ^7.23.4 + "@babel/plugin-transform-class-properties": ^7.23.3 + "@babel/plugin-transform-class-static-block": ^7.23.4 + "@babel/plugin-transform-classes": ^7.23.8 + "@babel/plugin-transform-computed-properties": ^7.23.3 + "@babel/plugin-transform-destructuring": ^7.23.3 + "@babel/plugin-transform-dotall-regex": ^7.23.3 + "@babel/plugin-transform-duplicate-keys": ^7.23.3 + "@babel/plugin-transform-dynamic-import": ^7.23.4 + "@babel/plugin-transform-exponentiation-operator": ^7.23.3 + "@babel/plugin-transform-export-namespace-from": ^7.23.4 + "@babel/plugin-transform-for-of": ^7.23.6 + "@babel/plugin-transform-function-name": ^7.23.3 + "@babel/plugin-transform-json-strings": ^7.23.4 + "@babel/plugin-transform-literals": ^7.23.3 + "@babel/plugin-transform-logical-assignment-operators": ^7.23.4 + "@babel/plugin-transform-member-expression-literals": ^7.23.3 + "@babel/plugin-transform-modules-amd": ^7.23.3 + "@babel/plugin-transform-modules-commonjs": ^7.23.3 + "@babel/plugin-transform-modules-systemjs": ^7.23.3 + "@babel/plugin-transform-modules-umd": ^7.23.3 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.5 + "@babel/plugin-transform-new-target": ^7.23.3 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.23.4 + "@babel/plugin-transform-numeric-separator": ^7.23.4 + "@babel/plugin-transform-object-rest-spread": ^7.23.4 + "@babel/plugin-transform-object-super": ^7.23.3 + "@babel/plugin-transform-optional-catch-binding": ^7.23.4 + "@babel/plugin-transform-optional-chaining": ^7.23.4 + "@babel/plugin-transform-parameters": ^7.23.3 + "@babel/plugin-transform-private-methods": ^7.23.3 + "@babel/plugin-transform-private-property-in-object": ^7.23.4 + "@babel/plugin-transform-property-literals": ^7.23.3 + "@babel/plugin-transform-regenerator": ^7.23.3 + "@babel/plugin-transform-reserved-words": ^7.23.3 + "@babel/plugin-transform-shorthand-properties": ^7.23.3 + "@babel/plugin-transform-spread": ^7.23.3 + "@babel/plugin-transform-sticky-regex": ^7.23.3 + "@babel/plugin-transform-template-literals": ^7.23.3 + "@babel/plugin-transform-typeof-symbol": ^7.23.3 + "@babel/plugin-transform-unicode-escapes": ^7.23.3 + "@babel/plugin-transform-unicode-property-regex": ^7.23.3 + "@babel/plugin-transform-unicode-regex": ^7.23.3 + "@babel/plugin-transform-unicode-sets-regex": ^7.23.3 + "@babel/preset-modules": 0.1.6-no-external-plugins + babel-plugin-polyfill-corejs2: ^0.4.7 + babel-plugin-polyfill-corejs3: ^0.8.7 + babel-plugin-polyfill-regenerator: ^0.5.4 + core-js-compat: ^3.31.0 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b850f99fc4aed4ba22c7d9207bd2bbc7a729b49ea6f2c2c36e819fe209e309b96fba336096e555b46f791b39f7cdd5ac41246b556283d435a99106eb825a209f languageName: node linkType: hard -"@babel/preset-env@npm:^7.20.2": - version: 7.22.9 - resolution: "@babel/preset-env@npm:7.22.9" +"@babel/preset-flow@npm:^7.22.15": + version: 7.23.3 + resolution: "@babel/preset-flow@npm:7.23.3" dependencies: - "@babel/compat-data": "npm:^7.22.9" - "@babel/helper-compilation-targets": "npm:^7.22.9" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-validator-option": "npm:^7.22.5" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.22.5" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.22.5" - "@babel/plugin-proposal-private-property-in-object": "npm:7.21.0-placeholder-for-preset-env.2" - "@babel/plugin-syntax-async-generators": "npm:^7.8.4" - "@babel/plugin-syntax-class-properties": "npm:^7.12.13" - "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" - "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" - "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" - "@babel/plugin-syntax-import-assertions": "npm:^7.22.5" - "@babel/plugin-syntax-import-attributes": "npm:^7.22.5" - "@babel/plugin-syntax-import-meta": "npm:^7.10.4" - "@babel/plugin-syntax-json-strings": "npm:^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" - "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" - "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" - "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" - "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" - "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" - "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" - "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" - "@babel/plugin-transform-arrow-functions": "npm:^7.22.5" - "@babel/plugin-transform-async-generator-functions": "npm:^7.22.7" - "@babel/plugin-transform-async-to-generator": "npm:^7.22.5" - "@babel/plugin-transform-block-scoped-functions": "npm:^7.22.5" - "@babel/plugin-transform-block-scoping": "npm:^7.22.5" - "@babel/plugin-transform-class-properties": "npm:^7.22.5" - "@babel/plugin-transform-class-static-block": "npm:^7.22.5" - "@babel/plugin-transform-classes": "npm:^7.22.6" - "@babel/plugin-transform-computed-properties": "npm:^7.22.5" - "@babel/plugin-transform-destructuring": "npm:^7.22.5" - "@babel/plugin-transform-dotall-regex": "npm:^7.22.5" - "@babel/plugin-transform-duplicate-keys": "npm:^7.22.5" - "@babel/plugin-transform-dynamic-import": "npm:^7.22.5" - "@babel/plugin-transform-exponentiation-operator": "npm:^7.22.5" - "@babel/plugin-transform-export-namespace-from": "npm:^7.22.5" - "@babel/plugin-transform-for-of": "npm:^7.22.5" - "@babel/plugin-transform-function-name": "npm:^7.22.5" - "@babel/plugin-transform-json-strings": "npm:^7.22.5" - "@babel/plugin-transform-literals": "npm:^7.22.5" - "@babel/plugin-transform-logical-assignment-operators": "npm:^7.22.5" - "@babel/plugin-transform-member-expression-literals": "npm:^7.22.5" - "@babel/plugin-transform-modules-amd": "npm:^7.22.5" - "@babel/plugin-transform-modules-commonjs": "npm:^7.22.5" - "@babel/plugin-transform-modules-systemjs": "npm:^7.22.5" - "@babel/plugin-transform-modules-umd": "npm:^7.22.5" - "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.22.5" - "@babel/plugin-transform-new-target": "npm:^7.22.5" - "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.22.5" - "@babel/plugin-transform-numeric-separator": "npm:^7.22.5" - "@babel/plugin-transform-object-rest-spread": "npm:^7.22.5" - "@babel/plugin-transform-object-super": "npm:^7.22.5" - "@babel/plugin-transform-optional-catch-binding": "npm:^7.22.5" - "@babel/plugin-transform-optional-chaining": "npm:^7.22.6" - "@babel/plugin-transform-parameters": "npm:^7.22.5" - "@babel/plugin-transform-private-methods": "npm:^7.22.5" - "@babel/plugin-transform-private-property-in-object": "npm:^7.22.5" - "@babel/plugin-transform-property-literals": "npm:^7.22.5" - "@babel/plugin-transform-regenerator": "npm:^7.22.5" - "@babel/plugin-transform-reserved-words": "npm:^7.22.5" - "@babel/plugin-transform-shorthand-properties": "npm:^7.22.5" - "@babel/plugin-transform-spread": "npm:^7.22.5" - "@babel/plugin-transform-sticky-regex": "npm:^7.22.5" - "@babel/plugin-transform-template-literals": "npm:^7.22.5" - "@babel/plugin-transform-typeof-symbol": "npm:^7.22.5" - "@babel/plugin-transform-unicode-escapes": "npm:^7.22.5" - "@babel/plugin-transform-unicode-property-regex": "npm:^7.22.5" - "@babel/plugin-transform-unicode-regex": "npm:^7.22.5" - "@babel/plugin-transform-unicode-sets-regex": "npm:^7.22.5" - "@babel/preset-modules": "npm:^0.1.5" - "@babel/types": "npm:^7.22.5" - babel-plugin-polyfill-corejs2: "npm:^0.4.4" - babel-plugin-polyfill-corejs3: "npm:^0.8.2" - babel-plugin-polyfill-regenerator: "npm:^0.5.1" - core-js-compat: "npm:^3.31.0" - semver: "npm:^6.3.1" + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-transform-flow-strip-types": ^7.23.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: fad75686dd55638be71657edbd428bb0266a3f34bc6e367bd55fbff911652c971fcea3e5c346288d4e0a15c81b732c4a2549fce97910b602e19170fe1ddf72d0 + checksum: 60b5dde79621ae89943af459c4dc5b6030795f595a20ca438c8100f8d82c9ebc986881719030521ff5925799518ac5aa7f3fe62af8c33ab96be3681a71f88d03 languageName: node linkType: hard -"@babel/preset-flow@npm:^7.13.13": - version: 7.22.5 - resolution: "@babel/preset-flow@npm:7.22.5" +"@babel/preset-modules@npm:0.1.6-no-external-plugins": + version: 0.1.6-no-external-plugins + resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-validator-option": "npm:^7.22.5" - "@babel/plugin-transform-flow-strip-types": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.0.0 + "@babel/types": ^7.4.4 + esutils: ^2.0.2 peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: d3a54fbaa6da304bedc08847876f23c4bd6f9b13eb8b675ae48c45c678066f7610437b16a8972209c5250bdb205bde8800b8055a844922488b899fdbfe295f31 + "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 + checksum: 4855e799bc50f2449fb5210f78ea9e8fd46cf4f242243f1e2ed838e2bd702e25e73e822e7f8447722a5f4baa5e67a8f7a0e403f3e7ce04540ff743a9c411c375 languageName: node linkType: hard @@ -1764,7 +2488,7 @@ __metadata: esutils: "npm:^2.0.2" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: bd90081d96b746c1940dc1ce056dee06ed3a128d20936aee1d1795199f789f9a61293ef738343ae10c6d53970c17285d5e147a945dded35423aacb75083b8a89 + checksum: 8430e0e9e9d520b53e22e8c4c6a5a080a12b63af6eabe559c2310b187bd62ae113f3da82ba33e9d1d0f3230930ca702843aae9dd226dec51f7d7114dc1f51c10 languageName: node linkType: hard @@ -1780,7 +2504,7 @@ __metadata: "@babel/plugin-transform-react-pure-annotations": "npm:^7.18.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 19a5b238809e85875488e06f415fde175852ff2361f29ff60233053e3c9914afbaf8befe80cf636d5a49821e8b13067e60c85636deb8e1d6ac543643f5ef2559 + checksum: 540d9cf0a0cc0bb07e6879994e6fb7152f87dafbac880b56b65e2f528134c7ba33e0cd140b58700c77b2ebf4c81fa6468fed0ba391462d75efc7f8c1699bb4c3 languageName: node linkType: hard @@ -1795,44 +2519,44 @@ __metadata: "@babel/plugin-transform-typescript": "npm:^7.21.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ed50d19abb80af5dd5fbb2de21210164368e20ebfc86fea01f185c23ff49412c2b71daec4867309451e5d430d0026539cce74e3ef341ae64a7f11693dc5c6d5e + checksum: e7b35c435139eec1d6bd9f57e8f3eb79bfc2da2c57a34ad9e9ea848ba4ecd72791cf4102df456604ab07c7f4518525b0764754b6dd5898036608b351e0792448 languageName: node linkType: hard -"@babel/preset-typescript@npm:^7.13.0": - version: 7.22.5 - resolution: "@babel/preset-typescript@npm:7.22.5" +"@babel/preset-typescript@npm:^7.23.0": + version: 7.23.3 + resolution: "@babel/preset-typescript@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-validator-option": "npm:^7.22.5" - "@babel/plugin-syntax-jsx": "npm:^7.22.5" - "@babel/plugin-transform-modules-commonjs": "npm:^7.22.5" - "@babel/plugin-transform-typescript": "npm:^7.22.5" + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-syntax-jsx": ^7.23.3 + "@babel/plugin-transform-modules-commonjs": ^7.23.3 + "@babel/plugin-transform-typescript": ^7.23.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2d5924be38bdfea693548359dc547e8bb2c51793d6293168a7248d5ac1f5e94c5f8acea115b006bdd6fa4a20a8e92aa87a826a4aeaf143649e1683d0fe1b82d6 + checksum: 105a2d39bbc464da0f7e1ad7f535c77c5f62d6b410219355b20e552e7d29933567a5c55339b5d0aec1a5c7a0a7dfdf1b54aae601a4fe15a157d54dcbfcb3e854 languageName: node linkType: hard -"@babel/register@npm:^7.13.16": - version: 7.22.5 - resolution: "@babel/register@npm:7.22.5" +"@babel/register@npm:^7.22.15": + version: 7.23.7 + resolution: "@babel/register@npm:7.23.7" dependencies: - clone-deep: "npm:^4.0.1" - find-cache-dir: "npm:^2.0.0" - make-dir: "npm:^2.1.0" - pirates: "npm:^4.0.5" - source-map-support: "npm:^0.5.16" + clone-deep: ^4.0.1 + find-cache-dir: ^2.0.0 + make-dir: ^2.1.0 + pirates: ^4.0.6 + source-map-support: ^0.5.16 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 60b04871442fecb2a296fd3acbbab07e45c3e1c1f7972e72f6c61c575c3a0d95140710c52c4aa7a9b4bb8622641af6da00e3767b8fe17999a1daa1543025fc64 + checksum: c72a6d4856ef04f13490370d805854d2d98a77786bfaec7d85e2c585e1217011c4f3df18197a890e14520906c9111bef95551ba1a9b59c88df4dfc2dfe2c8d1b languageName: node linkType: hard "@babel/regjsgen@npm:^0.8.0": version: 0.8.0 resolution: "@babel/regjsgen@npm:0.8.0" - checksum: 4f3ddd8c7c96d447e05c8304c1d5ba3a83fcabd8a716bc1091c2f31595cdd43a3a055fff7cb5d3042b8cb7d402d78820fcb4e05d896c605a7d8bcf30f2424c4a + checksum: 89c338fee774770e5a487382170711014d49a68eb281e74f2b5eac88f38300a4ad545516a7786a8dd5702e9cf009c94c2f582d200f077ac5decd74c56b973730 languageName: node linkType: hard @@ -1841,7 +2565,16 @@ __metadata: resolution: "@babel/runtime@npm:7.22.6" dependencies: regenerator-runtime: "npm:^0.13.11" - checksum: 5a273e7d66586582041c68332028db5376d754d483422541fdc904e10474a6f8aef14dd3a5aabcbcb6daea87b64531cc4be993d2943557ede4a2613f5328a981 + checksum: e585338287c4514a713babf4fdb8fc2a67adcebab3e7723a739fc62c79cfda875b314c90fd25f827afb150d781af97bc16c85bfdbfa2889f06053879a1ddb597 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.13.10": + version: 7.23.8 + resolution: "@babel/runtime@npm:7.23.8" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 0bd5543c26811153822a9f382fd39886f66825ff2a397a19008011376533747cd05c33a91f6248c0b8b0edf0448d7c167ebfba34786088f1b7eb11c65be7dfc3 languageName: node linkType: hard @@ -1852,13 +2585,42 @@ __metadata: "@babel/code-frame": "npm:^7.22.5" "@babel/parser": "npm:^7.22.5" "@babel/types": "npm:^7.22.5" - checksum: dd8fc1b0bfe0128bace25da0e0a708e26320e8030322d3a53bb6366f199b46a277bfa4281dd370d73ab19087c7e27d166070a0659783b4715f7470448c7342b1 + checksum: c5746410164039aca61829cdb42e9a55410f43cace6f51ca443313f3d0bdfa9a5a330d0b0df73dc17ef885c72104234ae05efede37c1cc8a72dc9f93425977a3 languageName: node linkType: hard -"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.21.5, @babel/traverse@npm:^7.22.6, @babel/traverse@npm:^7.22.8": - version: 7.22.8 - resolution: "@babel/traverse@npm:7.22.8" +"@babel/template@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/template@npm:7.22.15" + dependencies: + "@babel/code-frame": ^7.22.13 + "@babel/parser": ^7.22.15 + "@babel/types": ^7.22.15 + checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.23.7": + version: 7.23.7 + resolution: "@babel/traverse@npm:7.23.7" + dependencies: + "@babel/code-frame": ^7.23.5 + "@babel/generator": ^7.23.6 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/parser": ^7.23.6 + "@babel/types": ^7.23.6 + debug: ^4.3.1 + globals: ^11.1.0 + checksum: d4a7afb922361f710efc97b1e25ec343fab8b2a4ddc81ca84f9a153f22d4482112cba8f263774be8d297918b6c4767c7a98988ab4e53ac73686c986711dd002e + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.21.5, @babel/traverse@npm:^7.22.6, @babel/traverse@npm:^7.22.8": + version: 7.22.8 + resolution: "@babel/traverse@npm:7.22.8" dependencies: "@babel/code-frame": "npm:^7.22.5" "@babel/generator": "npm:^7.22.7" @@ -1870,82 +2632,64 @@ __metadata: "@babel/types": "npm:^7.22.5" debug: "npm:^4.1.0" globals: "npm:^11.1.0" - checksum: 839014824c210388ed46f92bf5265522bd5bbb4a9a03c700f9d79b151bdd0aa077c2f6448a0cef41132188cc2bc6d8cdcad98a297ba59983401e882bdc256b1f - languageName: node - linkType: hard - -"@babel/traverse@npm:~7.21.2": - version: 7.21.5 - resolution: "@babel/traverse@npm:7.21.5" - dependencies: - "@babel/code-frame": "npm:^7.21.4" - "@babel/generator": "npm:^7.21.5" - "@babel/helper-environment-visitor": "npm:^7.21.5" - "@babel/helper-function-name": "npm:^7.21.0" - "@babel/helper-hoist-variables": "npm:^7.18.6" - "@babel/helper-split-export-declaration": "npm:^7.18.6" - "@babel/parser": "npm:^7.21.5" - "@babel/types": "npm:^7.21.5" - debug: "npm:^4.1.0" - globals: "npm:^11.1.0" - checksum: 1b126b71b98aaff01ec1f0f0389d08beb6eda3d0b71878af4c6cf386686933a076d969240f270c6a01910d8036a1fb9013d53bd5c136b9b24025204a4dc48d03 + checksum: a381369bc3eedfd13ed5fef7b884657f1c29024ea7388198149f0edc34bd69ce3966e9f40188d15f56490a5e12ba250ccc485f2882b53d41b054fccefb233e33 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.21.5, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.21.5, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.22.5 resolution: "@babel/types@npm:7.22.5" dependencies: "@babel/helper-string-parser": "npm:^7.22.5" "@babel/helper-validator-identifier": "npm:^7.22.5" to-fast-properties: "npm:^2.0.0" - checksum: 2473295056520432ec0b5fe2dc7b37914292d211ccdbc2cb05650f9c44d5168a760bca0f492a9fff7c72459defee15cd48ef152e74961cfdc03144c7a4b8bec8 + checksum: c13a9c1dc7d2d1a241a2f8363540cb9af1d66e978e8984b400a20c4f38ba38ca29f06e26a0f2d49a70bad9e57615dac09c35accfddf1bb90d23cd3e0a0bab892 languageName: node linkType: hard -"@babel/types@npm:~7.21.2": - version: 7.21.5 - resolution: "@babel/types@npm:7.21.5" +"@babel/types@npm:^7.18.9, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/types@npm:7.23.6" dependencies: - "@babel/helper-string-parser": "npm:^7.21.5" - "@babel/helper-validator-identifier": "npm:^7.19.1" - to-fast-properties: "npm:^2.0.0" - checksum: 23c943aa2c0d11b798e9298b55b1993da8b386504aac2f781a49b4bbf2cf2ad5e1003409241578574e421c999ff7a3aab2cf30ad3581d33eb9053d82b9e20408 + "@babel/helper-string-parser": ^7.23.4 + "@babel/helper-validator-identifier": ^7.22.20 + to-fast-properties: ^2.0.0 + checksum: 68187dbec0d637f79bc96263ac95ec8b06d424396678e7e225492be866414ce28ebc918a75354d4c28659be6efe30020b4f0f6df81cc418a2d30645b690a8de0 languageName: node linkType: hard "@base2/pretty-print-object@npm:1.0.1": version: 1.0.1 resolution: "@base2/pretty-print-object@npm:1.0.1" - checksum: 98f77ea185a30c854897feb2a68fe51be8451a1a0b531bac61a5dd67033926a0ba0c9be6e0f819b8cb72ca349b3e7648bf81c12fd21df0b45219c75a3a75784b + checksum: 1e8a5af578037a9d47d72f815983f9e4efb038e5f03e7635fc893194c5daa723215d71af33267893a9b618656c8eaea7be931b1c063c9b066a40994be0d23545 languageName: node linkType: hard "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" - checksum: 6b80ae4cb3db53f486da2dc63b6e190a74c8c3cca16bb2733f234a0b6a9382b09b146488ae08e2b22cf00f6c83e20f3e040a2f7894f05c045c946d6a090b1d52 + checksum: 850f9305536d0f2bd13e9e0881cb5f02e4f93fad1189f7b2d4bebf694e3206924eadee1068130d43c11b750efcc9405f88a8e42ef098b6d75239c0f047de1a27 languageName: node linkType: hard "@braintree/browser-detection@npm:^2.0.0": version: 2.0.0 resolution: "@braintree/browser-detection@npm:2.0.0" - checksum: ce9ac99d46547e8fb3a48352897cfa21d0788f34f76e58ade3201b8f8bcc9a1dc9403ff3b213f82f6f9a629e27cc629f7d09114642ea664e2f4add5e82b675d7 + checksum: b509669a044550cfabbe2b107b4c8066c977f5cd5942a36e4dffd090a50df609029337367207735c9609bc87794ec829f5caf418cd31aa6849160014c352d15a languageName: node linkType: hard "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" - checksum: eb42729851adca56d19a08e48d5a1e95efd2a32c55ae0323de8119052be0510d4b7a1611f2abcbf28c044a6c11e6b7d38f99fccdad7429300c37a8ea5fb95b44 + checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425 languageName: node linkType: hard "@discoveryjs/json-ext@npm:^0.5.3": version: 0.5.7 resolution: "@discoveryjs/json-ext@npm:0.5.7" - checksum: e10f1b02b78e4812646ddf289b7d9f2cb567d336c363b266bd50cd223cf3de7c2c74018d91cd2613041568397ef3a4a2b500aba588c6e5bd78c38374ba68f38c + checksum: 2176d301cc258ea5c2324402997cf8134ebb212469c0d397591636cea8d3c02f2b3cf9fd58dcb748c7a0dade77ebdc1b10284fa63e608c033a1db52fddc69918 languageName: node linkType: hard @@ -1954,14 +2698,7 @@ __metadata: resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.0.1" peerDependencies: react: ">=16.8.0" - checksum: a15b2167940e3a908160687b73fc4fcd81e59ab45136b6967f02c7c419d9a149acd22a416b325c389642d4f1c3d33cf4196cad6b618128b55b7c74f6807a240b - languageName: node - linkType: hard - -"@esbuild/android-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-arm64@npm:0.17.19" - conditions: os=android & cpu=arm64 + checksum: 700b6e5bbb37a9231f203bb3af11295eed01d73b2293abece0bc2a2237015e944d7b5114d4887ad9a79776504aa51ed2a8b0ddbc117c54495dd01a6b22f93786 languageName: node linkType: hard @@ -1972,10 +2709,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-arm@npm:0.17.19" - conditions: os=android & cpu=arm +"@esbuild/android-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm64@npm:0.18.20" + conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -1986,10 +2723,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-x64@npm:0.17.19" - conditions: os=android & cpu=x64 +"@esbuild/android-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm@npm:0.18.20" + conditions: os=android & cpu=arm languageName: node linkType: hard @@ -2000,10 +2737,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/darwin-arm64@npm:0.17.19" - conditions: os=darwin & cpu=arm64 +"@esbuild/android-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-x64@npm:0.18.20" + conditions: os=android & cpu=x64 languageName: node linkType: hard @@ -2014,10 +2751,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/darwin-x64@npm:0.17.19" - conditions: os=darwin & cpu=x64 +"@esbuild/darwin-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-arm64@npm:0.18.20" + conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -2028,10 +2765,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/freebsd-arm64@npm:0.17.19" - conditions: os=freebsd & cpu=arm64 +"@esbuild/darwin-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-x64@npm:0.18.20" + conditions: os=darwin & cpu=x64 languageName: node linkType: hard @@ -2042,10 +2779,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/freebsd-x64@npm:0.17.19" - conditions: os=freebsd & cpu=x64 +"@esbuild/freebsd-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-arm64@npm:0.18.20" + conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard @@ -2056,10 +2793,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-arm64@npm:0.17.19" - conditions: os=linux & cpu=arm64 +"@esbuild/freebsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-x64@npm:0.18.20" + conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -2070,10 +2807,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-arm@npm:0.17.19" - conditions: os=linux & cpu=arm +"@esbuild/linux-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm64@npm:0.18.20" + conditions: os=linux & cpu=arm64 languageName: node linkType: hard @@ -2084,10 +2821,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-ia32@npm:0.17.19" - conditions: os=linux & cpu=ia32 +"@esbuild/linux-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm@npm:0.18.20" + conditions: os=linux & cpu=arm languageName: node linkType: hard @@ -2098,10 +2835,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-loong64@npm:0.17.19" - conditions: os=linux & cpu=loong64 +"@esbuild/linux-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ia32@npm:0.18.20" + conditions: os=linux & cpu=ia32 languageName: node linkType: hard @@ -2112,10 +2849,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-mips64el@npm:0.17.19" - conditions: os=linux & cpu=mips64el +"@esbuild/linux-loong64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-loong64@npm:0.18.20" + conditions: os=linux & cpu=loong64 languageName: node linkType: hard @@ -2126,10 +2863,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-ppc64@npm:0.17.19" - conditions: os=linux & cpu=ppc64 +"@esbuild/linux-mips64el@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-mips64el@npm:0.18.20" + conditions: os=linux & cpu=mips64el languageName: node linkType: hard @@ -2140,10 +2877,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-riscv64@npm:0.17.19" - conditions: os=linux & cpu=riscv64 +"@esbuild/linux-ppc64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ppc64@npm:0.18.20" + conditions: os=linux & cpu=ppc64 languageName: node linkType: hard @@ -2154,10 +2891,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-s390x@npm:0.17.19" - conditions: os=linux & cpu=s390x +"@esbuild/linux-riscv64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-riscv64@npm:0.18.20" + conditions: os=linux & cpu=riscv64 languageName: node linkType: hard @@ -2168,10 +2905,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-x64@npm:0.17.19" - conditions: os=linux & cpu=x64 +"@esbuild/linux-s390x@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-s390x@npm:0.18.20" + conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -2182,10 +2919,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/netbsd-x64@npm:0.17.19" - conditions: os=netbsd & cpu=x64 +"@esbuild/linux-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-x64@npm:0.18.20" + conditions: os=linux & cpu=x64 languageName: node linkType: hard @@ -2196,10 +2933,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/openbsd-x64@npm:0.17.19" - conditions: os=openbsd & cpu=x64 +"@esbuild/netbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/netbsd-x64@npm:0.18.20" + conditions: os=netbsd & cpu=x64 languageName: node linkType: hard @@ -2210,10 +2947,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/sunos-x64@npm:0.17.19" - conditions: os=sunos & cpu=x64 +"@esbuild/openbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/openbsd-x64@npm:0.18.20" + conditions: os=openbsd & cpu=x64 languageName: node linkType: hard @@ -2224,10 +2961,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-arm64@npm:0.17.19" - conditions: os=win32 & cpu=arm64 +"@esbuild/sunos-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/sunos-x64@npm:0.18.20" + conditions: os=sunos & cpu=x64 languageName: node linkType: hard @@ -2238,10 +2975,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-ia32@npm:0.17.19" - conditions: os=win32 & cpu=ia32 +"@esbuild/win32-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-arm64@npm:0.18.20" + conditions: os=win32 & cpu=arm64 languageName: node linkType: hard @@ -2252,10 +2989,10 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-x64@npm:0.17.19" - conditions: os=win32 & cpu=x64 +"@esbuild/win32-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-ia32@npm:0.18.20" + conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -2266,6 +3003,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-x64@npm:0.18.20" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" @@ -2273,14 +3017,14 @@ __metadata: eslint-visitor-keys: "npm:^3.3.0" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 7e559c4ce59cd3a06b1b5a517b593912e680a7f981ae7affab0d01d709e99cd5647019be8fafa38c350305bc32f1f7d42c7073edde2ab536c745e365f37b607e + checksum: cdfe3ae42b4f572cbfb46d20edafe6f36fc5fb52bf2d90875c58aefe226892b9677fef60820e2832caf864a326fe4fc225714c46e8389ccca04d5f9288aabd22 languageName: node linkType: hard "@eslint-community/regexpp@npm:^4.4.0": version: 4.5.1 resolution: "@eslint-community/regexpp@npm:4.5.1" - checksum: d79cbd99cc4dcfbb17e8dd30a30bb5aec5da9c60b9471043f886f116615bb15f0d417cb0ca638cefedba0b4c67c339e2011b53d88264a4540775f042a5879e01 + checksum: 6d901166d64998d591fab4db1c2f872981ccd5f6fe066a1ad0a93d4e11855ecae6bfb76660869a469563e8882d4307228cebd41142adb409d182f2966771e57e languageName: node linkType: hard @@ -2297,28 +3041,28 @@ __metadata: js-yaml: "npm:^4.1.0" minimatch: "npm:^3.1.2" strip-json-comments: "npm:^3.1.1" - checksum: 6ffbc3e7867b377754492539af0e2f5b55645a2c67279a70508fe09080bc76d49ba64b579e59a2a04014f84d0768301736fbcdd94c7b3ad4f0e648c32bf21e43 + checksum: d5ed0adbe23f6571d8c9bb0ca6edf7618dc6aed4046aa56df7139f65ae7b578874e0d9c796df784c25bda648ceb754b6320277d828c8b004876d7443b8dc018c languageName: node linkType: hard "@eslint/js@npm:8.38.0": version: 8.38.0 resolution: "@eslint/js@npm:8.38.0" - checksum: e2f4b565d542758779b98019cfa63e24fc56fabfb8d04caf7f6310753703116b880b6a8061d671f2a40a68dba24a8a199eb01d5c8b140f53c49f05c75b404ff5 + checksum: 1f28987aa8c9cd93e23384e16c7220863b39b5dc4b66e46d7cdbccce868040f455a98d24cd8b567a884f26545a0555b761f7328d4a00c051e7ef689cbea5fce1 languageName: node linkType: hard "@fal-works/esbuild-plugin-global-externals@npm:^2.1.2": version: 2.1.2 resolution: "@fal-works/esbuild-plugin-global-externals@npm:2.1.2" - checksum: 2c84a8e6121b00ac8e4eb2469ab8f188142db2f1927391758e5d0142cb684b7eb0fad0c9d6caf358616eb2a77af2c067e08b9ec8e05749b415fc4dd0ef96d0fe + checksum: c59715902b9062aa7ff38973f298b509499fd146dbf564dc338b3f9e896da5bffb4ca676c27587fde79b3586003e24d65960acb62f009bca43dca34c76f8cbf7 languageName: node linkType: hard "@floating-ui/core@npm:^1.2.6, @floating-ui/core@npm:^1.3.1": version: 1.3.1 resolution: "@floating-ui/core@npm:1.3.1" - checksum: 894bc3637c03beda184a4460cb53155fd30c2a0956569e1c714b7df9e3439517b1c34ad9a8114ea15a6c08d1e3f1d40741d259f0f1087fc3ea96fae7dfeb697e + checksum: fe3b40fcaec95b0825c01a98330ae75b60c61c395ca012055a32f9c22ab97fde8ce1bd14fce3d242beb9dbe4564c90ce4a7a767851911d4215b9ec7721440e5b languageName: node linkType: hard @@ -2327,7 +3071,7 @@ __metadata: resolution: "@floating-ui/dom@npm:1.2.9" dependencies: "@floating-ui/core": "npm:^1.2.6" - checksum: cc7307ac189f1f9d744970c6dfe9e15cb14a7c0262b7223081b7b0005e113d727828f41aafb34f7ffa3670ccef0457921551add325fa67de85cc2e65cf10f7fd + checksum: 16ae5e05a41c2ca16d51579d12729ca9d346241319f68ce5678f5fbeb9c4f9a16176c95089bbd7a0eb37c6ed90e5fd55a310ffc9948af7c841d5b8bfa0afe1b8 languageName: node linkType: hard @@ -2336,7 +3080,7 @@ __metadata: resolution: "@floating-ui/dom@npm:1.4.4" dependencies: "@floating-ui/core": "npm:^1.3.1" - checksum: 31f3511d981e84add1154c159632527263395efbd36f0780cefd2d53918fd808bcd0b3bc19d775e97315ebc44e405b4e617fc8601dbb14d46305be1cca9f522a + checksum: e8e43c786e24f8f111a72d7d17c3a9563cab8eddf2a2b3dacc2785370a97313a8dda0f3470b2b2ef2d3b9d6f1fd706ccf786d9441e54e283ed47c90aa0c0b1e1 languageName: node linkType: hard @@ -2348,7 +3092,7 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 856c0c9de0a9117bcc69b1363fd9fa188133b9714394609db937903ab4330e9851becfd2a83453f40834de1a18377caf329b6b71afc1c69d7c5687f87da80ed4 + checksum: 00fef2cf69ac2b15952e47505fd9e23f6cc5c20a26adc707862932826d1682f3c30f83c9887abfc93574fdca2d34dd2fc00271527318b1db403549cd6bc9eb00 languageName: node linkType: hard @@ -2362,7 +3106,7 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 7ed57426703c49a6f7715c5dcdf3bea29935272eb955fbaf23a6d793a6f024e2c6d9a42d4d1e513c19bdcab210ceb904a30df39cca7c3b895d297ad401a83974 + checksum: 0d8300f5706ca7cf69c1b4c26822287fd545b23d9f89c03fca1c04d3899edd188f374567ed98e1ccebd80869b50cd7c4908e9d4be91d25dd5800b787961faf83 languageName: node linkType: hard @@ -2373,21 +3117,21 @@ __metadata: "@humanwhocodes/object-schema": "npm:^1.2.1" debug: "npm:^4.1.1" minimatch: "npm:^3.0.5" - checksum: 9e307a49a5baa28beb243d2c14c145f288fccd6885f4c92a9055707057ec40980242256b2a07c976cfa6c75f7081da111a40a9844d1ca8daeff2302f8b640e76 + checksum: 1b1302e2403d0e35bc43e66d67a2b36b0ad1119efc704b5faff68c41f791a052355b010fb2d27ef022670f550de24cd6d08d5ecf0821c16326b7dcd0ee5d5d8a languageName: node linkType: hard "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 + checksum: 0fd22007db8034a2cdf2c764b140d37d9020bbfce8a49d3ec5c05290e77d4b0263b1b972b752df8c89e5eaa94073408f2b7d977aed131faf6cf396ebb5d7fb61 languageName: node linkType: hard "@humanwhocodes/object-schema@npm:^1.2.1": version: 1.2.1 resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: c3c35fdb70c04a569278351c75553e293ae339684ed75895edc79facc7276e351115786946658d78133130c0cca80e57e2203bc07f8fa7fe7980300e8deef7db + checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 languageName: node linkType: hard @@ -2401,7 +3145,7 @@ __metadata: strip-ansi-cjs: "npm:strip-ansi@^6.0.1" wrap-ansi: "npm:^8.1.0" wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e + checksum: 4a473b9b32a7d4d3cfb7a614226e555091ff0c5a29a1734c28c72a182c2f6699b26fc6b5c2131dfd841e86b185aea714c72201d7c98c2fba5f17709333a67aeb languageName: node linkType: hard @@ -2414,14 +3158,14 @@ __metadata: get-package-type: "npm:^0.1.0" js-yaml: "npm:^3.13.1" resolve-from: "npm:^5.0.0" - checksum: dd2a8b094887da5a1a2339543a4933d06db2e63cbbc2e288eb6431bd832065df0c099d091b6a67436e71b7d6bf85f01ce7c15f9253b4cbebcc3b9a496165ba42 + checksum: d578da5e2e804d5c93228450a1380e1a3c691de4953acc162f387b717258512a3e07b83510a936d9fab03eac90817473917e24f5d16297af3867f59328d58568 languageName: node linkType: hard -"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": +"@istanbuljs/schema@npm:^0.1.2": version: 0.1.3 resolution: "@istanbuljs/schema@npm:0.1.3" - checksum: 61c5286771676c9ca3eb2bd8a7310a9c063fb6e0e9712225c8471c582d157392c88f5353581c8c9adbe0dff98892317d2fdfc56c3499aa42e0194405206a963a + checksum: 5282759d961d61350f33d9118d16bcaed914ebf8061a52f4fa474b2cb08720c9c81d165e13b82f2e5a8a212cc5af482f0c6fc1ac27b9e067e5394c9a6ed186c9 languageName: node linkType: hard @@ -2435,7 +3179,7 @@ __metadata: jest-message-util: "npm:^29.6.1" jest-util: "npm:^29.6.1" slash: "npm:^3.0.0" - checksum: d62b089015f06d2ca277d8bff63a2c19b861b12161f5b8a69207498b980659dedfdcdcdcd1c0d5078a73cba5dd270392c65476ba9a48b795d1276517ba30f7ed + checksum: d0ab23a00947bfb4bff8c0a7e5a7afd16519de16dde3fe7e77b9f13e794c6df7043ecf7fcdde66ac0d2b5fb3262e9cab3d92eaf61f89a12d3b8e3602e06a9902 languageName: node linkType: hard @@ -2476,7 +3220,7 @@ __metadata: peerDependenciesMeta: node-notifier: optional: true - checksum: dccd83243af657da9af4c7ae578d55267c85e5bf1755a3a3e189c9ec0d23d409956e0eff7c13b81a388940ab9f294b0afc0241288d5832769687d919fae576fe + checksum: 736dcc90c6c58dd9e1d2da122103b851187719ce3b3d4167689c63e68252632cd817712955b52ddaa648eba9c6f98f86cd58677325f0db4185f76899c64d7dac languageName: node linkType: hard @@ -2488,7 +3232,7 @@ __metadata: "@jest/types": "npm:^29.6.1" "@types/node": "npm:*" jest-mock: "npm:^29.6.1" - checksum: 9c9fddcbec02b59b9719ede7d51e23e5dcd2230365a1df45ff782ea18af4b51fa0d9f5a3e76fbee6d0b7403ae4cd3fb9c45e9f86177c9be02bbbf84ae7f778c6 + checksum: fb671f91f27e7aa1ba04983ef87a83f0794a597aba0a57d08cbb1fcb484c2aedc2201e99f85fafe27aec9be78af6f2d1d7e6ea88267938992a1d0f9d4615f5b2 languageName: node linkType: hard @@ -2497,7 +3241,7 @@ __metadata: resolution: "@jest/expect-utils@npm:29.6.1" dependencies: jest-get-type: "npm:^29.4.3" - checksum: e04164280c0b47a6285f39e70323b54eafc42367d9304897d55d70abd50324e060cb81efc7df82b1031eb46b82b85ecf343ed50c72654b11f1492b34c5e1a7b9 + checksum: 037ee017eca62f7b45e1465fb5c6f9e92d5709a9ac716b8bff0bd294240a54de734e8f968fb69309cc4aef6c83b9552d5a821f3b18371af394bf04783859d706 languageName: node linkType: hard @@ -2507,7 +3251,7 @@ __metadata: dependencies: expect: "npm:^29.6.1" jest-snapshot: "npm:^29.6.1" - checksum: 7766e9e02eac18edd2dfdf3481083f1a45b42efdc5fb13e3290132a0379d807a8b892ba1055c6917a3a2ed902240c556ac8704e17652b1b8387a58711867ca2f + checksum: 5c56977b3cc8489744d97d9dc2dcb196c1dfecc83a058a7ef0fd4f63d68cf120a23d27669272d1e1b184fb4337b85e4ac1fc7f886e3988fdf243d42d73973eac languageName: node linkType: hard @@ -2521,7 +3265,7 @@ __metadata: jest-message-util: "npm:^29.6.1" jest-mock: "npm:^29.6.1" jest-util: "npm:^29.6.1" - checksum: 112b1f26f48f16dd8732f9842d480b66545cd5226d674e59c758f56680d234fc4debb77497784bf26130b21caab4d8cd39cf09afbbb2863a0a4ee0ccdb4c6e14 + checksum: 86991276944b7d6c2ada3703a272517f5f8f2f4e2af1fe26065f6db1dac4dc6299729a88c46bcb781dcc1b20504c1d4bbd8119fd8a0838ac81a9a4b5d2c8e429 languageName: node linkType: hard @@ -2533,7 +3277,7 @@ __metadata: "@jest/expect": "npm:^29.6.1" "@jest/types": "npm:^29.6.1" jest-mock: "npm:^29.6.1" - checksum: 9ee8a6e476b8e74d4aa16150ea0ba0b8ecc25328062762cb46095fdec9638fc525d0e7f06e3aa1413600749c79d02a4db18da9912675843672242ea44763fa49 + checksum: fcca0b970a8b4894a1cdff0f500a86b45609e72c0a4319875e9504237b839df1a46c44d2f1362c6d87fdc7a05928edcc4b5a3751c9e6648dd70a761cdab64c94 languageName: node linkType: hard @@ -2570,7 +3314,7 @@ __metadata: peerDependenciesMeta: node-notifier: optional: true - checksum: fd6e1eab9afee7eebb0a5f461b447b72d227459ce0e96e3ad4024e8795a36d03e1110c91fae9c61a5da50df42978041455f96bf5b09e5b0cead33fb44c63150b + checksum: b7dae415f3f6342b4db2671261bbee29af20a829f42135316c3dd548b9ef85290c9bb64a0e3aec4a55486596be1257ac8216a0f8d9794acd43f8b8fb686fc7e3 languageName: node linkType: hard @@ -2579,7 +3323,7 @@ __metadata: resolution: "@jest/schemas@npm:29.6.0" dependencies: "@sinclair/typebox": "npm:^0.27.8" - checksum: 8671b1fb59c4296204d335190e8451e1983d9f2db6dbbd38f838c6c273fd222fc11e4e0df04adfb6169d36acfb9693d525db136653ec04e6884180f45a131d8f + checksum: c00511c69cf89138a7d974404d3a5060af375b5a52b9c87215d91873129b382ca11c1ff25bd6d605951404bb381ddce5f8091004a61e76457da35db1f5c51365 languageName: node linkType: hard @@ -2590,7 +3334,7 @@ __metadata: "@jridgewell/trace-mapping": "npm:^0.3.18" callsites: "npm:^3.0.0" graceful-fs: "npm:^4.2.9" - checksum: afa654e3634ad74d5f8388ccffd7ecbd745bdce7f6f0860b69c07827c3ee5bb408f52b6c3136b43157ef5874c099059484e43bd3aa391232ab27d8c330399789 + checksum: 9c6c40387410bb70b2fae8124287fc28f6bdd1b2d7f24348e8611e1bb638b404518228a4ce64a582365b589c536ae8e7ebab0126cef59a87874b71061d19783b languageName: node linkType: hard @@ -2602,7 +3346,7 @@ __metadata: "@jest/types": "npm:^29.6.1" "@types/istanbul-lib-coverage": "npm:^2.0.0" collect-v8-coverage: "npm:^1.0.0" - checksum: 0b460253f092042cb2edaae92f9f22aed150a2dc3eaa8dbd60a31db8a3b12fc14c89784b580e0a678ef52e7438a11b27eaaedd2bc9c4328dbbd6d5d72983de6c + checksum: 9397a3a3410c5df564e79297b1be4fe33807a6157a017a1f74b54a6ef14de1530f12b922299e822e66a82c53269da16661772bffde3d883a78c5eefd2cd6d1cc languageName: node linkType: hard @@ -2614,7 +3358,7 @@ __metadata: graceful-fs: "npm:^4.2.9" jest-haste-map: "npm:^29.6.1" slash: "npm:^3.0.0" - checksum: 411b7fd3a55daaf6f3ce7d3f3cd7114580126df9190a3f27d4e5a5429d91cb56c77899560afefd69451cde4911259c44f9e5fb09d975dc1f1ba597295a64f165 + checksum: f3437178b5dca0401ed2e990d8b69161442351856d56f5725e009a487f5232b51039f8829673884b9bea61c861120d08a53a36432f4a4b8aab38915a68f7000d languageName: node linkType: hard @@ -2637,7 +3381,7 @@ __metadata: pirates: "npm:^4.0.4" slash: "npm:^3.0.0" write-file-atomic: "npm:^4.0.2" - checksum: e34ddd89f372af749e983e29febfbb6f9a96eb677af32b5b299ce36eeab7b1ae55ddda2b64ff91437991f3f9b43cfc7ffa3b511ce7e7c1c23ae2b50d8a65a07f + checksum: 1635cd66e4b3dbba0689ecefabc6137301756c9c12d1d23e25124dd0dd9b4a6a38653d51e825e90f74faa022152ac1eaf200591fb50417aa7e1f7d1d1c2bc11d languageName: node linkType: hard @@ -2650,7 +3394,7 @@ __metadata: "@types/node": "npm:*" "@types/yargs": "npm:^16.0.0" chalk: "npm:^4.0.0" - checksum: 4598b302398db0eb77168b75a6c58148ea02cc9b9f21c5d1bbe985c1c9257110a5653cf7b901c3cab87fba231e3fed83633687f1c0903b4bc6939ab2a8452504 + checksum: d1f43cc946d87543ddd79d49547aab2399481d34025d5c5f2025d3d99c573e1d9832fa83cef25e9d9b07a8583500229d15bbb07b8e233d127d911d133e2f14b1 languageName: node linkType: hard @@ -2664,25 +3408,25 @@ __metadata: "@types/node": "npm:*" "@types/yargs": "npm:^17.0.8" chalk: "npm:^4.0.0" - checksum: 58de1c2484f6c4968b566fb1661506794d3df79476c0605a71b6e40b8a5a1a9837b9c692782540a179daa424c572c7d0818afa306918e3fcd29c4a962ed34a7b + checksum: 89fc1ccf71a84fe0da643e0675b1cfe6a6f19ea72e935b2ab1dbdb56ec547e94433fb59b3536d3832a6e156c077865b7176fe9dae707dab9c3d2f9405ba6233c languageName: node linkType: hard -"@joshwooding/vite-plugin-react-docgen-typescript@npm:0.2.1": - version: 0.2.1 - resolution: "@joshwooding/vite-plugin-react-docgen-typescript@npm:0.2.1" +"@joshwooding/vite-plugin-react-docgen-typescript@npm:0.3.0": + version: 0.3.0 + resolution: "@joshwooding/vite-plugin-react-docgen-typescript@npm:0.3.0" dependencies: - glob: "npm:^7.2.0" - glob-promise: "npm:^4.2.0" - magic-string: "npm:^0.27.0" - react-docgen-typescript: "npm:^2.2.2" + glob: ^7.2.0 + glob-promise: ^4.2.0 + magic-string: ^0.27.0 + react-docgen-typescript: ^2.2.2 peerDependencies: typescript: ">= 4.3.x" - vite: ^3.0.0 || ^4.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 506fea864748cce273d19c628c69ef529c4ec4b3d3a5f0d8fb9ab430dc45a0155a2ac52881410f5a475ddb6c34bc8a344b64f4edd9f738c02d43275e991906ee + checksum: 3fe2dc68dcb43920cc08bc5cc2937953bed1080e9c453dc3f513156b9a862fe6af0cda94b70272a4844a27964070129f8d0d31056211b1486a8fd9f6e1c20559 languageName: node linkType: hard @@ -2693,35 +3437,35 @@ __metadata: "@jridgewell/set-array": "npm:^1.0.1" "@jridgewell/sourcemap-codec": "npm:^1.4.10" "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 376fc11cf5a967318ba3ddd9d8e91be528eab6af66810a713c49b0c3f8dc67e9949452c51c38ab1b19aa618fb5e8594da5a249977e26b1e7fea1ee5a1fcacc74 + checksum: 4a74944bd31f22354fc01c3da32e83c19e519e3bbadafa114f6da4522ea77dd0c2842607e923a591d60a76699d819a2fbb6f3552e277efdb9b58b081390b60ab languageName: node linkType: hard "@jridgewell/resolve-uri@npm:3.1.0": version: 3.1.0 resolution: "@jridgewell/resolve-uri@npm:3.1.0" - checksum: 78055e2526108331126366572045355051a930f017d1904a4f753d3f4acee8d92a14854948095626f6163cffc24ea4e3efa30637417bb866b84743dec7ef6fd9 + checksum: b5ceaaf9a110fcb2780d1d8f8d4a0bfd216702f31c988d8042e5f8fbe353c55d9b0f55a1733afdc64806f8e79c485d2464680ac48a0d9fcadb9548ee6b81d267 languageName: node linkType: hard "@jridgewell/set-array@npm:^1.0.1": version: 1.1.2 resolution: "@jridgewell/set-array@npm:1.1.2" - checksum: bc7ab4c4c00470de4e7562ecac3c0c84f53e7ee8a711e546d67c47da7febe7c45cd67d4d84ee3c9b2c05ae8e872656cdded8a707a283d30bd54fbc65aef821ab + checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e languageName: node linkType: hard "@jridgewell/sourcemap-codec@npm:1.4.14": version: 1.4.14 resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" - checksum: 3fbaff1387c1338b097eeb6ff92890d7838f7de0dde259e4983763b44540bfd5ca6a1f7644dc8ad003a57f7e80670d5b96a8402f1386ba9aee074743ae9bad51 + checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13, @jridgewell/sourcemap-codec@npm:^1.4.15": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" - checksum: 0c6b5ae663087558039052a626d2d7ed5208da36cfd707dcc5cea4a07cfc918248403dcb5989a8f7afaf245ce0573b7cc6fd94c4a30453bd10e44d9363940ba5 + checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 languageName: node linkType: hard @@ -2731,14 +3475,14 @@ __metadata: dependencies: "@jridgewell/resolve-uri": "npm:3.1.0" "@jridgewell/sourcemap-codec": "npm:1.4.14" - checksum: e5045775f076022b6c7cc64a7b55742faa5442301cb3389fd0e6712fafc46a2bb13c68fa1ffaf7b8bb665a91196f050b4115885fc802094ebc06a1cf665935ac + checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02 languageName: node linkType: hard "@juggle/resize-observer@npm:^3.3.1": version: 3.4.0 resolution: "@juggle/resize-observer@npm:3.4.0" - checksum: 12930242357298c6f2ad5d4ec7cf631dfb344ca7c8c830ab7f64e6ac11eb1aae486901d8d880fd08fb1b257800c160a0da3aee1e7ed9adac0ccbb9b7c5d93347 + checksum: 2505028c05cc2e17639fcad06218b1c4b60f932a4ebb4b41ab546ef8c157031ae377e3f560903801f6d01706dbefd4943b6c4704bf19ed86dfa1c62f1473a570 languageName: node linkType: hard @@ -2750,7 +3494,7 @@ __metadata: "@types/react": "npm:>=16" peerDependencies: react: ">=16" - checksum: 6d647115703dbe258f7fe372499fa8c6fe17a053ff0f2a208111c9973a71ae738a0ed376770445d39194d217e00e1a015644b24f32c2f7cb4f57988de0649b15 + checksum: f45fe779556e6cd9a787f711274480e0638b63c460f192ebdcd77cc07ffa61e23c98cb46dd46e577093e1cb4997a232a848d1fb0ba850ae204422cf603add524 languageName: node linkType: hard @@ -2761,16 +3505,7 @@ __metadata: gunzip-maybe: "npm:^1.4.2" pump: "npm:^3.0.0" tar-fs: "npm:^2.1.1" - checksum: d66e76c6c990745d691c85d1dfa7f3dfd181405bb52c295baf4d1838b847d40c686e24602ea0ab1cdeb14d409db59f6bb9e2f96f56fe53da275da9cccf778e27 - languageName: node - linkType: hard - -"@nicolo-ribaudo/semver-v6@npm:^6.3.3": - version: 6.3.3 - resolution: "@nicolo-ribaudo/semver-v6@npm:6.3.3" - bin: - semver: bin/semver.js - checksum: 9ef70305fa9b03709805128611c0d95beec479cdd6f6b608386d6cee7a3d36f61e6f749378b60f1e5fca19fc58da7b06fccfe3540c0dbc40719731827d4eb1df + checksum: 7fa8ac40b4e85738a4ee6bf891bc27fce2445b65b4477e0ec86aed0fa62ab18bdf5d193ce04553ad9bfa639e1eef33b8b30da4ef3e7218f12bf95f24c8786e5b languageName: node linkType: hard @@ -2780,14 +3515,14 @@ __metadata: dependencies: "@nodelib/fs.stat": "npm:2.0.5" run-parallel: "npm:^1.1.9" - checksum: 732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb + checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 languageName: node linkType: hard "@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": version: 2.0.5 resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d + checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 languageName: node linkType: hard @@ -2797,7 +3532,7 @@ __metadata: dependencies: "@nodelib/fs.scandir": "npm:2.1.5" fastq: "npm:^1.6.0" - checksum: db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 + checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 languageName: node linkType: hard @@ -2806,1112 +3541,1419 @@ __metadata: resolution: "@npmcli/fs@npm:3.1.0" dependencies: semver: "npm:^7.3.5" - checksum: 162b4a0b8705cd6f5c2470b851d1dc6cd228c86d2170e1769d738c1fbb69a87160901411c3c035331e9e99db72f1f1099a8b734bf1637cc32b9a5be1660e4e1e + checksum: a50a6818de5fc557d0b0e6f50ec780a7a02ab8ad07e5ac8b16bf519e0ad60a144ac64f97d05c443c3367235d337182e1d012bbac0eb8dbae8dc7b40b193efd0e languageName: node linkType: hard "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd + checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f languageName: node linkType: hard -"@reduxjs/toolkit@npm:1.9.5": - version: 1.9.5 - resolution: "@reduxjs/toolkit@npm:1.9.5" +"@radix-ui/number@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/number@npm:1.0.1" dependencies: - immer: "npm:^9.0.21" - redux: "npm:^4.2.1" - redux-thunk: "npm:^2.4.2" - reselect: "npm:^4.1.8" - peerDependencies: - react: ^16.9.0 || ^17.0.0 || ^18 - react-redux: ^7.2.1 || ^8.0.2 - peerDependenciesMeta: - react: - optional: true - react-redux: - optional: true - checksum: e816b91271e9d32a9d6ea6620cc5e3ddcb77384b08dda1d083f8de26531ee6aa4ee93e9849ee344ba54a83e1e5ce50761b10bb9f979e80a7764fc835f87d9725 + "@babel/runtime": ^7.13.10 + checksum: 621ea8b7d4195d1a65a9c0aee918e8335e7f198088eec91577512c89c2ba3a3bab4a767cfb872a2b9c3092a78ff41cad9a924845a939f6bb87fe9356241ea0ea languageName: node linkType: hard -"@remix-run/router@npm:1.6.2": - version: 1.6.2 - resolution: "@remix-run/router@npm:1.6.2" - checksum: 73da6884e53873e4290abb3978373cafc3f351994273b0663eda5e12c81cb427fc6fe4df1924569d9a214f701d0106cf37122455951e0239d7e6fa35071df558 - languageName: node - linkType: hard - -"@rollup/pluginutils@npm:^4.2.0, @rollup/pluginutils@npm:^4.2.1": - version: 4.2.1 - resolution: "@rollup/pluginutils@npm:4.2.1" +"@radix-ui/primitive@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/primitive@npm:1.0.1" dependencies: - estree-walker: "npm:^2.0.1" - picomatch: "npm:^2.2.2" - checksum: 3ee56b2c8f1ed8dfd0a92631da1af3a2dfdd0321948f089b3752b4de1b54dc5076701eadd0e5fc18bd191b77af594ac1db6279e83951238ba16bf8a414c64c48 + "@babel/runtime": ^7.13.10 + checksum: 2b93e161d3fdabe9a64919def7fa3ceaecf2848341e9211520c401181c9eaebb8451c630b066fad2256e5c639c95edc41de0ba59c40eff37e799918d019822d1 languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.0.2": - version: 5.0.2 - resolution: "@rollup/pluginutils@npm:5.0.2" +"@radix-ui/react-arrow@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-arrow@npm:1.0.3" dependencies: - "@types/estree": "npm:^1.0.0" - estree-walker: "npm:^2.0.2" - picomatch: "npm:^2.3.1" + "@babel/runtime": ^7.13.10 + "@radix-ui/react-primitive": 1.0.3 peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - rollup: + "@types/react": optional: true - checksum: b06f73c15bb59418aa6fbfead5675bab2d6922e15663525ffc2eb8429530bc5add516600adb251cfbf9b60f3d12fb821cde155cb5103415154a476bd0f163432 - languageName: node - linkType: hard - -"@sinclair/typebox@npm:^0.27.8": - version: 0.27.8 - resolution: "@sinclair/typebox@npm:0.27.8" - checksum: ef6351ae073c45c2ac89494dbb3e1f87cc60a93ce4cde797b782812b6f97da0d620ae81973f104b43c9b7eaa789ad20ba4f6a1359f1cc62f63729a55a7d22d4e - languageName: node - linkType: hard - -"@sinonjs/commons@npm:^3.0.0": - version: 3.0.0 - resolution: "@sinonjs/commons@npm:3.0.0" - dependencies: - type-detect: "npm:4.0.8" - checksum: 1df9cd257942f4e4960dfb9fd339d9e97b6a3da135f3d5b8646562918e863809cb8e00268535f4f4723535d2097881c8fc03d545c414d8555183376cfc54ee84 + "@types/react-dom": + optional: true + checksum: 8cca086f0dbb33360e3c0142adf72f99fc96352d7086d6c2356dbb2ea5944cfb720a87d526fc48087741c602cd8162ca02b0af5e6fdf5f56d20fddb44db8b4c3 languageName: node linkType: hard -"@sinonjs/fake-timers@npm:^10.0.2": - version: 10.3.0 - resolution: "@sinonjs/fake-timers@npm:10.3.0" +"@radix-ui/react-collection@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-collection@npm:1.0.3" dependencies: - "@sinonjs/commons": "npm:^3.0.0" - checksum: 2e2fb6cc57f227912814085b7b01fede050cd4746ea8d49a1e44d5a0e56a804663b0340ae2f11af7559ea9bf4d087a11f2f646197a660ea3cb04e19efc04aa63 - languageName: node - linkType: hard - -"@storybook/addon-actions@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-actions@npm:7.0.12" - dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/theming": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - dequal: "npm:^2.0.2" - lodash: "npm:^4.17.21" - polished: "npm:^4.2.2" - prop-types: "npm:^15.7.2" - react-inspector: "npm:^6.0.0" - telejson: "npm:^7.0.3" - ts-dedent: "npm:^2.0.0" - uuid: "npm:^9.0.0" + "@babel/runtime": ^7.13.10 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-slot": 1.0.2 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - react: + "@types/react": optional: true - react-dom: + "@types/react-dom": optional: true - checksum: 9a2a0f4914a830651efffa8d7dbd35d2691e187f2e0fbe17ce2ad93be01fe66f3045361c4c0b7abd58c61f3ec8339f825d33a21e0dca4ddb355033565a139f71 + checksum: acfbc9b0b2c553d343c22f02c9f098bc5cfa99e6e48df91c0d671855013f8b877ade9c657b7420a7aa523b5aceadea32a60dd72c23b1291f415684fb45d00cff languageName: node linkType: hard -"@storybook/addon-backgrounds@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-backgrounds@npm:7.0.12" - dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/theming": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - memoizerific: "npm:^1.11.3" - ts-dedent: "npm:^2.0.0" +"@radix-ui/react-compose-refs@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-compose-refs@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - react: - optional: true - react-dom: + "@types/react": optional: true - checksum: edcf4dd2d66bcad58bd5b278eca8548297a5a8b1dccb11b5e11a97a387f6a60bd7aff3280a45ab6b2e6fb70eeb5ccfe8cdcc05096b2c04377a10be4189560af9 + checksum: 2b9a613b6db5bff8865588b6bf4065f73021b3d16c0a90b2d4c23deceeb63612f1f15de188227ebdc5f88222cab031be617a9dd025874c0487b303be3e5cc2a8 languageName: node linkType: hard -"@storybook/addon-controls@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-controls@npm:7.0.12" - dependencies: - "@storybook/blocks": "npm:7.0.12" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/core-common": "npm:7.0.12" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/node-logger": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/theming": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - lodash: "npm:^4.17.21" - ts-dedent: "npm:^2.0.0" +"@radix-ui/react-context@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-context@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - react: - optional: true - react-dom: + "@types/react": optional: true - checksum: 8ad4391ed7e0dee20b78abf3f153fc76db013a491cbf8c1dc41047a148795d7ae081c30b5b929d277e028023a2f3e1f29e741fa1636bb37d4a0f7c5e28ac18ce + checksum: 60e9b81d364f40c91a6213ec953f7c64fcd9d75721205a494a5815b3e5ae0719193429b62ee6c7002cd6aaf70f8c0e2f08bdbaba9ffcc233044d32b56d2127d1 languageName: node linkType: hard -"@storybook/addon-docs@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-docs@npm:7.0.12" - dependencies: - "@babel/core": "npm:^7.20.2" - "@babel/plugin-transform-react-jsx": "npm:^7.19.0" - "@jest/transform": "npm:^29.3.1" - "@mdx-js/react": "npm:^2.1.5" - "@storybook/blocks": "npm:7.0.12" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/csf-plugin": "npm:7.0.12" - "@storybook/csf-tools": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/mdx2-csf": "npm:^1.0.0" - "@storybook/node-logger": "npm:7.0.12" - "@storybook/postinstall": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/react-dom-shim": "npm:7.0.12" - "@storybook/theming": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - fs-extra: "npm:^11.1.0" - remark-external-links: "npm:^8.0.0" - remark-slug: "npm:^6.0.0" - ts-dedent: "npm:^2.0.0" +"@radix-ui/react-direction@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-direction@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 56ea6e002e028d0f72fc8875935e3209e15af64ad03ea08b842b6c2cd2c2cc8f49ac6c628474b8d7c25a30ed7999441945439659932fd3568e4391540443bb52 + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 5336a8b0d4f1cde585d5c2b4448af7b3d948bb63a1aadb37c77771b0e5902dc6266e409cf35fd0edaca7f33e26424be19e64fb8f9d7f7be2d6f1714ea2764210 languageName: node linkType: hard -"@storybook/addon-essentials@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-essentials@npm:7.0.12" - dependencies: - "@storybook/addon-actions": "npm:7.0.12" - "@storybook/addon-backgrounds": "npm:7.0.12" - "@storybook/addon-controls": "npm:7.0.12" - "@storybook/addon-docs": "npm:7.0.12" - "@storybook/addon-highlight": "npm:7.0.12" - "@storybook/addon-measure": "npm:7.0.12" - "@storybook/addon-outline": "npm:7.0.12" - "@storybook/addon-toolbars": "npm:7.0.12" - "@storybook/addon-viewport": "npm:7.0.12" - "@storybook/core-common": "npm:7.0.12" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/node-logger": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - ts-dedent: "npm:^2.0.0" +"@radix-ui/react-dismissable-layer@npm:1.0.4": + version: 1.0.4 + resolution: "@radix-ui/react-dismissable-layer@npm:1.0.4" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-callback-ref": 1.0.1 + "@radix-ui/react-use-escape-keydown": 1.0.3 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 8ef3bbd508d04241459a770d65b25909a555d3e88985b6fa74026f450ef3df69fe3ce4165bc35d1eb220e52064dfc09ae2eb572649f2d0f88437d543b0737ca8 + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: ea86004ed56a10609dd84eef39dc1e57b400d687a35be41bb4aaa06dc7ad6dbd0a8da281e08c8c077fdbd523122e4d860cb7438a60c664f024f77c8b41299ec6 languageName: node linkType: hard -"@storybook/addon-highlight@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-highlight@npm:7.0.12" +"@radix-ui/react-focus-guards@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-focus-guards@npm:1.0.1" dependencies: - "@storybook/core-events": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/preview-api": "npm:7.0.12" - checksum: 67d639e9b33b1c0f818aa0d932cb9cbc0dbe963f877d3525ddab1b699e9ecde230068e61ed4ba83ff81b52673d379abc5a917d018f874c69c15227abc85c18ef + "@babel/runtime": ^7.13.10 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 1f8ca8f83b884b3612788d0742f3f054e327856d90a39841a47897dbed95e114ee512362ae314177de226d05310047cabbf66b686ae86ad1b65b6b295be24ef7 languageName: node linkType: hard -"@storybook/addon-interactions@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-interactions@npm:7.0.12" - dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/core-common": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/instrumenter": "npm:7.0.12" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/theming": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - jest-mock: "npm:^27.0.6" - polished: "npm:^4.2.2" - ts-dedent: "npm:^2.2.0" +"@radix-ui/react-focus-scope@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-focus-scope@npm:1.0.3" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-callback-ref": 1.0.1 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - react: + "@types/react": optional: true - react-dom: + "@types/react-dom": optional: true - checksum: 07c54b9bcd63685d4dc35d43022a150d09212af3817db6ea67985fed93651e278cc21c9adcd71a7a211895f11a7adced54f3aa0248b614fb9c231ac2e37aab5c + checksum: e5b1a089071fbe77aca11124a4ad9623fc2bcaf4c019759b0cd044bf0878ecc924131ee09c6a22d38a3f094684ef68ed18fa65c8d891918412e0afc685a464e0 languageName: node linkType: hard -"@storybook/addon-links@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-links@npm:7.0.12" - dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/csf": "npm:^0.1.0" - "@storybook/global": "npm:^5.0.0" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/router": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - prop-types: "npm:^15.7.2" - ts-dedent: "npm:^2.0.0" +"@radix-ui/react-id@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-id@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-use-layout-effect": 1.0.1 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - react: - optional: true - react-dom: + "@types/react": optional: true - checksum: 4571fd13911bb1586709429ce4c731add55a7fb89c6862b45754d0c72189a74b2cc837cc8a1123f07782177c83651ee6576b5b9c7b2ca27afcbb5d0e4dac33c7 + checksum: 446a453d799cc790dd2a1583ff8328da88271bff64530b5a17c102fa7fb35eece3cf8985359d416f65e330cd81aa7b8fe984ea125fc4f4eaf4b3801d698e49fe languageName: node linkType: hard -"@storybook/addon-measure@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-measure@npm:7.0.12" - dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 +"@radix-ui/react-popper@npm:1.1.2": + version: 1.1.2 + resolution: "@radix-ui/react-popper@npm:1.1.2" + dependencies: + "@babel/runtime": ^7.13.10 + "@floating-ui/react-dom": ^2.0.0 + "@radix-ui/react-arrow": 1.0.3 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-callback-ref": 1.0.1 + "@radix-ui/react-use-layout-effect": 1.0.1 + "@radix-ui/react-use-rect": 1.0.1 + "@radix-ui/react-use-size": 1.0.1 + "@radix-ui/rect": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - react: + "@types/react": optional: true - react-dom: + "@types/react-dom": optional: true - checksum: 2f41dfa2bb8c768774f0fa0bfa832c237104d48dcb9b21f57d4a59c2d912e2bf4ee40797eefee6678bec15b9a598247a86e6e407c242689d637b9d680cd50aa3 + checksum: 4929daa0d1cccada3cff50de0e00c0d186ffea97a5f28545c77fa85ff9bc5c105a54dddac400c2e2dcac631f0f7ea88e59f2e5ad0f80bb2cb7b62cc7cd30400f languageName: node linkType: hard -"@storybook/addon-outline@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-outline@npm:7.0.12" +"@radix-ui/react-portal@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-portal@npm:1.0.3" dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - ts-dedent: "npm:^2.0.0" + "@babel/runtime": ^7.13.10 + "@radix-ui/react-primitive": 1.0.3 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - react: + "@types/react": optional: true - react-dom: + "@types/react-dom": optional: true - checksum: 493ca647e57d0f5c3fecf93771d4c59f63f6586b0658701a9944f8076bc1838a5e09d3d6c5098ebf563210930d019ee32912542bdd1c8e04ea096ab4c8fbff63 + checksum: d352bcd6ad65eb43c9e0d72d0755c2aae85e03fb287770866262be3a2d5302b2885aee3cd99f2bbf62ecd14fcb1460703f1dcdc40351f77ad887b931c6f0012a languageName: node linkType: hard -"@storybook/addon-toolbars@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-toolbars@npm:7.0.12" +"@radix-ui/react-primitive@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-primitive@npm:1.0.3" dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/theming": "npm:7.0.12" + "@babel/runtime": ^7.13.10 + "@radix-ui/react-slot": 1.0.2 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - react: + "@types/react": optional: true - react-dom: + "@types/react-dom": optional: true - checksum: c7a01268ddc4ccc79d5f10ca6506e253fbea395a3b4a5ff1e81481e32af853e0c9dc1dd383e4dc972663e2e37aa811737299856596e5868f91e89751232f4e2b + checksum: 9402bc22923c8e5c479051974a721c301535c36521c0237b83e5fa213d013174e77f3ad7905e6d60ef07e14f88ec7f4ea69891dc7a2b39047f8d3640e8f8d713 languageName: node linkType: hard -"@storybook/addon-viewport@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/addon-viewport@npm:7.0.12" - dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/theming": "npm:7.0.12" - memoizerific: "npm:^1.11.3" - prop-types: "npm:^15.7.2" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 +"@radix-ui/react-roving-focus@npm:1.0.4": + version: 1.0.4 + resolution: "@radix-ui/react-roving-focus@npm:1.0.4" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-collection": 1.0.3 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-id": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-callback-ref": 1.0.1 + "@radix-ui/react-use-controllable-state": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - react: + "@types/react": optional: true - react-dom: + "@types/react-dom": optional: true - checksum: e63f56f90fab17c8f56c03c3cfaa512ccdcf8f2b04f393a31f92db4576db5c414e79f9c6a33b10d1e3748cb8449510e1c4c8af1cb0bd52a0e921801410c55bd1 + checksum: 69b1c82c2d9db3ba71549a848f2704200dab1b2cd22d050c1e081a78b9a567dbfdc7fd0403ee010c19b79652de69924d8ca2076cd031d6552901e4213493ffc7 languageName: node linkType: hard -"@storybook/blocks@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/blocks@npm:7.0.12" - dependencies: - "@storybook/channels": "npm:7.0.12" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/components": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/csf": "npm:^0.1.0" - "@storybook/docs-tools": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/manager-api": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/theming": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - "@types/lodash": "npm:^4.14.167" - color-convert: "npm:^2.0.1" - dequal: "npm:^2.0.2" - lodash: "npm:^4.17.21" - markdown-to-jsx: "npm:^7.1.8" - memoizerific: "npm:^1.11.3" - polished: "npm:^4.2.2" - react-colorful: "npm:^5.1.2" - telejson: "npm:^7.0.3" - ts-dedent: "npm:^2.0.0" - util-deprecate: "npm:^1.0.2" +"@radix-ui/react-select@npm:^1.2.2": + version: 1.2.2 + resolution: "@radix-ui/react-select@npm:1.2.2" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/number": 1.0.1 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-collection": 1.0.3 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-dismissable-layer": 1.0.4 + "@radix-ui/react-focus-guards": 1.0.1 + "@radix-ui/react-focus-scope": 1.0.3 + "@radix-ui/react-id": 1.0.1 + "@radix-ui/react-popper": 1.1.2 + "@radix-ui/react-portal": 1.0.3 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-slot": 1.0.2 + "@radix-ui/react-use-callback-ref": 1.0.1 + "@radix-ui/react-use-controllable-state": 1.0.1 + "@radix-ui/react-use-layout-effect": 1.0.1 + "@radix-ui/react-use-previous": 1.0.1 + "@radix-ui/react-visually-hidden": 1.0.3 + aria-hidden: ^1.1.1 + react-remove-scroll: 2.5.5 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: af7b63cc9e2c6006ec08163392d244941e9e03534e7add1b7c5a86059d0eb8a0398d4f3e80d43ff22126874a02b985e44f1722d1de9218922f7aa653d09412e3 + languageName: node + linkType: hard + +"@radix-ui/react-separator@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-separator@npm:1.0.3" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-primitive": 1.0.3 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: e86d87ac28da2b7218b7021640a50ea7481dfebace9c54f037e9dc48a1143364ffc66a0f1860ff1fab15e6c883ad2f61e68c77dba2785354133ee009afe98710 + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 42f8c95e404de2ce9387040d78049808a48d423cd4c3bad8cca92c4b0bcbdcb3566b5b52a920d4e939a74b51188697f20a012221f0e630fc7f56de64096c15d2 languageName: node linkType: hard -"@storybook/builder-manager@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/builder-manager@npm:7.0.12" - dependencies: - "@fal-works/esbuild-plugin-global-externals": "npm:^2.1.2" - "@storybook/core-common": "npm:7.0.12" - "@storybook/manager": "npm:7.0.12" - "@storybook/node-logger": "npm:7.0.12" - "@types/ejs": "npm:^3.1.1" - "@types/find-cache-dir": "npm:^3.2.1" - "@yarnpkg/esbuild-plugin-pnp": "npm:^3.0.0-rc.10" - browser-assert: "npm:^1.2.1" - ejs: "npm:^3.1.8" - esbuild: "npm:^0.17.0" - esbuild-plugin-alias: "npm:^0.2.1" - express: "npm:^4.17.3" - find-cache-dir: "npm:^3.0.0" - fs-extra: "npm:^11.1.0" - process: "npm:^0.11.10" - util: "npm:^0.12.4" - checksum: 2a15916f46aa8be66ece8266633f5dd4d5ded96b8d82dfe7a6aa4f370552729dc1506552b3d36eed2f83fd6d92e01a492901459fb030264646d5cb027774e9c4 - languageName: node - linkType: hard - -"@storybook/builder-vite@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/builder-vite@npm:7.0.12" - dependencies: - "@storybook/channel-postmessage": "npm:7.0.12" - "@storybook/channel-websocket": "npm:7.0.12" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/core-common": "npm:7.0.12" - "@storybook/csf-plugin": "npm:7.0.12" - "@storybook/mdx2-csf": "npm:^1.0.0" - "@storybook/node-logger": "npm:7.0.12" - "@storybook/preview": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - browser-assert: "npm:^1.2.1" - es-module-lexer: "npm:^0.9.3" - express: "npm:^4.17.3" - fs-extra: "npm:^11.1.0" - glob: "npm:^8.1.0" - glob-promise: "npm:^6.0.2" - magic-string: "npm:^0.27.0" - remark-external-links: "npm:^8.0.0" - remark-slug: "npm:^6.0.0" - rollup: "npm:^2.25.0 || ^3.3.0" +"@radix-ui/react-slot@npm:1.0.2": + version: 1.0.2 + resolution: "@radix-ui/react-slot@npm:1.0.2" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-compose-refs": 1.0.1 peerDependencies: - "@preact/preset-vite": "*" - typescript: ">= 4.3.x" - vite: ^3.0.0 || ^4.0.0 - vite-plugin-glimmerx: "*" + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: - "@preact/preset-vite": + "@types/react": optional: true - typescript: + checksum: edf5edf435ff594bea7e198bf16d46caf81b6fb559493acad4fa8c308218896136acb16f9b7238c788fd13e94a904f2fd0b6d834e530e4cae94522cdb8f77ce9 + languageName: node + linkType: hard + +"@radix-ui/react-toggle-group@npm:1.0.4": + version: 1.0.4 + resolution: "@radix-ui/react-toggle-group@npm:1.0.4" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-roving-focus": 1.0.4 + "@radix-ui/react-toggle": 1.0.3 + "@radix-ui/react-use-controllable-state": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": optional: true - vite-plugin-glimmerx: + "@types/react-dom": optional: true - checksum: d22a787ea26887f65665578fc61ed1286f7b293219097e6637fda9be7ae677fbc2fd58f3dc464d1c2094a877bfdb229044ed4cfce9126c772197e3a597a81cf3 + checksum: b6c11fbbc3ca857ff68c0fa31f293c0d0111bcc8aa0cde2566214c090907530bfcb3b862f81585c2b02d8989b5c7971acff4d5c07c429870d80bd5602e30d376 languageName: node linkType: hard -"@storybook/channel-postmessage@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/channel-postmessage@npm:7.0.12" +"@radix-ui/react-toggle@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-toggle@npm:1.0.3" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-controllable-state": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: ed5407f48254f20cda542017774f259d0b2c0007ea4bd7287d10d751016dbf269cb13d1142591432c269c3ab768cde2f1ba0344743027d36bbec10af909f19de + languageName: node + linkType: hard + +"@radix-ui/react-toolbar@npm:^1.0.4": + version: 1.0.4 + resolution: "@radix-ui/react-toolbar@npm:1.0.4" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-roving-focus": 1.0.4 + "@radix-ui/react-separator": 1.0.3 + "@radix-ui/react-toggle-group": 1.0.4 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 7ebee1f8add6510108979433c5b38627e2de9d48ef2172ca15274b9edbbc106ff43bcd47ff733b03ed2215b92e7af364ff82c79e5a1728374847e2b1e315552c + languageName: node + linkType: hard + +"@radix-ui/react-use-callback-ref@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-use-callback-ref@npm:1.0.1" dependencies: - "@storybook/channels": "npm:7.0.12" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - qs: "npm:^6.10.0" - telejson: "npm:^7.0.3" - checksum: ad87aa8ceb554045b0274c78f67c2f6a6924b9f27641f522e0d683f7cc21fb10318c96aca55021307614f89f4b84536244283af279dcc1b9b1d5e56813404a92 + "@babel/runtime": ^7.13.10 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: b9fd39911c3644bbda14a84e4fca080682bef84212b8d8931fcaa2d2814465de242c4cfd8d7afb3020646bead9c5e539d478cea0a7031bee8a8a3bb164f3bc4c languageName: node linkType: hard -"@storybook/channel-postmessage@npm:7.0.27": - version: 7.0.27 - resolution: "@storybook/channel-postmessage@npm:7.0.27" +"@radix-ui/react-use-controllable-state@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-use-controllable-state@npm:1.0.1" dependencies: - "@storybook/channels": "npm:7.0.27" - "@storybook/client-logger": "npm:7.0.27" - "@storybook/core-events": "npm:7.0.27" - "@storybook/global": "npm:^5.0.0" - qs: "npm:^6.10.0" - telejson: "npm:^7.0.3" - checksum: 55e41a96f17852759eff3fc98c1bf7e142cce1df1c0e8202cc17bf845bcfe639164a168636c84d3efb7c7534f5f1e7a9244e75f6dd53e709d8f94b63f1ea4f91 + "@babel/runtime": ^7.13.10 + "@radix-ui/react-use-callback-ref": 1.0.1 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: dee2be1937d293c3a492cb6d279fc11495a8f19dc595cdbfe24b434e917302f9ac91db24e8cc5af9a065f3f209c3423115b5442e65a5be9fd1e9091338972be9 languageName: node linkType: hard -"@storybook/channel-websocket@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/channel-websocket@npm:7.0.12" +"@radix-ui/react-use-escape-keydown@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-use-escape-keydown@npm:1.0.3" dependencies: - "@storybook/channels": "npm:7.0.12" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - telejson: "npm:^7.0.3" - checksum: 15961543e7a0e0357bfda7deaafab8c0fa44a5f00ce712856140be1b93fd3f65bfe90b6fd6327caab0606f4938c621372a62961b8fdf2d55abeb3cdb3711d11a + "@babel/runtime": ^7.13.10 + "@radix-ui/react-use-callback-ref": 1.0.1 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: c6ed0d9ce780f67f924980eb305af1f6cce2a8acbaf043a58abe0aa3cc551d9aa76ccee14531df89bbee302ead7ecc7fce330886f82d4672c5eda52f357ef9b8 languageName: node linkType: hard -"@storybook/channels@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/channels@npm:7.0.12" - checksum: d62d1487b716c3d5769a072c8d381d226a77f57f88c41e32cb00e62f76c549bc5fcc9fa9e0d0a1ce21264a76eec99dca39f00bda86c86e76487c09646e4e568b +"@radix-ui/react-use-layout-effect@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-use-layout-effect@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: bed9c7e8de243a5ec3b93bb6a5860950b0dba359b6680c84d57c7a655e123dec9b5891c5dfe81ab970652e7779fe2ad102a23177c7896dde95f7340817d47ae5 languageName: node linkType: hard -"@storybook/channels@npm:7.0.27": - version: 7.0.27 - resolution: "@storybook/channels@npm:7.0.27" - checksum: 54ea3853981d83459447e552042b7713f18566a685b11f3a364646a8333c03c5457d2b210982919ce0bfc67fadf3079fb1dd3ee6faf9d21a98a929039c72bf1c +"@radix-ui/react-use-previous@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-use-previous@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 66b4312e857c58b75f3bf62a2048ef090b79a159e9da06c19a468c93e62336969c33dbef60ff16969f00b20386cc25d138f6a353f1658b35baac0a6eff4761b9 languageName: node linkType: hard -"@storybook/cli@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/cli@npm:7.0.12" - dependencies: - "@babel/core": "npm:^7.20.2" - "@babel/preset-env": "npm:^7.20.2" - "@ndelangen/get-tarball": "npm:^3.0.7" - "@storybook/codemod": "npm:7.0.12" - "@storybook/core-common": "npm:7.0.12" - "@storybook/core-server": "npm:7.0.12" - "@storybook/csf-tools": "npm:7.0.12" - "@storybook/node-logger": "npm:7.0.12" - "@storybook/telemetry": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - "@types/semver": "npm:^7.3.4" - boxen: "npm:^5.1.2" - chalk: "npm:^4.1.0" - commander: "npm:^6.2.1" - cross-spawn: "npm:^7.0.3" - detect-indent: "npm:^6.1.0" - envinfo: "npm:^7.7.3" - execa: "npm:^5.0.0" - express: "npm:^4.17.3" - find-up: "npm:^5.0.0" - fs-extra: "npm:^11.1.0" - get-npm-tarball-url: "npm:^2.0.3" - get-port: "npm:^5.1.1" - giget: "npm:^1.0.0" - globby: "npm:^11.0.2" - jscodeshift: "npm:^0.14.0" - leven: "npm:^3.1.0" - prettier: "npm:^2.8.0" - prompts: "npm:^2.4.0" - puppeteer-core: "npm:^2.1.1" - read-pkg-up: "npm:^7.0.1" - semver: "npm:^7.3.7" - shelljs: "npm:^0.8.5" - simple-update-notifier: "npm:^1.0.0" - strip-json-comments: "npm:^3.0.1" - tempy: "npm:^1.0.1" - ts-dedent: "npm:^2.0.0" - util-deprecate: "npm:^1.0.2" - bin: - getstorybook: bin/index.js - sb: bin/index.js - checksum: 7f1ef019ef4c8783d09c8ba148360238be83ceb135287f866f6a34002482857e752ffaa0f56cbbaaa25cd93f33ec9823c5f40e3df636c17b392e1281100091d2 +"@radix-ui/react-use-rect@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-use-rect@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/rect": 1.0.1 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 433f07e61e04eb222349825bb05f3591fca131313a1d03709565d6226d8660bd1d0423635553f95ee4fcc25c8f2050972d848808d753c388e2a9ae191ebf17f3 languageName: node linkType: hard -"@storybook/client-logger@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/client-logger@npm:7.0.12" +"@radix-ui/react-use-size@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-use-size@npm:1.0.1" dependencies: - "@storybook/global": "npm:^5.0.0" - checksum: 6df757c1649bc520570e0123e5edf4e6df1b0fac311cccc12ad3cc4cef4a53e3de9d24fa696ef848de1700b6cff38ef6b580df99eac7c522ca2c60dc8f031ee7 + "@babel/runtime": ^7.13.10 + "@radix-ui/react-use-layout-effect": 1.0.1 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 6cc150ad1e9fa85019c225c5a5d50a0af6cdc4653dad0c21b4b40cd2121f36ee076db326c43e6bc91a69766ccff5a84e917d27970176b592577deea3c85a3e26 languageName: node linkType: hard -"@storybook/client-logger@npm:7.0.27, @storybook/client-logger@npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": - version: 7.0.27 - resolution: "@storybook/client-logger@npm:7.0.27" +"@radix-ui/react-visually-hidden@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-visually-hidden@npm:1.0.3" dependencies: - "@storybook/global": "npm:^5.0.0" - checksum: 512cfa247b5f9a5f460b6c6ab03eafdb3870773ac7f4769ace6b50221161a511f860bfdd17d3ead2863062367fea4615e0c3a6d551ac3ad6c338a2a14042c1d7 + "@babel/runtime": ^7.13.10 + "@radix-ui/react-primitive": 1.0.3 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 2e9d0c8253f97e7d6ffb2e52a5cfd40ba719f813b39c3e2e42c496d54408abd09ef66b5aec4af9b8ab0553215e32452a5d0934597a49c51dd90dc39181ed0d57 languageName: node linkType: hard -"@storybook/codemod@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/codemod@npm:7.0.12" - dependencies: - "@babel/core": "npm:~7.21.0" - "@babel/preset-env": "npm:~7.21.0" - "@babel/types": "npm:~7.21.2" - "@storybook/csf": "npm:^0.1.0" - "@storybook/csf-tools": "npm:7.0.12" - "@storybook/node-logger": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - cross-spawn: "npm:^7.0.3" - globby: "npm:^11.0.2" - jscodeshift: "npm:^0.14.0" - lodash: "npm:^4.17.21" - prettier: "npm:^2.8.0" - recast: "npm:^0.23.1" - checksum: 4964d8ea31c8b07a76ffadf52aefbcf8d23987790e63b61b8b504e8c74f5588095c9e7ec5aa936f0f24a5e787ca6b0feee5c2e65f491f59b1a1293a5000d2d14 +"@radix-ui/rect@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/rect@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + checksum: aeec13b234a946052512d05239067d2d63422f9ec70bf2fe7acfd6b9196693fc33fbaf43c2667c167f777d90a095c6604eb487e0bce79e230b6df0f6cacd6a55 languageName: node linkType: hard -"@storybook/components@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/components@npm:7.0.12" +"@reduxjs/toolkit@npm:1.9.5": + version: 1.9.5 + resolution: "@reduxjs/toolkit@npm:1.9.5" dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/csf": "npm:^0.1.0" - "@storybook/global": "npm:^5.0.0" - "@storybook/theming": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - memoizerific: "npm:^1.11.3" - use-resize-observer: "npm:^9.1.0" - util-deprecate: "npm:^1.0.2" + immer: "npm:^9.0.21" + redux: "npm:^4.2.1" + redux-thunk: "npm:^2.4.2" + reselect: "npm:^4.1.8" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 1d92f6bfb3f24cf694e34216d8ed2260aace4c3ebec9e27fe4d8e6186700785060459f9e8a077770eda30c70db20efd36ff19316605354bbe119cb8776f4f139 + react: ^16.9.0 || ^17.0.0 || ^18 + react-redux: ^7.2.1 || ^8.0.2 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + checksum: 54672c5593d05208af577e948a338f23128d3aa01ef056ab0d40bcfa14400cf6566be99e11715388f12c1d7655cdf7c5c6b63cb92eb0fecf996c454a46a3914c languageName: node linkType: hard -"@storybook/core-client@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/core-client@npm:7.0.12" +"@remix-run/router@npm:1.6.2": + version: 1.6.2 + resolution: "@remix-run/router@npm:1.6.2" + checksum: 5969d313bff6ba5c75917910090cebafda84b9d3b4b453fae6b3d60fea9f938078578ffca769c532ab7ce252cd4a207b78d1024d7c727ab80dd572e62fd3b3f2 + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^4.2.1": + version: 4.2.1 + resolution: "@rollup/pluginutils@npm:4.2.1" dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - checksum: a6624d2e5976a94e8b2122f90c70174b526160cd85fe29e1ce36e080b6d40b2bfa07b8a4dbdd743e25264cf301c01dc578a977d9e83387c26289c3a40697e16f + estree-walker: "npm:^2.0.1" + picomatch: "npm:^2.2.2" + checksum: 6bc41f22b1a0f1efec3043899e4d3b6b1497b3dea4d94292d8f83b4cf07a1073ecbaedd562a22d11913ff7659f459677b01b09e9598a98936e746780ecc93a12 languageName: node linkType: hard -"@storybook/core-common@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/core-common@npm:7.0.12" +"@rollup/pluginutils@npm:^5.0.2": + version: 5.0.2 + resolution: "@rollup/pluginutils@npm:5.0.2" dependencies: - "@storybook/node-logger": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - "@types/node": "npm:^16.0.0" - "@types/pretty-hrtime": "npm:^1.0.0" - chalk: "npm:^4.1.0" - esbuild: "npm:^0.17.0" - esbuild-register: "npm:^3.4.0" - file-system-cache: "npm:^2.0.0" - find-up: "npm:^5.0.0" - fs-extra: "npm:^11.1.0" - glob: "npm:^8.1.0" - glob-promise: "npm:^6.0.2" - handlebars: "npm:^4.7.7" - lazy-universal-dotenv: "npm:^4.0.0" - picomatch: "npm:^2.3.0" - pkg-dir: "npm:^5.0.0" - pretty-hrtime: "npm:^1.0.3" - resolve-from: "npm:^5.0.0" - ts-dedent: "npm:^2.0.0" - checksum: d616d0502fe35353add4685b54a28a3e1c202941f690df54553a2d3e9427ab45355090b4fe88c7814c8fa7ca309ae1b99cb7a30a980a909ba51a040028ca2832 + "@types/estree": "npm:^1.0.0" + estree-walker: "npm:^2.0.2" + picomatch: "npm:^2.3.1" + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: edea15e543bebc7dcac3b0ac8bc7b8e8e6dbd46e2864dbe5dd28072de1fbd5b0e10d545a610c0edaa178e8a7ac432e2a2a52e547ece1308471412caba47db8ce languageName: node linkType: hard -"@storybook/core-events@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/core-events@npm:7.0.12" - checksum: f84ced7961237b23e03ec184114135acf302357619ffa6745f3e9b1812e9424366d663ea56959304da728047de85da98f967896c2600e5d0215a9874eb757be1 +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.8 + resolution: "@sinclair/typebox@npm:0.27.8" + checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1 languageName: node linkType: hard -"@storybook/core-events@npm:7.0.27": - version: 7.0.27 - resolution: "@storybook/core-events@npm:7.0.27" - checksum: 2dc250bcc8633286c1da22abd72d9fd8d68371119dc41a84b25d6a259c8640bf7577864abbe8a60daee051021c819416e20d362d2a83f1ab633cc2aa9db18819 +"@sinonjs/commons@npm:^3.0.0": + version: 3.0.0 + resolution: "@sinonjs/commons@npm:3.0.0" + dependencies: + type-detect: "npm:4.0.8" + checksum: b4b5b73d4df4560fb8c0c7b38c7ad4aeabedd362f3373859d804c988c725889cde33550e4bcc7cd316a30f5152a2d1d43db71b6d0c38f5feef71fd8d016763f8 languageName: node linkType: hard -"@storybook/core-server@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/core-server@npm:7.0.12" - dependencies: - "@aw-web-design/x-default-browser": "npm:1.4.88" - "@discoveryjs/json-ext": "npm:^0.5.3" - "@storybook/builder-manager": "npm:7.0.12" - "@storybook/core-common": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/csf": "npm:^0.1.0" - "@storybook/csf-tools": "npm:7.0.12" - "@storybook/docs-mdx": "npm:^0.1.0" - "@storybook/global": "npm:^5.0.0" - "@storybook/manager": "npm:7.0.12" - "@storybook/node-logger": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/telemetry": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - "@types/detect-port": "npm:^1.3.0" - "@types/node": "npm:^16.0.0" - "@types/node-fetch": "npm:^2.5.7" - "@types/pretty-hrtime": "npm:^1.0.0" - "@types/semver": "npm:^7.3.4" - better-opn: "npm:^2.1.1" - boxen: "npm:^5.1.2" - chalk: "npm:^4.1.0" - cli-table3: "npm:^0.6.1" - compression: "npm:^1.7.4" - detect-port: "npm:^1.3.0" - express: "npm:^4.17.3" - fs-extra: "npm:^11.1.0" - globby: "npm:^11.0.2" - ip: "npm:^2.0.0" - lodash: "npm:^4.17.21" - node-fetch: "npm:^2.6.7" - open: "npm:^8.4.0" - pretty-hrtime: "npm:^1.0.3" - prompts: "npm:^2.4.0" - read-pkg-up: "npm:^7.0.1" - semver: "npm:^7.3.7" - serve-favicon: "npm:^2.5.0" - telejson: "npm:^7.0.3" - ts-dedent: "npm:^2.0.0" - util-deprecate: "npm:^1.0.2" - watchpack: "npm:^2.2.0" - ws: "npm:^8.2.3" - checksum: 3a4b00ba896aa2b8becad5198b390905a9f8f765717d3bbc69b1384e3587f8e0c710f83bebdfa329195f6d8b76d206063bd0546c0008ed2e6d4f1e19c1900784 +"@sinonjs/fake-timers@npm:^10.0.2": + version: 10.3.0 + resolution: "@sinonjs/fake-timers@npm:10.3.0" + dependencies: + "@sinonjs/commons": "npm:^3.0.0" + checksum: 614d30cb4d5201550c940945d44c9e0b6d64a888ff2cd5b357f95ad6721070d6b8839cd10e15b76bf5e14af0bcc1d8f9ec00d49a46318f1f669a4bec1d7f3148 languageName: node linkType: hard -"@storybook/csf-plugin@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/csf-plugin@npm:7.0.12" +"@storybook/addon-actions@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-actions@npm:7.6.7" dependencies: - "@storybook/csf-tools": "npm:7.0.12" - unplugin: "npm:^0.10.2" - checksum: eedf373314f74f9f19a020761a610d4b4400e347b146a31074f3073796b404f94d9cc27a971a7342fc762bacfad52df083034e3dcac766105586e741bd00640b + "@storybook/core-events": 7.6.7 + "@storybook/global": ^5.0.0 + "@types/uuid": ^9.0.1 + dequal: ^2.0.2 + polished: ^4.2.2 + uuid: ^9.0.0 + checksum: 0a68abbb89e2aa569dd0d1bb7793bd571e6095e108e19028a7f23afdbf4625d008c96e0b0c95c4a77fce97380f50765ef922152fe02134e5a9a96a66ca4237a7 languageName: node linkType: hard -"@storybook/csf-tools@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/csf-tools@npm:7.0.12" +"@storybook/addon-backgrounds@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-backgrounds@npm:7.6.7" dependencies: - "@babel/generator": "npm:~7.21.1" - "@babel/parser": "npm:~7.21.2" - "@babel/traverse": "npm:~7.21.2" - "@babel/types": "npm:~7.21.2" - "@storybook/csf": "npm:^0.1.0" - "@storybook/types": "npm:7.0.12" - fs-extra: "npm:^11.1.0" - recast: "npm:^0.23.1" - ts-dedent: "npm:^2.0.0" - checksum: 2eb9c7daa8c2595d08a8a838e85d1a580eb7421a33e5912c73cd00a8c21fdd9ff6b92161074e5686a92fb73b75961e37737e3e6e38b6088ca77e13052194633f + "@storybook/global": ^5.0.0 + memoizerific: ^1.11.3 + ts-dedent: ^2.0.0 + checksum: 0598707fef857c1bb9402875dcd08362b090b524ca02cb9a2d475150ae489b17c4cfa6b0f76759a1c41c8a00502b7e362ca3352ed1263a4c5295f5380ad0ba8a languageName: node linkType: hard -"@storybook/csf@npm:^0.0.1": - version: 0.0.1 - resolution: "@storybook/csf@npm:0.0.1" +"@storybook/addon-controls@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-controls@npm:7.6.7" dependencies: - lodash: "npm:^4.17.15" - checksum: 7b0f75763415f9147692a460b44417ee56ea9639433716a1fd4d1df4c8b0221cbc71b8da0fbed4dcecb3ccd6c7ed64be39f5c255c713539a6088a1d6488aaa24 + "@storybook/blocks": 7.6.7 + lodash: ^4.17.21 + ts-dedent: ^2.0.0 + checksum: b98166568f3479e628618f77d64baaf361e74f4388a2c15dd1fd2c353c497873890365d15af411af1f66b83b63627050939ad1a058125faa9f6f67714626308e languageName: node linkType: hard -"@storybook/csf@npm:^0.1.0": - version: 0.1.1 - resolution: "@storybook/csf@npm:0.1.1" +"@storybook/addon-docs@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-docs@npm:7.6.7" dependencies: - type-fest: "npm:^2.19.0" - checksum: 999bb87fbbe047a559bbaa5baf2ed84872fcd5cdcae3c1169f8e4c641eefe8759d09a09034a78ed114032c0e5cf6301b7fa89e5e3ce60d75cf0bd5e33ec0a6e7 + "@jest/transform": ^29.3.1 + "@mdx-js/react": ^2.1.5 + "@storybook/blocks": 7.6.7 + "@storybook/client-logger": 7.6.7 + "@storybook/components": 7.6.7 + "@storybook/csf-plugin": 7.6.7 + "@storybook/csf-tools": 7.6.7 + "@storybook/global": ^5.0.0 + "@storybook/mdx2-csf": ^1.0.0 + "@storybook/node-logger": 7.6.7 + "@storybook/postinstall": 7.6.7 + "@storybook/preview-api": 7.6.7 + "@storybook/react-dom-shim": 7.6.7 + "@storybook/theming": 7.6.7 + "@storybook/types": 7.6.7 + fs-extra: ^11.1.0 + remark-external-links: ^8.0.0 + remark-slug: ^6.0.0 + ts-dedent: ^2.0.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 967669f44014c194dab94ad572cbf6d89dce86376ccf43867ae1801609598cb70faca49b7df8426227bfe6348887688285fae5f6cebb12e58048e74dec6ba0ce languageName: node linkType: hard -"@storybook/docs-mdx@npm:^0.1.0": - version: 0.1.0 - resolution: "@storybook/docs-mdx@npm:0.1.0" - checksum: e4d510f0452a7a3cb09d9617920c18b974f836299dfba38d6b2e62fbfea418d71f340b6c280a87201b1336a7221c7cc16b47794c1f8e81d01dcfa1f599343085 +"@storybook/addon-essentials@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-essentials@npm:7.6.7" + dependencies: + "@storybook/addon-actions": 7.6.7 + "@storybook/addon-backgrounds": 7.6.7 + "@storybook/addon-controls": 7.6.7 + "@storybook/addon-docs": 7.6.7 + "@storybook/addon-highlight": 7.6.7 + "@storybook/addon-measure": 7.6.7 + "@storybook/addon-outline": 7.6.7 + "@storybook/addon-toolbars": 7.6.7 + "@storybook/addon-viewport": 7.6.7 + "@storybook/core-common": 7.6.7 + "@storybook/manager-api": 7.6.7 + "@storybook/node-logger": 7.6.7 + "@storybook/preview-api": 7.6.7 + ts-dedent: ^2.0.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: a088873a7326a6b0ae7355b0bcd9a50b91b3b79bc0aef84f645efc479c4c7831345271430806572dbf743af4b01b490b2d733492ea08010de5af7d9d8d0db2db languageName: node linkType: hard -"@storybook/docs-tools@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/docs-tools@npm:7.0.12" +"@storybook/addon-highlight@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-highlight@npm:7.6.7" dependencies: - "@babel/core": "npm:^7.12.10" - "@storybook/core-common": "npm:7.0.12" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - "@types/doctrine": "npm:^0.0.3" - doctrine: "npm:^3.0.0" - lodash: "npm:^4.17.21" - checksum: 279e6e58170208db58e141e5df6191d35bb7345d4956fc6fd788fb03988e3c8513c409c329e35f9e4efbb6e99864ddd1c432ea7e3409a692726c8a5e40858842 + "@storybook/global": ^5.0.0 + checksum: a148e54c2a489ae452f77b2870359fe7800655735dd18046d3d081fd78b5caebacec016fbda649e24c0fcc779639a38641c18ba2efedf37f05e401232689168c languageName: node linkType: hard -"@storybook/global@npm:^5.0.0": - version: 5.0.0 - resolution: "@storybook/global@npm:5.0.0" - checksum: 8f1b61dcdd3a89584540896e659af2ecc700bc740c16909a7be24ac19127ea213324de144a141f7caf8affaed017d064fea0618d453afbe027cf60f54b4a6d0b +"@storybook/addon-interactions@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-interactions@npm:7.6.7" + dependencies: + "@storybook/global": ^5.0.0 + "@storybook/types": 7.6.7 + jest-mock: ^27.0.6 + polished: ^4.2.2 + ts-dedent: ^2.2.0 + checksum: f0e148c02602a5608c85295b39435ae9d672f657a23fdabb22d6882bb444bfd04aaf19aa8c015c6e8a59de48a498c1bb8c51b83c7b3172842ded18d5ff0e8cf4 languageName: node linkType: hard -"@storybook/instrumenter@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/instrumenter@npm:7.0.12" +"@storybook/addon-links@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-links@npm:7.6.7" dependencies: - "@storybook/channels": "npm:7.0.12" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/preview-api": "npm:7.0.12" - checksum: 19cc1b7392494e68a3fa5111bd8c1531bc9742c7cd5e92941ed62366af8f0dea62b1e2759f9adaff5ab36717a1f05e103cb67fa31ca61d0c26e4ca7eb095b0fd + "@storybook/csf": ^0.1.2 + "@storybook/global": ^5.0.0 + ts-dedent: ^2.0.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + react: + optional: true + checksum: a0ea89f2ffd09c2a5de66381d1a5b955b78a92d93f65885285af39c69e17ab35f0b6099742b7cb36816e14b307f59f88c85023499ab56d028d3e68fea6033c6c languageName: node linkType: hard -"@storybook/instrumenter@npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": - version: 7.0.27 - resolution: "@storybook/instrumenter@npm:7.0.27" +"@storybook/addon-measure@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-measure@npm:7.6.7" dependencies: - "@storybook/channels": "npm:7.0.27" - "@storybook/client-logger": "npm:7.0.27" - "@storybook/core-events": "npm:7.0.27" - "@storybook/global": "npm:^5.0.0" - "@storybook/preview-api": "npm:7.0.27" - checksum: 4c2ad4c15d5bbdede15603f5729e10bdc33f725f79a73d68273152543760b140651bbb74f81b7cdaee996dd73e7a85784998b7b33bf6c7aadd99147b671c58ad + "@storybook/global": ^5.0.0 + tiny-invariant: ^1.3.1 + checksum: 1c89eff8d5663cd1caf6f6ebe6a9bf0335dc4787948a7ec76c6bc440dd40a8fbc217ddcd0596f3823131a5264573c091683b6bb7859bdf7dac647d503b0870f5 languageName: node linkType: hard -"@storybook/manager-api@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/manager-api@npm:7.0.12" - dependencies: - "@storybook/channels": "npm:7.0.12" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/csf": "npm:^0.1.0" - "@storybook/global": "npm:^5.0.0" - "@storybook/router": "npm:7.0.12" - "@storybook/theming": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - dequal: "npm:^2.0.2" - lodash: "npm:^4.17.21" - memoizerific: "npm:^1.11.3" - semver: "npm:^7.3.7" - store2: "npm:^2.14.2" - telejson: "npm:^7.0.3" - ts-dedent: "npm:^2.0.0" +"@storybook/addon-outline@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-outline@npm:7.6.7" + dependencies: + "@storybook/global": ^5.0.0 + ts-dedent: ^2.0.0 + checksum: e4f39d4310d17defef60110e1927a4be1278ba1fbfdc5ca85563b41be29df1a685ec38aa591db830c3baf9234fd1a935ba49202491429e2f1142a7cbe88af88e + languageName: node + linkType: hard + +"@storybook/addon-toolbars@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-toolbars@npm:7.6.7" + checksum: beedf517f457e37e1e29144cefcbc0519bfd6588f0ac16831191453943842fec8ae96bbc4febeb70facde21bb7491db124235acd2b5e54addee5d766a71a33bd + languageName: node + linkType: hard + +"@storybook/addon-viewport@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/addon-viewport@npm:7.6.7" + dependencies: + memoizerific: ^1.11.3 + checksum: 724e83509ead4edb8720bb4fa803bb0ba0b76309be741d4a2322c63f5bc20964066e42c1dab0820251f60a8c67be42ea3aa285ebe8ffee32b9b938d097a3c9f4 + languageName: node + linkType: hard + +"@storybook/blocks@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/blocks@npm:7.6.7" + dependencies: + "@storybook/channels": 7.6.7 + "@storybook/client-logger": 7.6.7 + "@storybook/components": 7.6.7 + "@storybook/core-events": 7.6.7 + "@storybook/csf": ^0.1.2 + "@storybook/docs-tools": 7.6.7 + "@storybook/global": ^5.0.0 + "@storybook/manager-api": 7.6.7 + "@storybook/preview-api": 7.6.7 + "@storybook/theming": 7.6.7 + "@storybook/types": 7.6.7 + "@types/lodash": ^4.14.167 + color-convert: ^2.0.1 + dequal: ^2.0.2 + lodash: ^4.17.21 + markdown-to-jsx: ^7.1.8 + memoizerific: ^1.11.3 + polished: ^4.2.2 + react-colorful: ^5.1.2 + telejson: ^7.2.0 + tocbot: ^4.20.1 + ts-dedent: ^2.0.0 + util-deprecate: ^1.0.2 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 8c8577fb37071ed3efd199d400152dfe54e7a2073e1c6dc6ffa780875eef501f83df5fa4f54c9e59fa26d8ee92e10dd5e93155fd9355359b9d45fadfbf007306 + checksum: 6f5815cb8a7aae4ca9b104f1c5e5ec6b4949c90a373d904b44c5aebfec0b885606ef1ab2e44ecbbc544c3d6eed869f0feaa284d7336aeebb1f440d6797dc649f + languageName: node + linkType: hard + +"@storybook/builder-manager@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/builder-manager@npm:7.6.7" + dependencies: + "@fal-works/esbuild-plugin-global-externals": ^2.1.2 + "@storybook/core-common": 7.6.7 + "@storybook/manager": 7.6.7 + "@storybook/node-logger": 7.6.7 + "@types/ejs": ^3.1.1 + "@types/find-cache-dir": ^3.2.1 + "@yarnpkg/esbuild-plugin-pnp": ^3.0.0-rc.10 + browser-assert: ^1.2.1 + ejs: ^3.1.8 + esbuild: ^0.18.0 + esbuild-plugin-alias: ^0.2.1 + express: ^4.17.3 + find-cache-dir: ^3.0.0 + fs-extra: ^11.1.0 + process: ^0.11.10 + util: ^0.12.4 + checksum: dd4d64038cb8bcc06092cf239d95d7f8c8a7420243ce26db0b362f44182a138d9e1d5fee15bd12865df6d3b89d2fad1a167d5ebed2dba4357bd5c1d16be66874 + languageName: node + linkType: hard + +"@storybook/builder-vite@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/builder-vite@npm:7.6.7" + dependencies: + "@storybook/channels": 7.6.7 + "@storybook/client-logger": 7.6.7 + "@storybook/core-common": 7.6.7 + "@storybook/csf-plugin": 7.6.7 + "@storybook/node-logger": 7.6.7 + "@storybook/preview": 7.6.7 + "@storybook/preview-api": 7.6.7 + "@storybook/types": 7.6.7 + "@types/find-cache-dir": ^3.2.1 + browser-assert: ^1.2.1 + es-module-lexer: ^0.9.3 + express: ^4.17.3 + find-cache-dir: ^3.0.0 + fs-extra: ^11.1.0 + magic-string: ^0.30.0 + rollup: ^2.25.0 || ^3.3.0 + peerDependencies: + "@preact/preset-vite": "*" + typescript: ">= 4.3.x" + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + vite-plugin-glimmerx: "*" + peerDependenciesMeta: + "@preact/preset-vite": + optional: true + typescript: + optional: true + vite-plugin-glimmerx: + optional: true + checksum: 48fa0f0d4a6ec0f97c7e8ea4f6d45861722efda6ca6d8d0585afada32ea0cd44bf25fbb061538685378df6332b16adb59793704868c2110f1a38cb30b7f1a9ea + languageName: node + linkType: hard + +"@storybook/channels@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/channels@npm:7.6.7" + dependencies: + "@storybook/client-logger": 7.6.7 + "@storybook/core-events": 7.6.7 + "@storybook/global": ^5.0.0 + qs: ^6.10.0 + telejson: ^7.2.0 + tiny-invariant: ^1.3.1 + checksum: cc90ae81bfe7225f3d8de5c0d871870ccc126ae065b83ee9450993877b70d708d3ee198a556d8c3da0fb58ebe68b576a20907e2916308a8ac7a6d7c68eda59ac + languageName: node + linkType: hard + +"@storybook/cli@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/cli@npm:7.6.7" + dependencies: + "@babel/core": ^7.23.2 + "@babel/preset-env": ^7.23.2 + "@babel/types": ^7.23.0 + "@ndelangen/get-tarball": ^3.0.7 + "@storybook/codemod": 7.6.7 + "@storybook/core-common": 7.6.7 + "@storybook/core-events": 7.6.7 + "@storybook/core-server": 7.6.7 + "@storybook/csf-tools": 7.6.7 + "@storybook/node-logger": 7.6.7 + "@storybook/telemetry": 7.6.7 + "@storybook/types": 7.6.7 + "@types/semver": ^7.3.4 + "@yarnpkg/fslib": 2.10.3 + "@yarnpkg/libzip": 2.3.0 + chalk: ^4.1.0 + commander: ^6.2.1 + cross-spawn: ^7.0.3 + detect-indent: ^6.1.0 + envinfo: ^7.7.3 + execa: ^5.0.0 + express: ^4.17.3 + find-up: ^5.0.0 + fs-extra: ^11.1.0 + get-npm-tarball-url: ^2.0.3 + get-port: ^5.1.1 + giget: ^1.0.0 + globby: ^11.0.2 + jscodeshift: ^0.15.1 + leven: ^3.1.0 + ora: ^5.4.1 + prettier: ^2.8.0 + prompts: ^2.4.0 + puppeteer-core: ^2.1.1 + read-pkg-up: ^7.0.1 + semver: ^7.3.7 + simple-update-notifier: ^2.0.0 + strip-json-comments: ^3.0.1 + tempy: ^1.0.1 + ts-dedent: ^2.0.0 + util-deprecate: ^1.0.2 + bin: + getstorybook: ./bin/index.js + sb: ./bin/index.js + checksum: bb0d1babdf7c2c607bbaf0890ac102dd230c3576decf39d32c6ec551cc6fc841e552964d13efb40b526cb6fd05e02fda5307e888992f928805fe828107c07b88 + languageName: node + linkType: hard + +"@storybook/client-logger@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/client-logger@npm:7.6.7" + dependencies: + "@storybook/global": ^5.0.0 + checksum: 4f4934fa4e022fa4ae0b802653d8ac8bd353d7514b1afb36b387029d274bbf40ad7a6fd1a2858220d415e7f535d643d701b7cdb752d71565269d44fdb482ed45 + languageName: node + linkType: hard + +"@storybook/codemod@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/codemod@npm:7.6.7" + dependencies: + "@babel/core": ^7.23.2 + "@babel/preset-env": ^7.23.2 + "@babel/types": ^7.23.0 + "@storybook/csf": ^0.1.2 + "@storybook/csf-tools": 7.6.7 + "@storybook/node-logger": 7.6.7 + "@storybook/types": 7.6.7 + "@types/cross-spawn": ^6.0.2 + cross-spawn: ^7.0.3 + globby: ^11.0.2 + jscodeshift: ^0.15.1 + lodash: ^4.17.21 + prettier: ^2.8.0 + recast: ^0.23.1 + checksum: e850371a8df11a414fc3d06c87ff81d439ed2e8f87d76846b44ead6500fd97c51d000f7b12c3a137d05f64f0e21c10aaa397e44303269b7834b17f8da3c33f59 + languageName: node + linkType: hard + +"@storybook/components@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/components@npm:7.6.7" + dependencies: + "@radix-ui/react-select": ^1.2.2 + "@radix-ui/react-toolbar": ^1.0.4 + "@storybook/client-logger": 7.6.7 + "@storybook/csf": ^0.1.2 + "@storybook/global": ^5.0.0 + "@storybook/theming": 7.6.7 + "@storybook/types": 7.6.7 + memoizerific: ^1.11.3 + use-resize-observer: ^9.1.0 + util-deprecate: ^1.0.2 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: cbc7c12148a463b7efbac2c8568b7b8669d0a7a05c46cdddd735d0505619468a3842ac1893b5ba8cf4fd61c715fd7a1df09065406fc0634a7d61e9c8e6ebd6cd + languageName: node + linkType: hard + +"@storybook/core-client@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/core-client@npm:7.6.7" + dependencies: + "@storybook/client-logger": 7.6.7 + "@storybook/preview-api": 7.6.7 + checksum: 234af026a2447e91602a55522b616c0ead2dd996a845d4db393b400acf5a7054785b14a714fdb3919f8720083ee9d24a5d5dd8eda92090ce0f54c654d4f27155 + languageName: node + linkType: hard + +"@storybook/core-common@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/core-common@npm:7.6.7" + dependencies: + "@storybook/core-events": 7.6.7 + "@storybook/node-logger": 7.6.7 + "@storybook/types": 7.6.7 + "@types/find-cache-dir": ^3.2.1 + "@types/node": ^18.0.0 + "@types/node-fetch": ^2.6.4 + "@types/pretty-hrtime": ^1.0.0 + chalk: ^4.1.0 + esbuild: ^0.18.0 + esbuild-register: ^3.5.0 + file-system-cache: 2.3.0 + find-cache-dir: ^3.0.0 + find-up: ^5.0.0 + fs-extra: ^11.1.0 + glob: ^10.0.0 + handlebars: ^4.7.7 + lazy-universal-dotenv: ^4.0.0 + node-fetch: ^2.0.0 + picomatch: ^2.3.0 + pkg-dir: ^5.0.0 + pretty-hrtime: ^1.0.3 + resolve-from: ^5.0.0 + ts-dedent: ^2.0.0 + checksum: 5e9a03114aa964ff997e1185d4f1b45bff5db941afde57ff6e8f411e08371bd3c197bd69b4f4d71a4f81970182c90ca3ee0cdce713ad992dae29c550cbff2340 + languageName: node + linkType: hard + +"@storybook/core-events@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/core-events@npm:7.6.7" + dependencies: + ts-dedent: ^2.0.0 + checksum: b355f2cdfa8a805d035e7f05909cdb670cf1ced653d3cf2281976dbc7591faaeca066ba8c3b68f1b19097301b5908b3d37381ff00364ce509bce38c5f9c2465c + languageName: node + linkType: hard + +"@storybook/core-server@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/core-server@npm:7.6.7" + dependencies: + "@aw-web-design/x-default-browser": 1.4.126 + "@discoveryjs/json-ext": ^0.5.3 + "@storybook/builder-manager": 7.6.7 + "@storybook/channels": 7.6.7 + "@storybook/core-common": 7.6.7 + "@storybook/core-events": 7.6.7 + "@storybook/csf": ^0.1.2 + "@storybook/csf-tools": 7.6.7 + "@storybook/docs-mdx": ^0.1.0 + "@storybook/global": ^5.0.0 + "@storybook/manager": 7.6.7 + "@storybook/node-logger": 7.6.7 + "@storybook/preview-api": 7.6.7 + "@storybook/telemetry": 7.6.7 + "@storybook/types": 7.6.7 + "@types/detect-port": ^1.3.0 + "@types/node": ^18.0.0 + "@types/pretty-hrtime": ^1.0.0 + "@types/semver": ^7.3.4 + better-opn: ^3.0.2 + chalk: ^4.1.0 + cli-table3: ^0.6.1 + compression: ^1.7.4 + detect-port: ^1.3.0 + express: ^4.17.3 + fs-extra: ^11.1.0 + globby: ^11.0.2 + ip: ^2.0.0 + lodash: ^4.17.21 + open: ^8.4.0 + pretty-hrtime: ^1.0.3 + prompts: ^2.4.0 + read-pkg-up: ^7.0.1 + semver: ^7.3.7 + telejson: ^7.2.0 + tiny-invariant: ^1.3.1 + ts-dedent: ^2.0.0 + util: ^0.12.4 + util-deprecate: ^1.0.2 + watchpack: ^2.2.0 + ws: ^8.2.3 + checksum: 8759f1911868875eeee9b5b810395733037c84ae47885becd4e351f4d1c51821f5501b11f0ac651996fe31fd16d11e33c8bff29670d05c244d408f021b7ceaa9 + languageName: node + linkType: hard + +"@storybook/csf-plugin@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/csf-plugin@npm:7.6.7" + dependencies: + "@storybook/csf-tools": 7.6.7 + unplugin: ^1.3.1 + checksum: 1e9bba748b383a0a3d0e5bb1f36a6fc6eda192deefe5e0c056c8f743362a7dc7ade9d90723ce79189da9c9d4f9081db6173bc1c21978757090420995abd1b061 + languageName: node + linkType: hard + +"@storybook/csf-tools@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/csf-tools@npm:7.6.7" + dependencies: + "@babel/generator": ^7.23.0 + "@babel/parser": ^7.23.0 + "@babel/traverse": ^7.23.2 + "@babel/types": ^7.23.0 + "@storybook/csf": ^0.1.2 + "@storybook/types": 7.6.7 + fs-extra: ^11.1.0 + recast: ^0.23.1 + ts-dedent: ^2.0.0 + checksum: bf78f5bcf9885840caf6c03ef3bc431b1325d4b3074b1d94185a9d26563aa87731ed947b05553ec44867ac9637d43db7431e8e68ecc041d81f948f7812bdeafb + languageName: node + linkType: hard + +"@storybook/csf@npm:^0.0.1": + version: 0.0.1 + resolution: "@storybook/csf@npm:0.0.1" + dependencies: + lodash: "npm:^4.17.15" + checksum: fb57fa028b08a51edf44e1a2bf4be40a4607f5c6ccb58aae8924f476a42b9bbd61a0ad521cfc82196f23e6a912caae0a615e70a755e6800b284c91c509fd2de6 + languageName: node + linkType: hard + +"@storybook/csf@npm:^0.1.2": + version: 0.1.2 + resolution: "@storybook/csf@npm:0.1.2" + dependencies: + type-fest: ^2.19.0 + checksum: 22038dfd5e46cd9565c3dec615918c0712eb5fc5f56e9ec89cfa75d7b48667b8fcbf7e9d1f46c9f4d440eee074f1d23a84dc56a937add37b28ddf890fdedfb8a + languageName: node + linkType: hard + +"@storybook/docs-mdx@npm:^0.1.0": + version: 0.1.0 + resolution: "@storybook/docs-mdx@npm:0.1.0" + checksum: a7770842c3947a761bcbe776a9c4fd35163d30c3274fca034169f69ff614242eaa4cacaa2c95fd215827081ef9a43f4774d521a6f43a4d063ea5f4ea14b1d69a + languageName: node + linkType: hard + +"@storybook/docs-tools@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/docs-tools@npm:7.6.7" + dependencies: + "@storybook/core-common": 7.6.7 + "@storybook/preview-api": 7.6.7 + "@storybook/types": 7.6.7 + "@types/doctrine": ^0.0.3 + assert: ^2.1.0 + doctrine: ^3.0.0 + lodash: ^4.17.21 + checksum: a8b9a995ca8031b56bc1ba64b81b3fe491519f0999dfc315d3f73f99eb9e004f9d242f167d4629a7cffe89ef3ac2c72f79632a4030c779f9ac99fb92011c3833 + languageName: node + linkType: hard + +"@storybook/global@npm:^5.0.0": + version: 5.0.0 + resolution: "@storybook/global@npm:5.0.0" + checksum: ede0ad35ec411fe31c61150dbd118fef344d1d0e72bf5d3502368e35cf68126f6b7ae4a0ab5e2ffe2f0baa3b4286f03ad069ba3e098e1725449ef08b7e154ba8 + languageName: node + linkType: hard + +"@storybook/manager-api@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/manager-api@npm:7.6.7" + dependencies: + "@storybook/channels": 7.6.7 + "@storybook/client-logger": 7.6.7 + "@storybook/core-events": 7.6.7 + "@storybook/csf": ^0.1.2 + "@storybook/global": ^5.0.0 + "@storybook/router": 7.6.7 + "@storybook/theming": 7.6.7 + "@storybook/types": 7.6.7 + dequal: ^2.0.2 + lodash: ^4.17.21 + memoizerific: ^1.11.3 + store2: ^2.14.2 + telejson: ^7.2.0 + ts-dedent: ^2.0.0 + checksum: b40e667d647398d140f142aaf3033579308f23573a8023b4366ca9482dce47bd34c090ba0381f66fc0b19600c24032551ddb418683b907bee0f1c9a86899c2da languageName: node linkType: hard -"@storybook/manager@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/manager@npm:7.0.12" - checksum: f5a5abd56abf48c7254360df93efa7bebb2070fadc9687ef411881b6b8b88d5463eeeb892b909e4d62dd5af0950d47667306f760d5729cb132981905acb6c0cb +"@storybook/manager@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/manager@npm:7.6.7" + checksum: 1eba0f753f16dfd7358b5e184c16ee356b618304d374d067177cd898dc9b0106cb48563d8040a60d44b1e1ee48f8e1f2ea421a1540aa3f9efc67248262b6a3e6 languageName: node linkType: hard "@storybook/mdx2-csf@npm:^1.0.0": version: 1.1.0 resolution: "@storybook/mdx2-csf@npm:1.1.0" - checksum: ba4496a51efae35edb3e509e488cd16066ccf0768d2dc527bbc2650d0bc0f630540985205772d63d1711d1a5dae66136a919077c90fa2ac7a02a13de43446baa + checksum: 5ccdb13f4e59b989499f76e54ffaffb96b5710a696346efe19989b3373f375703adf516780894b270fa64a7e765b55274dc18575fc4a84e7fa92b844a4467c5d languageName: node linkType: hard -"@storybook/node-logger@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/node-logger@npm:7.0.12" - dependencies: - "@types/npmlog": "npm:^4.1.2" - chalk: "npm:^4.1.0" - npmlog: "npm:^5.0.1" - pretty-hrtime: "npm:^1.0.3" - checksum: a77567f0f5900060af10e74a514a72edf65eda8a09c1b0228c64e8ed437aa4b5698de43dd935cfc91ab3bcefd9d0711047f66892807d1fe5c515708819d87a0b +"@storybook/node-logger@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/node-logger@npm:7.6.7" + checksum: 85b0c63e37adbfbe30cff165d21d12df42a82648f0af9bd9d4d9ac3eb85be54946afa265cfeebc45712cf42ba4e9da9f5a6fed95eacca10b9cde87bbb79e20dd languageName: node linkType: hard -"@storybook/postinstall@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/postinstall@npm:7.0.12" - checksum: 34c8d0d4bdef10481c22aa189ca197eaeceac768067fb5597182b9b98986a9be856cfc694e80e6ea48fe81ef7e129e8ecf143413481d94997079c1e71d7271de +"@storybook/postinstall@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/postinstall@npm:7.6.7" + checksum: c3198f5a04c5970cb59d701a56b3fd08eb2074dbf47f39bce4643c1106c83d2e0a6112199b2257a089d28819bed25483112b78f6d11d83f87b36c0043e183133 languageName: node linkType: hard -"@storybook/preview-api@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/preview-api@npm:7.0.12" - dependencies: - "@storybook/channel-postmessage": "npm:7.0.12" - "@storybook/channels": "npm:7.0.12" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/core-events": "npm:7.0.12" - "@storybook/csf": "npm:^0.1.0" - "@storybook/global": "npm:^5.0.0" - "@storybook/types": "npm:7.0.12" - "@types/qs": "npm:^6.9.5" - dequal: "npm:^2.0.2" - lodash: "npm:^4.17.21" - memoizerific: "npm:^1.11.3" - qs: "npm:^6.10.0" - synchronous-promise: "npm:^2.0.15" - ts-dedent: "npm:^2.0.0" - util-deprecate: "npm:^1.0.2" - checksum: ddf8b812d223ddb7d58d94860b40f1dc61c1b8c7d5c592a2a68c880543029ac960e7e49fbd8deb1f5914dcd683f365de101dd9aee99a5e121772f5ee2e9c2ffe - languageName: node - linkType: hard - -"@storybook/preview-api@npm:7.0.27": - version: 7.0.27 - resolution: "@storybook/preview-api@npm:7.0.27" - dependencies: - "@storybook/channel-postmessage": "npm:7.0.27" - "@storybook/channels": "npm:7.0.27" - "@storybook/client-logger": "npm:7.0.27" - "@storybook/core-events": "npm:7.0.27" - "@storybook/csf": "npm:^0.1.0" - "@storybook/global": "npm:^5.0.0" - "@storybook/types": "npm:7.0.27" - "@types/qs": "npm:^6.9.5" - dequal: "npm:^2.0.2" - lodash: "npm:^4.17.21" - memoizerific: "npm:^1.11.3" - qs: "npm:^6.10.0" - synchronous-promise: "npm:^2.0.15" - ts-dedent: "npm:^2.0.0" - util-deprecate: "npm:^1.0.2" - checksum: 5d9789e98e1b36c9c1734f1082454bae07dec36270132d5a5095cc862c249e11acdf4ab210f23a53f4dbf27d188f31f9289b045d302ba452efa1f73c88acef26 - languageName: node - linkType: hard - -"@storybook/preview@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/preview@npm:7.0.12" - checksum: 7e0954a745e699a3251eafe0af6ad07d51b22d4dc40faea78153b52ce8e0791eee1d1f20eb04087b07fb963503e361fb58ab166d4ee3619e2874d062c61045c0 +"@storybook/preview-api@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/preview-api@npm:7.6.7" + dependencies: + "@storybook/channels": 7.6.7 + "@storybook/client-logger": 7.6.7 + "@storybook/core-events": 7.6.7 + "@storybook/csf": ^0.1.2 + "@storybook/global": ^5.0.0 + "@storybook/types": 7.6.7 + "@types/qs": ^6.9.5 + dequal: ^2.0.2 + lodash: ^4.17.21 + memoizerific: ^1.11.3 + qs: ^6.10.0 + synchronous-promise: ^2.0.15 + ts-dedent: ^2.0.0 + util-deprecate: ^1.0.2 + checksum: 2cea8458320f92eea604ac92c23051decf3208bc4d4546fde96de822b8acad010dd126a30fe211a4090b2b78c83fb33617ca64a0ecedfd3f42526350957f2ff7 languageName: node linkType: hard -"@storybook/react-dom-shim@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/react-dom-shim@npm:7.0.12" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 8e3bdb5d23c8f342638ff198ff7c454dadb5bbfcd412e1395ec273dcf3d1438c5214bc08aba9093c656a423c3362f030b11b8dbbc9e7957e4419bc3a6c7d4883 +"@storybook/preview@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/preview@npm:7.6.7" + checksum: caf4c9e52ff81a420f2cd14677d137e5af91da05303276712e0d7e96f8458e2cf71ef880a1736f92da083b0ef0ad9e1e75fa1174a6face8bc5797a5444f540b6 languageName: node linkType: hard -"@storybook/react-vite@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/react-vite@npm:7.0.12" - dependencies: - "@joshwooding/vite-plugin-react-docgen-typescript": "npm:0.2.1" - "@rollup/pluginutils": "npm:^4.2.0" - "@storybook/builder-vite": "npm:7.0.12" - "@storybook/react": "npm:7.0.12" - "@vitejs/plugin-react": "npm:^3.0.1" - ast-types: "npm:^0.14.2" - magic-string: "npm:^0.27.0" - react-docgen: "npm:6.0.0-alpha.3" +"@storybook/react-dom-shim@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/react-dom-shim@npm:7.6.7" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - vite: ^3.0.0 || ^4.0.0 - checksum: c09739a8cb05099bfd6544dc609edd8be53af20620c033f32bc9bda369975475c557620a41ab513f7412f55d1856c99b39edb969be17e0cfe1151e4d45f7534e + checksum: e5518543a87df2d8525ab6d48970398e82739f978317a3a6be8b9c1be116b947c6bca8cd4eddc918488f2d60ff6c12a63966e4e624a3b8b379fcf2846844dd69 languageName: node linkType: hard -"@storybook/react@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/react@npm:7.0.12" - dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/core-client": "npm:7.0.12" - "@storybook/docs-tools": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - "@storybook/preview-api": "npm:7.0.12" - "@storybook/react-dom-shim": "npm:7.0.12" - "@storybook/types": "npm:7.0.12" - "@types/escodegen": "npm:^0.0.6" - "@types/estree": "npm:^0.0.51" - "@types/node": "npm:^16.0.0" - acorn: "npm:^7.4.1" - acorn-jsx: "npm:^5.3.1" - acorn-walk: "npm:^7.2.0" - escodegen: "npm:^2.0.0" - html-tags: "npm:^3.1.0" - lodash: "npm:^4.17.21" - prop-types: "npm:^15.7.2" - react-element-to-jsx-string: "npm:^15.0.0" - ts-dedent: "npm:^2.0.0" - type-fest: "npm:^2.19.0" - util-deprecate: "npm:^1.0.2" +"@storybook/react-vite@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/react-vite@npm:7.6.7" + dependencies: + "@joshwooding/vite-plugin-react-docgen-typescript": 0.3.0 + "@rollup/pluginutils": ^5.0.2 + "@storybook/builder-vite": 7.6.7 + "@storybook/react": 7.6.7 + "@vitejs/plugin-react": ^3.0.1 + magic-string: ^0.30.0 + react-docgen: ^7.0.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + checksum: 344a7135234b320da7703a4d86ba2249a7ed2f2daebfbc915bc06a8f2343b6eac2a8e2db6811299ececa89fe589d1ccdfea62a5f513d2a513c3830b98afe5efb + languageName: node + linkType: hard + +"@storybook/react@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/react@npm:7.6.7" + dependencies: + "@storybook/client-logger": 7.6.7 + "@storybook/core-client": 7.6.7 + "@storybook/docs-tools": 7.6.7 + "@storybook/global": ^5.0.0 + "@storybook/preview-api": 7.6.7 + "@storybook/react-dom-shim": 7.6.7 + "@storybook/types": 7.6.7 + "@types/escodegen": ^0.0.6 + "@types/estree": ^0.0.51 + "@types/node": ^18.0.0 + acorn: ^7.4.1 + acorn-jsx: ^5.3.1 + acorn-walk: ^7.2.0 + escodegen: ^2.1.0 + html-tags: ^3.1.0 + lodash: ^4.17.21 + prop-types: ^15.7.2 + react-element-to-jsx-string: ^15.0.0 + ts-dedent: ^2.0.0 + type-fest: ~2.19 + util-deprecate: ^1.0.2 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + typescript: "*" peerDependenciesMeta: typescript: optional: true - checksum: 8b90e963f05a93b1e47ac6559c582d1e1850f01eb7bc251904d32e5c176903c14cd8f806c52591cebeac934e6aaaab5bd4e7f2cfebca3ca7ae13926ebbdee096 + checksum: 010707cf34f1ac982bdb4d6a364d89a7ebb3c10eb8f40793147c71bed2eeb4320fb2ab2a791073ad748b18a3a20d0ba85345415f3b155c864fb0cfb4f5677ba6 languageName: node linkType: hard -"@storybook/router@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/router@npm:7.0.12" +"@storybook/router@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/router@npm:7.6.7" dependencies: - "@storybook/client-logger": "npm:7.0.12" - memoizerific: "npm:^1.11.3" - qs: "npm:^6.10.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: be77e68da41ca223919dc7dc9db6700f79b06c78c2d28bea469ca2ded47f33a478b8dca6ca7d4a13c59ff2cb00fca511dea2f1c03f1d5faec17193d4226062e7 + "@storybook/client-logger": 7.6.7 + memoizerific: ^1.11.3 + qs: ^6.10.0 + checksum: b25f03b63b00851b3224d0ed97e4bf495b513d7e8af9aafc9eeab4c72b7561f848ec15f8595519056fc8a71b88fa75614252ce253c4c662d995bcaef6f98da5c languageName: node linkType: hard -"@storybook/telemetry@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/telemetry@npm:7.0.12" +"@storybook/telemetry@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/telemetry@npm:7.6.7" dependencies: - "@storybook/client-logger": "npm:7.0.12" - "@storybook/core-common": "npm:7.0.12" - chalk: "npm:^4.1.0" - detect-package-manager: "npm:^2.0.1" - fetch-retry: "npm:^5.0.2" - fs-extra: "npm:^11.1.0" - isomorphic-unfetch: "npm:^3.1.0" - nanoid: "npm:^3.3.1" - read-pkg-up: "npm:^7.0.1" - checksum: b0a972c7e3317b0a376437693014bf2ff79292e8ac55d1aad6ae13e60fa6681de1c6ef7fec50101ff9337822e49ddf913a8209f74dce17450e9ca26f924ebf12 + "@storybook/client-logger": 7.6.7 + "@storybook/core-common": 7.6.7 + "@storybook/csf-tools": 7.6.7 + chalk: ^4.1.0 + detect-package-manager: ^2.0.1 + fetch-retry: ^5.0.2 + fs-extra: ^11.1.0 + read-pkg-up: ^7.0.1 + checksum: 6b6786aef18a9133fed870e4030dbbab971d6dfc809ee81c6079f7816d34dd9295c35e796a772011c9dd6006abf7eb9b9c743f5e06e831a1d7e077f91ad81364 languageName: node linkType: hard -"@storybook/testing-library@npm:0.0.14-next.2": - version: 0.0.14-next.2 - resolution: "@storybook/testing-library@npm:0.0.14-next.2" +"@storybook/testing-library@npm:0.2.2": + version: 0.2.2 + resolution: "@storybook/testing-library@npm:0.2.2" dependencies: - "@storybook/client-logger": "npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0" - "@storybook/instrumenter": "npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0" - "@testing-library/dom": "npm:^8.3.0" - "@testing-library/user-event": "npm:^13.2.1" - ts-dedent: "npm:^2.2.0" - checksum: 53b87041a642c7c5bb90f4fc0f7cbda6fa8cb458711dd4ccdeaba8ab6064754f0681064ef3cce4969822aa7ca69808ebe7d709f0313a3a17eefc6a7e8c88e7e6 + "@testing-library/dom": ^9.0.0 + "@testing-library/user-event": ^14.4.0 + ts-dedent: ^2.2.0 + checksum: 8ccdc1fbbb3472264c56b0aaf2f1c5d273f1ae9b230a53adf9cf82bf82c1a555550894f0e8869c206fa07b1fe8423da4d56590377756c58de3ec560b35a96c46 languageName: node linkType: hard -"@storybook/theming@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/theming@npm:7.0.12" +"@storybook/theming@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/theming@npm:7.6.7" dependencies: - "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.0.0" - "@storybook/client-logger": "npm:7.0.12" - "@storybook/global": "npm:^5.0.0" - memoizerific: "npm:^1.11.3" + "@emotion/use-insertion-effect-with-fallbacks": ^1.0.0 + "@storybook/client-logger": 7.6.7 + "@storybook/global": ^5.0.0 + memoizerific: ^1.11.3 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 6fc8d1ffb0ce42843ffd598669a74759ef3867b486e202ea7569ba890b0e3ba46631c5c9d1fa232c3c565721b6888b60aca6747aced9efe044b6c9faf28218e3 - languageName: node - linkType: hard - -"@storybook/types@npm:7.0.12": - version: 7.0.12 - resolution: "@storybook/types@npm:7.0.12" - dependencies: - "@storybook/channels": "npm:7.0.12" - "@types/babel__core": "npm:^7.0.0" - "@types/express": "npm:^4.7.0" - file-system-cache: "npm:^2.0.0" - checksum: 670d8cc6ce57a054621e0a22b86231ba6625a739c3cde19ea5aa99979617d38262fd31e06a74154ef2024a449e1f7c84bf610af61a4f240ead85a7535d8f559c + checksum: a8f144e693167b10f170ff56ec38551f6606c7cc04450446838d7cb6ae15f5e1b82d2264cd24c0a75e8949b4cce2fe1d5f17cec88797e43f038a1d7832e8d72d languageName: node linkType: hard -"@storybook/types@npm:7.0.27": - version: 7.0.27 - resolution: "@storybook/types@npm:7.0.27" +"@storybook/types@npm:7.6.7": + version: 7.6.7 + resolution: "@storybook/types@npm:7.6.7" dependencies: - "@storybook/channels": "npm:7.0.27" - "@types/babel__core": "npm:^7.0.0" - "@types/express": "npm:^4.7.0" - file-system-cache: "npm:2.3.0" - checksum: e59aa96379051362ee127a80f6eb8f1a1e42b40a3aa295417ab4174ef793df53e60aa5f1a11b2d73436adaad9785c4943c9d2f95bd12084d13e179aedc50557f + "@storybook/channels": 7.6.7 + "@types/babel__core": ^7.0.0 + "@types/express": ^4.7.0 + file-system-cache: 2.3.0 + checksum: 3e3395409e42d0854b93afa12e6c588e6a47d42b9d60f714e71ee43f39356917ec1b5b1ab014155005091463bc4535a5e640dfc3d838da3517c6366e1d22a5a8 languageName: node linkType: hard @@ -3920,7 +4962,7 @@ __metadata: resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 66714c2961f21409b0d33f0f65cf52f2496838b4ed056e98c872faa9f60754fae491ca4397717991eaa9884a0a44ae8920fd550101c9877759bd73f361a49800 + checksum: ecdf432de38a6789e419758425e766651c14c78e6c537158796dfdbbb930f69fb36f11b5ad046c6fbb70d4c6ad567d6ffc45e3afa3fc5f3330234c34299e96a7 languageName: node linkType: hard @@ -3929,7 +4971,7 @@ __metadata: resolution: "@svgr/babel-plugin-remove-jsx-attribute@npm:7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8b2320919d918e83d8b5fc9d194a4354e3aac98801863defe4f732954bb48b665812a5e3813f2eaf8bdb0c8d78f0a2c9934675a2df5248b99d2eb7a33688d408 + checksum: 808ba216eea6904b2c0b664957b1ad4d3e0d9e36635ad2fca7fb2667031730cbbe067421ac0d50209f7c83dc3b6c2eff8f377780268cd1606c85603bc47b18d7 languageName: node linkType: hard @@ -3938,7 +4980,7 @@ __metadata: resolution: "@svgr/babel-plugin-remove-jsx-empty-expression@npm:7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c9d338206aade1bd280a4d45ec3f80f72b91e0a27502d38eeb68024e5fa21b0fcd20f72b6e591eb0e82cca9793012680888e66c2fd04bdcf17e79385f512e946 + checksum: da0cae989cc99b5437c877412da6251eef57edfff8514b879c1245b6519edfda101ebc4ba2be3cce3aa9a6014050ea4413e004084d839afd8ac8ffc587a921bf languageName: node linkType: hard @@ -3947,7 +4989,7 @@ __metadata: resolution: "@svgr/babel-plugin-replace-jsx-attribute-value@npm:7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9a39807bd09fb00c121e2b6952e24b90b6d9cd2318105176b93ccc4e1ec5b87b9999b96bce6f9f5e7769033583565908b440951de89ac9c3cb82ea0e0a3db686 + checksum: e624918b545e414a1d0fbace6fc6f8c1c27dac4bf6e5fd4cbc9d8fbc9353fdf4bf6c4fe8b84fb938dfb5c0076cd2ed90b91ac60c0a7011f6e8b0cb71eabe60b3 languageName: node linkType: hard @@ -3956,7 +4998,7 @@ __metadata: resolution: "@svgr/babel-plugin-svg-dynamic-title@npm:7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 49dd7907a63bd7643e6081d0bc4daee23e3fc095b6eafc58760f5d67314eee1ea60a6788ccbe68e2457f083ea31522c847119fe48eb6e2dc20956b9bb3316cbb + checksum: 3ffc97cc61573ae4fb2e013ec0572b2273f55e8e125bb6c7fc69ae9fb433a675dc879f85166979cf21e1d0f1a5e168dabf116dcc468f132e83928b66cd791e1a languageName: node linkType: hard @@ -3965,7 +5007,7 @@ __metadata: resolution: "@svgr/babel-plugin-svg-em-dimensions@npm:7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9d5b569b75a612074b03aab20837dd1858f97d002b05fc9a2ec939aebbc8053e893960e264a1f2261bf0c426e4f8fa93c72313bcf7dface89fc09bc643147ebd + checksum: 0f98ee5269983038ec8098fd1906f600199a9c7a48caca9ced1644f988cdb06acc434ec239554d8987bc2098a772c5b472f1cbb6a46dc8f39aa353aea818c963 languageName: node linkType: hard @@ -3974,7 +5016,7 @@ __metadata: resolution: "@svgr/babel-plugin-transform-react-native-svg@npm:7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9091bd61d787e8506965f10a946dec463881b337aa435eedb0d5423ece1d0589fa643c2e01003cbb3447d3dbdf5d937ff7bae487a3098abbbe94ac04c84022d8 + checksum: 20067965349a9ed5ec339d63a2983a613135ae4dac416bd754683e41fdc91671f62d1950955f4ae57ec03525d13d7b0db467d4c2eb31ec22eafbe240fc840836 languageName: node linkType: hard @@ -3983,7 +5025,7 @@ __metadata: resolution: "@svgr/babel-plugin-transform-svg-component@npm:7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 715c371bdae660fa9452083f2be6c1736d9ad516dc7134656c6e70374799de94eacda596504394aa6934aacb6da9099acd99569089220d66aaf91b34aa934c7b + checksum: cf5be9c6b24a4a9c0afefe67214370af1cd562d9a06082a89486ec25298a223766cdf57591c92750764068a0d27377c3ce3a9609d18eaae59f64c94e60f2b25c languageName: node linkType: hard @@ -4001,7 +5043,7 @@ __metadata: "@svgr/babel-plugin-transform-svg-component": "npm:^7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7d0755e2f007d4108b9ccbd7ccb2de2787ed3aa54cf873426bb211666996fe7a4fde73710a76bbdc169e1e72d7eca1dec5a6b26f14ab3124ff154ecbe387b69a + checksum: 8c3ff1df1627b2db03e4755281b02e7f440323c9c9f71e3c8ebdab0e1966e24ca16686224da72a92e34b722e693bfa408aca5c62d42b02382e0c528bd3860be6 languageName: node linkType: hard @@ -4013,7 +5055,7 @@ __metadata: "@svgr/babel-preset": "npm:^7.0.0" camelcase: "npm:^6.2.0" cosmiconfig: "npm:^8.1.3" - checksum: 347617081188fc0ed5de53a8643b70949c8737a1b5baf6e4a2dd23ecb8311de111d4e76f8f005959ec66e7d53a5f8155249f6b947c8111042b978fc798f53c4c + checksum: 34fa14557baf560c78a6d7ac79401d35feb081d54ab55ee1b43d1649a89b322b4ecc7dba3daca0063af1f639c499cea1c46e34e5b066655ae7dc3553c1a64672 languageName: node linkType: hard @@ -4023,7 +5065,7 @@ __metadata: dependencies: "@babel/types": "npm:^7.21.3" entities: "npm:^4.4.0" - checksum: 2d6880fac9445559cc2e29f87782a52c37d2db7b99a4892f65def1e79a8239d7961c483934ff9ce2d37cb087f5b34c80ca5a51f7bc9eaceacfe0bd66e4e64373 + checksum: c2168c36c8d25e876da879815728310cf204579c97a73908ce33b063cccfb9a18b6e53f53c6daf81506a96761d84b6261bf64faf26f16453f27e73cb322a9256 languageName: node linkType: hard @@ -4035,7 +5077,7 @@ __metadata: "@svgr/babel-preset": "npm:^7.0.0" "@svgr/hast-util-to-babel-ast": "npm:^7.0.0" svg-parser: "npm:^2.0.4" - checksum: bd649a306b83bc355315265046461cfa089c81604785b081fe0ccffd0112dc8bfad1e19d8e042d85339792458ab2e9022f8bf29fdd64bfea90718a40553ce00e + checksum: 009421b8e3f32bf13ebec4d47c7997106cd806c6922349871f2d9a77cd3304f55d30630dd8948ff77a9ead2ee1869ac39ad65cf95ab95b2192ef21d5704bd367 languageName: node linkType: hard @@ -4051,23 +5093,7 @@ __metadata: dom-accessibility-api: "npm:^0.5.9" lz-string: "npm:^1.5.0" pretty-format: "npm:^27.0.2" - checksum: c5f9b6cf6ddf31e4556961d5ec8a6d700b953df3181860355e9506efe8825d40952286ab392b2f6aeb5cbaebf2f022562ef168c34f730f88d7c977e63ac41d82 - languageName: node - linkType: hard - -"@testing-library/dom@npm:^8.3.0": - version: 8.20.1 - resolution: "@testing-library/dom@npm:8.20.1" - dependencies: - "@babel/code-frame": "npm:^7.10.4" - "@babel/runtime": "npm:^7.12.5" - "@types/aria-query": "npm:^5.0.1" - aria-query: "npm:5.1.3" - chalk: "npm:^4.1.0" - dom-accessibility-api: "npm:^0.5.9" - lz-string: "npm:^1.5.0" - pretty-format: "npm:^27.0.2" - checksum: 614013756706467f2a7f3f693c18377048c210ec809884f0f9be866f7d865d075805ad15f5d100e8a699467fdde09085bf79e23a00ea0a6ab001d9583ef15e5d + checksum: 790f4da6a8cbe7da8b7769e81e68caea1aed5b5f1973b808895692a945fb854fe8acdc66ffc34b6a57ec49bad9d76ccdd69b632ea8a82ad61d1e97d76cfdf9ec languageName: node linkType: hard @@ -4083,7 +5109,7 @@ __metadata: dom-accessibility-api: "npm:^0.5.9" lz-string: "npm:^1.5.0" pretty-format: "npm:^27.0.2" - checksum: 25d1deddba014c107fd9703181fbb7063ed376d3ad42d7918ee752e7e677edfb5abaf672b22afc5257ffe760c9c7e5cc981656297c328bc61578d23c6b65b4dc + checksum: 8ee3136451644e39990edea93709c38cf1e8ce5306f3c66273ca00935963faa51ca74e8d92b02eb442ccb842cfa28ca62833e393e075eb269cf9bef6f5600663 languageName: node linkType: hard @@ -4100,7 +5126,7 @@ __metadata: dom-accessibility-api: "npm:^0.5.6" lodash: "npm:^4.17.15" redent: "npm:^3.0.0" - checksum: 0925fda78096cca355d164d5358b84b9371c4fb6ba60ce60c2263446ac6d9c6aaca75e2792cdb42699fe78c379924c53db672a3510361b577ebb89a0c6e1c629 + checksum: 94911f901a8031f3e489d04ac057cb5373621230f5d92bed80e514e24b069fb58a3166d1dd86963e55f078a1bd999da595e2ab96ed95f452d477e272937d792a languageName: node linkType: hard @@ -4114,7 +5140,7 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 81035913024faf18ba7e163418af517b2c3b85aef496fbd6334bda38f6f6dd4072678c6b76c41148b46b7fc846764f875e1156cbfc7643ffa1b62ee069d78951 + checksum: 4a54c8f56cc4a39b50803205f84f06280bb76521d6d5d4b3b36651d760c7c7752ef142d857d52aaf4fad4848ed7a8be49afc793a5dda105955d2f8bef24901ac languageName: node linkType: hard @@ -4123,39 +5149,37 @@ __metadata: resolution: "@testing-library/user-event@npm:14.4.3" peerDependencies: "@testing-library/dom": ">=7.21.4" - checksum: 28e1e4ed2fdaa9486e203c6789386be228e305abd3fa41f38c828af415fd4a4e80f4de88de0e502ff11c4b4926f221b874a2a45bcc8170d30714e12dad2c1bd0 + checksum: 852c48ea6db1c9471b18276617c84fec4320771e466cd58339a732ca3fd73ad35e5a43ae14f51af51a8d0a150dcf60fcaab049ef367871207bea8f92c4b8195e languageName: node linkType: hard -"@testing-library/user-event@npm:^13.2.1": - version: 13.5.0 - resolution: "@testing-library/user-event@npm:13.5.0" - dependencies: - "@babel/runtime": "npm:^7.12.5" +"@testing-library/user-event@npm:^14.4.0": + version: 14.5.2 + resolution: "@testing-library/user-event@npm:14.5.2" peerDependencies: "@testing-library/dom": ">=7.21.4" - checksum: ff57edaeab31322c80c3f01d55404b4cebb907b9ec7672b96a1a14d053f172046b01c5f27b45677927ebee8ed91bce695a7d09edec9a48875cfacabe39d0426a + checksum: d76937dffcf0082fbf3bb89eb2b81a31bf5448048dd61c33928c5f10e33a58e035321d39145cefd469bb5a499c68a5b4086b22f1a44e3e7c7e817dc5f6782867 languageName: node linkType: hard "@tootallnate/once@npm:2": version: 2.0.0 resolution: "@tootallnate/once@npm:2.0.0" - checksum: 073bfa548026b1ebaf1659eb8961e526be22fa77139b10d60e712f46d2f0f05f4e6c8bec62a087d41088ee9e29faa7f54838568e475ab2f776171003c3920858 + checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 languageName: node linkType: hard "@trysound/sax@npm:0.2.0": version: 0.2.0 resolution: "@trysound/sax@npm:0.2.0" - checksum: 44907308549ce775a41c38a815f747009ac45929a45d642b836aa6b0a536e4978d30b8d7d680bbd116e9dd73b7dbe2ef0d1369dcfc2d09e83ba381e485ecbe12 + checksum: 11226c39b52b391719a2a92e10183e4260d9651f86edced166da1d95f39a0a1eaa470e44d14ac685ccd6d3df7e2002433782872c0feeb260d61e80f21250e65c languageName: node linkType: hard "@types/aria-query@npm:^5.0.1": version: 5.0.1 resolution: "@types/aria-query@npm:5.0.1" - checksum: bc9e40ce37bd3a1654948778c7829bd55aea1bc5f2cd06fcf6cd650b07bb388995799e9aab6e2d93a6cf55dcba3b85c155f7ba93adefcc7c2e152fc6057061b5 + checksum: 69fd7cceb6113ed370591aef04b3fd0742e9a1b06dd045c43531448847b85de181495e4566f98e776b37c422a12fd71866e0a1dfd904c5ec3f84d271682901de languageName: node linkType: hard @@ -4168,7 +5192,20 @@ __metadata: "@types/babel__generator": "npm:*" "@types/babel__template": "npm:*" "@types/babel__traverse": "npm:*" - checksum: c83402fc7ef8abd1f94ffe350b8bde9a35ccb6c3624bc8e39b6a7e1a675d112f6b70ac1b05391a579ca3b126baffe66b0b94f954edef086c4482b97d293c3659 + checksum: 9fcd9691a33074802d9057ff70b0e3ff3778f52470475b68698a0f6714fbe2ccb36c16b43dc924eb978cd8a81c1f845e5ff4699e7a47606043b539eb8c6331a8 + languageName: node + linkType: hard + +"@types/babel__core@npm:^7.18.0": + version: 7.20.5 + resolution: "@types/babel__core@npm:7.20.5" + dependencies: + "@babel/parser": ^7.20.7 + "@babel/types": ^7.20.7 + "@types/babel__generator": "*" + "@types/babel__template": "*" + "@types/babel__traverse": "*" + checksum: a3226f7930b635ee7a5e72c8d51a357e799d19cbf9d445710fa39ab13804f79ab1a54b72ea7d8e504659c7dfc50675db974b526142c754398d7413aa4bc30845 languageName: node linkType: hard @@ -4177,7 +5214,7 @@ __metadata: resolution: "@types/babel__generator@npm:7.6.4" dependencies: "@babel/types": "npm:^7.0.0" - checksum: e0051b450e4ba2df0a7e386f08df902a4e920f6f8d6f185d69ddbe9b0e2e2d3ae434bb51e437bc0fca2a9a0f5dc4ca44d3a1941ef75e74371e8be5bf64416fe4 + checksum: 20effbbb5f8a3a0211e95959d06ae70c097fb6191011b73b38fe86deebefad8e09ee014605e0fd3cdaedc73d158be555866810e9166e1f09e4cfd880b874dcb0 languageName: node linkType: hard @@ -4187,7 +5224,7 @@ __metadata: dependencies: "@babel/parser": "npm:^7.1.0" "@babel/types": "npm:^7.0.0" - checksum: 6f180e96c39765487f27e861d43eebed341ec7a2fc06cdf5a52c22872fae67f474ca165d149c708f4fd9d5482beb66c0a92f77411b234bb30262ed2303e50b1a + checksum: 649fe8b42c2876be1fd28c6ed9b276f78152d5904ec290b6c861d9ef324206e0a5c242e8305c421ac52ecf6358fa7e32ab7a692f55370484825c1df29b1596ee languageName: node linkType: hard @@ -4196,7 +5233,16 @@ __metadata: resolution: "@types/babel__traverse@npm:7.20.1" dependencies: "@babel/types": "npm:^7.20.7" - checksum: 5a6a3a26be090573309527184a31f1b82ef55f3d73d811c15f181d323e471305f2390651a04d49d4cd4ca41bbeabb53c9f7862a8e09eab5a0f8910a6aec6e867 + checksum: 58341e23c649c0eba134a1682d4f20d027fad290d92e5740faa1279978f6ed476fc467ae51ce17a877e2566d805aeac64eae541168994367761ec883a4150221 + languageName: node + linkType: hard + +"@types/babel__traverse@npm:^7.18.0": + version: 7.20.5 + resolution: "@types/babel__traverse@npm:7.20.5" + dependencies: + "@babel/types": ^7.20.7 + checksum: 608e0ab4fc31cd47011d98942e6241b34d461608c0c0e153377c5fd822c436c475f1ded76a56bfa76a1adf8d9266b727bbf9bfac90c4cb152c97f30dadc5b7e8 languageName: node linkType: hard @@ -4206,7 +5252,7 @@ __metadata: dependencies: "@types/connect": "npm:*" "@types/node": "npm:*" - checksum: c2dd533e1d4af958d656bdba7f376df68437d8dfb7e4522c88b6f3e6f827549e4be5bf0be68a5f1878accf5752ea37fba7e8a4b6dda53d0d122d77e27b69c750 + checksum: e17840c7d747a549f00aebe72c89313d09fbc4b632b949b2470c5cb3b1cb73863901ae84d9335b567a79ec5efcfb8a28ff8e3f36bc8748a9686756b6d5681f40 languageName: node linkType: hard @@ -4215,35 +5261,58 @@ __metadata: resolution: "@types/connect@npm:3.4.35" dependencies: "@types/node": "npm:*" - checksum: f11a1ccfed540723dddd7cb496543ad40a2f663f22ff825e9b220f0bae86db8b1ced2184ee41d3fb358b019ad6519e39481b06386db91ebb859003ad1d54fe6a + checksum: fe81351470f2d3165e8b12ce33542eef89ea893e36dd62e8f7d72566dfb7e448376ae962f9f3ea888547ce8b55a40020ca0e01d637fab5d99567673084542641 + languageName: node + linkType: hard + +"@types/cross-spawn@npm:^6.0.2": + version: 6.0.6 + resolution: "@types/cross-spawn@npm:6.0.6" + dependencies: + "@types/node": "*" + checksum: b4172927cd1387cf037c3ade785ef46c87537b7bc2803d7f6663b4904d0c5d6f726415d1adb2fee4fecb21746738f11336076449265d46be4ce110cc3a8c8436 languageName: node linkType: hard "@types/detect-port@npm:^1.3.0": version: 1.3.3 resolution: "@types/detect-port@npm:1.3.3" - checksum: 27c8000e3d41fd1158e2213b31c90b63852299ed66e4604b028a7146519530ab129b8ff867db02b06a32f61e7764f8d5aff0c44c5f543ce2b4b035e5968b62e1 + checksum: 0dadb520286a5cfd2832d12189dc795cc3589dfd9166d1b033453fb94b0212c4067a847045833e85b0f7c73135c944cb4ccb49c8e683491845c2e8a3da5d5c1c languageName: node linkType: hard "@types/doctrine@npm:^0.0.3": version: 0.0.3 resolution: "@types/doctrine@npm:0.0.3" - checksum: 566dcdc988c97ff01d14493ceb2223643347f07cf0a88c86cd7cb7c2821cfc837fd39295e6809a29614fdfdc6c4e981408155ca909b2e5da5d947af939b6c966 + checksum: 7ca9c8ff4d2da437785151c9eef0dd80b8fa12e0ff0fcb988458a78de4b6f0fc92727ba5bbee446e1df615a91f03053c5783b30b7c21ab6ceab6a42557e93e50 + languageName: node + linkType: hard + +"@types/doctrine@npm:^0.0.9": + version: 0.0.9 + resolution: "@types/doctrine@npm:0.0.9" + checksum: 3909eaca42e7386b2ab866f082b78da3e00718d2fa323597e254feb0556c678b41f2c490729067433630083ac9c806ec6ae1e146754f7f8ba7d3e43ed68d6500 languageName: node linkType: hard "@types/ejs@npm:^3.1.1": version: 3.1.2 resolution: "@types/ejs@npm:3.1.2" - checksum: 8e55275011009e7a44043d97348a4a1b5a7583e1f048b6ad8998f1b30667995314f15bc9cc9ed3e0e79722cce9a06845d06d5d023bca179bb00d52016b41ad7d + checksum: e4f0745b6ed53a63c08bdfdeb019a7d0e0c400896722b44d6732b4ee6bf6061d2dc965206186b8b0ae2ecd71303c29f1af1feddbca2df0acbd7bd234a74ca518 + languageName: node + linkType: hard + +"@types/emscripten@npm:^1.39.6": + version: 1.39.10 + resolution: "@types/emscripten@npm:1.39.10" + checksum: 1721da76593f9194e0b7c90a581e2d31c23bd4eb28f93030cd1dc58216cdf1e692c045274f2eedaed29c652c25c9a4dff2e503b11bd1258d07095c009a1956b1 languageName: node linkType: hard "@types/escodegen@npm:^0.0.6": version: 0.0.6 resolution: "@types/escodegen@npm:0.0.6" - checksum: bbef189319c7b0386486bc7224369f118c7aedf35cc13e40ae5879b9ab4f848936f31e8eea50e71d4de72d4b7a77d9e6e9e5ceec4406c648fbc0077ede634ed5 + checksum: 7b25aeedd48dbef68345224082c6bc774845cbfc1d9b2ce91a477130fe7ccabf33da126c1d6d55e5dfd838db429a7c80890628a167e5aa55b6a4620974da38d3 languageName: node linkType: hard @@ -4253,21 +5322,21 @@ __metadata: dependencies: "@types/estree": "npm:*" "@types/json-schema": "npm:*" - checksum: feac2a3aafe96844993aa0a3343e9265a13e4dbe2981a215b0103926253ce23adbee4563cef91ef0444f2463658bc10ce69fb6941f4297b4f9a021c77fdf1ec7 + checksum: 2655f409a4ecdd64bb9dd9eb6715e7a2ac30c0e7f902b414e10dbe9d6d497baa5a0f13105e1f7bd5ad7a913338e2ab4bed1faf192a7a0d27d1acd45ba79d3f69 languageName: node linkType: hard "@types/estree@npm:*, @types/estree@npm:^1.0.0": version: 1.0.1 resolution: "@types/estree@npm:1.0.1" - checksum: b4022067f834d86766f23074a1a7ac6c460e823b00cd8fe94c997bc491e7794615facd3e1520a934c42bd8c0689dbff81e5c643b01f1dee143fc758cac19669e + checksum: e9aa175eacb797216fafce4d41e8202c7a75555bc55232dee0f9903d7171f8f19f0ae7d5191bb1a88cb90e65468be508c0df850a9fb81b4433b293a5a749899d languageName: node linkType: hard "@types/estree@npm:^0.0.51": version: 0.0.51 resolution: "@types/estree@npm:0.0.51" - checksum: a70c60d5e634e752fcd45b58c9c046ef22ad59ede4bc93ad5193c7e3b736ebd6bcd788ade59d9c3b7da6eeb0939235f011d4c59bb4fc04d8c346b76035099dd1 + checksum: e56a3bcf759fd9185e992e7fdb3c6a5f81e8ff120e871641607581fb3728d16c811702a7d40fa5f869b7f7b4437ab6a87eb8d98ffafeee51e85bbe955932a189 languageName: node linkType: hard @@ -4279,7 +5348,7 @@ __metadata: "@types/qs": "npm:*" "@types/range-parser": "npm:*" "@types/send": "npm:*" - checksum: 08db6ffff07b5d53d852bb0a078ea5ee6dc3eb581d8c8fdf0d65f48c641db2830658074c797844e618b0933ce4ca2ddd08191f9d79b12eb2ec3d66f8551716ec + checksum: cc8995d10c6feda475ec1b3a0e69eb0f35f21ab6b49129ad5c6f279e0bc5de8175bc04ec51304cb79a43eec3ed2f5a1e01472eb6d5f827b8c35c6ca8ad24eb6e languageName: node linkType: hard @@ -4291,14 +5360,14 @@ __metadata: "@types/express-serve-static-core": "npm:^4.17.33" "@types/qs": "npm:*" "@types/serve-static": "npm:*" - checksum: 5802a0a28f7473744dd6a118479440d8c5c801c973d34fb6f31b5ee645a41fee936193978a8e905d55deefda9b675d19924167bf11a31339874c3161a3fc2922 + checksum: 0196dacc275ac3ce89d7364885cb08e7fb61f53ca101f65886dbf1daf9b7eb05c0943e2e4bbd01b0cc5e50f37e0eea7e4cbe97d0304094411ac73e1b7998f4da languageName: node linkType: hard "@types/find-cache-dir@npm:^3.2.1": version: 3.2.1 resolution: "@types/find-cache-dir@npm:3.2.1" - checksum: 68059aec88ef776a689c1711a881fd91a9ce1b03dd5898ea1d2ac5d77d7b0235f21fdf210f380c13deca8b45e4499841a63aaf31fd2123af687f2c6b472f41ce + checksum: bf5c4e96da40247cd9e6327f54dfccda961a0fb2d70e3c71bd05def94de4c2e6fb310fe8ecb0f04ecf5dbc52214e184b55a2337b0f87250d4ae1e2e7d58321e4 languageName: node linkType: hard @@ -4308,17 +5377,7 @@ __metadata: dependencies: "@types/minimatch": "npm:*" "@types/node": "npm:*" - checksum: a8eb5d5cb5c48fc58c7ca3ff1e1ddf771ee07ca5043da6e4871e6757b4472e2e73b4cfef2644c38983174a4bc728c73f8da02845c28a1212f98cabd293ecae98 - languageName: node - linkType: hard - -"@types/glob@npm:^8.0.0": - version: 8.1.0 - resolution: "@types/glob@npm:8.1.0" - dependencies: - "@types/minimatch": "npm:^5.1.2" - "@types/node": "npm:*" - checksum: ded07aa0d7a1caf3c47b85e262be82989ccd7933b4a14712b79c82fd45a239249811d9fc3a135b3e9457afa163e74a297033d7245b0dc63cd3d032f3906b053f + checksum: 6ae717fedfdfdad25f3d5a568323926c64f52ef35897bcac8aca8e19bc50c0bd84630bbd063e5d52078b2137d8e7d3c26eabebd1a2f03ff350fff8a91e79fc19 languageName: node linkType: hard @@ -4327,7 +5386,7 @@ __metadata: resolution: "@types/graceful-fs@npm:4.1.6" dependencies: "@types/node": "npm:*" - checksum: b1d32c5ae7bd52cf60e29df20407904c4312a39612e7ec2ee23c1e3731c1cfe31d97c6941bf6cb52f5f929d50d86d92dd506436b63fafa833181d439b628885e + checksum: c3070ccdc9ca0f40df747bced1c96c71a61992d6f7c767e8fd24bb6a3c2de26e8b84135ede000b7e79db530a23e7e88dcd9db60eee6395d0f4ce1dae91369dd4 languageName: node linkType: hard @@ -4336,7 +5395,7 @@ __metadata: resolution: "@types/hast@npm:2.3.5" dependencies: "@types/unist": "npm:^2" - checksum: 3fc5185e7fb5139a4f60f0d4450179c1f88b7e288a054415b273e4a32f0c4cfe825a4cad075824dcdf3984609b47f13141f8900dedb3aeab482ae5a16275e807 + checksum: e435e9fbf6afc616ade377d2246a632fb75f4064be4bfd619b67a1ba0d9935d75968a18fbdb66535dfb5e77ef81f4b9b56fd8f35c1cffa34b48ddb0287fec91e languageName: node linkType: hard @@ -4346,21 +5405,21 @@ __metadata: dependencies: "@types/react": "npm:*" hoist-non-react-statics: "npm:^3.3.0" - checksum: 5ed808e5fbf0979fe07acd631147420c30319383f4388a57e0fb811c6ff30abef286e937a84c7b00f4647ca7f1ab390cc42af0bfc7547a87d2e59e0e7072d92b + checksum: 2c0778570d9a01d05afabc781b32163f28409bb98f7245c38d5eaf082416fdb73034003f5825eb5e21313044e8d2d9e1f3fe2831e345d3d1b1d20bcd12270719 languageName: node linkType: hard "@types/http-errors@npm:*": version: 2.0.1 resolution: "@types/http-errors@npm:2.0.1" - checksum: 3bbc8c84fb02b381737e2eec563b434121384b1aef4e070edec4479a1bc74f27373edc09162680cd3ea1035ef8e5ab6d606bd7c99e3855c424045fb74376cb66 + checksum: 3bb0c50b0a652e679a84c30cd0340d696c32ef6558518268c238840346c077f899315daaf1c26c09c57ddd5dc80510f2a7f46acd52bf949e339e35ed3ee9654f languageName: node linkType: hard "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": version: 2.0.4 resolution: "@types/istanbul-lib-coverage@npm:2.0.4" - checksum: af5f6b64e788331ed3f7b2e2613cb6ca659c58b8500be94bbda8c995ad3da9216c006f1cfe6f66b321c39392b1bda18b16e63cef090a77d24a00b4bd5ba3b018 + checksum: a25d7589ee65c94d31464c16b72a9dc81dfa0bea9d3e105ae03882d616e2a0712a9c101a599ec482d297c3591e16336962878cb3eb1a0a62d5b76d277a890ce7 languageName: node linkType: hard @@ -4369,7 +5428,7 @@ __metadata: resolution: "@types/istanbul-lib-report@npm:3.0.0" dependencies: "@types/istanbul-lib-coverage": "npm:*" - checksum: 7ced458631276a28082ee40645224c3cdd8b861961039ff811d841069171c987ec7e50bc221845ec0d04df0022b2f457a21fb2f816dab2fbe64d59377b32031f + checksum: 656398b62dc288e1b5226f8880af98087233cdb90100655c989a09f3052b5775bf98ba58a16c5ae642fb66c61aba402e07a9f2bff1d1569e3b306026c59f3f36 languageName: node linkType: hard @@ -4378,7 +5437,7 @@ __metadata: resolution: "@types/istanbul-reports@npm:3.0.1" dependencies: "@types/istanbul-lib-report": "npm:*" - checksum: e147f0db9346a0cae9a359220bc76f7c78509fb6979a2597feb24d64b6e8328d2d26f9d152abbd59c6bca721e4ea2530af20116d01df50815efafd1e151fd777 + checksum: f1ad54bc68f37f60b30c7915886b92f86b847033e597f9b34f2415acdbe5ed742fa559a0a40050d74cdba3b6a63c342cac1f3a64dba5b68b66a6941f4abd7903 languageName: node linkType: hard @@ -4388,7 +5447,7 @@ __metadata: dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: ba5a28569368db62eeff85ea53661c7dff79a5be739a59926c37868888cc69f8b7d0c7c6209139ecca5b83056843ba67fa764f7e7fc9c8d1c4e1f80351ede0f4 + checksum: e36bb92e0b9e5ea7d6f8832baa42f087fc1697f6cd30ec309a07ea4c268e06ec460f1f0cfd2581daf5eff5763475190ec1ad8ac6520c49ccfe4f5c0a48bfa676 languageName: node linkType: hard @@ -4398,7 +5457,7 @@ __metadata: dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: e85525fe83a0792632a31ca32968b33a0014d617442e9a515357d2aa8890052ef622b1f6fd25d48f4f1a3ab806bed94e6d9b056dea23a897464e0e35957ff654 + checksum: 7d205599ea3cccc262bad5cc173d3242d6bf8138c99458509230e4ecef07a52d6ddcde5a1dbd49ace655c0af51d2dbadef3748697292ea4d86da19d9e03e19c0 languageName: node linkType: hard @@ -4409,145 +5468,131 @@ __metadata: "@types/node": "npm:*" "@types/tough-cookie": "npm:*" parse5: "npm:^7.0.0" - checksum: 3d4b2a3eab145674ee6da482607c5e48977869109f0f62560bf91ae1a792c9e847ac7c6aaf243ed2e97333cb3c51aef314ffa54a19ef174b8f9592dfcb836b25 + checksum: d55402c5256ef451f93a6e3d3881f98339fe73a5ac2030588df056d6835df8367b5a857b48d27528289057e26dcdd3f502edc00cb877c79174cb3a4c7f2198c1 languageName: node linkType: hard "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.9": version: 7.0.12 resolution: "@types/json-schema@npm:7.0.12" - checksum: 2c39946ae321fe42d085c61a85872a81bbee70f9b2054ad344e8811dfc478fdbaf1ebf5f2989bb87c895ba2dfc3b1dcba85db11e467bbcdc023708814207791c + checksum: 00239e97234eeb5ceefb0c1875d98ade6e922bfec39dd365ec6bd360b5c2f825e612ac4f6e5f1d13601b8b30f378f15e6faa805a3a732f4a1bbe61915163d293 languageName: node linkType: hard "@types/json5@npm:^0.0.29": version: 0.0.29 resolution: "@types/json5@npm:0.0.29" - checksum: 6bf5337bc447b706bb5b4431d37686aa2ea6d07cfd6f79cc31de80170d6ff9b1c7384a9c0ccbc45b3f512bae9e9f75c2e12109806a15331dc94e8a8db6dbb4ac + checksum: e60b153664572116dfea673c5bda7778dbff150498f44f998e34b5886d8afc47f16799280e4b6e241c0472aef1bc36add771c569c68fc5125fc2ae519a3eb9ac languageName: node linkType: hard "@types/lodash@npm:^4.14.167": version: 4.14.195 resolution: "@types/lodash@npm:4.14.195" - checksum: 6d733276df592614a0943a0053056140398b3c263cdf2557d4301b3a47b07ff561926cb9339a4725acbc7d8766f91ded218df11e0a4288cee369eafb5141d94d + checksum: 39b75ca635b3fa943d17d3d3aabc750babe4c8212485a4df166fe0516e39288e14b0c60afc6e21913cc0e5a84734633c71e617e2bd14eaa1cf51b8d7799c432e languageName: node linkType: hard "@types/mdx@npm:^2.0.0": version: 2.0.5 resolution: "@types/mdx@npm:2.0.5" - checksum: f46932365a24ad6927dd87678598b839fa64ef8c9d0714b45a0185ac52427b374899ba96022f97330b27aca3572a6815f844cf345a50b9c0c483f485c243eda1 + checksum: 1069baff0b2d0fb0bc724748e2386af626cc30f8ef99e680afb4dee566ed0aeabd31cea774212a7033f491e594a0acc234116078b252cba94ac413f91eb585a3 languageName: node linkType: hard "@types/mime-types@npm:^2.1.0": version: 2.1.1 resolution: "@types/mime-types@npm:2.1.1" - checksum: 131b33bfd89481f6a791996db9198c6c5ffccbb310e990d1dd9fab7a2287b5a0fd642bdd959a19281397c86f721498e09956e3892e5db17f93f38e726ca05008 + checksum: 106b5d556add46446a579ad25ff15d6b421851790d887edcad558c90c1e64b1defc72bfbaf4b08f208916e21d9cc45cdb951d77be51268b18221544cfe054a3c languageName: node linkType: hard "@types/mime@npm:*": version: 3.0.1 resolution: "@types/mime@npm:3.0.1" - checksum: c4c0fc89042822a3b5ffd6ef0da7006513454ee8376ffa492372d17d2925a4e4b1b194c977b718c711df38b33eb9d06deb5dbf9f851bcfb7e5e65f06b2a87f97 + checksum: 4040fac73fd0cea2460e29b348c1a6173da747f3a87da0dbce80dd7a9355a3d0e51d6d9a401654f3e5550620e3718b5a899b2ec1debf18424e298a2c605346e7 languageName: node linkType: hard "@types/mime@npm:^1": version: 1.3.2 resolution: "@types/mime@npm:1.3.2" - checksum: 61d144e5170c6cdf6de334ec0ee4bb499b1a0fb0233834a9e8cec6d289b0e3042bedf35cbc1c995d71a247635770dae3f13a9ddae69098bb54b933429bc08d35 + checksum: 0493368244cced1a69cb791b485a260a422e6fcc857782e1178d1e6f219f1b161793e9f87f5fae1b219af0f50bee24fcbe733a18b4be8fdd07a38a8fb91146fd languageName: node linkType: hard -"@types/minimatch@npm:*, @types/minimatch@npm:^5.1.2": +"@types/minimatch@npm:*": version: 5.1.2 resolution: "@types/minimatch@npm:5.1.2" - checksum: 83cf1c11748891b714e129de0585af4c55dd4c2cafb1f1d5233d79246e5e1e19d1b5ad9e8db449667b3ffa2b6c80125c429dbee1054e9efb45758dbc4e118562 + checksum: 0391a282860c7cb6fe262c12b99564732401bdaa5e395bee9ca323c312c1a0f45efbf34dce974682036e857db59a5c9b1da522f3d6055aeead7097264c8705a8 languageName: node linkType: hard -"@types/node-fetch@npm:^2.5.7": - version: 2.6.4 - resolution: "@types/node-fetch@npm:2.6.4" +"@types/node-fetch@npm:^2.6.4": + version: 2.6.11 + resolution: "@types/node-fetch@npm:2.6.11" dependencies: - "@types/node": "npm:*" - form-data: "npm:^3.0.0" - checksum: e43e4670ed8b7693dbf660ac1450b14fcfcdd8efca1eb0f501b6ad95af2d1fa06f8541db03e9511e82a5fee510a238fe0913330c9a58f8ac6892b985f6dd993e + "@types/node": "*" + form-data: ^4.0.0 + checksum: 180e4d44c432839bdf8a25251ef8c47d51e37355ddd78c64695225de8bc5dc2b50b7bb855956d471c026bb84bd7295688a0960085e7158cbbba803053492568b languageName: node linkType: hard "@types/node@npm:*": version: 20.4.2 resolution: "@types/node@npm:20.4.2" - checksum: ca506e089737d54effabda5d6534fdf9fdbe22adbcc4864a170feea390389f38cbae6abcf89c2b1ce5c3e4ffc450b35341509a7619f850babf43106009f01b2d + checksum: 99e544ea7560d51f01f95627fc40394c24a13da8f041121a0da13e4ef0a2aa332932eaf9a5e8d0e30d1c07106e96a183be392cbba62e8cf0bf6a085d5c0f4149 languageName: node linkType: hard -"@types/node@npm:^16.0.0": - version: 16.18.38 - resolution: "@types/node@npm:16.18.38" - checksum: 02631f1cfe0c111024e4bf0909c3bfc7476e65e03cb32dc48b2f71f000590b244d239b349b91a6b03667c33f31fbd3200c8fc5838623fcaadce3e92d60efee1a +"@types/node@npm:^18.0.0": + version: 18.19.8 + resolution: "@types/node@npm:18.19.8" + dependencies: + undici-types: ~5.26.4 + checksum: fa291495d6157a9d9393b4c3bdbf1ce12a8f661dc9da6a4fa19bcdb19af1c62bb8dbf7fb66ae135f29cd788b618e9845b83e9c47edcf39f0953a8561fdacd9a3 languageName: node linkType: hard "@types/normalize-package-data@npm:^2.4.0": version: 2.4.1 resolution: "@types/normalize-package-data@npm:2.4.1" - checksum: c90b163741f27a1a4c3b1869d7d5c272adbd355eb50d5f060f9ce122ce4342cf35f5b0005f55ef780596cacfeb69b7eee54cd3c2e02d37f75e664945b6e75fc6 - languageName: node - linkType: hard - -"@types/npmlog@npm:^4.1.2": - version: 4.1.4 - resolution: "@types/npmlog@npm:4.1.4" - checksum: 5670c38db51f2c4a5da05657920d7597bf9da00615920b42a001fde9011f05ab1e8ec8cbc671abb47915028e3e0ace5c3d981c23684c202a00bf518f16ece01d + checksum: e87bccbf11f95035c89a132b52b79ce69a1e3652fe55962363063c9c0dae0fe2477ebc585e03a9652adc6f381d24ba5589cc5e51849df4ced3d3e004a7d40ed5 languageName: node linkType: hard "@types/prettier@npm:^2.1.5": version: 2.7.3 resolution: "@types/prettier@npm:2.7.3" - checksum: 0960b5c1115bb25e979009d0b44c42cf3d792accf24085e4bfce15aef5794ea042e04e70c2139a2c3387f781f18c89b5706f000ddb089e9a4a2ccb7536a2c5f0 + checksum: 705384209cea6d1433ff6c187c80dcc0b95d99d5c5ce21a46a9a58060c527973506822e428789d842761e0280d25e3359300f017fbe77b9755bc772ab3dc2f83 languageName: node linkType: hard "@types/pretty-hrtime@npm:^1.0.0": version: 1.0.1 resolution: "@types/pretty-hrtime@npm:1.0.1" - checksum: e990110a3626e987319092c5149d5ea244785b83fbbd8e62605714ec1fa4317a3524ae0b6381cdc2ca92619d9a451b3fe9ff4085c42826f5398e3380d3031bff + checksum: a6cdee417eea6f7af914e4fcd13e05822864ce10b5d7646525632e86d69b79123eec55a5d3fff0155ba46b61902775e1644bcb80e1e4dffdac28e7febb089083 languageName: node linkType: hard "@types/prop-types@npm:*": version: 15.7.5 resolution: "@types/prop-types@npm:15.7.5" - checksum: 648aae41423821c61c83823ae36116c8d0f68258f8b609bdbc257752dcd616438d6343d554262aa9a7edaee5a19aca2e028a74fa2d0f40fffaf2816bc7056857 + checksum: 5b43b8b15415e1f298243165f1d44390403bb2bd42e662bca3b5b5633fdd39c938e91b7fce3a9483699db0f7a715d08cef220c121f723a634972fdf596aec980 languageName: node linkType: hard "@types/qs@npm:*, @types/qs@npm:6.9.7, @types/qs@npm:^6.9.5": version: 6.9.7 resolution: "@types/qs@npm:6.9.7" - checksum: 157eb05f4c75790b0ebdcf7b0547ff117feabc8cda03c3cac3d3ea82bb19a1912e76a411df3eb0bdd01026a9770f07bc0e7e3fbe39ebb31c1be4564c16be35f1 - languageName: node - linkType: hard - -"@types/ramda@npm:0.29.3": - version: 0.29.3 - resolution: "@types/ramda@npm:0.29.3" - dependencies: - types-ramda: "npm:^0.29.4" - checksum: 9c62a4600f5df5e65a01ffe4a470500c98f7c0d093fde47e0d4257675f1ec50effe4696cb004a6b53227948db67ea26a2345dbc91819ecc868105c0f64cecd1e + checksum: 7fd6f9c25053e9b5bb6bc9f9f76c1d89e6c04f7707a7ba0e44cc01f17ef5284adb82f230f542c2d5557d69407c9a40f0f3515e8319afd14e1e16b5543ac6cdba languageName: node linkType: hard "@types/range-parser@npm:*": version: 1.2.4 resolution: "@types/range-parser@npm:1.2.4" - checksum: 8e3c3cda88675efd9145241bcb454449715b7d015a7fb80d018dcb3d441fa1938b302242cc0dfa6b02c5d014dd8bc082ae90091e62b1e816cae3ec36c2a7dbcb + checksum: b7c0dfd5080a989d6c8bb0b6750fc0933d9acabeb476da6fe71d8bdf1ab65e37c136169d84148034802f48378ab94e3c37bb4ef7656b2bec2cb9c0f8d4146a95 languageName: node linkType: hard @@ -4556,7 +5601,7 @@ __metadata: resolution: "@types/react-copy-to-clipboard@npm:5.0.4" dependencies: "@types/react": "npm:*" - checksum: ac90c7ab30982cebdfc995022e724e898369c6b58a852f45aff0e18522cebe79a9ce75042e0f55b3bdc86300eff46764956ed49489fbc347141061c64002855b + checksum: c0fe51b79a393d4c1fa5f8a288793c03f791e0d979abaa6ae587de53b8e3bc1f05e3379e7539077a21c9d66c12c3fad3ab6684f836f2ba7a55b9589de8500738 languageName: node linkType: hard @@ -4565,7 +5610,7 @@ __metadata: resolution: "@types/react-dom@npm:18.0.11" dependencies: "@types/react": "npm:*" - checksum: 8bf1e3f710221a937613df4d192f3b9e5a30e5c3103cac52c5210fb56b79f7a8cc66137d3bc5c9d92d375165a97fae53284724191bc01cb9898564fa02595569 + checksum: 579691e4d5ec09688087568037c35edf8cfb1ab3e07f6c60029280733ee7b5c06d66df6fcc90786702c93ac8cb13bc7ff16c79ddfc75d082938fbaa36e1cdbf4 languageName: node linkType: hard @@ -4574,7 +5619,7 @@ __metadata: resolution: "@types/react-dom@npm:18.2.7" dependencies: "@types/react": "npm:*" - checksum: bd090f5e1b13765fbc191d9eb720dd152d26c20558221963009189c4636ce11e4c1c976e4cde4a74335f997a2be651af27d3727474a8091424101a83a71eebfb + checksum: e02ea908289a7ad26053308248d2b87f6aeafd73d0e2de2a3d435947bcea0422599016ffd1c3e38ff36c42f5e1c87c7417f05b0a157e48649e4a02f21727d54f languageName: node linkType: hard @@ -4583,7 +5628,7 @@ __metadata: resolution: "@types/react-syntax-highlighter@npm:15.5.7" dependencies: "@types/react": "npm:*" - checksum: e5e871b6431fa33f19a0d5050f05f333bf7c72589f624e08da6deae536f3da5b9f93201a4123dcddc808aee0f7a3b6f479290f1671f5859cf23a62e94e338193 + checksum: 1918d01baaa9bf485093fb04167d0dc87131be708bd68d32d3f614c0e7dba05de765fc62df139fa1972836b13e27983a2d89552eda5b5a38691a4ec300949648 languageName: node linkType: hard @@ -4594,7 +5639,7 @@ __metadata: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: a728a90e242fb41c233729fa46885cc47aca7df2035ed803f83bf0b582dde81143d465ecbf04a056bc6404f0f746f219d7043245ebd99baf83a178bbbb856c76 + checksum: a6a5e8cc78f486b9020d1ad009aa6c56943c68c7c6376e0f8399e9cbcd950b7b8f5d73f00200f5379f5e58d31d57d8aed24357f301d8e86108cd438ce6c8b3dd languageName: node linkType: hard @@ -4605,21 +5650,28 @@ __metadata: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: 6d94ec25c18b39aac687814b3a717e767f2fba3289c3b682caa4d0182160a72a9816a612b5a207c8ea73f1d288019f56f3d08742ac7cfff91719abb77da9d11a + checksum: e752df961105e5127652460504785897ca6e77259e0da8f233f694f9e8f451cde7fa0709d4456ade0ff600c8ce909cfe29f9b08b9c247fa9b734e126ec53edd7 + languageName: node + linkType: hard + +"@types/resolve@npm:^1.20.2": + version: 1.20.6 + resolution: "@types/resolve@npm:1.20.6" + checksum: dc35f5517606b6687cd971c0281ac58bdee2c50c051b030f04647d3991688be2259c304ee97e5b5d4b9936072c36767eb5933b54611a407d6557972bb6fea4f6 languageName: node linkType: hard "@types/scheduler@npm:*": version: 0.16.3 resolution: "@types/scheduler@npm:0.16.3" - checksum: c249d4b96fa05165ac22c214f94a045ee0af8beedefdbc54b769febd0044cab3a874e55419841a0dcc76439e379a63e257f3253c87168e3261e7bc783d623302 + checksum: 2b0aec39c24268e3ce938c5db2f2e77f5c3dd280e05c262d9c2fe7d890929e4632a6b8e94334017b66b45e4f92a5aa42ba3356640c2a1175fa37bef2f5200767 languageName: node linkType: hard "@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4": version: 7.5.0 resolution: "@types/semver@npm:7.5.0" - checksum: ca4ba4642b5972b6e88e73c5bc02bbaceb8d76bce71748d86e3e95042d4e5a44603113a1dcd2cb9b73ad6f91f6e4ab73185eb41bbfc9c73b11f0ed3db3b7443a + checksum: 0a64b9b9c7424d9a467658b18dd70d1d781c2d6f033096a6e05762d20ebbad23c1b69b0083b0484722aabf35640b78ccc3de26368bcae1129c87e9df028a22e2 languageName: node linkType: hard @@ -4629,7 +5681,7 @@ __metadata: dependencies: "@types/mime": "npm:^1" "@types/node": "npm:*" - checksum: 1aad6bfafdaa3a3cadad1b441843dfd166821c0e93513daabe979de85b552a1298cfb6f07d40f80b5ecf14a3194dc148deb138605039841f1dadc7132c73e634 + checksum: 10b620a5960058ef009afbc17686f680d6486277c62f640845381ec4baa0ea683fdd77c3afea4803daf5fcddd3fb2972c8aa32e078939f1d4e96f83195c89793 languageName: node linkType: hard @@ -4640,14 +5692,14 @@ __metadata: "@types/http-errors": "npm:*" "@types/mime": "npm:*" "@types/node": "npm:*" - checksum: 5e7b3e17b376f8910d5c9a0b1def38d7841c8939713940098f1b80a330d5caa9cfe9b632c122252cd70165052439e18fafa46635dc55b1d6058343901eec22eb + checksum: 15c261dbfc57890f7cc17c04d5b22b418dfa0330c912b46c5d8ae2064da5d6f844ef7f41b63c7f4bbf07675e97ebe6ac804b032635ec742ae45d6f1274259b3e languageName: node linkType: hard "@types/stack-utils@npm:^2.0.0": version: 2.0.1 resolution: "@types/stack-utils@npm:2.0.1" - checksum: 3327ee919a840ffe907bbd5c1d07dfd79137dd9732d2d466cf717ceec5bb21f66296173c53bb56cff95fae4185b9cd6770df3e9745fe4ba528bbc4975f54d13f + checksum: 205fdbe3326b7046d7eaf5e494d8084f2659086a266f3f9cf00bccc549c8e36e407f88168ad4383c8b07099957ad669f75f2532ed4bc70be2b037330f7bae019 languageName: node linkType: hard @@ -4656,35 +5708,42 @@ __metadata: resolution: "@types/testing-library__jest-dom@npm:5.14.8" dependencies: "@types/jest": "npm:*" - checksum: 83b9e7470da50d1a594c0afd999f689955e61cb8d9a8a32582ca14f73cc8503428376f98414becc1dc9e712f3de8ee2e49f41ed0117ab6a382c79988682e857e + checksum: 18f5ba7d0db8ebd91667b544537762ce63f11c4fd02b3d57afa92f9457a384d3ecf9bc7b50b6b445af1b3ea38b69862b4f95130720d4dd23621d598ac074d93a languageName: node linkType: hard "@types/tough-cookie@npm:*": version: 4.0.2 resolution: "@types/tough-cookie@npm:4.0.2" - checksum: 38d01fc79a9a87166253b8c548bb401599424c57a818bea1b47a68be6dcd37fc3bff381f978354e00221f284937d5066bb92d58bf79952f9d21deb934e8ec9a7 + checksum: e055556ffdaa39ad85ede0af192c93f93f986f4bd9e9426efdc2948e3e2632db3a4a584d4937dbf6d7620527419bc99e6182d3daf2b08685e710f2eda5291905 languageName: node linkType: hard "@types/unist@npm:^2, @types/unist@npm:^2.0.0": version: 2.0.7 resolution: "@types/unist@npm:2.0.7" - checksum: ecfb4ad9909ba9390fc3b6923a1d783e99753b0687f5cd99a0e56b6c05e1c72bf4e55cb1b8c0ffda49c6cbead4636de351a130f63d7648c554dc526038733b25 + checksum: b97a219554e83431f19a93ff113306bf0512909292815e8f32964e47d041c505af1aaa2a381c23e137c4c0b962fad58d4ce9c5c3256642921a466be43c1fc715 languageName: node linkType: hard "@types/use-sync-external-store@npm:^0.0.3": version: 0.0.3 resolution: "@types/use-sync-external-store@npm:0.0.3" - checksum: 82824c1051ba40a00e3d47964cdf4546a224e95f172e15a9c62aa3f118acee1c7518b627a34f3aa87298a2039f982e8509f92bfcc18bea7c255c189c293ba547 + checksum: 161ddb8eec5dbe7279ac971531217e9af6b99f7783213566d2b502e2e2378ea19cf5e5ea4595039d730aa79d3d35c6567d48599f69773a02ffcff1776ec2a44e + languageName: node + linkType: hard + +"@types/uuid@npm:^9.0.1": + version: 9.0.7 + resolution: "@types/uuid@npm:9.0.7" + checksum: c7321194aeba9ea173efd1e721403bdf4e7ae6945f8f8cdbc87c791f4b505ccf3dbc4a8883d90b394ef13b7c2dc778045792b05dbb23b3c746f8ea347804d448 languageName: node linkType: hard "@types/yargs-parser@npm:*": version: 21.0.0 resolution: "@types/yargs-parser@npm:21.0.0" - checksum: cb89f3bb2e8002f1479a65a934e825be4cc18c50b350bbc656405d41cf90b8a299b105e7da497d7eb1aa460472a07d1e5a389f3af0862f1d1252279cfcdd017c + checksum: b2f4c8d12ac18a567440379909127cf2cec393daffb73f246d0a25df36ea983b93b7e9e824251f959e9f928cbc7c1aab6728d0a0ff15d6145f66cec2be67d9a2 languageName: node linkType: hard @@ -4693,7 +5752,7 @@ __metadata: resolution: "@types/yargs@npm:16.0.5" dependencies: "@types/yargs-parser": "npm:*" - checksum: 7b2824c749b6e28f5ee3248d13b244eaf7d3c5bb96089add774997572b5a10f1a0826d29a7bc797d64d29ca504b0b0d6ba2e74931b3fabae78ccbbcf07282f0c + checksum: 22697f7cc8aa32dcc10981a87f035e183303a58351c537c81fb450270d5c494b1d918186210e445b0eb2e4a8b34a8bda2a595f346bdb1c9ed2b63d193cb00430 languageName: node linkType: hard @@ -4702,7 +5761,7 @@ __metadata: resolution: "@types/yargs@npm:17.0.24" dependencies: "@types/yargs-parser": "npm:*" - checksum: fbebf57e1d04199e5e7eb0c67a402566fa27177ee21140664e63da826408793d203d262b48f8f41d4a7665126393d2e952a463e960e761226def247d9bbcdbd0 + checksum: 5f3ac4dc4f6e211c1627340160fbe2fd247ceba002190da6cf9155af1798450501d628c9165a183f30a224fc68fa5e700490d740ff4c73e2cdef95bc4e8ba7bf languageName: node linkType: hard @@ -4726,7 +5785,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 3847db76ed4a5df9cbb0f0155afa81951323a93ba37de3dca872b325502d0203da859a67f6d201bcfdf4985188b80227b7fd039206f7b921c96d33befe7ed25d + checksum: 3ea842ef9615e298e28c6687c4dc285577ea0995944410553b3ca514ce9d437534b6e89114e9398c1a370324afe7a4a251c8c49540bb3bf13dcadde9ada3ecc2 languageName: node linkType: hard @@ -4743,7 +5802,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 4e2ea4694b261a25bca452db502666ddb4444cced9518eb2d34bd06d099885858307c9b320fd1aaeb45513811dc1984bbba370e5a8567671bad7fc5a0eb8bcc7 + checksum: db61a12a67bc45d814297e7f089768c0849f18162b330279aa15121223ec3b18d80df4c327f4ca0a40a7bddb9150ba1a9379fce00bc0e4a10cc189d04e36f0e3 languageName: node linkType: hard @@ -4753,7 +5812,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:5.57.1" "@typescript-eslint/visitor-keys": "npm:5.57.1" - checksum: f0905f70939980164c0205c6c6d3638bea40fd9afb1acc83632360e66725f185eee9da595721f0bcd57cc5f951224d9d47bd8dc9c9b2373920f9d236081a8344 + checksum: 4f03d54372f0591fbc5f6e0267a6f1b73e3012e8a319c1893829e0b8e71f882e17a696995dc8b11e700162daf74444fd2d8f55dba314e1a95221a9d3eabcfb2b languageName: node linkType: hard @@ -4763,7 +5822,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:5.62.0" "@typescript-eslint/visitor-keys": "npm:5.62.0" - checksum: 861253235576c1c5c1772d23cdce1418c2da2618a479a7de4f6114a12a7ca853011a1e530525d0931c355a8fd237b9cd828fac560f85f9623e24054fd024726f + checksum: 6062d6b797fe1ce4d275bb0d17204c827494af59b5eaf09d8a78cdd39dadddb31074dded4297aaf5d0f839016d601032857698b0e4516c86a41207de606e9573 languageName: node linkType: hard @@ -4780,21 +5839,21 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 21fb0653398d2d6d32e4bcb8fe4f4d802d63f0cd50f2e4b982f410b075f5441edffe64924dd1ba71f89eccef3b04eaae8c23543e7618723c7344914378ce3796 + checksum: 06fab95315fc1ffdaaa011e6ec1ae538826ef3d9b422e2c926dbe9b83e55d9e8bdaa07c43317a4c0a59b40a24c5c48a7c8284e6a18780475a65894b1b949fc23 languageName: node linkType: hard "@typescript-eslint/types@npm:5.57.1": version: 5.57.1 resolution: "@typescript-eslint/types@npm:5.57.1" - checksum: 549214a87a52359013270982ef4e69ce17d8a063717a8cb9d127425e76b9113a8db437b67e6802be2ba35c4c025cb37907b003cc29306a8d7d7800c58838aa38 + checksum: 21789eb697904bbb44a18df961d5918e7c5bd90c79df3a8b8b835da81d0c0f42c7eeb2d05f77cafe49a7367ae7f549a0c8281656ea44b6dc56ae1bf19a3a1eae languageName: node linkType: hard "@typescript-eslint/types@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/types@npm:5.62.0" - checksum: 7febd3a7f0701c0b927e094f02e82d8ee2cada2b186fcb938bc2b94ff6fbad88237afc304cbaf33e82797078bbbb1baf91475f6400912f8b64c89be79bfa4ddf + checksum: 48c87117383d1864766486f24de34086155532b070f6264e09d0e6139449270f8a9559cfef3c56d16e3bcfb52d83d42105d61b36743626399c7c2b5e0ac3b670 languageName: node linkType: hard @@ -4812,7 +5871,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 3c5483a9bb8413ba117be12de334b9e533fe75320b5308e7d21a41661dd627b8a403575e5bce84ff9ca7b0678446dd6e98e73b2f05b9f4bb2d02a0a067b421d7 + checksum: bf96520f6de562838a40c3f009fc61fbee5369621071cd0d1dba4470b2b2f746cf79afe4ffa3fbccb8913295a2fbb3d89681d5178529e8da4987c46ed4e5cbed languageName: node linkType: hard @@ -4830,7 +5889,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: d7984a3e9d56897b2481940ec803cb8e7ead03df8d9cfd9797350be82ff765dfcf3cfec04e7355e1779e948da8f02bc5e11719d07a596eb1cb995c48a95e38cf + checksum: 3624520abb5807ed8f57b1197e61c7b1ed770c56dfcaca66372d584ff50175225798bccb701f7ef129d62c5989070e1ee3a0aa2d84e56d9524dcf011a2bb1a52 languageName: node linkType: hard @@ -4848,7 +5907,7 @@ __metadata: semver: "npm:^7.3.7" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: bab8a94e30fc22fa6b3db5c6eee059697ce5e5e03f355c1fc465de184129b4824186a82235e14111c644d2b337721ae9f4d294a52a6f3dd4377edd35b922e3aa + checksum: 12e55144c8087f4e8f0f22e5693f3901b81bb7899dec42c7bfe540ac672a802028b688884bb43bd67bcf3cd3546a7205d207afcd948c731c19f551ea61267205 languageName: node linkType: hard @@ -4866,7 +5925,7 @@ __metadata: semver: "npm:^7.3.7" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: f09b7d9952e4a205eb1ced31d7684dd55cee40bf8c2d78e923aa8a255318d97279825733902742c09d8690f37a50243f4c4d383ab16bd7aefaf9c4b438f785e1 + checksum: ee9398c8c5db6d1da09463ca7bf36ed134361e20131ea354b2da16a5fdb6df9ba70c62a388d19f6eebb421af1786dbbd79ba95ddd6ab287324fc171c3e28d931 languageName: node linkType: hard @@ -4876,7 +5935,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:5.57.1" eslint-visitor-keys: "npm:^3.3.0" - checksum: 9a84589334fe675d18ca3a572aa0caf1b4c7baa80857642aee40378f5c79cf9dddd06a0fec31d7ff6a73f577f68f910fb745d51728fac317b388b8de764561db + checksum: d187dfac044b7c0f24264a9ba5eebcf6651412d840b4aaba8eacabff7e771babcd67c738525b1f7c9eb8c94b7edfe7658f6de99f5fdc9745e409c538c1374674 languageName: node linkType: hard @@ -4886,7 +5945,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:5.62.0" eslint-visitor-keys: "npm:^3.3.0" - checksum: 7c3b8e4148e9b94d9b7162a596a1260d7a3efc4e65199693b8025c71c4652b8042501c0bc9f57654c1e2943c26da98c0f77884a746c6ae81389fcb0b513d995d + checksum: 976b05d103fe8335bef5c93ad3f76d781e3ce50329c0243ee0f00c0fcfb186c81df50e64bfdd34970148113f8ade90887f53e3c4938183afba830b4ba8e30a35 languageName: node linkType: hard @@ -4900,7 +5959,7 @@ __metadata: react-refresh: "npm:^0.14.0" peerDependencies: vite: ^4.2.0 - checksum: 3cf2e044fb4c95dd7b0b3092dcc6c77d6f459ddfae6b1f8ea4ee1d57b33c158072ae9f1067eb1737b6706bad644457f261c70af196f676477fdf3a3ad5653da8 + checksum: 575298f66517c51348892d49b302490c48e15c9ddb0b2c5f710931804e559dceafca1be1e62cb72d0902cba5f3c98e4b1272970d328e3a62d59ecdf976e68d3d languageName: node linkType: hard @@ -4915,7 +5974,7 @@ __metadata: react-refresh: "npm:^0.14.0" peerDependencies: vite: ^4.1.0-beta.0 - checksum: 259a92a303cd736240dc0d3282d1261339e7bbcf51c5b326868c910b35d4bd22a360334b2dafa5bfc7f3e935f2cd0fdc7ccb6ec6b519b81017c4c4812cd05290 + checksum: 450fac79e67cba9e1581c860f78e687b44108ab4117663ef20db279316e03cd8e87f94fef376e27cc5e200bd52813dcc09b70ea570c7c7cc291fcd47eb260fbc languageName: node linkType: hard @@ -4926,21 +5985,41 @@ __metadata: tslib: "npm:^2.4.0" peerDependencies: esbuild: ">=0.10.0" - checksum: 5095bc316862971add31ca1fadb0095b6ad15f25120f6ab3a06086bb6a7be93c2f3c45bff80d5976689fc89b0e9bf82bd3d410e205c852739874d32d050c4e57 + checksum: 04da15355a99773b441742814ba4d0f3453a83df47aa07e215f167e156f109ab8e971489c8b1a4ddf3c79d568d35213f496ad52e97298228597e1aacc22680aa + languageName: node + linkType: hard + +"@yarnpkg/fslib@npm:2.10.3": + version: 2.10.3 + resolution: "@yarnpkg/fslib@npm:2.10.3" + dependencies: + "@yarnpkg/libzip": ^2.3.0 + tslib: ^1.13.0 + checksum: 0ca693f61d47bcf165411a121ed9123f512b1b5bfa5e1c6c8f280b4ffdbea9bf2a6db418f99ecfc9624587fdc695b2b64eb0fe7b4028e44095914b25ca99655e + languageName: node + linkType: hard + +"@yarnpkg/libzip@npm:2.3.0, @yarnpkg/libzip@npm:^2.3.0": + version: 2.3.0 + resolution: "@yarnpkg/libzip@npm:2.3.0" + dependencies: + "@types/emscripten": ^1.39.6 + tslib: ^1.13.0 + checksum: 533a4883f69bb013f955d80dc19719881697e6849ea5f0cbe6d87ef1d582b05cbae8a453802f92ad0c852f976296cac3ff7834be79a7e415b65cdf213e448110 languageName: node linkType: hard "abab@npm:^2.0.6": version: 2.0.6 resolution: "abab@npm:2.0.6" - checksum: 0b245c3c3ea2598fe0025abf7cc7bb507b06949d51e8edae5d12c1b847a0a0c09639abcb94788332b4e2044ac4491c1e8f571b51c7826fd4b0bda1685ad4a278 + checksum: 6ffc1af4ff315066c62600123990d87551ceb0aafa01e6539da77b0f5987ac7019466780bf480f1787576d4385e3690c81ccc37cfda12819bf510b8ab47e5a3e languageName: node linkType: hard "abbrev@npm:^1.0.0": version: 1.1.1 resolution: "abbrev@npm:1.1.1" - checksum: 3f762677702acb24f65e813070e306c61fafe25d4b2583f9dfc935131f774863f3addd5741572ed576bd69cabe473c5af18e1e108b829cb7b6b4747884f726e6 + checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 languageName: node linkType: hard @@ -4950,7 +6029,7 @@ __metadata: dependencies: mime-types: "npm:~2.1.34" negotiator: "npm:0.6.3" - checksum: 3a35c5f5586cfb9a21163ca47a5f77ac34fa8ceb5d17d2fa2c0d81f41cbd7f8c6fa52c77e2c039acc0f4d09e71abdc51144246900f6bef5e3c4b333f77d89362 + checksum: 50c43d32e7b50285ebe84b613ee4a3aa426715a7d131b65b786e2ead0fd76b6b60091b9916d3478a75f11f162628a2139991b6c03ab3f1d9ab7c86075dc8eab4 languageName: node linkType: hard @@ -4960,7 +6039,7 @@ __metadata: dependencies: acorn: "npm:^8.1.0" acorn-walk: "npm:^8.0.2" - checksum: 7437f58e92d99292dbebd0e79531af27d706c9f272f31c675d793da6c82d897e75302a8744af13c7f7978a8399840f14a353b60cf21014647f71012982456d2b + checksum: 2a2998a547af6d0db5f0cdb90acaa7c3cbca6709010e02121fb8b8617c0fbd8bab0b869579903fde358ac78454356a14fadcc1a672ecb97b04b1c2ccba955ce8 languageName: node linkType: hard @@ -4969,21 +6048,21 @@ __metadata: resolution: "acorn-jsx@npm:5.3.2" peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 + checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950 languageName: node linkType: hard "acorn-walk@npm:^7.2.0": version: 7.2.0 resolution: "acorn-walk@npm:7.2.0" - checksum: ff99f3406ed8826f7d6ef6ac76b7608f099d45a1ff53229fa267125da1924188dbacf02e7903dfcfd2ae4af46f7be8847dc7d564c73c4e230dfb69c8ea8e6b4c + checksum: 9252158a79b9d92f1bc0dd6acc0fcfb87a67339e84bcc301bb33d6078936d27e35d606b4d35626d2962cd43c256d6f27717e70cbe15c04fff999ab0b2260b21f languageName: node linkType: hard "acorn-walk@npm:^8.0.2": version: 8.2.0 resolution: "acorn-walk@npm:8.2.0" - checksum: dbe92f5b2452c93e960c5594e666dd1fae141b965ff2cb4a1e1d0381e3e4db4274c5ce4ffa3d681a86ca2a8d4e29d5efc0670a08e23fd2800051ea387df56ca2 + checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 languageName: node linkType: hard @@ -4992,16 +6071,25 @@ __metadata: resolution: "acorn@npm:7.4.1" bin: acorn: bin/acorn - checksum: bd0b2c2b0f334bbee48828ff897c12bd2eb5898d03bf556dcc8942022cec795ac5bb5b6b585e2de687db6231faf07e096b59a361231dd8c9344d5df5f7f0e526 + checksum: 1860f23c2107c910c6177b7b7be71be350db9e1080d814493fae143ae37605189504152d1ba8743ba3178d0b37269ce1ffc42b101547fdc1827078f82671e407 languageName: node linkType: hard -"acorn@npm:^8.1.0, acorn@npm:^8.8.0, acorn@npm:^8.8.1, acorn@npm:^8.9.0": +"acorn@npm:^8.1.0, acorn@npm:^8.8.1, acorn@npm:^8.9.0": version: 8.10.0 resolution: "acorn@npm:8.10.0" bin: acorn: bin/acorn - checksum: deaeebfbea6e40f6c0e1070e9b0e16e76ba484de54cbd735914d1d41d19169a450de8630b7a3a0c4e271a3b0c0b075a3427ad1a40d8a69f8747c0e8cb02ee3e2 + checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d + languageName: node + linkType: hard + +"acorn@npm:^8.11.2": + version: 8.11.3 + resolution: "acorn@npm:8.11.3" + bin: + acorn: bin/acorn + checksum: 76d8e7d559512566b43ab4aadc374f11f563f0a9e21626dd59cb2888444e9445923ae9f3699972767f18af61df89cd89f5eaaf772d1327b055b45cb829b4a88c languageName: node linkType: hard @@ -5009,93 +6097,93 @@ __metadata: version: 0.0.0-use.local resolution: "adcm-web2@workspace:." dependencies: - "@babel/core": "npm:7.21.8" - "@babel/preset-env": "npm:7.21.5" - "@babel/preset-react": "npm:7.18.6" - "@babel/preset-typescript": "npm:7.21.5" - "@braintree/browser-detection": "npm:^2.0.0" - "@floating-ui/dom": "npm:1.2.9" - "@floating-ui/react": "npm:0.24.2" - "@reduxjs/toolkit": "npm:1.9.5" - "@storybook/addon-essentials": "npm:7.0.12" - "@storybook/addon-interactions": "npm:7.0.12" - "@storybook/addon-links": "npm:7.0.12" - "@storybook/blocks": "npm:7.0.12" - "@storybook/builder-vite": "npm:7.0.12" - "@storybook/react": "npm:7.0.12" - "@storybook/react-vite": "npm:7.0.12" - "@storybook/testing-library": "npm:0.0.14-next.2" - "@testing-library/dom": "npm:9.3.0" - "@testing-library/jest-dom": "npm:5.16.5" - "@testing-library/react": "npm:14.0.0" - "@testing-library/user-event": "npm:14.4.3" - "@types/jest": "npm:29.5.2" - "@types/json-schema": "npm:^7.0.12" - "@types/qs": "npm:6.9.7" - "@types/react": "npm:18.0.28" - "@types/react-copy-to-clipboard": "npm:5.0.4" - "@types/react-dom": "npm:18.0.11" - "@types/react-syntax-highlighter": "npm:15.5.7" - "@typescript-eslint/eslint-plugin": "npm:5.57.1" - "@typescript-eslint/parser": "npm:5.57.1" - "@vitejs/plugin-react": "npm:4.0.0" - ajv: "npm:^8.12.0" - axios: "npm:1.4.0" - classnames: "npm:2.3.2" - date-fns: "npm:2.30.0" - eslint: "npm:8.38.0" - eslint-config-prettier: "npm:8.8.0" - eslint-plugin-import: "npm:2.27.5" - eslint-plugin-jsx-a11y: "npm:6.7.1" - eslint-plugin-prettier: "npm:4.2.1" - eslint-plugin-react: "npm:7.32.2" - eslint-plugin-react-hooks: "npm:4.6.0" - eslint-plugin-react-refresh: "npm:0.3.4" - eslint-plugin-spellcheck: "npm:0.0.20" - eslint-plugin-storybook: "npm:0.6.12" - html-react-parser: "npm:4.2.1" - husky: "npm:8.0.3" - identity-obj-proxy: "npm:3.0.0" - jest: "npm:29.5.0" - jest-environment-jsdom: "npm:29.5.0" - js-base64: "npm:3.7.5" - json-schema: "npm:0.4.0" - prettier: "npm:2.8.8" - prop-types: "npm:15.8.1" - qs: "npm:6.11.2" - react: "npm:18.2.0" - react-collapsed: "npm:4.0.2" - react-copy-to-clipboard: "npm:5.1.0" - react-dom: "npm:18.2.0" - react-json-view-compare: "npm:^2.0.2" - react-merge-refs: "npm:2.0.2" - react-redux: "npm:8.1.1" - react-router-dom: "npm:6.11.2" - react-syntax-highlighter: "npm:15.5.0" - redux: "npm:4.2.1" - sass: "npm:1.62.1" - storybook: "npm:7.0.12" - typescript: "npm:5.0.2" - vite: "npm:4.4.1" - vite-plugin-eslint: "npm:1.8.1" - vite-plugin-react-remove-attributes: "npm:1.0.3" - vite-plugin-svg-sprite: "npm:0.3.2" - vite-plugin-svgr: "npm:3.2.0" - vite-tsconfig-paths: "npm:4.2.0" + "@babel/core": 7.21.8 + "@babel/preset-env": 7.21.5 + "@babel/preset-react": 7.18.6 + "@babel/preset-typescript": 7.21.5 + "@braintree/browser-detection": ^2.0.0 + "@floating-ui/dom": 1.2.9 + "@floating-ui/react": 0.24.2 + "@reduxjs/toolkit": 1.9.5 + "@storybook/addon-essentials": 7.6.7 + "@storybook/addon-interactions": 7.6.7 + "@storybook/addon-links": 7.6.7 + "@storybook/blocks": 7.6.7 + "@storybook/builder-vite": 7.6.7 + "@storybook/react": 7.6.7 + "@storybook/react-vite": 7.6.7 + "@storybook/testing-library": 0.2.2 + "@testing-library/dom": 9.3.0 + "@testing-library/jest-dom": 5.16.5 + "@testing-library/react": 14.0.0 + "@testing-library/user-event": 14.4.3 + "@types/jest": 29.5.2 + "@types/json-schema": ^7.0.12 + "@types/qs": 6.9.7 + "@types/react": 18.0.28 + "@types/react-copy-to-clipboard": 5.0.4 + "@types/react-dom": 18.0.11 + "@types/react-syntax-highlighter": 15.5.7 + "@typescript-eslint/eslint-plugin": 5.57.1 + "@typescript-eslint/parser": 5.57.1 + "@vitejs/plugin-react": 4.0.0 + ajv: ^8.12.0 + axios: 1.4.0 + classnames: 2.3.2 + date-fns: 2.30.0 + eslint: 8.38.0 + eslint-config-prettier: 8.8.0 + eslint-plugin-import: 2.27.5 + eslint-plugin-jsx-a11y: 6.7.1 + eslint-plugin-prettier: 4.2.1 + eslint-plugin-react: 7.32.2 + eslint-plugin-react-hooks: 4.6.0 + eslint-plugin-react-refresh: 0.3.4 + eslint-plugin-spellcheck: 0.0.20 + eslint-plugin-storybook: 0.6.12 + html-react-parser: 4.2.1 + husky: 8.0.3 + identity-obj-proxy: 3.0.0 + jest: 29.5.0 + jest-environment-jsdom: 29.5.0 + js-base64: 3.7.5 + json-schema: 0.4.0 + prettier: 2.8.8 + prop-types: 15.8.1 + qs: 6.11.2 + react: 18.2.0 + react-collapsed: 4.0.2 + react-copy-to-clipboard: 5.1.0 + react-dom: 18.2.0 + react-json-view-compare: ^2.0.2 + react-merge-refs: 2.0.2 + react-redux: 8.1.1 + react-router-dom: 6.11.2 + react-syntax-highlighter: 15.5.0 + redux: 4.2.1 + sass: 1.62.1 + storybook: 7.6.7 + typescript: 5.0.2 + vite: 4.4.1 + vite-plugin-eslint: 1.8.1 + vite-plugin-react-remove-attributes: 1.0.3 + vite-plugin-svg-sprite: 0.3.2 + vite-plugin-svgr: 3.2.0 + vite-tsconfig-paths: 4.2.0 languageName: unknown linkType: soft "address@npm:^1.0.1": version: 1.2.2 resolution: "address@npm:1.2.2" - checksum: 1c8056b77fb124456997b78ed682ecc19d2fd7ea8bd5850a2aa8c3e3134c913847c57bcae418622efd32ba858fa1e242a40a251ac31da0515664fc0ac03a047d + checksum: ace439960c1e3564d8f523aff23a841904bf33a2a7c2e064f7f60a064194075758b9690e65bd9785692a4ef698a998c57eb74d145881a1cecab8ba658ddb1607 languageName: node linkType: hard "agent-base@npm:5": version: 5.1.1 resolution: "agent-base@npm:5.1.1" - checksum: 3baa3f01072c16e3955ce7802166e576cde9831af82b262aae1c780af49c0c84e82e64ba9ef9e7d1704fe29e9f0096a78a4f998ec137360fee3cb95186f97161 + checksum: 61ae789f3019f1dc10e8cba6d3ae9826949299a4e54aaa1cfa2fa37c95a108e70e95423b963bb987d7891a703fd9a5c383a506f4901819f3ee56f3147c0aa8ab languageName: node linkType: hard @@ -5104,7 +6192,7 @@ __metadata: resolution: "agent-base@npm:6.0.2" dependencies: debug: "npm:4" - checksum: dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261 + checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d languageName: node linkType: hard @@ -5115,7 +6203,7 @@ __metadata: debug: "npm:^4.1.0" depd: "npm:^2.0.0" humanize-ms: "npm:^1.2.1" - checksum: 61cbdab12d45e82e9ae515b0aa8d09617b66f72409e541a646dd7be4b7260d335d7f56a38079ad305bf0ffb8405592a459faf1294111289107f48352a20c2799 + checksum: 982453aa44c11a06826c836025e5162c846e1200adb56f2d075400da7d32d87021b3b0a58768d949d824811f5654223d5a8a3dad120921a2439625eb847c6260 languageName: node linkType: hard @@ -5125,7 +6213,7 @@ __metadata: dependencies: clean-stack: "npm:^2.0.0" indent-string: "npm:^4.0.0" - checksum: a42f67faa79e3e6687a4923050e7c9807db3848a037076f791d10e092677d65c1d2d863b7848560699f40fc0502c19f40963fb1cd1fb3d338a7423df8e45e039 + checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 languageName: node linkType: hard @@ -5137,7 +6225,7 @@ __metadata: fast-json-stable-stringify: "npm:^2.0.0" json-schema-traverse: "npm:^0.4.1" uri-js: "npm:^4.2.2" - checksum: 41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 + checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4 languageName: node linkType: hard @@ -5149,16 +6237,7 @@ __metadata: json-schema-traverse: "npm:^1.0.0" require-from-string: "npm:^2.0.2" uri-js: "npm:^4.2.2" - checksum: ac4f72adf727ee425e049bc9d8b31d4a57e1c90da8d28bcd23d60781b12fcd6fc3d68db5df16994c57b78b94eed7988f5a6b482fd376dc5b084125e20a0a622e - languageName: node - linkType: hard - -"ansi-align@npm:^3.0.0": - version: 3.0.1 - resolution: "ansi-align@npm:3.0.1" - dependencies: - string-width: "npm:^4.1.0" - checksum: ad8b755a253a1bc8234eb341e0cec68a857ab18bf97ba2bda529e86f6e30460416523e0ec58c32e5c21f0ca470d779503244892873a5895dbd0c39c788e82467 + checksum: 4dc13714e316e67537c8b31bc063f99a1d9d9a497eb4bbd55191ac0dcd5e4985bbb71570352ad6f1e76684fb6d790928f96ba3b2d4fd6e10024be9612fe3f001 languageName: node linkType: hard @@ -5167,35 +6246,35 @@ __metadata: resolution: "ansi-escapes@npm:4.3.2" dependencies: type-fest: "npm:^0.21.3" - checksum: da917be01871525a3dfcf925ae2977bc59e8c513d4423368645634bf5d4ceba5401574eb705c1e92b79f7292af5a656f78c5725a4b0e1cec97c4b413705c1d50 + checksum: 93111c42189c0a6bed9cdb4d7f2829548e943827ee8479c74d6e0b22ee127b2a21d3f8b5ca57723b8ef78ce011fbfc2784350eb2bde3ccfccf2f575fa8489815 languageName: node linkType: hard "ansi-regex@npm:^2.0.0": version: 2.1.1 resolution: "ansi-regex@npm:2.1.1" - checksum: 78cebaf50bce2cb96341a7230adf28d804611da3ce6bf338efa7b72f06cc6ff648e29f80cd95e582617ba58d5fdbec38abfeed3500a98bce8381a9daec7c548b + checksum: 190abd03e4ff86794f338a31795d262c1dfe8c91f7e01d04f13f646f1dcb16c5800818f886047876f1272f065570ab86b24b99089f8b68a0e11ff19aed4ca8f1 languageName: node linkType: hard "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" - checksum: 9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737 + checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b languageName: node linkType: hard "ansi-regex@npm:^6.0.1": version: 6.0.1 resolution: "ansi-regex@npm:6.0.1" - checksum: cbe16dbd2c6b2735d1df7976a7070dd277326434f0212f43abf6d87674095d247968209babdaad31bb00882fa68807256ba9be340eec2f1004de14ca75f52a08 + checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 languageName: node linkType: hard "ansi-styles@npm:^2.2.1": version: 2.2.1 resolution: "ansi-styles@npm:2.2.1" - checksum: 7c68aed4f1857389e7a12f85537ea5b40d832656babbf511cc7ecd9efc52889b9c3e5653a71a6aade783c3c5e0aa223ad4ff8e83c27ac8a666514e6c79068cab + checksum: ebc0e00381f2a29000d1dac8466a640ce11943cef3bda3cd0020dc042e31e1058ab59bf6169cd794a54c3a7338a61ebc404b7c91e004092dd20e028c432c9c2c languageName: node linkType: hard @@ -5204,7 +6283,7 @@ __metadata: resolution: "ansi-styles@npm:3.2.1" dependencies: color-convert: "npm:^1.9.0" - checksum: ece5a8ef069fcc5298f67e3f4771a663129abd174ea2dfa87923a2be2abf6cd367ef72ac87942da00ce85bd1d651d4cd8595aebdb1b385889b89b205860e977b + checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 languageName: node linkType: hard @@ -5213,21 +6292,21 @@ __metadata: resolution: "ansi-styles@npm:4.3.0" dependencies: color-convert: "npm:^2.0.1" - checksum: 895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 + checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 languageName: node linkType: hard "ansi-styles@npm:^5.0.0": version: 5.2.0 resolution: "ansi-styles@npm:5.2.0" - checksum: 9c4ca80eb3c2fb7b33841c210d2f20807f40865d27008d7c3f707b7f95cab7d67462a565e2388ac3285b71cb3d9bb2173de8da37c57692a362885ec34d6e27df + checksum: d7f4e97ce0623aea6bc0d90dcd28881ee04cba06c570b97fd3391bd7a268eedfd9d5e2dd4fdcbdd82b8105df5faf6f24aaedc08eaf3da898e702db5948f63469 languageName: node linkType: hard "ansi-styles@npm:^6.1.0": version: 6.2.1 resolution: "ansi-styles@npm:6.2.1" - checksum: 5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c + checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 languageName: node linkType: hard @@ -5237,31 +6316,21 @@ __metadata: dependencies: normalize-path: "npm:^3.0.0" picomatch: "npm:^2.0.4" - checksum: 57b06ae984bc32a0d22592c87384cd88fe4511b1dd7581497831c56d41939c8a001b28e7b853e1450f2bf61992dfcaa8ae2d0d161a0a90c4fb631ef07098fbac + checksum: 3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 languageName: node linkType: hard "app-root-dir@npm:^1.0.2": version: 1.0.2 resolution: "app-root-dir@npm:1.0.2" - checksum: 0225e4be7788968a82bb76df9b14b0d7f212a5c12e8c625cdc34f80548780bcbfc5f3287d0806dddd83bf9dbf9ce302e76b2887cd3a6f4be52b79df7f3aa9e7c + checksum: d4b1653fc60b6465b982bf5a88b12051ed2d807d70609386a809306e1c636496f53522d61fa30f9f98c71aaae34f34e1651889cf17d81a44e3dafd2859d495ad languageName: node linkType: hard "aproba@npm:^1.0.3 || ^2.0.0": version: 2.0.0 resolution: "aproba@npm:2.0.0" - checksum: d06e26384a8f6245d8c8896e138c0388824e259a329e0c9f196b4fa533c82502a6fd449586e3604950a0c42921832a458bb3aa0aa9f0ba449cfd4f50fd0d09b5 - languageName: node - linkType: hard - -"are-we-there-yet@npm:^2.0.0": - version: 2.0.0 - resolution: "are-we-there-yet@npm:2.0.0" - dependencies: - delegates: "npm:^1.0.0" - readable-stream: "npm:^3.6.0" - checksum: 375f753c10329153c8d66dc95e8f8b6c7cc2aa66e05cb0960bd69092b10dae22900cacc7d653ad11d26b3ecbdbfe1e8bfb6ccf0265ba8077a7d979970f16b99c + checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 languageName: node linkType: hard @@ -5271,7 +6340,7 @@ __metadata: dependencies: delegates: "npm:^1.0.0" readable-stream: "npm:^3.6.0" - checksum: 8373f289ba42e4b5ec713bb585acdac14b5702c75f2a458dc985b9e4fa5762bc5b46b40a21b72418a3ed0cfb5e35bdc317ef1ae132f3035f633d581dd03168c3 + checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 languageName: node linkType: hard @@ -5280,23 +6349,23 @@ __metadata: resolution: "argparse@npm:1.0.10" dependencies: sprintf-js: "npm:~1.0.2" - checksum: b2972c5c23c63df66bca144dbc65d180efa74f25f8fd9b7d9a0a6c88ae839db32df3d54770dcb6460cf840d232b60695d1a6b1053f599d84e73f7437087712de + checksum: 7ca6e45583a28de7258e39e13d81e925cfa25d7d4aacbf806a382d3c02fcb13403a07fb8aeef949f10a7cfe4a62da0e2e807b348a5980554cc28ee573ef95945 languageName: node linkType: hard "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" - checksum: c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e + checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced languageName: node linkType: hard -"aria-hidden@npm:^1.1.3": +"aria-hidden@npm:^1.1.1, aria-hidden@npm:^1.1.3": version: 1.2.3 resolution: "aria-hidden@npm:1.2.3" dependencies: tslib: "npm:^2.0.0" - checksum: 46b07b7273167ad3fc2625f1ecbb43f8e6f73115c66785cbb5dcf1e2508133a43b6419d610c39676ceaeb563239efbd8974d5c0187695db8b3e8c3e11f549c2d + checksum: 7d7d211629eef315e94ed3b064c6823d13617e609d3f9afab1c2ed86399bb8e90405f9bdd358a85506802766f3ecb468af985c67c846045a34b973bcc0289db9 languageName: node linkType: hard @@ -5305,7 +6374,7 @@ __metadata: resolution: "aria-query@npm:5.1.3" dependencies: deep-equal: "npm:^2.0.5" - checksum: edcbc8044c4663d6f88f785e983e6784f98cb62b4ba1e9dd8d61b725d0203e4cfca38d676aee984c31f354103461102a3d583aa4fbe4fd0a89b679744f4e5faf + checksum: 929ff95f02857b650fb4cbcd2f41072eee2f46159a6605ea03bf63aa572e35ffdff43d69e815ddc462e16e07de8faba3978afc2813650b4448ee18c9895d982b languageName: node linkType: hard @@ -5314,28 +6383,28 @@ __metadata: resolution: "aria-query@npm:5.3.0" dependencies: dequal: "npm:^2.0.3" - checksum: 2bff0d4eba5852a9dd578ecf47eaef0e82cc52569b48469b0aac2db5145db0b17b7a58d9e01237706d1e14b7a1b0ac9b78e9c97027ad97679dd8f91b85da1469 + checksum: 305bd73c76756117b59aba121d08f413c7ff5e80fa1b98e217a3443fcddb9a232ee790e24e432b59ae7625aebcf4c47cb01c2cac872994f0b426f5bdfcd96ba9 languageName: node linkType: hard "arr-diff@npm:^4.0.0": version: 4.0.0 resolution: "arr-diff@npm:4.0.0" - checksum: 67b80067137f70c89953b95f5c6279ad379c3ee39f7143578e13bd51580a40066ee2a55da066e22d498dce10f68c2d70056d7823f972fab99dfbf4c78d0bc0f7 + checksum: ea7c8834842ad3869297f7915689bef3494fd5b102ac678c13ffccab672d3d1f35802b79e90c4cfec2f424af3392e44112d1ccf65da34562ed75e049597276a0 languageName: node linkType: hard "arr-flatten@npm:^1.1.0": version: 1.1.0 resolution: "arr-flatten@npm:1.1.0" - checksum: bef53be02ed3bc58f202b3861a5b1eb6e1ae4fecf39c3ad4d15b1e0433f941077d16e019a33312d820844b0661777322acbb7d0c447b04d9bdf7d6f9c532548a + checksum: 963fe12564fca2f72c055f3f6c206b9e031f7c433a0c66ca9858b484821f248c5b1e5d53c8e4989d80d764cd776cf6d9b160ad05f47bdc63022bfd63b5455e22 languageName: node linkType: hard "arr-union@npm:^3.1.0": version: 3.1.0 resolution: "arr-union@npm:3.1.0" - checksum: 7d5aa05894e54aa93c77c5726c1dd5d8e8d3afe4f77983c0aa8a14a8a5cbe8b18f0cf4ecaa4ac8c908ef5f744d2cbbdaa83fd6e96724d15fea56cfa7f5efdd51 + checksum: b5b0408c6eb7591143c394f3be082fee690ddd21f0fdde0a0a01106799e847f67fcae1b7e56b0a0c173290e29c6aca9562e82b300708a268bc8f88f3d6613cb9 languageName: node linkType: hard @@ -5345,14 +6414,14 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" is-array-buffer: "npm:^3.0.1" - checksum: 12f84f6418b57a954caa41654e5e63e019142a4bbb2c6829ba86d1ba65d31ccfaf1461d1743556fd32b091fac34ff44d9dfbdb001402361c45c373b2c86f5c20 + checksum: 044e101ce150f4804ad19c51d6c4d4cfa505c5b2577bd179256e4aa3f3f6a0a5e9874c78cd428ee566ac574c8a04d7ce21af9fe52e844abfdccb82b33035a7c3 languageName: node linkType: hard "array-flatten@npm:1.1.1": version: 1.1.1 resolution: "array-flatten@npm:1.1.1" - checksum: 806966c8abb2f858b08f5324d9d18d7737480610f3bd5d3498aaae6eb5efdc501a884ba019c9b4a8f02ff67002058749d05548fd42fa8643f02c9c7f22198b91 + checksum: a9925bf3512d9dce202112965de90c222cd59a4fbfce68a0951d25d965cf44642931f40aac72309c41f12df19afa010ecadceb07cfff9ccc1621e99d89ab5f3b languageName: node linkType: hard @@ -5365,21 +6434,21 @@ __metadata: es-abstract: "npm:^1.20.4" get-intrinsic: "npm:^1.1.3" is-string: "npm:^1.0.7" - checksum: d0caeaa57bea7d14b8480daee30cf8611899321006b15a6cd872b831bd7aaed7649f8764e060d01c5d33b8d9e998e5de5c87f4901874e1c1f467f429b7db2929 + checksum: f22f8cd8ba8a6448d91eebdc69f04e4e55085d09232b5216ee2d476dab3ef59984e8d1889e662c6a0ed939dcb1b57fd05b2c0209c3370942fc41b752c82a2ca5 languageName: node linkType: hard "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" - checksum: 429897e68110374f39b771ec47a7161fc6a8fc33e196857c0a396dc75df0b5f65e4d046674db764330b6bb66b39ef48dd7c53b6a2ee75cfb0681e0c1a7033962 + checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d languageName: node linkType: hard "array-unique@npm:^0.3.2": version: 0.3.2 resolution: "array-unique@npm:0.3.2" - checksum: dbf4462cdba8a4b85577be07705210b3d35be4b765822a3f52962d907186617638ce15e0603a4fefdcf82f4cbbc9d433f8cbbd6855148a68872fa041b6474121 + checksum: da344b89cfa6b0a5c221f965c21638bfb76b57b45184a01135382186924f55973cd9b171d4dad6bf606c6d9d36b0d721d091afdc9791535ead97ccbe78f8a888 languageName: node linkType: hard @@ -5391,7 +6460,7 @@ __metadata: define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" es-shim-unscopables: "npm:^1.0.0" - checksum: 8eda91d6925cc84b73ebf5a3d406ff28745d93a22ef6a0afb967755107081a937cf6c4555d3c18354870b2c5366c0ff51b3f597c11079e689869810a418b1b4f + checksum: 5a8415949df79bf6e01afd7e8839bbde5a3581300e8ad5d8449dea52639e9e59b26a467665622783697917b43bf39940a6e621877c7dd9b3d1c1f97484b9b88b languageName: node linkType: hard @@ -5403,7 +6472,7 @@ __metadata: define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" es-shim-unscopables: "npm:^1.0.0" - checksum: 2bd58a0e79d5d90cb4f5ef0e287edf8b28e87c65428f54025ac6b7b4c204224b92811c266f296c53a2dbc93872117c0fcea2e51d3c9e8cecfd5024d4a4a57db4 + checksum: 8c1c43a4995f12cf12523436da28515184c753807b3f0bc2ca6c075f71c470b099e2090cc67dba8e5280958fea401c1d0c59e1db0143272aef6cd1103921a987 languageName: node linkType: hard @@ -5416,7 +6485,7 @@ __metadata: es-abstract: "npm:^1.20.4" es-shim-unscopables: "npm:^1.0.0" get-intrinsic: "npm:^1.1.3" - checksum: fd5f57aca3c7ddcd1bb83965457b625f3a67d8f334f5cbdb8ac8ef33d5b0d38281524114db2936f8c08048115d5158af216c94e6ae1eb966241b9b6f4ab8a7e8 + checksum: 7923324a67e70a2fc0a6e40237405d92395e45ebd76f5cb89c2a5cf1e66b47aca6baacd0cd628ffd88830b90d47fff268071493d09c9ae123645613dac2c2ca3 languageName: node linkType: hard @@ -5428,39 +6497,34 @@ __metadata: is-nan: "npm:^1.2.1" object-is: "npm:^1.0.1" util: "npm:^0.12.0" - checksum: a25c7ebc07b52cc4dadd5c46d73472e7d4b86e40eb7ebaa12f78c1ba954dbe83612be5dea314b862fc364c305ab3bdbcd1c9d4ec2d92bc37214ae7d5596347f3 + checksum: bb91f181a86d10588ee16c5e09c280f9811373974c29974cbe401987ea34e966699d7989a812b0e19377b511ea0bc627f5905647ce569311824848ede382cae8 + languageName: node + linkType: hard + +"assert@npm:^2.1.0": + version: 2.1.0 + resolution: "assert@npm:2.1.0" + dependencies: + call-bind: ^1.0.2 + is-nan: ^1.3.2 + object-is: ^1.1.5 + object.assign: ^4.1.4 + util: ^0.12.5 + checksum: 1ed1cabba9abe55f4109b3f7292b4e4f3cf2953aad8dc148c0b3c3bd676675c31b1abb32ef563b7d5a19d1715bf90d1e5f09fad2a4ee655199468902da80f7c2 languageName: node linkType: hard "assign-symbols@npm:^1.0.0": version: 1.0.0 resolution: "assign-symbols@npm:1.0.0" - checksum: 29a654b8a6da6889a190d0d0efef4b1bfb5948fa06cbc245054aef05139f889f2f7c75b989917e3fde853fc4093b88048e4de8578a73a76f113d41bfd66e5775 + checksum: c0eb895911d05b6b2d245154f70461c5e42c107457972e5ebba38d48967870dee53bcdf6c7047990586daa80fab8dab3cc6300800fbd47b454247fdedd859a2c languageName: node linkType: hard "ast-types-flow@npm:^0.0.7": version: 0.0.7 resolution: "ast-types-flow@npm:0.0.7" - checksum: f381529f2da535949ba6cceddbdfaa33b4d5105842e147ec63582f560ea9ecc1a08f66457664f3109841d3053641fa8b9fa94ba607f1ea9f6c804fe5dee44a1d - languageName: node - linkType: hard - -"ast-types@npm:0.15.2": - version: 0.15.2 - resolution: "ast-types@npm:0.15.2" - dependencies: - tslib: "npm:^2.0.1" - checksum: 5b26e3656e9e8d1db8c8d14971d0cb88ca0138aacce72171cb4cd4555fc8dc53c07e821c568e57fe147366931708fefd25cb9d7e880d42ce9cb569947844c962 - languageName: node - linkType: hard - -"ast-types@npm:^0.14.2": - version: 0.14.2 - resolution: "ast-types@npm:0.14.2" - dependencies: - tslib: "npm:^2.0.1" - checksum: 5d66d89b6c07fe092087454b6042dbaf81f2882b176db93861e2b986aafe0bce49e1f1ff59aac775d451c1426ad1e967d250e9e3548f5166ea8a3475e66c169d + checksum: a26dcc2182ffee111cad7c471759b0bda22d3b7ebacf27c348b22c55f16896b18ab0a4d03b85b4020dce7f3e634b8f00b593888f622915096ea1927fa51866c4 languageName: node linkType: hard @@ -5469,28 +6533,28 @@ __metadata: resolution: "ast-types@npm:0.16.1" dependencies: tslib: "npm:^2.0.1" - checksum: abcc49e42eb921a7ebc013d5bec1154651fb6dbc3f497541d488859e681256901b2990b954d530ba0da4d0851271d484f7057d5eff5e07cb73e8b10909f711bf + checksum: 21c186da9fdb1d8087b1b7dabbc4059f91aa5a1e593a9776b4393cc1eaa857e741b2dda678d20e34b16727b78fef3ab59cf8f0c75ed1ba649c78fe194e5c114b languageName: node linkType: hard "async-limiter@npm:~1.0.0": version: 1.0.1 resolution: "async-limiter@npm:1.0.1" - checksum: 0693d378cfe86842a70d4c849595a0bb50dc44c11649640ca982fa90cbfc74e3cc4753b5a0847e51933f2e9c65ce8e05576e75e5e1fd963a086e673735b35969 + checksum: 2b849695b465d93ad44c116220dee29a5aeb63adac16c1088983c339b0de57d76e82533e8e364a93a9f997f28bbfc6a92948cefc120652bd07f3b59f8d75cf2b languageName: node linkType: hard "async@npm:^3.2.3": version: 3.2.4 resolution: "async@npm:3.2.4" - checksum: b5d02fed64717edf49e35b2b156debd9cf524934ea670108fa5528e7615ed66a5e0bf6c65f832c9483b63aa7f0bffe3e588ebe8d58a539b833798d324516e1c9 + checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 languageName: node linkType: hard "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" - checksum: d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d + checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be languageName: node linkType: hard @@ -5499,21 +6563,21 @@ __metadata: resolution: "atob@npm:2.1.2" bin: atob: bin/atob.js - checksum: ada635b519dc0c576bb0b3ca63a73b50eefacf390abb3f062558342a8d68f2db91d0c8db54ce81b0d89de3b0f000de71f3ae7d761fd7d8cc624278fe443d6c7e + checksum: dfeeeb70090c5ebea7be4b9f787f866686c645d9f39a0d184c817252d0cf08455ed25267d79c03254d3be1f03ac399992a792edcd5ffb9c91e097ab5ef42833a languageName: node linkType: hard "available-typed-arrays@npm:^1.0.5": version: 1.0.5 resolution: "available-typed-arrays@npm:1.0.5" - checksum: c4df567ca72d2754a6cbad20088f5f98b1065b3360178169fa9b44ea101af62c0f423fc3854fa820fd6895b6b9171b8386e71558203103ff8fc2ad503fdcc660 + checksum: 20eb47b3cefd7db027b9bbb993c658abd36d4edd3fe1060e83699a03ee275b0c9b216cc076ff3f2db29073225fb70e7613987af14269ac1fe2a19803ccc97f1a languageName: node linkType: hard "axe-core@npm:^4.6.2": version: 4.7.2 resolution: "axe-core@npm:4.7.2" - checksum: 8dfc61f038fbd9623ae8a264c8a475d887113a027fb440a2b377b82ffd300e71d1a0bcf042ff13b517a8d548b34c44b4159eff693725c5d7cde240d0aa68feac + checksum: 5d86fa0f45213b0e54cbb5d713ce885c4a8fe3a72b92dd915a47aa396d6fd149c4a87fec53aa978511f6d941402256cfeb26f2db35129e370f25a453c688655a languageName: node linkType: hard @@ -5524,7 +6588,7 @@ __metadata: follow-redirects: "npm:^1.15.0" form-data: "npm:^4.0.0" proxy-from-env: "npm:^1.1.0" - checksum: a925a07590b0ec1d4daf28cd27890f930daab980371558deb3b883af174b881da09e5ba2cb8393a648fda5859e39934982d0b8b092fe89fc84cb6c80a70a1910 + checksum: 7fb6a4313bae7f45e89d62c70a800913c303df653f19eafec88e56cea2e3821066b8409bc68be1930ecca80e861c52aa787659df0ffec6ad4d451c7816b9386b languageName: node linkType: hard @@ -5533,7 +6597,7 @@ __metadata: resolution: "axobject-query@npm:3.2.1" dependencies: dequal: "npm:^2.0.3" - checksum: f7debc2012e456139b57d888c223f6d3cb4b61eb104164a85e3d346273dd6ef0bc9a04b6660ca9407704a14a8e05fa6b6eb9d55f44f348c7210de7ffb350c3a7 + checksum: a94047e702b57c91680e6a952ec4a1aaa2cfd0d80ead76bc8c954202980d8c51968a6ea18b4d8010e8e2cf95676533d8022a8ebba9abc1dfe25686721df26fd2 languageName: node linkType: hard @@ -5542,7 +6606,7 @@ __metadata: resolution: "babel-core@npm:7.0.0-bridge.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f57576e30267be4607d163b7288031d332cf9200ea35efe9fb33c97f834e304376774c28c1f9d6928d6733fcde7041e4010f1248a0519e7730c590d4b07b9608 + checksum: 2a1cb879019dffb08d17bec36e13c3a6d74c94773f41c1fd8b14de13f149cc34b705b0a1e07b42fcf35917b49d78db6ff0c5c3b00b202a5235013d517b5c6bbb languageName: node linkType: hard @@ -5559,7 +6623,7 @@ __metadata: slash: "npm:^3.0.0" peerDependencies: "@babel/core": ^7.8.0 - checksum: a32ac32f3b5bd66f3f8370cfd6244b0f7b18c2dd367d5829e86dea9f8516ffda63edfb2743d3e1768db93a0698b4db09cd9d22961447e0ed6fd309b5b9c22764 + checksum: bc46cfba468edde91f34a8292501d4448a39fab72d80d7d95f4349feb114fa21becb01def007d6166de7933ab9633bf5b5e1b72ba6ffeaa991f7abf014a2f61d languageName: node linkType: hard @@ -5572,7 +6636,7 @@ __metadata: "@istanbuljs/schema": "npm:^0.1.2" istanbul-lib-instrument: "npm:^5.0.4" test-exclude: "npm:^6.0.0" - checksum: 1075657feb705e00fd9463b329921856d3775d9867c5054b449317d39153f8fbcebd3e02ebf00432824e647faff3683a9ca0a941325ef1afe9b3c4dd51b24beb + checksum: cb4fd95738219f232f0aece1116628cccff16db891713c4ccb501cddbbf9272951a5df81f2f2658dfdf4b3e7b236a9d5cbcf04d5d8c07dd5077297339598061a languageName: node linkType: hard @@ -5584,7 +6648,7 @@ __metadata: "@babel/types": "npm:^7.3.3" "@types/babel__core": "npm:^7.1.14" "@types/babel__traverse": "npm:^7.0.6" - checksum: 385547c4d81647848dc3e86fecf4381032be99ed97d87aee78d422631f651042600371ee31e37ec9bb6f4a0a4f296b3b5798d69c410626ea94eae76d9c64da63 + checksum: 099b5254073b6bc985b6d2d045ad26fb8ed30ff8ae6404c4fe8ee7cd0e98a820f69e3dfb871c7c65aae0f4b65af77046244c07bb92d49ef9005c90eedf681539 languageName: node linkType: hard @@ -5597,20 +6661,20 @@ __metadata: semver: "npm:^6.1.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 21e34d4ba961de66d3fe31f3fecca5612d5db99638949766a445d37de72c1f736552fe436f3bd3792e5cc307f48e8f78a498a01e858c84946627ddb662415cc4 + checksum: 7db3044993f3dddb3cc3d407bc82e640964a3bfe22de05d90e1f8f7a5cb71460011ab136d3c03c6c1ba428359ebf635688cd6205e28d0469bba221985f5c6179 languageName: node linkType: hard -"babel-plugin-polyfill-corejs2@npm:^0.4.4": - version: 0.4.4 - resolution: "babel-plugin-polyfill-corejs2@npm:0.4.4" +"babel-plugin-polyfill-corejs2@npm:^0.4.7": + version: 0.4.7 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.7" dependencies: - "@babel/compat-data": "npm:^7.22.6" - "@babel/helper-define-polyfill-provider": "npm:^0.4.1" - "@nicolo-ribaudo/semver-v6": "npm:^6.3.3" + "@babel/compat-data": ^7.22.6 + "@babel/helper-define-polyfill-provider": ^0.4.4 + semver: ^6.3.1 peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 4bb3056ae17002776e3003314068bdd7dd8e5d4b038ce1198db84346b953e73beb8d2b4445bff831c09ff217e533466eb28e771a80c3696decc2dae1347164e3 + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: b3c84ce44d00211c919a94f76453fb2065861612f3e44862eb7acf854e325c738a7441ad82690deba2b6fddfa2ad2cf2c46960f46fab2e3b17c6ed4fd2d73b38 languageName: node linkType: hard @@ -5622,19 +6686,19 @@ __metadata: core-js-compat: "npm:^3.25.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 58f7d16c1fbc5e4a68cc58126039cb997edc9b9d29adf1bc4124eb6a12ec31eb9e1da8df769b7219714748af7916cfbb194b2f15bd55571b3b43cdcd7839fe8f + checksum: 470bb8c59f7c0912bd77fe1b5a2e72f349b3f65bbdee1d60d6eb7e1f4a085c6f24b2dd5ab4ac6c2df6444a96b070ef6790eccc9edb6a2668c60d33133bfb62c6 languageName: node linkType: hard -"babel-plugin-polyfill-corejs3@npm:^0.8.2": - version: 0.8.2 - resolution: "babel-plugin-polyfill-corejs3@npm:0.8.2" +"babel-plugin-polyfill-corejs3@npm:^0.8.7": + version: 0.8.7 + resolution: "babel-plugin-polyfill-corejs3@npm:0.8.7" dependencies: - "@babel/helper-define-polyfill-provider": "npm:^0.4.1" - core-js-compat: "npm:^3.31.0" + "@babel/helper-define-polyfill-provider": ^0.4.4 + core-js-compat: ^3.33.1 peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: de094cc9d703a3bf6518f4312491b6f033f2db45791825499c905173b2d7d0f8ab9b1919a607eb76833907c6533a2106c951108da7689c0929354d38c661f346 + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 51bc215ab0c062bbb2225d912f69f8a6705d1837c8e01f9651307b5b937804287c1d73ebd8015689efcc02c3c21f37688b9ee6f5997635619b7a9cc4b7d9908d languageName: node linkType: hard @@ -5645,18 +6709,18 @@ __metadata: "@babel/helper-define-polyfill-provider": "npm:^0.3.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: bd915d51e30259201b289a58dfa46c8c1bc8827a38c275ff3134c8194d27e634d5c32ec62137d489d81c7dd5f6ea46b04057eb44b7180d06c19388e3a5f4f8c6 + checksum: ab0355efbad17d29492503230387679dfb780b63b25408990d2e4cf421012dae61d6199ddc309f4d2409ce4e9d3002d187702700dd8f4f8770ebbba651ed066c languageName: node linkType: hard -"babel-plugin-polyfill-regenerator@npm:^0.5.1": - version: 0.5.1 - resolution: "babel-plugin-polyfill-regenerator@npm:0.5.1" +"babel-plugin-polyfill-regenerator@npm:^0.5.4": + version: 0.5.4 + resolution: "babel-plugin-polyfill-regenerator@npm:0.5.4" dependencies: - "@babel/helper-define-polyfill-provider": "npm:^0.4.1" + "@babel/helper-define-polyfill-provider": ^0.4.4 peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 5ec9e2ab2f031028a36f8d611f3fc3bc8347e2842e4354a28ac303e81697968549ea0ebea79cf0c28658e1e09d3a55a2a2085bb5a53d00f28bd688daa301fd6b + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 461b735c6c0eca3c7b4434d14bfa98c2ab80f00e2bdc1c69eb46d1d300092a9786d76bbd3ee55e26d2d1a2380c14592d8d638e271dfd2a2b78a9eacffa3645d1 languageName: node linkType: hard @@ -5678,7 +6742,7 @@ __metadata: "@babel/plugin-syntax-top-level-await": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0 - checksum: 5ba39a3a0e6c37d25e56a4fb843be632dac98d54706d8a0933f9bcb1a07987a96d55c2b5a6c11788a74063fb2534fe68c1f1dbb6c93626850c785e0938495627 + checksum: d118c2742498c5492c095bc8541f4076b253e705b5f1ad9a2e7d302d81a84866f0070346662355c8e25fc02caa28dc2da8d69bcd67794a0d60c4d6fab6913cc8 languageName: node linkType: hard @@ -5690,21 +6754,21 @@ __metadata: babel-preset-current-node-syntax: "npm:^1.0.0" peerDependencies: "@babel/core": ^7.0.0 - checksum: 752b8682c8cf55bca46d870003f4ce43a4ba0fcaa1138ff7f0e02340628e221810b0c2c3e77a7d5070168dc163eb11907f6c9256f187242abe0f14219d1f6b12 + checksum: 5566ca2762766c9319b4973d018d2fa08c0fcf6415c72cc54f4c8e7199e851ea8f5e6c6730f03ed7ed44fc8beefa959dd15911f2647dee47c615ff4faeddb1ad languageName: node linkType: hard "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" - checksum: 9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee + checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 languageName: node linkType: hard "base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" - checksum: f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf + checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 languageName: node linkType: hard @@ -5719,55 +6783,55 @@ __metadata: isobject: "npm:^3.0.1" mixin-deep: "npm:^1.2.0" pascalcase: "npm:^0.1.1" - checksum: 30a2c0675eb52136b05ef496feb41574d9f0bb2d6d677761da579c00a841523fccf07f1dbabec2337b5f5750f428683b8ca60d89e56a1052c4ae1c0cd05de64d + checksum: a4a146b912e27eea8f66d09cb0c9eab666f32ce27859a7dfd50f38cd069a2557b39f16dba1bc2aecb3b44bf096738dd207b7970d99b0318423285ab1b1994edd languageName: node linkType: hard -"better-opn@npm:^2.1.1": - version: 2.1.1 - resolution: "better-opn@npm:2.1.1" +"better-opn@npm:^3.0.2": + version: 3.0.2 + resolution: "better-opn@npm:3.0.2" dependencies: - open: "npm:^7.0.3" - checksum: c483f52a1c71555926df37a89ae7e521cddff6509e2a02c6af83c2c500e20cb3307417579ce1d5ec4d09855cc7d30f608b20934e7cedc54218888722d5bfc1d3 + open: ^8.0.4 + checksum: 1471552fa7f733561e7f49e812be074b421153006ca744de985fb6d38939807959fc5fe9cb819cf09f864782e294704fd3b31711ea14c115baf3330a2f1135de languageName: node linkType: hard "big-integer@npm:^1.6.44": version: 1.6.51 resolution: "big-integer@npm:1.6.51" - checksum: c8139662d57f8833a44802f4b65be911679c569535ea73c5cfd3c1c8994eaead1b84b6f63e1db63833e4d4cacb6b6a9e5522178113dfdc8e4c81ed8436f1e8cc + checksum: 3d444173d1b2e20747e2c175568bedeebd8315b0637ea95d75fd27830d3b8e8ba36c6af40374f36bdaea7b5de376dcada1b07587cb2a79a928fccdb6e6e3c518 languageName: node linkType: hard "big.js@npm:^5.2.2": version: 5.2.2 resolution: "big.js@npm:5.2.2" - checksum: 230520f1ff920b2d2ce3e372d77a33faa4fa60d802fe01ca4ffbc321ee06023fe9a741ac02793ee778040a16b7e497f7d60c504d1c402b8fdab6f03bb785a25f + checksum: b89b6e8419b097a8fb4ed2399a1931a68c612bce3cfd5ca8c214b2d017531191070f990598de2fc6f3f993d91c0f08aa82697717f6b3b8732c9731866d233c9e languageName: node linkType: hard "binary-extensions@npm:^2.0.0": version: 2.2.0 resolution: "binary-extensions@npm:2.2.0" - checksum: d73d8b897238a2d3ffa5f59c0241870043aa7471335e89ea5e1ff48edb7c2d0bb471517a3e4c5c3f4c043615caa2717b5f80a5e61e07503d51dc85cb848e665d + checksum: ccd267956c58d2315f5d3ea6757cf09863c5fc703e50fbeb13a7dc849b812ef76e3cf9ca8f35a0c48498776a7478d7b4a0418e1e2b8cb9cb9731f2922aaad7f8 languageName: node linkType: hard -"bl@npm:^4.0.3": +"bl@npm:^4.0.3, bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" dependencies: buffer: "npm:^5.5.0" inherits: "npm:^2.0.4" readable-stream: "npm:^3.4.0" - checksum: 02847e1d2cb089c9dc6958add42e3cdeaf07d13f575973963335ac0fdece563a50ac770ac4c8fa06492d2dd276f6cc3b7f08c7cd9c7a7ad0f8d388b2a28def5f + checksum: 9e8521fa7e83aa9427c6f8ccdcba6e8167ef30cc9a22df26effcc5ab682ef91d2cbc23a239f945d099289e4bbcfae7a192e9c28c84c6202e710a0dfec3722662 languageName: node linkType: hard "bluebird@npm:^3.5.0": version: 3.7.2 resolution: "bluebird@npm:3.7.2" - checksum: 680de03adc54ff925eaa6c7bb9a47a0690e8b5de60f4792604aae8ed618c65e6b63a7893b57ca924beaf53eee69c5af4f8314148c08124c550fe1df1add897d2 + checksum: 869417503c722e7dc54ca46715f70e15f4d9c602a423a02c825570862d12935be59ed9c7ba34a9b31f186c017c23cac6b54e35446f8353059c101da73eac22ef languageName: node linkType: hard @@ -5787,30 +6851,14 @@ __metadata: raw-body: "npm:2.5.1" type-is: "npm:~1.6.18" unpipe: "npm:1.0.0" - checksum: a202d493e2c10a33fb7413dac7d2f713be579c4b88343cd814b6df7a38e5af1901fc31044e04de176db56b16d9772aa25a7723f64478c20f4d91b1ac223bf3b8 + checksum: f1050dbac3bede6a78f0b87947a8d548ce43f91ccc718a50dd774f3c81f2d8b04693e52acf62659fad23101827dd318da1fb1363444ff9a8482b886a3e4a5266 languageName: node linkType: hard "boolbase@npm:^1.0.0": version: 1.0.0 resolution: "boolbase@npm:1.0.0" - checksum: e4b53deb4f2b85c52be0e21a273f2045c7b6a6ea002b0e139c744cb6f95e9ec044439a52883b0d74dedd1ff3da55ed140cfdddfed7fb0cccbed373de5dce1bcf - languageName: node - linkType: hard - -"boxen@npm:^5.1.2": - version: 5.1.2 - resolution: "boxen@npm:5.1.2" - dependencies: - ansi-align: "npm:^3.0.0" - camelcase: "npm:^6.2.0" - chalk: "npm:^4.1.0" - cli-boxes: "npm:^2.2.1" - string-width: "npm:^4.2.2" - type-fest: "npm:^0.20.2" - widest-line: "npm:^3.1.0" - wrap-ansi: "npm:^7.0.0" - checksum: 71f31c2eb3dcacd5fce524ae509e0cc90421752e0bfbd0281fd3352871d106c462a0f810c85f2fdb02f3a9fab2d7a84e9718b4999384d651b76104ebe5d2c024 + checksum: 3e25c80ef626c3a3487c73dbfc70ac322ec830666c9ad915d11b701142fab25ec1e63eff2c450c74347acfd2de854ccde865cd79ef4db1683f7c7b046ea43bb0 languageName: node linkType: hard @@ -5819,7 +6867,7 @@ __metadata: resolution: "bplist-parser@npm:0.2.0" dependencies: big-integer: "npm:^1.6.44" - checksum: ce79c69e0f6efe506281e7c84e3712f7d12978991675b6e3a58a295b16f13ca81aa9b845c335614a545e0af728c8311b6aa3142af76ba1cb616af9bbac5c4a9f + checksum: d5339dd16afc51de6c88f88f58a45b72ed6a06aa31f5557d09877575f220b7c1d3fbe375da0b62e6a10d4b8ed80523567e351f24014f5bc886ad523758142cdd languageName: node linkType: hard @@ -5829,7 +6877,7 @@ __metadata: dependencies: balanced-match: "npm:^1.0.0" concat-map: "npm:0.0.1" - checksum: 695a56cd058096a7cb71fb09d9d6a7070113c7be516699ed361317aca2ec169f618e28b8af352e02ab4233fb54eb0168460a40dc320bab0034b36ab59aaad668 + checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 languageName: node linkType: hard @@ -5838,7 +6886,7 @@ __metadata: resolution: "brace-expansion@npm:2.0.1" dependencies: balanced-match: "npm:^1.0.0" - checksum: b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f + checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 languageName: node linkType: hard @@ -5856,7 +6904,7 @@ __metadata: snapdragon-node: "npm:^2.0.1" split-string: "npm:^3.0.2" to-regex: "npm:^3.0.1" - checksum: 72b27ea3ea2718f061c29e70fd6e17606e37c65f5801abddcf0b0052db1de7d60f3bf92cfc220ab57b44bd0083a5f69f9d03b3461d2816cfe9f9398207acc728 + checksum: e30dcb6aaf4a31c8df17d848aa283a65699782f75ad61ae93ec25c9729c66cf58e66f0000a9fec84e4add1135bb7da40f7cb9601b36bebcfa9ca58e8d5c07de0 languageName: node linkType: hard @@ -5865,14 +6913,14 @@ __metadata: resolution: "braces@npm:3.0.2" dependencies: fill-range: "npm:^7.0.1" - checksum: 321b4d675791479293264019156ca322163f02dc06e3c4cab33bb15cd43d80b51efef69b0930cfde3acd63d126ebca24cd0544fa6f261e093a0fb41ab9dda381 + checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459 languageName: node linkType: hard "browser-assert@npm:^1.2.1": version: 1.2.1 resolution: "browser-assert@npm:1.2.1" - checksum: 902abf999f92c9c951fdb6d7352c09eea9a84706258699655f7e7906e42daa06a1ae286398a755872740e05a6a71c43c5d1a0c0431d67a8cdb66e5d859a3fc0c + checksum: 8b2407cd04c1ed592cf892dec35942b7d72635829221e0788c9a16c4d2afa8b7156bc9705b1c4b32c30d88136c576fda3cbcb8f494d6f865264c706ea8798d92 languageName: node linkType: hard @@ -5881,7 +6929,7 @@ __metadata: resolution: "browserify-zlib@npm:0.1.4" dependencies: pako: "npm:~0.2.0" - checksum: 0cde7ca5d33d43125649330fd75c056397e53731956a2593c4a2529f4e609a8e6abdb2b8e1921683abf5645375b92cfb2a21baa42fe3c9fc3e2556d32043af93 + checksum: abee4cb4349e8a21391fd874564f41b113fe691372913980e6fa06a777e4ea2aad4e942af14ab99bce190d5ac8f5328201432f4ef0eae48c6d02208bc212976f languageName: node linkType: hard @@ -5895,7 +6943,21 @@ __metadata: update-browserslist-db: "npm:^1.0.11" bin: browserslist: cli.js - checksum: 903189787141f645f47ec46ec482dc85985d1297948062690dc2ea8480eb98fd6213507234eb17177825acaae49c53888445910f1af984abce5373fb65c270b8 + checksum: 80d3820584e211484ad1b1a5cfdeca1dd00442f47be87e117e1dda34b628c87e18b81ae7986fa5977b3e6a03154f6d13cd763baa6b8bf5dd9dd19f4926603698 + languageName: node + linkType: hard + +"browserslist@npm:^4.22.2": + version: 4.22.2 + resolution: "browserslist@npm:4.22.2" + dependencies: + caniuse-lite: ^1.0.30001565 + electron-to-chromium: ^1.4.601 + node-releases: ^2.0.14 + update-browserslist-db: ^1.0.13 + bin: + browserslist: cli.js + checksum: 33ddfcd9145220099a7a1ac533cecfe5b7548ffeb29b313e1b57be6459000a1f8fa67e781cf4abee97268ac594d44134fcc4a6b2b4750ceddc9796e3a22076d9 languageName: node linkType: hard @@ -5904,21 +6966,21 @@ __metadata: resolution: "bser@npm:2.1.1" dependencies: node-int64: "npm:^0.4.0" - checksum: 24d8dfb7b6d457d73f32744e678a60cc553e4ec0e9e1a01cf614b44d85c3c87e188d3cc78ef0442ce5032ee6818de20a0162ba1074725c0d08908f62ea979227 + checksum: 9ba4dc58ce86300c862bffc3ae91f00b2a03b01ee07f3564beeeaf82aa243b8b03ba53f123b0b842c190d4399b94697970c8e7cf7b1ea44b61aa28c3526a4449 languageName: node linkType: hard "buffer-crc32@npm:~0.2.3": version: 0.2.13 resolution: "buffer-crc32@npm:0.2.13" - checksum: cb0a8ddf5cf4f766466db63279e47761eb825693eeba6a5a95ee4ec8cb8f81ede70aa7f9d8aeec083e781d47154290eb5d4d26b3f7a465ec57fb9e7d59c47150 + checksum: 06252347ae6daca3453b94e4b2f1d3754a3b146a111d81c68924c22d91889a40623264e95e67955b1cb4a68cbedf317abeabb5140a9766ed248973096db5ce1c languageName: node linkType: hard "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" - checksum: 124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 + checksum: 0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb languageName: node linkType: hard @@ -5928,43 +6990,21 @@ __metadata: dependencies: base64-js: "npm:^1.3.1" ieee754: "npm:^1.1.13" - checksum: 27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e + checksum: e2cf8429e1c4c7b8cbd30834ac09bd61da46ce35f5c22a78e6c2f04497d6d25541b16881e30a019c6fd3154150650ccee27a308eff3e26229d788bbdeb08ab84 languageName: node linkType: hard "bytes@npm:3.0.0": version: 3.0.0 resolution: "bytes@npm:3.0.0" - checksum: 91d42c38601c76460519ffef88371caacaea483a354c8e4b8808e7b027574436a5713337c003ea3de63ee4991c2a9a637884fdfe7f761760d746929d9e8fec60 + checksum: a2b386dd8188849a5325f58eef69c3b73c51801c08ffc6963eddc9be244089ba32d19347caf6d145c86f315ae1b1fc7061a32b0c1aa6379e6a719090287ed101 languageName: node linkType: hard "bytes@npm:3.1.2": version: 3.1.2 resolution: "bytes@npm:3.1.2" - checksum: 76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e - languageName: node - linkType: hard - -"c8@npm:^7.6.0": - version: 7.14.0 - resolution: "c8@npm:7.14.0" - dependencies: - "@bcoe/v8-coverage": "npm:^0.2.3" - "@istanbuljs/schema": "npm:^0.1.3" - find-up: "npm:^5.0.0" - foreground-child: "npm:^2.0.0" - istanbul-lib-coverage: "npm:^3.2.0" - istanbul-lib-report: "npm:^3.0.0" - istanbul-reports: "npm:^3.1.4" - rimraf: "npm:^3.0.2" - test-exclude: "npm:^6.0.0" - v8-to-istanbul: "npm:^9.0.0" - yargs: "npm:^16.2.0" - yargs-parser: "npm:^20.2.9" - bin: - c8: bin/c8.js - checksum: 8946f55f2dcc85bf146f429a3deeede78502da245e515a2d181342475d8d8698b4055ec1d9b887ab8e1615f49c1a2af4d63557e68b2005844572fb785991e148 + checksum: e4bcd3948d289c5127591fbedf10c0b639ccbf00243504e4e127374a15c3bc8eed0d28d4aaab08ff6f1cf2abc0cce6ba3085ed32f4f90e82a5683ce0014e1b6e languageName: node linkType: hard @@ -5984,7 +7024,7 @@ __metadata: ssri: "npm:^10.0.0" tar: "npm:^6.1.11" unique-filename: "npm:^3.0.0" - checksum: fcb0843c8e152b0e1440328508a2c0d6435c431198155e31daa591b348a1739b089ce2a72a4528690ed10a2bf086c180ee4980e2116457131b4c8a6e65e10976 + checksum: 385756781e1e21af089160d89d7462b7ed9883c978e848c7075b90b73cb823680e66092d61513050164588387d2ca87dd6d910e28d64bc13a9ac82cd8580c796 languageName: node linkType: hard @@ -6001,7 +7041,7 @@ __metadata: to-object-path: "npm:^0.3.0" union-value: "npm:^1.0.0" unset-value: "npm:^1.0.0" - checksum: a7142e25c73f767fa520957dcd179b900b86eac63b8cfeaa3b2a35e18c9ca5968aa4e2d2bed7a3e7efd10f13be404344cfab3a4156217e71f9bdb95940bb9c8c + checksum: 9114b8654fe2366eedc390bad0bcf534e2f01b239a888894e2928cb58cdc1e6ea23a73c6f3450dcfd2058aa73a8a981e723cd1e7c670c047bf11afdc65880107 languageName: node linkType: hard @@ -6011,35 +7051,42 @@ __metadata: dependencies: function-bind: "npm:^1.1.1" get-intrinsic: "npm:^1.0.2" - checksum: 74ba3f31e715456e22e451d8d098779b861eba3c7cac0d9b510049aced70d75c231ba05071f97e1812c98e34e2bee734c0c6126653e0088c2d9819ca047f4073 + checksum: f8e31de9d19988a4b80f3e704788c4a2d6b6f3d17cfec4f57dc29ced450c53a49270dc66bf0fbd693329ee948dd33e6c90a329519aef17474a4d961e8d6426b0 languageName: node linkType: hard "callsites@npm:^3.0.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" - checksum: fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 + checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 languageName: node linkType: hard "camelcase@npm:^5.3.1": version: 5.3.1 resolution: "camelcase@npm:5.3.1" - checksum: 92ff9b443bfe8abb15f2b1513ca182d16126359ad4f955ebc83dc4ddcc4ef3fdd2c078bc223f2673dc223488e75c99b16cc4d056624374b799e6a1555cf61b23 + checksum: e6effce26b9404e3c0f301498184f243811c30dfe6d0b9051863bd8e4034d09c8c2923794f280d6827e5aa055f6c434115ff97864a16a963366fb35fd673024b languageName: node linkType: hard "camelcase@npm:^6.2.0": version: 6.3.0 resolution: "camelcase@npm:6.3.0" - checksum: 0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 + checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d languageName: node linkType: hard "caniuse-lite@npm:^1.0.30001503": version: 1.0.30001515 resolution: "caniuse-lite@npm:1.0.30001515" - checksum: c4f7ef015eff6da9a173fe7bff1ebf55faf2d944aeb03e5e92f362591f95c6780157e003eeb77093840f2eb71c58d541676b8855441e53d052b24a287b85adc3 + checksum: ec5d51785aea6af5cf62ca9d35821d36ab7fa0f85e3e7f752d532025ad59e07131fa3cb3a0a6c486b5ac8620c8c3440e761dc5b38c990d49c17655906f216123 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001565": + version: 1.0.30001578 + resolution: "caniuse-lite@npm:1.0.30001578" + checksum: b0cd4fed07ae1224f564baaed5e096c9c479b3063d023fc629df52caa14e59b7436b33498729161e253a5b8974d644374ff1ce47ccf1885ef3d1541f4067705f languageName: node linkType: hard @@ -6052,18 +7099,18 @@ __metadata: has-ansi: "npm:^2.0.0" strip-ansi: "npm:^3.0.0" supports-color: "npm:^2.0.0" - checksum: 28c3e399ec286bb3a7111fd4225ebedb0d7b813aef38a37bca7c498d032459c265ef43404201d5fbb8d888d29090899c95335b4c0cda13e8b126ff15c541cef8 + checksum: 9d2ea6b98fc2b7878829eec223abcf404622db6c48396a9b9257f6d0ead2acf18231ae368d6a664a83f272b0679158da12e97b5229f794939e555cc574478acd languageName: node linkType: hard -"chalk@npm:^2.0.0": +"chalk@npm:^2.0.0, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: ansi-styles: "npm:^3.2.1" escape-string-regexp: "npm:^1.0.5" supports-color: "npm:^5.3.0" - checksum: e6543f02ec877732e3a2d1c3c3323ddb4d39fbab687c23f526e25bd4c6a9bf3b83a696e8c769d078e04e5754921648f7821b2a2acfd16c550435fd630026e073 + checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 languageName: node linkType: hard @@ -6073,7 +7120,7 @@ __metadata: dependencies: ansi-styles: "npm:^4.1.0" supports-color: "npm:^7.1.0" - checksum: ee650b0a065b3d7a6fda258e75d3a86fc8e4effa55871da730a9e42ccb035bf5fd203525e5a1ef45ec2582ecc4f65b47eb11357c526b84dd29a14fb162c414d2 + checksum: 8e3ddf3981c4da405ddbd7d9c8d91944ddf6e33d6837756979f7840a29272a69a5189ecae0ff84006750d6d1e92368d413335eab4db5476db6e6703a1d1e0505 languageName: node linkType: hard @@ -6083,35 +7130,35 @@ __metadata: dependencies: ansi-styles: "npm:^4.1.0" supports-color: "npm:^7.1.0" - checksum: 4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 + checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc languageName: node linkType: hard "char-regex@npm:^1.0.2": version: 1.0.2 resolution: "char-regex@npm:1.0.2" - checksum: 57a09a86371331e0be35d9083ba429e86c4f4648ecbe27455dbfb343037c16ee6fdc7f6b61f433a57cc5ded5561d71c56a150e018f40c2ffb7bc93a26dae341e + checksum: b563e4b6039b15213114626621e7a3d12f31008bdce20f9c741d69987f62aeaace7ec30f6018890ad77b2e9b4d95324c9f5acfca58a9441e3b1dcdd1e2525d17 languageName: node linkType: hard "character-entities-legacy@npm:^1.0.0": version: 1.1.4 resolution: "character-entities-legacy@npm:1.1.4" - checksum: ea4ca9c29887335eed86d78fc67a640168342b1274da84c097abb0575a253d1265281a5052f9a863979e952bcc267b4ecaaf4fe233a7e1e0d8a47806c65b96c7 + checksum: fe03a82c154414da3a0c8ab3188e4237ec68006cbcd681cf23c7cfb9502a0e76cd30ab69a2e50857ca10d984d57de3b307680fff5328ccd427f400e559c3a811 languageName: node linkType: hard "character-entities@npm:^1.0.0": version: 1.2.4 resolution: "character-entities@npm:1.2.4" - checksum: ad015c3d7163563b8a0ee1f587fb0ef305ef344e9fd937f79ca51cccc233786a01d591d989d5bf7b2e66b528ac9efba47f3b1897358324e69932f6d4b25adfe1 + checksum: e1545716571ead57beac008433c1ff69517cd8ca5b336889321c5b8ff4a99c29b65589a701e9c086cda8a5e346a67295e2684f6c7ea96819fe85cbf49bf8686d languageName: node linkType: hard "character-reference-invalid@npm:^1.0.0": version: 1.1.4 resolution: "character-reference-invalid@npm:1.1.4" - checksum: 29f05081c5817bd1e975b0bf61e77b60a40f62ad371d0f0ce0fdb48ab922278bc744d1fbe33771dced751887a8403f265ff634542675c8d7375f6ff4811efd0e + checksum: 20274574c70e05e2f81135f3b93285536bc8ff70f37f0809b0d17791a832838f1e49938382899ed4cb444e5bbd4314ca1415231344ba29f4222ce2ccf24fea0b languageName: node linkType: hard @@ -6130,35 +7177,35 @@ __metadata: dependenciesMeta: fsevents: optional: true - checksum: 1076953093e0707c882a92c66c0f56ba6187831aa51bb4de878c1fec59ae611a3bf02898f190efec8e77a086b8df61c2b2a3ea324642a0558bdf8ee6c5dc9ca1 + checksum: b49fcde40176ba007ff361b198a2d35df60d9bb2a5aab228279eb810feae9294a6b4649ab15981304447afe1e6ffbf4788ad5db77235dc770ab777c6e771980c languageName: node linkType: hard "chownr@npm:^1.1.1": version: 1.1.4 resolution: "chownr@npm:1.1.4" - checksum: ed57952a84cc0c802af900cf7136de643d3aba2eecb59d29344bc2f3f9bf703a301b9d84cdc71f82c3ffc9ccde831b0d92f5b45f91727d6c9da62f23aef9d9db + checksum: 115648f8eb38bac5e41c3857f3e663f9c39ed6480d1349977c4d96c95a47266fcacc5a5aabf3cb6c481e22d72f41992827db47301851766c4fd77ac21a4f081d languageName: node linkType: hard "chownr@npm:^2.0.0": version: 2.0.0 resolution: "chownr@npm:2.0.0" - checksum: 594754e1303672171cc04e50f6c398ae16128eb134a88f801bf5354fd96f205320f23536a045d9abd8b51024a149696e51231565891d4efdab8846021ecf88e6 + checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f languageName: node linkType: hard "ci-info@npm:^3.2.0": version: 3.8.0 resolution: "ci-info@npm:3.8.0" - checksum: 0d3052193b58356372b34ab40d2668c3e62f1006d5ca33726d1d3c423853b19a85508eadde7f5908496fb41448f465263bf61c1ee58b7832cb6a924537e3863a + checksum: d0a4d3160497cae54294974a7246202244fff031b0a6ea20dd57b10ec510aa17399c41a1b0982142c105f3255aff2173e5c0dd7302ee1b2f28ba3debda375098 languageName: node linkType: hard "cjs-module-lexer@npm:^1.0.0": version: 1.2.3 resolution: "cjs-module-lexer@npm:1.2.3" - checksum: 0de9a9c3fad03a46804c0d38e7b712fb282584a9c7ef1ed44cae22fb71d9bb600309d66a9711ac36a596fd03422f5bb03e021e8f369c12a39fa1786ae531baab + checksum: 5ea3cb867a9bb609b6d476cd86590d105f3cfd6514db38ff71f63992ab40939c2feb68967faa15a6d2b1f90daa6416b79ea2de486e9e2485a6f8b66a21b4fb0a languageName: node linkType: hard @@ -6170,28 +7217,37 @@ __metadata: define-property: "npm:^0.2.5" isobject: "npm:^3.0.0" static-extend: "npm:^0.1.1" - checksum: d44f4afc7a3e48dba4c2d3fada5f781a1adeeff371b875c3b578bc33815c6c29d5d06483c2abfd43a32d35b104b27b67bfa39c2e8a422fa858068bd756cfbd42 + checksum: be108900801e639e50f96a7e4bfa8867c753a7750a7603879f3981f8b0a89cba657497a2d5f40cd4ea557ff15d535a100818bb486baf6e26fe5d7872e75f1078 languageName: node linkType: hard "classnames@npm:2.3.2": version: 2.3.2 resolution: "classnames@npm:2.3.2" - checksum: cd50ead57b4f97436aaa9f9885c6926323efc7c2bea8e3d4eb10e4e972aa6a1cfca1c7a0e06f8a199ca7498d4339e30bb6002e589e61c9f21248cbf3e8b0b18d + checksum: 2c62199789618d95545c872787137262e741f9db13328e216b093eea91c85ef2bfb152c1f9e63027204e2559a006a92eb74147d46c800a9f96297ae1d9f96f4e languageName: node linkType: hard "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" - checksum: 1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1 + checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 languageName: node linkType: hard -"cli-boxes@npm:^2.2.1": - version: 2.2.1 - resolution: "cli-boxes@npm:2.2.1" - checksum: 6111352edbb2f62dbc7bfd58f2d534de507afed7f189f13fa894ce5a48badd94b2aa502fda28f1d7dd5f1eb456e7d4033d09a76660013ef50c7f66e7a034f050 +"cli-cursor@npm:^3.1.0": + version: 3.1.0 + resolution: "cli-cursor@npm:3.1.0" + dependencies: + restore-cursor: ^3.1.0 + checksum: 2692784c6cd2fd85cfdbd11f53aea73a463a6d64a77c3e098b2b4697a20443f430c220629e1ca3b195ea5ac4a97a74c2ee411f3807abf6df2b66211fec0c0a29 + languageName: node + linkType: hard + +"cli-spinners@npm:^2.5.0": + version: 2.9.2 + resolution: "cli-spinners@npm:2.9.2" + checksum: 1bd588289b28432e4676cb5d40505cfe3e53f2e4e10fbe05c8a710a154d6fe0ce7836844b00d6858f740f2ffe67cdc36e0fce9c7b6a8430e80e6388d5aa4956c languageName: node linkType: hard @@ -6204,18 +7260,7 @@ __metadata: dependenciesMeta: "@colors/colors": optional: true - checksum: 39e580cb346c2eaf1bd8f4ff055ae644e902b8303c164a1b8894c0dc95941f92e001db51f49649011be987e708d9fa3183ccc2289a4d376a057769664048cc0c - languageName: node - linkType: hard - -"cliui@npm:^7.0.2": - version: 7.0.4 - resolution: "cliui@npm:7.0.4" - dependencies: - string-width: "npm:^4.2.0" - strip-ansi: "npm:^6.0.0" - wrap-ansi: "npm:^7.0.0" - checksum: 6035f5daf7383470cef82b3d3db00bec70afb3423538c50394386ffbbab135e26c3689c41791f911fa71b62d13d3863c712fdd70f0fbdffd938a1e6fd09aac00 + checksum: 09897f68467973f827c04e7eaadf13b55f8aec49ecd6647cc276386ea660059322e2dd8020a8b6b84d422dbdd619597046fa89cbbbdc95b2cea149a2df7c096c languageName: node linkType: hard @@ -6226,7 +7271,7 @@ __metadata: string-width: "npm:^4.2.0" strip-ansi: "npm:^6.0.1" wrap-ansi: "npm:^7.0.0" - checksum: 4bda0f09c340cbb6dfdc1ed508b3ca080f12992c18d68c6be4d9cf51756033d5266e61ec57529e610dacbf4da1c634423b0c1b11037709cc6b09045cbd815df5 + checksum: 79648b3b0045f2e285b76fb2e24e207c6db44323581e421c3acbd0e86454cba1b37aea976ab50195a49e7384b871e6dfb2247ad7dec53c02454ac6497394cb56 languageName: node linkType: hard @@ -6237,28 +7282,35 @@ __metadata: is-plain-object: "npm:^2.0.4" kind-of: "npm:^6.0.2" shallow-clone: "npm:^3.0.0" - checksum: 637753615aa24adf0f2d505947a1bb75e63964309034a1cf56ba4b1f30af155201edd38d26ffe26911adaae267a3c138b344a4947d39f5fc1b6d6108125aa758 + checksum: 770f912fe4e6f21873c8e8fbb1e99134db3b93da32df271d00589ea4a29dbe83a9808a322c93f3bcaf8584b8b4fa6fc269fc8032efbaa6728e0c9886c74467d2 + languageName: node + linkType: hard + +"clone@npm:^1.0.2": + version: 1.0.4 + resolution: "clone@npm:1.0.4" + checksum: d06418b7335897209e77bdd430d04f882189582e67bd1f75a04565f3f07f5b3f119a9d670c943b6697d0afb100f03b866b3b8a1f91d4d02d72c4ecf2bb64b5dd languageName: node linkType: hard "clone@npm:^2.1.1": version: 2.1.2 resolution: "clone@npm:2.1.2" - checksum: ed0601cd0b1606bc7d82ee7175b97e68d1dd9b91fd1250a3617b38d34a095f8ee0431d40a1a611122dcccb4f93295b4fdb94942aa763392b5fe44effa50c2d5e + checksum: aaf106e9bc025b21333e2f4c12da539b568db4925c0501a1bf4070836c9e848c892fa22c35548ce0d1132b08bbbfa17a00144fe58fccdab6fa900fec4250f67d languageName: node linkType: hard "co@npm:^4.6.0": version: 4.6.0 resolution: "co@npm:4.6.0" - checksum: c0e85ea0ca8bf0a50cbdca82efc5af0301240ca88ebe3644a6ffb8ffe911f34d40f8fbcf8f1d52c5ddd66706abd4d3bfcd64259f1e8e2371d4f47573b0dc8c28 + checksum: 5210d9223010eb95b29df06a91116f2cf7c8e0748a9013ed853b53f362ea0e822f1e5bb054fb3cefc645239a4cf966af1f6133a3b43f40d591f3b68ed6cf0510 languageName: node linkType: hard "collect-v8-coverage@npm:^1.0.0": version: 1.0.2 resolution: "collect-v8-coverage@npm:1.0.2" - checksum: ed7008e2e8b6852c5483b444a3ae6e976e088d4335a85aa0a9db2861c5f1d31bd2d7ff97a60469b3388deeba661a619753afbe201279fb159b4b9548ab8269a1 + checksum: c10f41c39ab84629d16f9f6137bc8a63d332244383fc368caf2d2052b5e04c20cd1fd70f66fcf4e2422b84c8226598b776d39d5f2d2a51867cc1ed5d1982b4da languageName: node linkType: hard @@ -6268,7 +7320,7 @@ __metadata: dependencies: map-visit: "npm:^1.0.0" object-visit: "npm:^1.0.0" - checksum: add72a8d1c37cb90e53b1aaa2c31bf1989bfb733f0b02ce82c9fa6828c7a14358dba2e4f8e698c02f69e424aeccae1ffb39acdeaf872ade2f41369e84a2fcf8a + checksum: 15d9658fe6eb23594728346adad5433b86bb7a04fd51bbab337755158722f9313a5376ef479de5b35fbc54140764d0d39de89c339f5d25b959ed221466981da9 languageName: node linkType: hard @@ -6277,7 +7329,7 @@ __metadata: resolution: "color-convert@npm:1.9.3" dependencies: color-name: "npm:1.1.3" - checksum: 5ad3c534949a8c68fca8fbc6f09068f435f0ad290ab8b2f76841b9e6af7e0bb57b98cb05b0e19fe33f5d91e5a8611ad457e5f69e0a484caad1f7487fd0e8253c + checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203 languageName: node linkType: hard @@ -6286,37 +7338,37 @@ __metadata: resolution: "color-convert@npm:2.0.1" dependencies: color-name: "npm:~1.1.4" - checksum: 37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 + checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 languageName: node linkType: hard "color-name@npm:1.1.3": version: 1.1.3 resolution: "color-name@npm:1.1.3" - checksum: 566a3d42cca25b9b3cd5528cd7754b8e89c0eb646b7f214e8e2eaddb69994ac5f0557d9c175eb5d8f0ad73531140d9c47525085ee752a91a2ab15ab459caf6d6 + checksum: 09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d languageName: node linkType: hard "color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" - checksum: a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 + checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 languageName: node linkType: hard -"color-support@npm:^1.1.2, color-support@npm:^1.1.3": +"color-support@npm:^1.1.3": version: 1.1.3 resolution: "color-support@npm:1.1.3" bin: color-support: bin.js - checksum: 8ffeaa270a784dc382f62d9be0a98581db43e11eee301af14734a6d089bd456478b1a8b3e7db7ca7dc5b18a75f828f775c44074020b51c05fc00e6d0992b1cc6 + checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b languageName: node linkType: hard "colorette@npm:^2.0.19": version: 2.0.20 resolution: "colorette@npm:2.0.20" - checksum: e94116ff33b0ff56f3b83b9ace895e5bf87c2a7a47b3401b8c3f3226e050d5ef76cf4072fb3325f9dc24d1698f9b730baf4e05eeaf861d74a1883073f4c98a40 + checksum: 0c016fea2b91b733eb9f4bcdb580018f52c0bc0979443dad930e5037a968237ac53d9beb98e218d2e9235834f8eebce7f8e080422d6194e957454255bde71d3d languageName: node linkType: hard @@ -6325,49 +7377,42 @@ __metadata: resolution: "combined-stream@npm:1.0.8" dependencies: delayed-stream: "npm:~1.0.0" - checksum: 0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 + checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c languageName: node linkType: hard "comma-separated-tokens@npm:^1.0.0": version: 1.0.8 resolution: "comma-separated-tokens@npm:1.0.8" - checksum: c3bcfeaa6d50313528a006a40bcc0f9576086665c9b48d4b3a76ddd63e7d6174734386c98be1881cbf6ecfc25e1db61cd775a7b896d2ea7a65de28f83a0f9b17 - languageName: node - linkType: hard - -"commander@npm:^2.19.0": - version: 2.20.3 - resolution: "commander@npm:2.20.3" - checksum: 74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 + checksum: 0adcb07174fa4d08cf0f5c8e3aec40a36b5ff0c2c720e5e23f50fe02e6789d1d00a67036c80e0c1e1539f41d3e7f0101b074039dd833b4e4a59031b659d6ca0d languageName: node linkType: hard "commander@npm:^6.2.1": version: 6.2.1 resolution: "commander@npm:6.2.1" - checksum: 85748abd9d18c8bc88febed58b98f66b7c591d9b5017cad459565761d7b29ca13b7783ea2ee5ce84bf235897333706c4ce29adf1ce15c8252780e7000e2ce9ea + checksum: d7090410c0de6bc5c67d3ca41c41760d6d268f3c799e530aafb73b7437d1826bbf0d2a3edac33f8b57cc9887b4a986dce307fa5557e109be40eadb7c43b21742 languageName: node linkType: hard "commander@npm:^7.2.0": version: 7.2.0 resolution: "commander@npm:7.2.0" - checksum: 8d690ff13b0356df7e0ebbe6c59b4712f754f4b724d4f473d3cc5b3fdcf978e3a5dc3078717858a2ceb50b0f84d0660a7f22a96cdc50fb877d0c9bb31593d23a + checksum: 53501cbeee61d5157546c0bef0fedb6cdfc763a882136284bed9a07225f09a14b82d2a84e7637edfd1a679fb35ed9502fd58ef1d091e6287f60d790147f68ddc languageName: node linkType: hard "commondir@npm:^1.0.1": version: 1.0.1 resolution: "commondir@npm:1.0.1" - checksum: 33a124960e471c25ee19280c9ce31ccc19574b566dc514fe4f4ca4c34fa8b0b57cf437671f5de380e11353ea9426213fca17687dd2ef03134fea2dbc53809fd6 + checksum: 59715f2fc456a73f68826285718503340b9f0dd89bfffc42749906c5cf3d4277ef11ef1cca0350d0e79204f00f1f6d83851ececc9095dc88512a697ac0b9bdcb languageName: node linkType: hard "component-emitter@npm:^1.2.1": version: 1.3.0 resolution: "component-emitter@npm:1.3.0" - checksum: 68774a0a3754fb6c0ba53c2e88886dfbd0c773931066abb1d7fd1b0c893b2a838d8f088ab4dca1f18cc1a4fc2e6932019eba3ded2d931b5ba2241ce40e93a24f + checksum: b3c46de38ffd35c57d1c02488355be9f218e582aec72d72d1b8bbec95a3ac1b38c96cd6e03ff015577e68f550fbb361a3bfdbd9bb248be9390b7b3745691be6b languageName: node linkType: hard @@ -6376,7 +7421,7 @@ __metadata: resolution: "compressible@npm:2.0.18" dependencies: mime-db: "npm:>= 1.43.0 < 2" - checksum: 8a03712bc9f5b9fe530cc5a79e164e665550d5171a64575d7dcf3e0395d7b4afa2d79ab176c61b5b596e28228b350dd07c1a2a6ead12fd81d1b6cd632af2fef7 + checksum: 58321a85b375d39230405654721353f709d0c1442129e9a17081771b816302a012471a9b8f4864c7dbe02eef7f2aaac3c614795197092262e94b409c9be108f0 languageName: node linkType: hard @@ -6391,14 +7436,14 @@ __metadata: on-headers: "npm:~1.0.2" safe-buffer: "npm:5.1.2" vary: "npm:~1.1.2" - checksum: 138db836202a406d8a14156a5564fb1700632a76b6e7d1546939472895a5304f2b23c80d7a22bf44c767e87a26e070dbc342ea63bb45ee9c863354fa5556bbbc + checksum: 35c0f2eb1f28418978615dc1bc02075b34b1568f7f56c62d60f4214d4b7cc00d0f6d282b5f8a954f59872396bd770b6b15ffd8aa94c67d4bce9b8887b906999b languageName: node linkType: hard "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" - checksum: c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f + checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af languageName: node linkType: hard @@ -6410,14 +7455,14 @@ __metadata: inherits: "npm:^2.0.3" readable-stream: "npm:^2.2.2" typedarray: "npm:^0.0.6" - checksum: 2e9864e18282946dabbccb212c5c7cec0702745e3671679eb8291812ca7fd12023f7d8cb36493942a62f770ac96a7f90009dc5c82ad69893438371720fa92617 + checksum: 1ef77032cb4459dcd5187bd710d6fc962b067b64ec6a505810de3d2b8cc0605638551b42f8ec91edf6fcd26141b32ef19ad749239b58fae3aba99187adc32285 languageName: node linkType: hard -"console-control-strings@npm:^1.0.0, console-control-strings@npm:^1.1.0": +"console-control-strings@npm:^1.1.0": version: 1.1.0 resolution: "console-control-strings@npm:1.1.0" - checksum: 7ab51d30b52d461412cd467721bb82afe695da78fff8f29fe6f6b9cbaac9a2328e27a22a966014df9532100f6dd85370460be8130b9c677891ba36d96a343f50 + checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed languageName: node linkType: hard @@ -6426,49 +7471,49 @@ __metadata: resolution: "content-disposition@npm:0.5.4" dependencies: safe-buffer: "npm:5.2.1" - checksum: bac0316ebfeacb8f381b38285dc691c9939bf0a78b0b7c2d5758acadad242d04783cee5337ba7d12a565a19075af1b3c11c728e1e4946de73c6ff7ce45f3f1bb + checksum: afb9d545e296a5171d7574fcad634b2fdf698875f4006a9dd04a3e1333880c5c0c98d47b560d01216fb6505a54a2ba6a843ee3a02ec86d7e911e8315255f56c3 languageName: node linkType: hard "content-type@npm:~1.0.4": version: 1.0.5 resolution: "content-type@npm:1.0.5" - checksum: b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af + checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 languageName: node linkType: hard "convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" - checksum: 281da55454bf8126cbc6625385928c43479f2060984180c42f3a86c8b8c12720a24eac260624a7d1e090004028d2dee78602330578ceec1a08e27cb8bb0a8a5b + checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 languageName: node linkType: hard "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" - checksum: 8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b + checksum: 63ae9933be5a2b8d4509daca5124e20c14d023c820258e484e32dc324d34c2754e71297c94a05784064ad27615037ef677e3f0c00469fb55f409d2bb21261035 languageName: node linkType: hard "cookie-signature@npm:1.0.6": version: 1.0.6 resolution: "cookie-signature@npm:1.0.6" - checksum: b36fd0d4e3fef8456915fcf7742e58fbfcc12a17a018e0eb9501c9d5ef6893b596466f03b0564b81af29ff2538fd0aa4b9d54fe5ccbfb4c90ea50ad29fe2d221 + checksum: f4e1b0a98a27a0e6e66fd7ea4e4e9d8e038f624058371bf4499cfcd8f3980be9a121486995202ba3fca74fbed93a407d6d54d43a43f96fd28d0bd7a06761591a languageName: node linkType: hard "cookie@npm:0.5.0": version: 0.5.0 resolution: "cookie@npm:0.5.0" - checksum: c01ca3ef8d7b8187bae434434582288681273b5a9ed27521d4d7f9f7928fe0c920df0decd9f9d3bbd2d14ac432b8c8cf42b98b3bdd5bfe0e6edddeebebe8b61d + checksum: 1f4bd2ca5765f8c9689a7e8954183f5332139eb72b6ff783d8947032ec1fdf43109852c178e21a953a30c0dd42257828185be01b49d1eb1a67fd054ca588a180 languageName: node linkType: hard "copy-descriptor@npm:^0.1.0": version: 0.1.1 resolution: "copy-descriptor@npm:0.1.1" - checksum: 161f6760b7348c941007a83df180588fe2f1283e0867cc027182734e0f26134e6cc02de09aa24a95dc267b2e2025b55659eef76c8019df27bc2d883033690181 + checksum: d4b7b57b14f1d256bb9aa0b479241048afd7f5bcf22035fc7b94e8af757adeae247ea23c1a774fe44869fd5694efba4a969b88d966766c5245fdee59837fe45b languageName: node linkType: hard @@ -6477,7 +7522,7 @@ __metadata: resolution: "copy-to-clipboard@npm:3.3.3" dependencies: toggle-selection: "npm:^1.0.6" - checksum: 3ebf5e8ee00601f8c440b83ec08d838e8eabb068c1fae94a9cda6b42f288f7e1b552f3463635f419af44bf7675afc8d0390d30876cf5c2d5d35f86d9c56a3e5f + checksum: e0a325e39b7615108e6c1c8ac110ae7b829cdc4ee3278b1df6a0e4228c490442cc86444cd643e2da344fbc424b3aab8909e2fec82f8bc75e7e5b190b7c24eecf languageName: node linkType: hard @@ -6486,14 +7531,23 @@ __metadata: resolution: "core-js-compat@npm:3.31.1" dependencies: browserslist: "npm:^4.21.9" - checksum: 2f05c5d5b04e8a69cf50f538ef3fb1932ab83bd7dc690c438c7b876049cb1515eb4ca9fa29400ed7cd5885f34c901bf6a26d9149dfff8665d8302cace7e96d72 + checksum: 9a16d6992621f4e099169297381a28d5712cdef7df1fa85352a7c285a5885d5d7a117ec2eae9ad715ed88c7cc774787a22cdb8aceababf6775fbc8b0cbeccdb7 + languageName: node + linkType: hard + +"core-js-compat@npm:^3.33.1": + version: 3.35.0 + resolution: "core-js-compat@npm:3.35.0" + dependencies: + browserslist: ^4.22.2 + checksum: 64c41ce6870aa9130b9d0cb8f00c05204094f46db7e345d520ec2e38f8b6e1d51e921d4974ceb880948f19c0a79e5639e55be0e56f88ea20e32e9a6274da7f82 languageName: node linkType: hard "core-util-is@npm:~1.0.0": version: 1.0.3 resolution: "core-util-is@npm:1.0.3" - checksum: 90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 + checksum: 9de8597363a8e9b9952491ebe18167e3b36e7707569eed0ebf14f8bba773611376466ae34575bca8cfe3c767890c859c74056084738f09d4e4a6f902b2ad7d99 languageName: node linkType: hard @@ -6505,7 +7559,7 @@ __metadata: js-yaml: "npm:^4.1.0" parse-json: "npm:^5.0.0" path-type: "npm:^4.0.0" - checksum: 4180aa6d1881b75ba591b2fc04b022741a3a4b67e9e243c0eb8d169b6e1efbd3cdf7e8ca19243c0f2e53a9d59ac3eccd5cad5f95f487fcbf4e740f9e86745747 + checksum: 836d5d8efa750f3fb17b03d6ca74cd3154ed025dffd045304b3ef59637f662bde1e5dc88f8830080d180ec60841719cf4ea2ce73fb21ec694b16865c478ff297 languageName: node linkType: hard @@ -6516,14 +7570,14 @@ __metadata: path-key: "npm:^3.1.0" shebang-command: "npm:^2.0.0" which: "npm:^2.0.1" - checksum: 5738c312387081c98d69c98e105b6327b069197f864a60593245d64c8089c8a0a744e16349281210d56835bb9274130d825a78b2ad6853ca13cfbeffc0c31750 + checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 languageName: node linkType: hard "crypto-random-string@npm:^2.0.0": version: 2.0.0 resolution: "crypto-random-string@npm:2.0.0" - checksum: 288589b2484fe787f9e146f56c4be90b940018f17af1b152e4dde12309042ff5a2bf69e949aab8b8ac253948381529cc6f3e5a2427b73643a71ff177fa122b37 + checksum: 0283879f55e7c16fdceacc181f87a0a65c53bc16ffe1d58b9d19a6277adcd71900d02bb2c4843dd55e78c51e30e89b0fec618a7f170ebcc95b33182c28f05fd6 languageName: node linkType: hard @@ -6536,7 +7590,7 @@ __metadata: domhandler: "npm:^4.3.1" domutils: "npm:^2.8.0" nth-check: "npm:^2.0.1" - checksum: a489d8e5628e61063d5a8fe0fa1cc7ae2478cb334a388a354e91cf2908154be97eac9fa7ed4dffe87a3e06cf6fcaa6016553115335c4fd3377e13dac7bd5a8e1 + checksum: d6202736839194dd7f910320032e7cfc40372f025e4bf21ca5bf6eb0a33264f322f50ba9c0adc35dadd342d3d6fae5ca244779a4873afbfa76561e343f2058e0 languageName: node linkType: hard @@ -6546,21 +7600,21 @@ __metadata: dependencies: mdn-data: "npm:2.0.14" source-map: "npm:^0.6.1" - checksum: 499a507bfa39b8b2128f49736882c0dd636b0cd3370f2c69f4558ec86d269113286b7df469afc955de6a68b0dba00bc533e40022a73698081d600072d5d83c1c + checksum: 79f9b81803991b6977b7fcb1588799270438274d89066ce08f117f5cdb5e20019b446d766c61506dd772c839df84caa16042d6076f20c97187f5abe3b50e7d1f languageName: node linkType: hard "css-what@npm:^6.0.1": version: 6.1.0 resolution: "css-what@npm:6.1.0" - checksum: a09f5a6b14ba8dcf57ae9a59474722e80f20406c53a61e9aedb0eedc693b135113ffe2983f4efc4b5065ae639442e9ae88df24941ef159c218b231011d733746 + checksum: b975e547e1e90b79625918f84e67db5d33d896e6de846c9b584094e529f0c63e2ab85ee33b9daffd05bff3a146a1916bec664e18bb76dd5f66cbff9fc13b2bbe languageName: node linkType: hard "css.escape@npm:^1.5.1": version: 1.5.1 resolution: "css.escape@npm:1.5.1" - checksum: 5e09035e5bf6c2c422b40c6df2eb1529657a17df37fda5d0433d722609527ab98090baf25b13970ca754079a0f3161dd3dfc0e743563ded8cfa0749d861c1525 + checksum: f6d38088d870a961794a2580b2b2af1027731bb43261cfdce14f19238a88664b351cc8978abc20f06cc6bbde725699dec8deb6fe9816b139fc3f2af28719e774 languageName: node linkType: hard @@ -6569,21 +7623,21 @@ __metadata: resolution: "csso@npm:4.2.0" dependencies: css-tree: "npm:^1.1.2" - checksum: f8c6b1300efaa0f8855a7905ae3794a29c6496e7f16a71dec31eb6ca7cfb1f058a4b03fd39b66c4deac6cb06bf6b4ba86da7b67d7320389cb9994d52b924b903 + checksum: 380ba9663da3bcea58dee358a0d8c4468bb6539be3c439dc266ac41c047217f52fd698fb7e4b6b6ccdfb8cf53ef4ceed8cc8ceccb8dfca2aa628319826b5b998 languageName: node linkType: hard "cssom@npm:^0.5.0": version: 0.5.0 resolution: "cssom@npm:0.5.0" - checksum: 8c4121c243baf0678c65dcac29b201ff0067dfecf978de9d5c83b2ff127a8fdefd2bfd54577f5ad8c80ed7d2c8b489ae01c82023545d010c4ecb87683fb403dd + checksum: 823471aa30091c59e0a305927c30e7768939b6af70405808f8d2ce1ca778cddcb24722717392438329d1691f9a87cb0183b64b8d779b56a961546d54854fde01 languageName: node linkType: hard "cssom@npm:~0.3.6": version: 0.3.8 resolution: "cssom@npm:0.3.8" - checksum: d74017b209440822f9e24d8782d6d2e808a8fdd58fa626a783337222fe1c87a518ba944d4c88499031b4786e68772c99dfae616638d71906fe9f203aeaf14411 + checksum: 24beb3087c76c0d52dd458be9ee1fbc80ac771478a9baef35dd258cdeb527c68eb43204dd439692bb2b1ae5272fa5f2946d10946edab0d04f1078f85e06bc7f6 languageName: node linkType: hard @@ -6592,21 +7646,21 @@ __metadata: resolution: "cssstyle@npm:2.3.0" dependencies: cssom: "npm:~0.3.6" - checksum: 863400da2a458f73272b9a55ba7ff05de40d850f22eb4f37311abebd7eff801cf1cd2fb04c4c92b8c3daed83fe766e52e4112afb7bc88d86c63a9c2256a7d178 + checksum: 5f05e6fd2e3df0b44695c2f08b9ef38b011862b274e320665176467c0725e44a53e341bc4959a41176e83b66064ab786262e7380fd1cabeae6efee0d255bb4e3 languageName: node linkType: hard "csstype@npm:^3.0.2": version: 3.1.2 resolution: "csstype@npm:3.1.2" - checksum: 32c038af259897c807ac738d9eab16b3d86747c72b09d5c740978e06f067f9b7b1737e1b75e407c7ab1fe1543dc95f20e202b4786aeb1b8d3bdf5d5ce655e6c6 + checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5 languageName: node linkType: hard "damerau-levenshtein@npm:^1.0.8": version: 1.0.8 resolution: "damerau-levenshtein@npm:1.0.8" - checksum: 4c2647e0f42acaee7d068756c1d396e296c3556f9c8314bac1ac63ffb236217ef0e7e58602b18bb2173deec7ec8e0cac8e27cccf8f5526666b4ff11a13ad54a3 + checksum: d240b7757544460ae0586a341a53110ab0a61126570ef2d8c731e3eab3f0cb6e488e2609e6a69b46727635de49be20b071688698744417ff1b6c1d7ccd03e0de languageName: node linkType: hard @@ -6617,7 +7671,7 @@ __metadata: abab: "npm:^2.0.6" whatwg-mimetype: "npm:^3.0.0" whatwg-url: "npm:^11.0.0" - checksum: 051c3aaaf3e961904f136aab095fcf6dff4db23a7fc759dd8ba7b3e6ba03fc07ef608086caad8ab910d864bd3b5e57d0d2f544725653d77c96a2c971567045f4 + checksum: 033fc3dd0fba6d24bc9a024ddcf9923691dd24f90a3d26f6545d6a2f71ec6956f93462f2cdf2183cc46f10dc01ed3bcb36731a8208456eb1a08147e571fe2a76 languageName: node linkType: hard @@ -6626,7 +7680,7 @@ __metadata: resolution: "date-fns@npm:2.30.0" dependencies: "@babel/runtime": "npm:^7.21.0" - checksum: e4b521fbf22bc8c3db332bbfb7b094fd3e7627de0259a9d17c7551e2d2702608a7307a449206065916538e384f37b181565447ce2637ae09828427aed9cb5581 + checksum: f7be01523282e9bb06c0cd2693d34f245247a29098527d4420628966a2d9aad154bd0e90a6b1cf66d37adcb769cd108cf8a7bd49d76db0fb119af5cdd13644f4 languageName: node linkType: hard @@ -6635,11 +7689,11 @@ __metadata: resolution: "debug@npm:2.6.9" dependencies: ms: "npm:2.0.0" - checksum: 121908fb839f7801180b69a7e218a40b5a0b718813b886b7d6bdb82001b931c938e2941d1e4450f33a1b1df1da653f5f7a0440c197f29fbf8a6e9d45ff6ef589 + checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6 languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -6647,7 +7701,7 @@ __metadata: peerDependenciesMeta: supports-color: optional: true - checksum: cedbec45298dd5c501d01b92b119cd3faebe5438c3917ff11ae1bff86a6c722930ac9c8659792824013168ba6db7c4668225d845c633fbdafbbf902a6389f736 + checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 languageName: node linkType: hard @@ -6656,28 +7710,28 @@ __metadata: resolution: "debug@npm:3.2.7" dependencies: ms: "npm:^2.1.1" - checksum: 37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a + checksum: b3d8c5940799914d30314b7c3304a43305fd0715581a919dacb8b3176d024a782062368405b47491516d2091d6462d4d11f2f4974a405048094f8bfebfa3071c languageName: node linkType: hard "decimal.js@npm:^10.4.2": version: 10.4.3 resolution: "decimal.js@npm:10.4.3" - checksum: 6d60206689ff0911f0ce968d40f163304a6c1bc739927758e6efc7921cfa630130388966f16bf6ef6b838cb33679fbe8e7a78a2f3c478afce841fd55ac8fb8ee + checksum: 796404dcfa9d1dbfdc48870229d57f788b48c21c603c3f6554a1c17c10195fc1024de338b0cf9e1efe0c7c167eeb18f04548979bcc5fdfabebb7cc0ae3287bae languageName: node linkType: hard "decode-uri-component@npm:^0.2.0": version: 0.2.2 resolution: "decode-uri-component@npm:0.2.2" - checksum: 1f4fa54eb740414a816b3f6c24818fbfcabd74ac478391e9f4e2282c994127db02010ce804f3d08e38255493cfe68608b3f5c8e09fd6efc4ae46c807691f7a31 + checksum: 95476a7d28f267292ce745eac3524a9079058bbb35767b76e3ee87d42e34cd0275d2eb19d9d08c3e167f97556e8a2872747f5e65cbebcac8b0c98d83e285f139 languageName: node linkType: hard "dedent@npm:^0.7.0": version: 0.7.0 resolution: "dedent@npm:0.7.0" - checksum: 7c3aa00ddfe3e5fcd477958e156156a5137e3bb6ff1493ca05edff4decf29a90a057974cc77e75951f8eb801c1816cb45aea1f52d628cdd000b82b36ab839d1b + checksum: 87de191050d9a40dd70cad01159a0bcf05ecb59750951242070b6abf9569088684880d00ba92a955b4058804f16eeaf91d604f283929b4f614d181cd7ae633d2 languageName: node linkType: hard @@ -6703,21 +7757,21 @@ __metadata: which-boxed-primitive: "npm:^1.0.2" which-collection: "npm:^1.0.1" which-typed-array: "npm:^1.1.9" - checksum: 07b46a9a848efdab223abc7e3ba612ef9168d88970c3400df185d5840a30ca384749c996ae5d7af844d6b27c42587fb73a4445c63e38aac77c2d0ed9a63faa87 + checksum: eb61c35157b6ecb96a5359b507b083fbff8ddb4c86a78a781ee38485f77a667465e45d63ee2ebd8a00e86d94c80e499906900cd82c2debb400237e1662cd5397 languageName: node linkType: hard "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" - checksum: 7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c + checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804 languageName: node linkType: hard "deepmerge@npm:^4.2.2": version: 4.3.1 resolution: "deepmerge@npm:4.3.1" - checksum: e53481aaf1aa2c4082b5342be6b6d8ad9dfe387bc92ce197a66dea08bd4265904a087e75e464f14d1347cf2ac8afe1e4c16b266e0561cc5df29382d3c5f80044 + checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 languageName: node linkType: hard @@ -6727,14 +7781,23 @@ __metadata: dependencies: bplist-parser: "npm:^0.2.0" untildify: "npm:^4.0.0" - checksum: 8db3ab882eb3e1e8b59d84c8641320e6c66d8eeb17eb4bb848b7dd549b1e6fd313988e4a13542e95fbaeff03f6e9dedc5ad191ad4df7996187753eb0d45c00b7 + checksum: 279c7ad492542e5556336b6c254a4eaf31b2c63a5433265655ae6e47301197b6cfb15c595a6fdc6463b2ff8e1a1a1ed3cba56038a60e1527ba4ab1628c6b9941 + languageName: node + linkType: hard + +"defaults@npm:^1.0.3": + version: 1.0.4 + resolution: "defaults@npm:1.0.4" + dependencies: + clone: ^1.0.2 + checksum: 3a88b7a587fc076b84e60affad8b85245c01f60f38fc1d259e7ac1d89eb9ce6abb19e27215de46b98568dd5bc48471730b327637e6f20b0f1bc85cf00440c80a languageName: node linkType: hard "define-lazy-prop@npm:^2.0.0": version: 2.0.0 resolution: "define-lazy-prop@npm:2.0.0" - checksum: db6c63864a9d3b7dc9def55d52764968a5af296de87c1b2cc71d8be8142e445208071953649e0386a8cc37cfcf9a2067a47207f1eb9ff250c2a269658fdae422 + checksum: 0115fdb065e0490918ba271d7339c42453d209d4cb619dfe635870d906731eff3e1ade8028bb461ea27ce8264ec5e22c6980612d332895977e89c1bbc80fcee2 languageName: node linkType: hard @@ -6744,7 +7807,7 @@ __metadata: dependencies: has-property-descriptors: "npm:^1.0.0" object-keys: "npm:^1.1.1" - checksum: 34b58cae4651936a3c8c720310ce393a3227f5123640ab5402e7d6e59bb44f8295b789cb5d74e7513682b2e60ff20586d6f52b726d964d617abffa3da76344e0 + checksum: e60aee6a19b102df4e2b1f301816804e81ab48bb91f00d0d935f269bf4b3f79c88b39e4f89eaa132890d23267335fd1140dfcd8d5ccd61031a0a2c41a54e33a6 languageName: node linkType: hard @@ -6753,7 +7816,7 @@ __metadata: resolution: "define-property@npm:0.2.5" dependencies: is-descriptor: "npm:^0.1.0" - checksum: 9986915c0893818dedc9ca23eaf41370667762fd83ad8aa4bf026a28563120dbaacebdfbfbf2b18d3b929026b9c6ee972df1dbf22de8fafb5fe6ef18361e4750 + checksum: 85af107072b04973b13f9e4128ab74ddfda48ec7ad2e54b193c0ffb57067c4ce5b7786a7b4ae1f24bd03e87c5d18766b094571810b314d7540f86d4354dbd394 languageName: node linkType: hard @@ -6762,7 +7825,7 @@ __metadata: resolution: "define-property@npm:1.0.0" dependencies: is-descriptor: "npm:^1.0.0" - checksum: d7cf09db10d55df305f541694ed51dafc776ad9bb8a24428899c9f2d36b11ab38dce5527a81458d1b5e7c389f8cbe803b4abad6e91a0037a329d153b84fc975e + checksum: 5fbed11dace44dd22914035ba9ae83ad06008532ca814d7936a53a09e897838acdad5b108dd0688cc8d2a7cf0681acbe00ee4136cf36743f680d10517379350a languageName: node linkType: hard @@ -6772,14 +7835,14 @@ __metadata: dependencies: is-descriptor: "npm:^1.0.2" isobject: "npm:^3.0.1" - checksum: f91a08ad008fa764172a2c072adc7312f10217ade89ddaea23018321c6d71b2b68b8c229141ed2064179404e345c537f1a2457c379824813695b51a6ad3e4969 + checksum: 3217ed53fc9eed06ba8da6f4d33e28c68a82e2f2a8ab4d562c4920d8169a166fe7271453675e6c69301466f36a65d7f47edf0cf7f474b9aa52a5ead9c1b13c99 languageName: node linkType: hard "defu@npm:^6.1.2": version: 6.1.2 resolution: "defu@npm:6.1.2" - checksum: ceb467f8f30d4000ae5300105904736113826a3d4124640b70e145b243d6c78c868de03634038d870e0855ff4cdfd17324a8caf7386229501a5bb776adb682f4 + checksum: 2ec0ff8414d5a1ab2b8c7e9a79bbad6d97d23ea7ebf5dcf80c3c7ffd9715c30f84a3cc47b917379ea756b3db0dc4701ce6400e493a1ae1688dffcd0f884233b2 languageName: node linkType: hard @@ -6795,56 +7858,63 @@ __metadata: p-map: "npm:^4.0.0" rimraf: "npm:^3.0.2" slash: "npm:^3.0.0" - checksum: 8a095c5ccade42c867a60252914ae485ec90da243d735d1f63ec1e64c1cfbc2b8810ad69a29ab6326d159d4fddaa2f5bad067808c42072351ec458efff86708f + checksum: 563288b73b8b19a7261c47fd21a330eeab6e2acd7c6208c49790dfd369127120dd7836cdf0c1eca216b77c94782a81507eac6b4734252d3bef2795cb366996b6 languageName: node linkType: hard "delayed-stream@npm:~1.0.0": version: 1.0.0 resolution: "delayed-stream@npm:1.0.0" - checksum: d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 + checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 languageName: node linkType: hard "delegates@npm:^1.0.0": version: 1.0.0 resolution: "delegates@npm:1.0.0" - checksum: ba05874b91148e1db4bf254750c042bf2215febd23a6d3cda2e64896aef79745fbd4b9996488bd3cafb39ce19dbce0fd6e3b6665275638befffe1c9b312b91b5 + checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd languageName: node linkType: hard "depd@npm:2.0.0, depd@npm:^2.0.0": version: 2.0.0 resolution: "depd@npm:2.0.0" - checksum: 58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c + checksum: abbe19c768c97ee2eed6282d8ce3031126662252c58d711f646921c9623f9052e3e1906443066beec1095832f534e57c523b7333f8e7e0d93051ab6baef5ab3a languageName: node linkType: hard "dequal@npm:^2.0.2, dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" - checksum: f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 + checksum: 8679b850e1a3d0ebbc46ee780d5df7b478c23f335887464023a631d1b9af051ad4a6595a44220f9ff8ff95a8ddccf019b5ad778a976fd7bbf77383d36f412f90 languageName: node linkType: hard "destroy@npm:1.2.0": version: 1.2.0 resolution: "destroy@npm:1.2.0" - checksum: bd7633942f57418f5a3b80d5cb53898127bcf53e24cdf5d5f4396be471417671f0fee48a4ebe9a1e9defbde2a31280011af58a57e090ff822f589b443ed4e643 + checksum: 0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 languageName: node linkType: hard "detect-indent@npm:^6.1.0": version: 6.1.0 resolution: "detect-indent@npm:6.1.0" - checksum: dd83cdeda9af219cf77f5e9a0dc31d828c045337386cfb55ce04fad94ba872ee7957336834154f7647b89b899c3c7acc977c57a79b7c776b506240993f97acc7 + checksum: ab953a73c72dbd4e8fc68e4ed4bfd92c97eb6c43734af3900add963fd3a9316f3bc0578b018b24198d4c31a358571eff5f0656e81a1f3b9ad5c547d58b2d093d languageName: node linkType: hard "detect-newline@npm:^3.0.0": version: 3.1.0 resolution: "detect-newline@npm:3.1.0" - checksum: c38cfc8eeb9fda09febb44bcd85e467c970d4e3bf526095394e5a4f18bc26dd0cf6b22c69c1fa9969261521c593836db335c2795218f6d781a512aea2fb8209d + checksum: ae6cd429c41ad01b164c59ea36f264a2c479598e61cba7c99da24175a7ab80ddf066420f2bec9a1c57a6bead411b4655ff15ad7d281c000a89791f48cbe939e7 + languageName: node + linkType: hard + +"detect-node-es@npm:^1.1.0": + version: 1.1.0 + resolution: "detect-node-es@npm:1.1.0" + checksum: e46307d7264644975b71c104b9f028ed1d3d34b83a15b8a22373640ce5ea630e5640b1078b8ea15f202b54641da71e4aa7597093bd4b91f113db520a26a37449 languageName: node linkType: hard @@ -6853,7 +7923,7 @@ __metadata: resolution: "detect-package-manager@npm:2.0.1" dependencies: execa: "npm:^5.1.1" - checksum: 56ffd65228d1ff3ead5ea7f8ab951a517a29270de27510b790c9a8b77d4f36efbd61493e170ca77ee3dc13cbb5218583ce65b78ad14a59dc48565c9bcbbf3c71 + checksum: e72b910182d5ad479198d4235be206ac64a479257b32201bb06f3c842cc34c65ea851d46f72cc1d4bf535bcc6c4b44b5b86bb29fe1192b8c9c07b46883672f28 languageName: node linkType: hard @@ -6866,14 +7936,14 @@ __metadata: bin: detect: bin/detect-port.js detect-port: bin/detect-port.js - checksum: f2b204ad3a9f8e8b53fea35fcc97469f31a8e3e786a2f59fbc886397e33b5f130c5f964bf001b9a64d990047c3824f6a439308461ff19801df04ab48a754639e + checksum: b48da9340481742547263d5d985e65d078592557863402ecf538511735e83575867e94f91fe74405ea19b61351feb99efccae7e55de9a151d5654e3417cea05b languageName: node linkType: hard "diff-sequences@npm:^29.4.3": version: 29.4.3 resolution: "diff-sequences@npm:29.4.3" - checksum: 183800b9fd8523a05a3a50ade0fafe81d4b8a8ac113b077d2bc298052ccdc081e3b896f19bf65768b536daebd8169a493c4764cb70a2195e14c442c12538d121 + checksum: 28b265e04fdddcf7f9f814effe102cc95a9dec0564a579b5aed140edb24fc345c611ca52d76d725a3cab55d3888b915b5e8a4702e0f6058968a90fa5f41fcde7 languageName: node linkType: hard @@ -6882,7 +7952,7 @@ __metadata: resolution: "dir-glob@npm:3.0.1" dependencies: path-type: "npm:^4.0.0" - checksum: dcac00920a4d503e38bb64001acb19df4efc14536ada475725e12f52c16777afdee4db827f55f13a908ee7efc0cb282e2e3dbaeeb98c0993dd93d1802d3bf00c + checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 languageName: node linkType: hard @@ -6891,7 +7961,7 @@ __metadata: resolution: "doctrine@npm:2.1.0" dependencies: esutils: "npm:^2.0.2" - checksum: b6416aaff1f380bf56c3b552f31fdf7a69b45689368deca72d28636f41c16bb28ec3ebc40ace97db4c1afc0ceeb8120e8492fe0046841c94c2933b2e30a7d5ac + checksum: a45e277f7feaed309fe658ace1ff286c6e2002ac515af0aaf37145b8baa96e49899638c7cd47dccf84c3d32abfc113246625b3ac8f552d1046072adee13b0dc8 languageName: node linkType: hard @@ -6900,14 +7970,14 @@ __metadata: resolution: "doctrine@npm:3.0.0" dependencies: esutils: "npm:^2.0.2" - checksum: c96bdccabe9d62ab6fea9399fdff04a66e6563c1d6fb3a3a063e8d53c3bb136ba63e84250bbf63d00086a769ad53aef92d2bd483f03f837fc97b71cbee6b2520 + checksum: fd7673ca77fe26cd5cba38d816bc72d641f500f1f9b25b83e8ce28827fe2da7ad583a8da26ab6af85f834138cf8dae9f69b0cd6ab925f52ddab1754db44d99ce languageName: node linkType: hard "dom-accessibility-api@npm:^0.5.6, dom-accessibility-api@npm:^0.5.9": version: 0.5.16 resolution: "dom-accessibility-api@npm:0.5.16" - checksum: b2c2eda4fae568977cdac27a9f0c001edf4f95a6a6191dfa611e3721db2478d1badc01db5bb4fa8a848aeee13e442a6c2a4386d65ec65a1436f24715a2f8d053 + checksum: 005eb283caef57fc1adec4d5df4dd49189b628f2f575af45decb210e04d634459e3f1ee64f18b41e2dcf200c844bc1d9279d80807e686a30d69a4756151ad248 languageName: node linkType: hard @@ -6917,7 +7987,7 @@ __metadata: dependencies: domelementtype: "npm:^2.0.1" entities: "npm:^2.0.0" - checksum: 5cb595fb77e1a23eca56742f47631e6f4af66ce1982c7ed28b3d0ef21f1f50304c067adc29d3eaf824c572be022cee88627d0ac9b929408f24e923f3c7bed37b + checksum: 376344893e4feccab649a14ca1a46473e9961f40fe62479ea692d4fee4d9df1c00ca8654811a79c1ca7b020096987e1ca4fb4d7f8bae32c1db800a680a0e5d5e languageName: node linkType: hard @@ -6928,7 +7998,7 @@ __metadata: domelementtype: "npm:^2.0.1" domhandler: "npm:^4.2.0" entities: "npm:^2.0.0" - checksum: 67d775fa1ea3de52035c98168ddcd59418356943b5eccb80e3c8b3da53adb8e37edb2cc2f885802b7b1765bf5022aec21dfc32910d7f9e6de4c3148f095ab5e0 + checksum: fbb0b01f87a8a2d18e6e5a388ad0f7ec4a5c05c06d219377da1abc7bb0f674d804f4a8a94e3f71ff15f6cb7dcfc75704a54b261db672b9b3ab03da6b758b0b22 languageName: node linkType: hard @@ -6939,21 +8009,21 @@ __metadata: domelementtype: "npm:^2.3.0" domhandler: "npm:^5.0.2" entities: "npm:^4.2.0" - checksum: d5ae2b7110ca3746b3643d3ef60ef823f5f078667baf530cec096433f1627ec4b6fa8c072f09d079d7cda915fd2c7bc1b7b935681e9b09e591e1e15f4040b8e2 + checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 languageName: node linkType: hard "domelementtype@npm:1, domelementtype@npm:^1.3.1": version: 1.3.1 resolution: "domelementtype@npm:1.3.1" - checksum: 6d4f5761060a21eaf3c96545501e9d188745c7e1c31b8d141bf15d8748feeadba868f4ea32877751b8678b286fb1afbe6ae905ca3fb8f0214d8322e482cdbec0 + checksum: 7893da40218ae2106ec6ffc146b17f203487a52f5228b032ea7aa470e41dfe03e1bd762d0ee0139e792195efda765434b04b43cddcf63207b098f6ae44b36ad6 languageName: node linkType: hard "domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0, domelementtype@npm:^2.3.0": version: 2.3.0 resolution: "domelementtype@npm:2.3.0" - checksum: 686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9 + checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 languageName: node linkType: hard @@ -6962,7 +8032,7 @@ __metadata: resolution: "domexception@npm:4.0.0" dependencies: webidl-conversions: "npm:^7.0.0" - checksum: 774277cd9d4df033f852196e3c0077a34dbd15a96baa4d166e0e47138a80f4c0bdf0d94e4703e6ff5883cec56bb821a6fff84402d8a498e31de7c87eb932a294 + checksum: ddbc1268edf33a8ba02ccc596735ede80375ee0cf124b30d2f05df5b464ba78ef4f49889b6391df4a04954e63d42d5631c7fcf8b1c4f12bc531252977a5f13d5 languageName: node linkType: hard @@ -6971,7 +8041,7 @@ __metadata: resolution: "domhandler@npm:5.0.3" dependencies: domelementtype: "npm:^2.3.0" - checksum: bba1e5932b3e196ad6862286d76adc89a0dbf0c773e5ced1eb01f9af930c50093a084eff14b8de5ea60b895c56a04d5de8bbc4930c5543d029091916770b2d2a + checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c languageName: node linkType: hard @@ -6980,7 +8050,7 @@ __metadata: resolution: "domhandler@npm:2.4.2" dependencies: domelementtype: "npm:1" - checksum: 6670cab73e97e3c6771dcf22b537db3f6a0be0ad6b370f03bb5f1b585d3b563d326787fdabe1190b7ca9d81c804e9b3f8a1431159c27c44f6c05f94afa92be2d + checksum: 49bd70c9c784f845cd047e1dfb3611bd10891c05719acfc93f01fc726a419ed09fbe0b69f9064392d556a63fffc5a02010856cedae9368f4817146d95a97011f languageName: node linkType: hard @@ -6989,7 +8059,7 @@ __metadata: resolution: "domhandler@npm:4.3.1" dependencies: domelementtype: "npm:^2.2.0" - checksum: 5c199c7468cb052a8b5ab80b13528f0db3d794c64fc050ba793b574e158e67c93f8336e87fd81e9d5ee43b0e04aea4d8b93ed7be4899cb726a1601b3ba18538b + checksum: 4c665ceed016e1911bf7d1dadc09dc888090b64dee7851cccd2fcf5442747ec39c647bb1cb8c8919f8bbdd0f0c625a6bafeeed4b2d656bbecdbae893f43ffaaa languageName: node linkType: hard @@ -6999,7 +8069,7 @@ __metadata: dependencies: dom-serializer: "npm:0" domelementtype: "npm:1" - checksum: 437fcd2d6d6be03f488152e73c6f953e289c58496baa22be9626b2b46f9cfd40486ae77d144487ff6b102929a3231cdb9a8bf8ef485fb7b7c30c985daedc77eb + checksum: f60a725b1f73c1ae82f4894b691601ecc6ecb68320d87923ac3633137627c7865725af813ae5d188ad3954283853bcf46779eb50304ec5d5354044569fcefd2b languageName: node linkType: hard @@ -7010,7 +8080,7 @@ __metadata: dom-serializer: "npm:^1.0.1" domelementtype: "npm:^2.2.0" domhandler: "npm:^4.2.0" - checksum: d58e2ae01922f0dd55894e61d18119924d88091837887bf1438f2327f32c65eb76426bd9384f81e7d6dcfb048e0f83c19b222ad7101176ad68cdc9c695b563db + checksum: abf7434315283e9aadc2a24bac0e00eab07ae4313b40cc239f89d84d7315ebdfd2fb1b5bf750a96bc1b4403d7237c7b2ebf60459be394d625ead4ca89b934391 languageName: node linkType: hard @@ -7021,21 +8091,21 @@ __metadata: dom-serializer: "npm:^2.0.0" domelementtype: "npm:^2.3.0" domhandler: "npm:^5.0.3" - checksum: 342d64cf4d07b8a0573fb51e0a6312a88fb520c7fefd751870bf72fa5fc0f2e0cb9a3958a573610b1d608c6e2a69b8e9b4b40f0bfb8f87a71bce4f180cca1887 + checksum: e5757456ddd173caa411cfc02c2bb64133c65546d2c4081381a3bafc8a57411a41eed70494551aa58030be9e58574fcc489828bebd673863d39924fb4878f416 languageName: node linkType: hard "dotenv-expand@npm:^10.0.0": version: 10.0.0 resolution: "dotenv-expand@npm:10.0.0" - checksum: 298f5018e29cfdcb0b5f463ba8e8627749103fbcf6cf81c561119115754ed582deee37b49dfc7253028aaba875ab7aea5fa90e5dac88e511d009ab0e6677924e + checksum: 2a38b470efe0abcb1ac8490421a55e1d764dc9440fd220942bce40965074f3fb00b585f4346020cb0f0f219966ee6b4ee5023458b3e2953fe5b3214de1b314ee languageName: node linkType: hard "dotenv@npm:^16.0.0": version: 16.3.1 resolution: "dotenv@npm:16.3.1" - checksum: b95ff1bbe624ead85a3cd70dbd827e8e06d5f05f716f2d0cbc476532d54c7c9469c3bc4dd93ea519f6ad711cb522c00ac9a62b6eb340d5affae8008facc3fbd7 + checksum: 15d75e7279018f4bafd0ee9706593dd14455ddb71b3bcba9c52574460b7ccaf67d5cf8b2c08a5af1a9da6db36c956a04a1192b101ee102a3e0cf8817bbcf3dfd languageName: node linkType: hard @@ -7047,21 +8117,21 @@ __metadata: inherits: "npm:^2.0.1" readable-stream: "npm:^2.0.0" stream-shift: "npm:^1.0.0" - checksum: 59d1440c1b4e3a4db35ae96933392703ce83518db1828d06b9b6322920d6cbbf0b7159e88be120385fe459e77f1eb0c7622f26e9ec1f47c9ff05c2b35747dbd3 + checksum: 3c2ed2223d956a5da713dae12ba8295acb61d9acd966ccbba938090d04f4574ca4dca75cca089b5077c2d7e66101f32e6ea9b36a78ca213eff574e7a8b8accf2 languageName: node linkType: hard "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" - checksum: 26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 + checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed languageName: node linkType: hard "ee-first@npm:1.1.1": version: 1.1.1 resolution: "ee-first@npm:1.1.1" - checksum: b5bb125ee93161bc16bfe6e56c6b04de5ad2aa44234d8f644813cc95d861a6910903132b05093706de2b706599367c4130eb6d170f6b46895686b95f87d017b7 + checksum: 1b4cac778d64ce3b582a7e26b218afe07e207a0f9bfe13cc7395a6d307849cfe361e65033c3251e00c27dd060cab43014c2d6b2647676135e18b77d2d05b3f4f languageName: node linkType: hard @@ -7072,49 +8142,56 @@ __metadata: jake: "npm:^10.8.5" bin: ejs: bin/cli.js - checksum: f0e249c79128810f5f6d5cbf347fc906d86bb9384263db0b2a9004aea649f2bc2d112736de5716c509c80afb4721c47281bd5b57c757d3b63f1bf5ac5f885893 + checksum: af6f10eb815885ff8a8cfacc42c6b6cf87daf97a4884f87a30e0c3271fedd85d76a3a297d9c33a70e735b97ee632887f85e32854b9cdd3a2d97edf931519a35f languageName: node linkType: hard "electron-to-chromium@npm:^1.4.431": version: 1.4.459 resolution: "electron-to-chromium@npm:1.4.459" - checksum: e2618145abddef596accfcc70280904876cccdcbc4178c1e0c6af5070c1fb5bc1b0a084422ec19d6d59a435d1d4a1f9abf00f1e8e546130737bbe4fd0006d0ff + checksum: 2052797a639c131e459c7d8261506b52b277c3e9c0622a1171dcc9b9dc2293c3b2b43260687d320e89a2a82264521135a525c4ed97beba43f5507583d8c0d532 + languageName: node + linkType: hard + +"electron-to-chromium@npm:^1.4.601": + version: 1.4.634 + resolution: "electron-to-chromium@npm:1.4.634" + checksum: 5fdaf23ab5162f6cceb115d2151345b9b9258ee4e7635a489c665fd7ccd5b4291ee1eb9017fbab876dadaf9fbea311c3e4c3d7b5b6de75049e76d9960d15583c languageName: node linkType: hard "emittery@npm:^0.13.1": version: 0.13.1 resolution: "emittery@npm:0.13.1" - checksum: 1573d0ae29ab34661b6c63251ff8f5facd24ccf6a823f19417ae8ba8c88ea450325788c67f16c99edec8de4b52ce93a10fe441ece389fd156e88ee7dab9bfa35 + checksum: 2b089ab6306f38feaabf4f6f02792f9ec85fc054fda79f44f6790e61bbf6bc4e1616afb9b232e0c5ec5289a8a452f79bfa6d905a6fd64e94b49981f0934001c6 languageName: node linkType: hard "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" - checksum: b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 + checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 languageName: node linkType: hard "emoji-regex@npm:^9.2.2": version: 9.2.2 resolution: "emoji-regex@npm:9.2.2" - checksum: af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 + checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 languageName: node linkType: hard "emojis-list@npm:^3.0.0": version: 3.0.0 resolution: "emojis-list@npm:3.0.0" - checksum: 7dc4394b7b910444910ad64b812392159a21e1a7ecc637c775a440227dcb4f80eff7fe61f4453a7d7603fa23d23d30cc93fe9e4b5ed985b88d6441cd4a35117b + checksum: ddaaa02542e1e9436c03970eeed445f4ed29a5337dfba0fe0c38dfdd2af5da2429c2a0821304e8a8d1cadf27fdd5b22ff793571fa803ae16852a6975c65e8e70 languageName: node linkType: hard "encodeurl@npm:~1.0.2": version: 1.0.2 resolution: "encodeurl@npm:1.0.2" - checksum: f6c2387379a9e7c1156c1c3d4f9cb7bb11cf16dd4c1682e1f6746512564b053df5781029b6061296832b59fb22f459dbe250386d217c2f6e203601abb2ee0bec + checksum: e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c languageName: node linkType: hard @@ -7123,7 +8200,7 @@ __metadata: resolution: "encoding@npm:0.1.13" dependencies: iconv-lite: "npm:^0.6.2" - checksum: 36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 + checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f languageName: node linkType: hard @@ -7132,35 +8209,35 @@ __metadata: resolution: "end-of-stream@npm:1.4.4" dependencies: once: "npm:^1.4.0" - checksum: 870b423afb2d54bb8d243c63e07c170409d41e20b47eeef0727547aea5740bd6717aca45597a9f2745525667a6b804c1e7bede41f856818faee5806dd9ff3975 + checksum: 530a5a5a1e517e962854a31693dbb5c0b2fc40b46dad2a56a2deec656ca040631124f4795823acc68238147805f8b021abbe221f4afed5ef3c8e8efc2024908b languageName: node linkType: hard "entities@npm:^1.1.1": version: 1.1.2 resolution: "entities@npm:1.1.2" - checksum: 5b12fa8c4fb942f88af6f8791bbe7be0a59ebd91c8933cee091d94455efd1eeb200418c7b1bc8dd0f74cdd4db8cf4538eb043db14cfd1919130c25d8c6095215 + checksum: d537b02799bdd4784ffd714d000597ed168727bddf4885da887c5a491d735739029a00794f1998abbf35f3f6aeda32ef5c15010dca1817d401903a501b6d3e05 languageName: node linkType: hard "entities@npm:^2.0.0": version: 2.2.0 resolution: "entities@npm:2.2.0" - checksum: 7fba6af1f116300d2ba1c5673fc218af1961b20908638391b4e1e6d5850314ee2ac3ec22d741b3a8060479911c99305164aed19b6254bde75e7e6b1b2c3f3aa3 + checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 languageName: node linkType: hard "entities@npm:^4.2.0, entities@npm:^4.4.0, entities@npm:^4.5.0": version: 4.5.0 resolution: "entities@npm:4.5.0" - checksum: 5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 + checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 languageName: node linkType: hard "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" - checksum: 285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 + checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e languageName: node linkType: hard @@ -7169,14 +8246,14 @@ __metadata: resolution: "envinfo@npm:7.10.0" bin: envinfo: dist/cli.js - checksum: ebc7792fbedca72bc829913abe0c2a3384b883903012f97b56085afd4e83d26f7dd0652403fedd99cd3e1c93d4fb0706f5d2c3dc06ac6a1eda348280a06a9dcf + checksum: 05e81a5768c42cbd5c580dc3f274db3401facadd53e9bd52e2aa49dfbb5d8b26f6181c25a6652d79618a6994185bd2b1c137673101690b147f758e4e71d42f7d languageName: node linkType: hard "err-code@npm:^2.0.2": version: 2.0.3 resolution: "err-code@npm:2.0.3" - checksum: b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 + checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 languageName: node linkType: hard @@ -7185,7 +8262,7 @@ __metadata: resolution: "error-ex@npm:1.3.2" dependencies: is-arrayish: "npm:^0.2.1" - checksum: ba827f89369b4c93382cfca5a264d059dfefdaa56ecc5e338ffa58a6471f5ed93b71a20add1d52290a4873d92381174382658c885ac1a2305f7baca363ce9cce + checksum: c1c2b8b65f9c91b0f9d75f0debaa7ec5b35c266c2cac5de412c1a6de86d4cbae04ae44e510378cb14d032d0645a36925d0186f8bb7367bcc629db256b743a001 languageName: node linkType: hard @@ -7228,7 +8305,7 @@ __metadata: typed-array-length: "npm:^1.0.4" unbox-primitive: "npm:^1.0.2" which-typed-array: "npm:^1.1.10" - checksum: 0bbb09d119e2c53f28b101a61692af3e02673ce50b03f05909677a6327f7e4ee2cce193877c0173500ca751bad60e27e597f221aa33460849d1f5e6abcb5de5b + checksum: 4c5ee900699030a629fc224a3595dcd05f9ff31d607e72bc9042d15e3b1bfde99f408c940b622e96439e755a7b23a3b9e47f3be234015750d32dad38b8f772f4 languageName: node linkType: hard @@ -7245,14 +8322,14 @@ __metadata: is-string: "npm:^1.0.7" isarray: "npm:^2.0.5" stop-iteration-iterator: "npm:^1.0.0" - checksum: ebd11effa79851ea75d7f079405f9d0dc185559fd65d986c6afea59a0ff2d46c2ed8675f19f03dce7429d7f6c14ff9aede8d121fbab78d75cfda6a263030bac0 + checksum: 8fa118da42667a01a7c7529f8a8cca514feeff243feec1ce0bb73baaa3514560bd09d2b3438873cf8a5aaec5d52da248131de153b28e2638a061b6e4df13267d languageName: node linkType: hard "es-module-lexer@npm:^0.9.3": version: 0.9.3 resolution: "es-module-lexer@npm:0.9.3" - checksum: be77d73aee709fdc68d22b9938da81dfee3bc45e8d601629258643fe5bfdab253d6e2540035e035cfa8cf52a96366c1c19b46bcc23b4507b1d44e5907d2e7f6c + checksum: 84bbab23c396281db2c906c766af58b1ae2a1a2599844a504df10b9e8dc77ec800b3211fdaa133ff700f5703d791198807bba25d9667392d27a5e9feda344da8 languageName: node linkType: hard @@ -7263,7 +8340,7 @@ __metadata: get-intrinsic: "npm:^1.1.3" has: "npm:^1.0.3" has-tostringtag: "npm:^1.0.0" - checksum: 9af096365e3861bb29755cc5f76f15f66a7eab0e83befca396129090c1d9737e54090278b8e5357e97b5f0a5b0459fca07c40c6740884c2659cbf90ef8e508cc + checksum: ec416a12948cefb4b2a5932e62093a7cf36ddc3efd58d6c58ca7ae7064475ace556434b869b0bbeb0c365f1032a8ccd577211101234b69837ad83ad204fff884 languageName: node linkType: hard @@ -7272,7 +8349,7 @@ __metadata: resolution: "es-shim-unscopables@npm:1.0.0" dependencies: has: "npm:^1.0.3" - checksum: d54a66239fbd19535b3e50333913260394f14d2d7adb136a95396a13ca584bab400cf9cb2ffd9232f3fe2f0362540bd3a708240c493e46e13fe0b90cfcfedc3d + checksum: 83e95cadbb6ee44d3644dfad60dcad7929edbc42c85e66c3e99aefd68a3a5c5665f2686885cddb47dfeabfd77bd5ea5a7060f2092a955a729bbd8834f0d86fa1 languageName: node linkType: hard @@ -7283,61 +8360,61 @@ __metadata: is-callable: "npm:^1.1.4" is-date-object: "npm:^1.0.1" is-symbol: "npm:^1.0.2" - checksum: 0886572b8dc075cb10e50c0af62a03d03a68e1e69c388bd4f10c0649ee41b1fbb24840a1b7e590b393011b5cdbe0144b776da316762653685432df37d6de60f1 + checksum: 4ead6671a2c1402619bdd77f3503991232ca15e17e46222b0a41a5d81aebc8740a77822f5b3c965008e631153e9ef0580540007744521e72de8e33599fca2eed languageName: node linkType: hard "es6-object-assign@npm:^1.1.0": version: 1.1.0 resolution: "es6-object-assign@npm:1.1.0" - checksum: 11c165ae16866aca897dee9b689402f0e871589e859809343ef9e0fdd067133684db16fd15abdba2a99e7319222b9f43e6b747baabb909cee9d0ecbac8deebee + checksum: 8d4fdf63484d78b5c64cacc2c2e1165bc7b6a64b739d2a9db6a4dc8641d99cc9efb433cdd4dc3d3d6b00bfa6ce959694e4665e3255190339945c5f33b692b5d8 languageName: node linkType: hard "esbuild-plugin-alias@npm:^0.2.1": version: 0.2.1 resolution: "esbuild-plugin-alias@npm:0.2.1" - checksum: a67bc6bc2744fc8637f7321f00c1f00e4fae86c182662421738ebfabf3ad344967b9c667185c6c34d9edd5b289807d34bfdceef94620e94e0a45683534af69e0 + checksum: afe2d2c8b5f09d5321cb8d9c0825e8a9f6e03c2d50df92f953a291d4620cc29eddb3da9e33b238f6d8f77738e0277bdcb831f127399449fecf78fb84c04e5da9 languageName: node linkType: hard -"esbuild-register@npm:^3.4.0": - version: 3.4.2 - resolution: "esbuild-register@npm:3.4.2" +"esbuild-register@npm:^3.5.0": + version: 3.5.0 + resolution: "esbuild-register@npm:3.5.0" dependencies: - debug: "npm:^4.3.4" + debug: ^4.3.4 peerDependencies: esbuild: ">=0.12 <1" - checksum: a7cb278126cf46fee04dad05e362c47e586aaa4bbaa43fc74931f85929b756077a01ee30ebec05c4096c915a980d2d2e75ec7df55685de5a58fa90595a0a1153 - languageName: node - linkType: hard - -"esbuild@npm:^0.17.0": - version: 0.17.19 - resolution: "esbuild@npm:0.17.19" - dependencies: - "@esbuild/android-arm": "npm:0.17.19" - "@esbuild/android-arm64": "npm:0.17.19" - "@esbuild/android-x64": "npm:0.17.19" - "@esbuild/darwin-arm64": "npm:0.17.19" - "@esbuild/darwin-x64": "npm:0.17.19" - "@esbuild/freebsd-arm64": "npm:0.17.19" - "@esbuild/freebsd-x64": "npm:0.17.19" - "@esbuild/linux-arm": "npm:0.17.19" - "@esbuild/linux-arm64": "npm:0.17.19" - "@esbuild/linux-ia32": "npm:0.17.19" - "@esbuild/linux-loong64": "npm:0.17.19" - "@esbuild/linux-mips64el": "npm:0.17.19" - "@esbuild/linux-ppc64": "npm:0.17.19" - "@esbuild/linux-riscv64": "npm:0.17.19" - "@esbuild/linux-s390x": "npm:0.17.19" - "@esbuild/linux-x64": "npm:0.17.19" - "@esbuild/netbsd-x64": "npm:0.17.19" - "@esbuild/openbsd-x64": "npm:0.17.19" - "@esbuild/sunos-x64": "npm:0.17.19" - "@esbuild/win32-arm64": "npm:0.17.19" - "@esbuild/win32-ia32": "npm:0.17.19" - "@esbuild/win32-x64": "npm:0.17.19" + checksum: f4307753c9672a2c901d04a1165031594a854f0a4c6f4c1db08aa393b68a193d38f2df483dc8ca0513e89f7b8998415e7e26fb9830989fb8cdccc5fb5f181c6b + languageName: node + linkType: hard + +"esbuild@npm:^0.18.0": + version: 0.18.20 + resolution: "esbuild@npm:0.18.20" + dependencies: + "@esbuild/android-arm": 0.18.20 + "@esbuild/android-arm64": 0.18.20 + "@esbuild/android-x64": 0.18.20 + "@esbuild/darwin-arm64": 0.18.20 + "@esbuild/darwin-x64": 0.18.20 + "@esbuild/freebsd-arm64": 0.18.20 + "@esbuild/freebsd-x64": 0.18.20 + "@esbuild/linux-arm": 0.18.20 + "@esbuild/linux-arm64": 0.18.20 + "@esbuild/linux-ia32": 0.18.20 + "@esbuild/linux-loong64": 0.18.20 + "@esbuild/linux-mips64el": 0.18.20 + "@esbuild/linux-ppc64": 0.18.20 + "@esbuild/linux-riscv64": 0.18.20 + "@esbuild/linux-s390x": 0.18.20 + "@esbuild/linux-x64": 0.18.20 + "@esbuild/netbsd-x64": 0.18.20 + "@esbuild/openbsd-x64": 0.18.20 + "@esbuild/sunos-x64": 0.18.20 + "@esbuild/win32-arm64": 0.18.20 + "@esbuild/win32-ia32": 0.18.20 + "@esbuild/win32-x64": 0.18.20 dependenciesMeta: "@esbuild/android-arm": optional: true @@ -7385,7 +8462,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: c7ac14bfaaebe4745d5d18347b4f6854fd1140acb9389e88dbfa5c20d4e2122451d9647d5498920470a880a605d6e5502b5c2102da6c282b01f129ddd49d2874 + checksum: 5d253614e50cdb6ec22095afd0c414f15688e7278a7eb4f3720a6dd1306b0909cf431e7b9437a90d065a31b1c57be60130f63fe3e8d0083b588571f31ee6ec7b languageName: node linkType: hard @@ -7462,46 +8539,46 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 338b41e008edb0dd7afee6e3454b4be031da55ead1b7c19fddd15088047fc73b5da7199089a7b04461f1589952471a695fe3b03812cc1e579b783b10c56bccca + checksum: 9d5aac77f637bf69f161dbf900f91cdec38c4bd47562b81302a2f790781fc1430f17790ee934058fa18379673c2987b0310fa61e8ccefb37065b8cc79956f099 languageName: node linkType: hard "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" - checksum: afd02e6ca91ffa813e1108b5e7756566173d6bc0d1eb951cb44d6b21702ec17c1cf116cfe75d4a2b02e05acb0b808a7a9387d0d1ca5cf9c04ad03a8445c3e46d + checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 languageName: node linkType: hard "escape-html@npm:~1.0.3": version: 1.0.3 resolution: "escape-html@npm:1.0.3" - checksum: 524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3 + checksum: 6213ca9ae00d0ab8bccb6d8d4e0a98e76237b2410302cf7df70aaa6591d509a2a37ce8998008cbecae8fc8ffaadf3fb0229535e6a145f3ce0b211d060decbb24 languageName: node linkType: hard "escape-string-regexp@npm:1.0.5, escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" - checksum: a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371 + checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 languageName: node linkType: hard "escape-string-regexp@npm:^2.0.0": version: 2.0.0 resolution: "escape-string-regexp@npm:2.0.0" - checksum: 2530479fe8db57eace5e8646c9c2a9c80fa279614986d16dcc6bcaceb63ae77f05a851ba6c43756d816c61d7f4534baf56e3c705e3e0d884818a46808811c507 + checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 languageName: node linkType: hard "escape-string-regexp@npm:^4.0.0": version: 4.0.0 resolution: "escape-string-regexp@npm:4.0.0" - checksum: 9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 + checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 languageName: node linkType: hard -"escodegen@npm:^2.0.0": +"escodegen@npm:^2.0.0, escodegen@npm:^2.1.0": version: 2.1.0 resolution: "escodegen@npm:2.1.0" dependencies: @@ -7515,7 +8592,7 @@ __metadata: bin: escodegen: bin/escodegen.js esgenerate: bin/esgenerate.js - checksum: e1450a1f75f67d35c061bf0d60888b15f62ab63aef9df1901cffc81cffbbb9e8b3de237c5502cf8613a017c1df3a3003881307c78835a1ab54d8c8d2206e01d3 + checksum: 096696407e161305cd05aebb95134ad176708bc5cb13d0dcc89a5fcbb959b8ed757e7f2591a5f8036f8f4952d4a724de0df14cd419e29212729fa6df5ce16bf6 languageName: node linkType: hard @@ -7526,7 +8603,7 @@ __metadata: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: 9e3bb602184b7ec59239d2f901b1594cd7cc59ff38c3ddcd812137817e50840f4d65d62b61c515c7eae86d85f8b6fb2ebda659a3f83b2f2c5da75feb15531508 + checksum: 1e94c3882c4d5e41e1dcfa2c368dbccbfe3134f6ac7d40101644d3bfbe3eb2f2ffac757f3145910b5eacf20c0e85e02b91293d3126d770cbf3dc390b3564681c languageName: node linkType: hard @@ -7537,7 +8614,7 @@ __metadata: debug: "npm:^3.2.7" is-core-module: "npm:^2.11.0" resolve: "npm:^1.22.1" - checksum: 39c562b59ec8dfd6b85ffa52273dbf0edb661b616463e2c453c60b2398b0a76f268f15f949a1648046c9c996d29599b57f6266df4b5d3562bff1088ded3672d5 + checksum: 3379aacf1d2c6952c1b9666c6fa5982c3023df695430b0d391c0029f6403a7775414873d90f397e98ba6245372b6c8960e16e74d9e4a3b0c0a4582f3bdbe3d6e languageName: node linkType: hard @@ -7549,7 +8626,7 @@ __metadata: peerDependenciesMeta: eslint: optional: true - checksum: c7a8d1a58d76ec8217a8fea49271ec8132d1b9390965a75f6a4ecbc9e5983d742195b46d2e4378231d2186801439fe1aa5700714b0bfd4eb17aac6e1b65309df + checksum: 74c6dfea7641ebcfe174be61168541a11a14aa8d72e515f5f09af55cd0d0862686104b0524aa4b8e0ce66418a44aa38a94d2588743db5fd07a6b49ffd16921d2 languageName: node linkType: hard @@ -7574,7 +8651,7 @@ __metadata: tsconfig-paths: "npm:^3.14.1" peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: e561e79889ad3c662e305ca9a9b273a5baf8f492dad8198e42987efc4f0532c0d49caee206e78e057cec3365b36f9cef8340915e9f08adec5f29c9d631e6f691 + checksum: f500571a380167e25d72a4d925ef9a7aae8899eada57653e5f3051ec3d3c16d08271fcefe41a30a9a2f4fefc232f066253673ee4ea77b30dba65ae173dade85d languageName: node linkType: hard @@ -7600,7 +8677,7 @@ __metadata: semver: "npm:^6.3.0" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: 41ad3d0c8036b36cd475685c1ad639157f403b16e8ac23c07f1dbe0226ccf8458f2805cbd5cc8e56856a5d8a356f3276e3139274d819476ccad80c41b9245502 + checksum: f166dd5fe7257c7b891c6692e6a3ede6f237a14043ae3d97581daf318fc5833ddc6b4871aa34ab7656187430170500f6d806895747ea17ecdf8231a666c3c2fd languageName: node linkType: hard @@ -7615,7 +8692,7 @@ __metadata: peerDependenciesMeta: eslint-config-prettier: optional: true - checksum: c5e7316baeab9d96ac39c279f16686e837277e5c67a8006c6588bcff317edffdc1532fb580441eb598bc6770f6444006756b68a6575dff1cd85ebe227252d0b7 + checksum: b9e839d2334ad8ec7a5589c5cb0f219bded260839a857d7a486997f9870e95106aa59b8756ff3f37202085ebab658de382b0267cae44c3a7f0eb0bcc03a4f6d6 languageName: node linkType: hard @@ -7624,7 +8701,7 @@ __metadata: resolution: "eslint-plugin-react-hooks@npm:4.6.0" peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 58c7e10ea5792c33346fcf5cb4024e14837035ce412ff99c2dcb7c4f903dc9b17939078f80bfef826301ce326582c396c00e8e0ac9d10ac2cde2b42d33763c65 + checksum: 23001801f14c1d16bf0a837ca7970d9dd94e7b560384b41db378b49b6e32dc43d6e2790de1bd737a652a86f81a08d6a91f402525061b47719328f586a57e86c3 languageName: node linkType: hard @@ -7633,7 +8710,7 @@ __metadata: resolution: "eslint-plugin-react-refresh@npm:0.3.4" peerDependencies: eslint: ">=7" - checksum: 95fb7e887851655c34fd0ea990955e3f8fd4409d9f50afb4c6e2e17d45a51699042d5a5dcfd7d6a249ddb26f9c0463bbead4f339272d405379f2ce11ce005449 + checksum: cfed1cc698da5e2c58d3c1e5868eb579e985418f10bbf5da84d6c4923499ce544c4d152c6fa6fa02ffcc02c248a1da77190741ab923075ee6cab181268ad6652 languageName: node linkType: hard @@ -7658,7 +8735,7 @@ __metadata: string.prototype.matchall: "npm:^4.0.8" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: 9ddd5cfc508555a5cb3edbdcc9138dd472d269d3a45da0be3e267ea2b3fa1b5990823675208c0e11376c9c55e46aaad5b7a5f46c965eb4dcf6f1eebcebf174c3 + checksum: 2232b3b8945aa50b7773919c15cd96892acf35d2f82503667a79e2f55def90f728ed4f0e496f0f157acbe1bd4397c5615b676ae7428fe84488a544ca53feb944 languageName: node linkType: hard @@ -7671,7 +8748,7 @@ __metadata: lodash: "npm:^4.17.15" peerDependencies: eslint: ">=0.8.0" - checksum: 848ff1a4007cf4ad4c566373b1c80b260f65d41cbaa01c787c82c2690b7242e60f4777518015f000b5a88bd087280d3b70efd2265d67f247359937adc33af727 + checksum: 2ab85337774910de86586581f76bf10e40f83be4e0971d2f6f5a31b658ed3bb003528bedd25d70b07e2942e8418cd0009bf6eeab829eb7cbf2108e13afa83f35 languageName: node linkType: hard @@ -7685,7 +8762,7 @@ __metadata: ts-dedent: "npm:^2.2.0" peerDependencies: eslint: ">=6" - checksum: b6a4da70ce4c13cfcbe80a4049d07f36ff4e5b0f9b21452c9df98d28ffb603498cd3d518672d36fb1abffe0f1b97f39aa9c1284042d03ed233ab796c66f2e581 + checksum: 8e0e160c71216019c291a5a03b797b5359076067d16ea03b3dec63594093d45398f028d15c47eb89f2ddb6e8db18cc7e376b02d921dacc4fb31bbc8da46363c8 languageName: node linkType: hard @@ -7695,7 +8772,7 @@ __metadata: dependencies: esrecurse: "npm:^4.3.0" estraverse: "npm:^4.1.1" - checksum: d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a + checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb languageName: node linkType: hard @@ -7705,14 +8782,14 @@ __metadata: dependencies: esrecurse: "npm:^4.3.0" estraverse: "npm:^5.2.0" - checksum: 5b48a3cc2485a3a58ca0bdecfb557c349009308a9b2afb24d070b1c0c254d445ee86d78bfee2c4ed6d1b8944307604a987c92f6d7e611e29de5d06256747a0ff + checksum: 64591a2d8b244ade9c690b59ef238a11d5c721a98bcee9e9f445454f442d03d3e04eda88e95a4daec558220a99fa384309d9faae3d459bd40e7a81b4063980ae languageName: node linkType: hard "eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.0, eslint-visitor-keys@npm:^3.4.1": version: 3.4.1 resolution: "eslint-visitor-keys@npm:3.4.1" - checksum: b4ebd35aed5426cd81b1fb92487825f1acf47a31e91d76597a3ee0664d69627140c4dafaf9b319cfeb1f48c1113a393e21a734c669e6565a72e6fcc311bd9911 + checksum: f05121d868202736b97de7d750847a328fcfa8593b031c95ea89425333db59676ac087fa905eba438d0a3c5769632f828187e0c1a0d271832a2153c1d3661c2c languageName: node linkType: hard @@ -7762,7 +8839,7 @@ __metadata: text-table: "npm:^0.2.0" bin: eslint: bin/eslint.js - checksum: 1aeba0106770bd29834bb01550c72fa0ebea851ceeaef61d2860ecb455391992b316f222600939f11d12db2a7ea6fb9443f4aa137566f98f9f26af9fa40b96b5 + checksum: 73b6d9b650d0434aa7c07d0a1802f099b086ee70a8d8ba7be730439a26572a5eb71def12125c82942be2ec8ee5be38a6f1b42a13e40d4b67f11a148ec9e263eb languageName: node linkType: hard @@ -7773,7 +8850,7 @@ __metadata: acorn: "npm:^8.9.0" acorn-jsx: "npm:^5.3.2" eslint-visitor-keys: "npm:^3.4.1" - checksum: f064a43bcf7f435d34e600c056320dde1c15b3eeb5da24e7585ed6cf83adcbbeafb4fa4d062ff14281b0d246b0a9645dd9d3796a638099f19595004eee4ac8be + checksum: 1287979510efb052a6a97c73067ea5d0a40701b29adde87bbe2d3eb1667e39ca55e8129e20e2517fed3da570150e7ef470585228459a8f3e3755f45007a1c662 languageName: node linkType: hard @@ -7783,7 +8860,7 @@ __metadata: bin: esparse: ./bin/esparse.js esvalidate: ./bin/esvalidate.js - checksum: ad4bab9ead0808cf56501750fd9d3fb276f6b105f987707d059005d57e182d18a7c9ec7f3a01794ebddcca676773e42ca48a32d67a250c9d35e009ca613caba3 + checksum: b45bc805a613dbea2835278c306b91aff6173c8d034223fa81498c77dcbce3b2931bf6006db816f62eacd9fd4ea975dfd85a5b7f3c6402cfd050d4ca3c13a628 languageName: node linkType: hard @@ -7792,7 +8869,7 @@ __metadata: resolution: "esquery@npm:1.5.0" dependencies: estraverse: "npm:^5.1.0" - checksum: a084bd049d954cc88ac69df30534043fb2aee5555b56246493f42f27d1e168f00d9e5d4192e46f10290d312dc30dc7d58994d61a609c579c1219d636996f9213 + checksum: aefb0d2596c230118656cd4ec7532d447333a410a48834d80ea648b1e7b5c9bc9ed8b5e33a89cb04e487b60d622f44cf5713bf4abed7c97343edefdc84a35900 languageName: node linkType: hard @@ -7801,53 +8878,42 @@ __metadata: resolution: "esrecurse@npm:4.3.0" dependencies: estraverse: "npm:^5.2.0" - checksum: 81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 + checksum: ebc17b1a33c51cef46fdc28b958994b1dc43cd2e86237515cbc3b4e5d2be6a811b2315d0a1a4d9d340b6d2308b15322f5c8291059521cc5f4802f65e7ec32837 languageName: node linkType: hard "estraverse@npm:^4.1.1": version: 4.3.0 resolution: "estraverse@npm:4.3.0" - checksum: 9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d + checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827 languageName: node linkType: hard "estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" - checksum: 1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 - languageName: node - linkType: hard - -"estree-to-babel@npm:^3.1.0": - version: 3.2.1 - resolution: "estree-to-babel@npm:3.2.1" - dependencies: - "@babel/traverse": "npm:^7.1.6" - "@babel/types": "npm:^7.2.0" - c8: "npm:^7.6.0" - checksum: c7949b141f569528b2608ab715d593a04f7e2e529df04e0b595d0a7dea819b410e71d1f04716e43ac1480942afc5701cb5151ad2906ee8402969651a389881bb + checksum: 072780882dc8416ad144f8fe199628d2b3e7bbc9989d9ed43795d2c90309a2047e6bc5979d7e2322a341163d22cfad9e21f4110597fe487519697389497e4e2b languageName: node linkType: hard "estree-walker@npm:^2.0.1, estree-walker@npm:^2.0.2": version: 2.0.2 resolution: "estree-walker@npm:2.0.2" - checksum: 53a6c54e2019b8c914dc395890153ffdc2322781acf4bd7d1a32d7aedc1710807bdcd866ac133903d5629ec601fbb50abe8c2e5553c7f5a0afdd9b6af6c945af + checksum: 6151e6f9828abe2259e57f5fd3761335bb0d2ebd76dc1a01048ccee22fabcfef3c0859300f6d83ff0d1927849368775ec5a6d265dde2f6de5a1be1721cd94efc languageName: node linkType: hard "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" - checksum: 9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 + checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 languageName: node linkType: hard "etag@npm:~1.8.1": version: 1.8.1 resolution: "etag@npm:1.8.1" - checksum: 12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84 + checksum: 571aeb3dbe0f2bbd4e4fadbdb44f325fc75335cd5f6f6b6a091e6a06a9f25ed5392f0863c5442acb0646787446e816f13cbfc6edce5b07658541dff573cab1ff languageName: node linkType: hard @@ -7864,14 +8930,14 @@ __metadata: onetime: "npm:^5.1.2" signal-exit: "npm:^3.0.3" strip-final-newline: "npm:^2.0.0" - checksum: c8e615235e8de4c5addf2fa4c3da3e3aa59ce975a3e83533b4f6a71750fb816a2e79610dc5f1799b6e28976c9ae86747a36a606655bf8cb414a74d8d507b304f + checksum: fba9022c8c8c15ed862847e94c252b3d946036d7547af310e344a527e59021fd8b6bb0723883ea87044dc4f0201f949046993124a42ccb0855cae5bf8c786343 languageName: node linkType: hard "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" - checksum: 71d2ad9b36bc25bb8b104b17e830b40a08989be7f7d100b13269aaae7c3784c3e6e1e88a797e9e87523993a25ba27c8958959a554535370672cfb4d824af8989 + checksum: abc407f07a875c3961e4781dfcb743b58d6c93de9ab263f4f8c9d23bb6da5f9b7764fc773f86b43dd88030444d5ab8abcb611cb680fba8ca075362b77114bba3 languageName: node linkType: hard @@ -7886,7 +8952,7 @@ __metadata: regex-not: "npm:^1.0.0" snapdragon: "npm:^0.8.1" to-regex: "npm:^3.0.1" - checksum: 3e2fb95d2d7d7231486493fd65db913927b656b6fcdfcce41e139c0991a72204af619ad4acb1be75ed994ca49edb7995ef241dbf8cf44dc3c03d211328428a87 + checksum: 1781d422e7edfa20009e2abda673cadb040a6037f0bd30fcd7357304f4f0c284afd420d7622722ca4a016f39b6d091841ab57b401c1f7e2e5131ac65b9f14fa1 languageName: node linkType: hard @@ -7900,14 +8966,14 @@ __metadata: jest-matcher-utils: "npm:^29.6.1" jest-message-util: "npm:^29.6.1" jest-util: "npm:^29.6.1" - checksum: 8ffdd2c8c09d6d632ae85a1172a7e785e75f187ac0009330fa5bcb00e07a06d781b8016579952a1f0ef43e1604068fcdaade3029c8b5ffb99931f79bff57e778 + checksum: 4e712e52c90f6c54e748fd2876be33c43ada6a59088ddf6a1acb08b18b3b97b3a672124684abe32599986d2f2a438d5afad148837ee06ea386d2a4bf0348de78 languageName: node linkType: hard "exponential-backoff@npm:^3.1.1": version: 3.1.1 resolution: "exponential-backoff@npm:3.1.1" - checksum: 160456d2d647e6019640bd07111634d8c353038d9fa40176afb7cd49b0548bdae83b56d05e907c2cce2300b81cae35d800ef92fefb9d0208e190fa3b7d6bb579 + checksum: 3d21519a4f8207c99f7457287291316306255a328770d320b401114ec8481986e4e467e854cb9914dd965e0a1ca810a23ccb559c642c88f4c7f55c55778a9b48 languageName: node linkType: hard @@ -7946,7 +9012,7 @@ __metadata: type-is: "npm:~1.6.18" utils-merge: "npm:1.0.1" vary: "npm:~1.1.2" - checksum: 75af556306b9241bc1d7bdd40c9744b516c38ce50ae3210658efcbf96e3aed4ab83b3432f06215eae5610c123bc4136957dc06e50dfc50b7d4d775af56c4c59c + checksum: 3c4b9b076879442f6b968fe53d85d9f1eeacbb4f4c41e5f16cc36d77ce39a2b0d81b3f250514982110d815b2f7173f5561367f9110fcc541f9371948e8c8b037 languageName: node linkType: hard @@ -7955,7 +9021,7 @@ __metadata: resolution: "extend-shallow@npm:2.0.1" dependencies: is-extendable: "npm:^0.1.0" - checksum: ee1cb0a18c9faddb42d791b2d64867bd6cfd0f3affb711782eb6e894dd193e2934a7f529426aac7c8ddb31ac5d38000a00aa2caf08aa3dfc3e1c8ff6ba340bd9 + checksum: 8fb58d9d7a511f4baf78d383e637bd7d2e80843bd9cd0853649108ea835208fb614da502a553acc30208e1325240bb7cc4a68473021612496bb89725483656d8 languageName: node linkType: hard @@ -7965,14 +9031,14 @@ __metadata: dependencies: assign-symbols: "npm:^1.0.0" is-extendable: "npm:^1.0.1" - checksum: f39581b8f98e3ad94995e33214fff725b0297cf09f2725b6f624551cfb71e0764accfd0af80becc0182af5014d2a57b31b85ec999f9eb8a6c45af81752feac9a + checksum: a920b0cd5838a9995ace31dfd11ab5e79bf6e295aa566910ce53dff19f4b1c0fda2ef21f26b28586c7a2450ca2b42d97bd8c0f5cec9351a819222bf861e02461 languageName: node linkType: hard "extend@npm:^3.0.0": version: 3.0.2 resolution: "extend@npm:3.0.2" - checksum: 73bf6e27406e80aa3e85b0d1c4fd987261e628064e170ca781125c0b635a3dabad5e05adbf07595ea0cf1e6c5396cacb214af933da7cbaf24fe75ff14818e8f9 + checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515 languageName: node linkType: hard @@ -7988,7 +9054,7 @@ __metadata: regex-not: "npm:^1.0.0" snapdragon: "npm:^0.8.1" to-regex: "npm:^3.0.1" - checksum: e1a891342e2010d046143016c6c03d58455c2c96c30bf5570ea07929984ee7d48fad86b363aee08f7a8a638f5c3a66906429b21ecb19bc8e90df56a001cd282c + checksum: a41531b8934735b684cef5e8c5a01d0f298d7d384500ceca38793a9ce098125aab04ee73e2d75d5b2901bc5dddd2b64e1b5e3bf19139ea48bac52af4a92f1d00 languageName: node linkType: hard @@ -8002,21 +9068,21 @@ __metadata: yauzl: "npm:^2.10.0" bin: extract-zip: cli.js - checksum: 333f1349ee678d47268315f264dbfcd7003747d25640441e186e87c66efd7129f171f1bcfe8ff1151a24da19d5f8602daff002ee24145dc65516bc9a8e40ee08 + checksum: 011bab660d738614555773d381a6ba4815d98c1cfcdcdf027e154ebcc9fc8c9ef637b3ea5c9b2144013100071ee41722ed041fc9aacc60f6198ef747cac0c073 languageName: node linkType: hard "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" - checksum: 40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 + checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d languageName: node linkType: hard "fast-diff@npm:^1.1.2": version: 1.3.0 resolution: "fast-diff@npm:1.3.0" - checksum: 5c19af237edb5d5effda008c891a18a585f74bf12953be57923f17a3a4d0979565fc64dbc73b9e20926b9d895f5b690c618cbb969af0cf022e3222471220ad29 + checksum: d22d371b994fdc8cce9ff510d7b8dc4da70ac327bcba20df607dd5b9cae9f908f4d1028f5fe467650f058d1e7270235ae0b8230809a262b4df587a3b3aa216c3 languageName: node linkType: hard @@ -8029,21 +9095,21 @@ __metadata: glob-parent: "npm:^5.1.2" merge2: "npm:^1.3.0" micromatch: "npm:^4.0.4" - checksum: 4700063a2d7c9aae178f575648580bee1fc3f02ab3f358236d77811f52332bc10a398e75c6d5ecde61216996f3308247b37d70e2ee605a0748abe147f01b8f64 + checksum: 20df62be28eb5426fe8e40e0d05601a63b1daceb7c3d87534afcad91bdcf1e4b1743cf2d5247d6e225b120b46df0b9053a032b2691ba34ee121e033acd81f547 languageName: node linkType: hard "fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: 7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b + checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb languageName: node linkType: hard "fast-levenshtein@npm:^2.0.6": version: 2.0.6 resolution: "fast-levenshtein@npm:2.0.6" - checksum: 111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 + checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c languageName: node linkType: hard @@ -8052,7 +9118,7 @@ __metadata: resolution: "fastq@npm:1.15.0" dependencies: reusify: "npm:^1.0.4" - checksum: 5ce4f83afa5f88c9379e67906b4d31bc7694a30826d6cc8d0f0473c966929017fda65c2174b0ec89f064ede6ace6c67f8a4fe04cef42119b6a55b0d465554c24 + checksum: 0170e6bfcd5d57a70412440b8ef600da6de3b2a6c5966aeaf0a852d542daff506a0ee92d6de7679d1de82e644bce69d7a574a6c93f0b03964b5337eed75ada1a languageName: node linkType: hard @@ -8061,7 +9127,7 @@ __metadata: resolution: "fault@npm:1.0.4" dependencies: format: "npm:^0.2.0" - checksum: c86c11500c1b676787296f31ade8473adcc6784f118f07c1a9429730b6288d0412f96e069ce010aa57e4f65a9cccb5abee8868bbe3c5f10de63b20482c9baebd + checksum: 5ac610d8b09424e0f2fa8cf913064372f2ee7140a203a79957f73ed557c0e79b1a3d096064d7f40bde8132a69204c1fe25ec23634c05c6da2da2039cff26c4e7 languageName: node linkType: hard @@ -8070,7 +9136,7 @@ __metadata: resolution: "fb-watchman@npm:2.0.2" dependencies: bser: "npm:2.1.1" - checksum: feae89ac148adb8f6ae8ccd87632e62b13563e6fb114cacb5265c51f585b17e2e268084519fb2edd133872f1d47a18e6bfd7e5e08625c0d41b93149694187581 + checksum: b15a124cef28916fe07b400eb87cbc73ca082c142abf7ca8e8de6af43eca79ca7bd13eb4d4d48240b3bd3136eaac40d16e42d6edf87a8e5d1dd8070626860c78 languageName: node linkType: hard @@ -8079,14 +9145,14 @@ __metadata: resolution: "fd-slicer@npm:1.1.0" dependencies: pend: "npm:~1.2.0" - checksum: 304dd70270298e3ffe3bcc05e6f7ade2511acc278bc52d025f8918b48b6aa3b77f10361bddfadfe2a28163f7af7adbdce96f4d22c31b2f648ba2901f0c5fc20e + checksum: c8585fd5713f4476eb8261150900d2cb7f6ff2d87f8feb306ccc8a1122efd152f1783bdb2b8dc891395744583436bfd8081d8e63ece0ec8687eeefea394d4ff2 languageName: node linkType: hard "fetch-retry@npm:^5.0.2": version: 5.0.6 resolution: "fetch-retry@npm:5.0.6" - checksum: 349f50db631039630e915f70c763469cb696f3ac92ca6f63823109334a2bc62f63670b8c5a5c7e0195c39df517e60ef385cc5264f4c4904d0c6707d371fa8999 + checksum: 4ad8bca6ec7a7b1212e636bb422a9ae8bb9dce38df0b441c9eb77a29af99b368029d6248ff69427da67e3d43c53808b121135ea395e7fe4f8f383e0ad65b4f27 languageName: node linkType: hard @@ -8095,7 +9161,7 @@ __metadata: resolution: "file-entry-cache@npm:6.0.1" dependencies: flat-cache: "npm:^3.0.4" - checksum: 58473e8a82794d01b38e5e435f6feaf648e3f36fdb3a56e98f417f4efae71ad1c0d4ebd8a9a7c50c3ad085820a93fc7494ad721e0e4ebc1da3573f4e1c3c7cdd + checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 languageName: node linkType: hard @@ -8105,18 +9171,7 @@ __metadata: dependencies: fs-extra: "npm:11.1.1" ramda: "npm:0.29.0" - checksum: 43de19f0db32e6546bb7abeecb1d6ea83c1eca23b38905c9415a29f6219cc9d6d87b0c1a6aca92c46a0f1bc276241a339f2f68b8aa0ca5c2eb64b6e1e3e4da01 - languageName: node - linkType: hard - -"file-system-cache@npm:^2.0.0": - version: 2.4.2 - resolution: "file-system-cache@npm:2.4.2" - dependencies: - "@types/ramda": "npm:0.29.3" - fs-extra: "npm:11.1.1" - ramda: "npm:0.29.0" - checksum: fe7f348b7a88501656173f82269ac509dfc7fca720aecea26dc549996c253878e6a0af302afd30ffd5eea275f6801db7d17584031c31ee4ad01e1b89db5503c6 + checksum: 74afa2870a062500643d41e02d1fbd47a3f30100f9e153dec5233d59f05545f4c8ada6085629d624e043479ac28c0cafc31824f7b49a3f997efab8cc5d05bfee languageName: node linkType: hard @@ -8125,7 +9180,7 @@ __metadata: resolution: "filelist@npm:1.0.4" dependencies: minimatch: "npm:^5.0.1" - checksum: 426b1de3944a3d153b053f1c0ebfd02dccd0308a4f9e832ad220707a6d1f1b3c9784d6cadf6b2f68f09a57565f63ebc7bcdc913ccf8012d834f472c46e596f41 + checksum: a303573b0821e17f2d5e9783688ab6fbfce5d52aaac842790ae85e704a6f5e4e3538660a63183d6453834dedf1e0f19a9dadcebfa3e926c72397694ea11f5160 languageName: node linkType: hard @@ -8137,7 +9192,7 @@ __metadata: is-number: "npm:^3.0.0" repeat-string: "npm:^1.6.1" to-regex-range: "npm:^2.1.0" - checksum: ccd57b7c43d7e28a1f8a60adfa3c401629c08e2f121565eece95e2386ebc64dedc7128d8c3448342aabf19db0c55a34f425f148400c7a7be9a606ba48749e089 + checksum: dbb5102467786ab42bc7a3ec7380ae5d6bfd1b5177b2216de89e4a541193f8ba599a6db84651bd2c58c8921db41b8cc3d699ea83b477342d3ce404020f73c298 languageName: node linkType: hard @@ -8146,7 +9201,7 @@ __metadata: resolution: "fill-range@npm:7.0.1" dependencies: to-regex-range: "npm:^5.0.1" - checksum: 7cdad7d426ffbaadf45aeb5d15ec675bbd77f7597ad5399e3d2766987ed20bda24d5fac64b3ee79d93276f5865608bb22344a26b9b1ae6c4d00bd94bf611623f + checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917 languageName: node linkType: hard @@ -8161,7 +9216,7 @@ __metadata: parseurl: "npm:~1.3.3" statuses: "npm:2.0.1" unpipe: "npm:~1.0.0" - checksum: 64b7e5ff2ad1fcb14931cd012651631b721ce657da24aedb5650ddde9378bf8e95daa451da43398123f5de161a81e79ff5affe4f9f2a6d2df4a813d6d3e254b7 + checksum: 92effbfd32e22a7dff2994acedbd9bcc3aa646a3e919ea6a53238090e87097f8ef07cced90aa2cc421abdf993aefbdd5b00104d55c7c5479a8d00ed105b45716 languageName: node linkType: hard @@ -8172,7 +9227,7 @@ __metadata: commondir: "npm:^1.0.1" make-dir: "npm:^2.0.0" pkg-dir: "npm:^3.0.0" - checksum: 556117fd0af14eb88fb69250f4bba9e905e7c355c6136dff0e161b9cbd1f5285f761b778565a278da73a130f42eccc723d7ad4c002ae547ed1d698d39779dabb + checksum: 60ad475a6da9f257df4e81900f78986ab367d4f65d33cf802c5b91e969c28a8762f098693d7a571b6e4dd4c15166c2da32ae2d18b6766a18e2071079448fdce4 languageName: node linkType: hard @@ -8183,7 +9238,7 @@ __metadata: commondir: "npm:^1.0.1" make-dir: "npm:^3.0.2" pkg-dir: "npm:^4.1.0" - checksum: 92747cda42bff47a0266b06014610981cfbb71f55d60f2c8216bc3108c83d9745507fb0b14ecf6ab71112bed29cd6fb1a137ee7436179ea36e11287e3159e587 + checksum: 1e61c2e64f5c0b1c535bd85939ae73b0e5773142713273818cc0b393ee3555fb0fd44e1a5b161b8b6c3e03e98c2fcc9c227d784850a13a90a8ab576869576817 languageName: node linkType: hard @@ -8192,7 +9247,7 @@ __metadata: resolution: "find-up@npm:3.0.0" dependencies: locate-path: "npm:^3.0.0" - checksum: 2c2e7d0a26db858e2f624f39038c74739e38306dee42b45f404f770db357947be9d0d587f1cac72d20c114deb38aa57316e879eb0a78b17b46da7dab0a3bd6e3 + checksum: 38eba3fe7a66e4bc7f0f5a1366dc25508b7cfc349f852640e3678d26ad9a6d7e2c43eff0a472287de4a9753ef58f066a0ea892a256fa3636ad51b3fe1e17fae9 languageName: node linkType: hard @@ -8202,7 +9257,7 @@ __metadata: dependencies: locate-path: "npm:^5.0.0" path-exists: "npm:^4.0.0" - checksum: 0406ee89ebeefa2d507feb07ec366bebd8a6167ae74aa4e34fb4c4abd06cf782a3ce26ae4194d70706f72182841733f00551c209fe575cb00bd92104056e78c1 + checksum: 4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 languageName: node linkType: hard @@ -8212,7 +9267,7 @@ __metadata: dependencies: locate-path: "npm:^6.0.0" path-exists: "npm:^4.0.0" - checksum: 062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a + checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 languageName: node linkType: hard @@ -8222,21 +9277,21 @@ __metadata: dependencies: flatted: "npm:^3.1.0" rimraf: "npm:^3.0.2" - checksum: f274dcbadb09ad8d7b6edf2ee9b034bc40bf0c12638f6c4084e9f1d39208cb104a5ebbb24b398880ef048200eaa116852f73d2d8b72e8c9627aba8c3e27ca057 + checksum: 4fdd10ecbcbf7d520f9040dd1340eb5dfe951e6f0ecf2252edeec03ee68d989ec8b9a20f4434270e71bcfd57800dc09b3344fca3966b2eb8f613072c7d9a2365 languageName: node linkType: hard "flatted@npm:^3.1.0": version: 3.2.7 resolution: "flatted@npm:3.2.7" - checksum: 207a87c7abfc1ea6928ea16bac84f9eaa6d44d365620ece419e5c41cf44a5e9902b4c1f59c9605771b10e4565a0cb46e99d78e0464e8aabb42c97de880642257 + checksum: 427633049d55bdb80201c68f7eb1cbd533e03eac541f97d3aecab8c5526f12a20ccecaeede08b57503e772c769e7f8680b37e8d482d1e5f8d7e2194687f9ea35 languageName: node linkType: hard "flow-parser@npm:0.*": version: 0.212.0 resolution: "flow-parser@npm:0.212.0" - checksum: ea3ea009d3b6d7c368e57676de5ac8d317ec509566e042613be0a183918640a60366f66859c71245a69a8647e19e2ab1fcd5afdcc858320447346175d8817ef6 + checksum: e9ae67959134a610079b22d6c12b09e8fa2f2a4f6e6e83c31c2603a94b6b687f78c9ad1229cbcc9c8c50d5f040ac582dd5c25aaeda0acd535dad93c41b4701f7 languageName: node linkType: hard @@ -8246,7 +9301,7 @@ __metadata: peerDependenciesMeta: debug: optional: true - checksum: da5932b70e63944d38eecaa16954bac4347036f08303c913d166eda74809d8797d38386e3a0eb1d2fe37d2aaff2764cce8e9dbd99459d860cf2cdfa237923b5f + checksum: faa66059b66358ba65c234c2f2a37fcec029dc22775f35d9ad6abac56003268baf41e55f9ee645957b32c7d9f62baf1f0b906e68267276f54ec4b4c597c2b190 languageName: node linkType: hard @@ -8255,24 +9310,14 @@ __metadata: resolution: "for-each@npm:0.3.3" dependencies: is-callable: "npm:^1.1.3" - checksum: 22330d8a2db728dbf003ec9182c2d421fbcd2969b02b4f97ec288721cda63eb28f2c08585ddccd0f77cb2930af8d958005c9e72f47141dc51816127a118f39aa + checksum: 6c48ff2bc63362319c65e2edca4a8e1e3483a2fabc72fbe7feaf8c73db94fc7861bd53bc02c8a66a0c1dd709da6b04eec42e0abdd6b40ce47305ae92a25e5d28 languageName: node linkType: hard "for-in@npm:^1.0.2": version: 1.0.2 resolution: "for-in@npm:1.0.2" - checksum: 42bb609d564b1dc340e1996868b67961257fd03a48d7fdafd4f5119530b87f962be6b4d5b7e3a3fc84c9854d149494b1d358e0b0ce9837e64c4c6603a49451d6 - languageName: node - linkType: hard - -"foreground-child@npm:^2.0.0": - version: 2.0.0 - resolution: "foreground-child@npm:2.0.0" - dependencies: - cross-spawn: "npm:^7.0.0" - signal-exit: "npm:^3.0.2" - checksum: 6719982783a448162f9a01500757fb2053bc5dcd4d67c7cd30739b38ccc01b39f84e408c30989d1d8774519c021c0498e2450ab127690fb09d7f2568fd94ffcc + checksum: 09f4ae93ce785d253ac963d94c7f3432d89398bf25ac7a24ed034ca393bf74380bdeccc40e0f2d721a895e54211b07c8fad7132e8157827f6f7f059b70b4043d languageName: node linkType: hard @@ -8282,18 +9327,7 @@ __metadata: dependencies: cross-spawn: "npm:^7.0.0" signal-exit: "npm:^4.0.1" - checksum: 9700a0285628abaeb37007c9a4d92bd49f67210f09067638774338e146c8e9c825c5c877f072b2f75f41dc6a2d0be8664f79ffc03f6576649f54a84fb9b47de0 - languageName: node - linkType: hard - -"form-data@npm:^3.0.0": - version: 3.0.1 - resolution: "form-data@npm:3.0.1" - dependencies: - asynckit: "npm:^0.4.0" - combined-stream: "npm:^1.0.8" - mime-types: "npm:^2.1.12" - checksum: 1ccc3ae064a080a799923f754d49fcebdd90515a8924f0f54de557540b50e7f1fe48ba5f2bd0435a5664aa2d49729107e6aaf2155a9abf52339474c5638b4485 + checksum: 139d270bc82dc9e6f8bc045fe2aae4001dc2472157044fdfad376d0a3457f77857fa883c1c8b21b491c6caade9a926a4bed3d3d2e8d3c9202b151a4cbbd0bcd5 languageName: node linkType: hard @@ -8304,21 +9338,21 @@ __metadata: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" mime-types: "npm:^2.1.12" - checksum: cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e + checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c languageName: node linkType: hard "format@npm:^0.2.0": version: 0.2.2 resolution: "format@npm:0.2.2" - checksum: 6032ba747541a43abf3e37b402b2f72ee08ebcb58bf84d816443dd228959837f1cddf1e8775b29fa27ff133f4bd146d041bfca5f9cf27f048edf3d493cf8fee6 + checksum: 646a60e1336250d802509cf24fb801e43bd4a70a07510c816fa133aa42cdbc9c21e66e9cc0801bb183c5b031c9d68be62e7fbb6877756e52357850f92aa28799 languageName: node linkType: hard "forwarded@npm:0.2.0": version: 0.2.0 resolution: "forwarded@npm:0.2.0" - checksum: 9b67c3fac86acdbc9ae47ba1ddd5f2f81526fa4c8226863ede5600a3f7c7416ef451f6f1e240a3cc32d0fd79fcfe6beb08fd0da454f360032bde70bf80afbb33 + checksum: fd27e2394d8887ebd16a66ffc889dc983fbbd797d5d3f01087c020283c0f019a7d05ee85669383d8e0d216b116d720fc0cef2f6e9b7eb9f4c90c6e0bc7fd28e6 languageName: node linkType: hard @@ -8327,21 +9361,21 @@ __metadata: resolution: "fragment-cache@npm:0.2.1" dependencies: map-cache: "npm:^0.2.2" - checksum: 5891d1c1d1d5e1a7fb3ccf28515c06731476fa88f7a50f4ede8a0d8d239a338448e7f7cc8b73db48da19c229fa30066104fe6489862065a4f1ed591c42fbeabf + checksum: 1cbbd0b0116b67d5790175de0038a11df23c1cd2e8dcdbade58ebba5594c2d641dade6b4f126d82a7b4a6ffc2ea12e3d387dbb64ea2ae97cf02847d436f60fdc languageName: node linkType: hard "fresh@npm:0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" - checksum: c6d27f3ed86cc5b601404822f31c900dd165ba63fff8152a3ef714e2012e7535027063bc67ded4cb5b3a49fa596495d46cacd9f47d6328459cf570f08b7d9e5a + checksum: 13ea8b08f91e669a64e3ba3a20eb79d7ca5379a81f1ff7f4310d54e2320645503cc0c78daedc93dfb6191287295f6479544a649c64d8e41a1c0fb0c221552346 languageName: node linkType: hard "fs-constants@npm:^1.0.0": version: 1.0.0 resolution: "fs-constants@npm:1.0.0" - checksum: a0cde99085f0872f4d244e83e03a46aa387b74f5a5af750896c6b05e9077fac00e9932fdf5aef84f2f16634cd473c63037d7a512576da7d5c2b9163d1909f3a8 + checksum: 18f5b718371816155849475ac36c7d0b24d39a11d91348cfcb308b4494824413e03572c403c86d3a260e049465518c4f0d5bd00f0371cdfcad6d4f30a85b350d languageName: node linkType: hard @@ -8352,7 +9386,7 @@ __metadata: graceful-fs: "npm:^4.2.0" jsonfile: "npm:^6.0.1" universalify: "npm:^2.0.0" - checksum: a2480243d7dcfa7d723c5f5b24cf4eba02a6ccece208f1524a2fbde1c629492cfb9a59e4b6d04faff6fbdf71db9fdc8ef7f396417a02884195a625f5d8dc9427 + checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd languageName: node linkType: hard @@ -8361,7 +9395,7 @@ __metadata: resolution: "fs-minipass@npm:2.1.0" dependencies: minipass: "npm:^3.0.0" - checksum: 703d16522b8282d7299337539c3ed6edddd1afe82435e4f5b76e34a79cd74e488a8a0e26a636afc2440e1a23b03878e2122e3a2cfe375a5cf63c37d92b86a004 + checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 languageName: node linkType: hard @@ -8370,14 +9404,14 @@ __metadata: resolution: "fs-minipass@npm:3.0.2" dependencies: minipass: "npm:^5.0.0" - checksum: 34726f25b968ac05f6122ea7e9457fe108c7ae3b82beff0256953b0e405def61af2850570e32be2eb05c1e7660b663f24e14b6ab882d1d8a858314faacc4c972 + checksum: e9cc0e1f2d01c6f6f62f567aee59530aba65c6c7b2ae88c5027bc34c711ebcfcfaefd0caf254afa6adfe7d1fba16bc2537508a6235196bac7276747d078aef0a languageName: node linkType: hard "fs.realpath@npm:^1.0.0": version: 1.0.0 resolution: "fs.realpath@npm:1.0.0" - checksum: 444cf1291d997165dfd4c0d58b69f0e4782bfd9149fd72faa4fe299e68e0e93d6db941660b37dd29153bf7186672ececa3b50b7e7249477b03fdf850f287c948 + checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 languageName: node linkType: hard @@ -8386,14 +9420,14 @@ __metadata: resolution: "fsevents@npm:2.3.2" dependencies: node-gyp: "npm:latest" - checksum: be78a3efa3e181cda3cf7a4637cb527bcebb0bd0ea0440105a3bb45b86f9245b307dc10a2507e8f4498a7d4ec349d1910f4d73e4d4495b16103106e07eee735b + checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f conditions: os=darwin languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": +"fsevents@patch:fsevents@npm%3A^2.3.2#~builtin, fsevents@patch:fsevents@npm%3A~2.3.2#~builtin": version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1" + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" dependencies: node-gyp: "npm:latest" conditions: os=darwin @@ -8403,7 +9437,7 @@ __metadata: "function-bind@npm:^1.1.1": version: 1.1.1 resolution: "function-bind@npm:1.1.1" - checksum: 60b74b2407e1942e1ed7f8c284f8ef714d0689dcfce5319985a5b7da3fc727f40b4a59ec72dc55aa83365ad7b8fa4fac3a30d93c850a2b452f29ae03dbc10a1e + checksum: b32fbaebb3f8ec4969f033073b43f5c8befbb58f1a79e12f1d7490358150359ebd92f49e72ff0144f65f2c48ea2a605bff2d07965f548f6474fd8efd95bf361a languageName: node linkType: hard @@ -8412,34 +9446,17 @@ __metadata: resolution: "function.prototype.name@npm:1.1.5" dependencies: call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.0" - functions-have-names: "npm:^1.2.2" - checksum: b75fb8c5261f03a54f7cb53a8c99e0c40297efc3cf750c51d3a2e56f6741701c14eda51986d30c24063136a4c32d1643df9d1dd2f2a14b64fa011edd3e7117ae - languageName: node - linkType: hard - -"functions-have-names@npm:^1.2.2, functions-have-names@npm:^1.2.3": - version: 1.2.3 - resolution: "functions-have-names@npm:1.2.3" - checksum: 33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca - languageName: node - linkType: hard - -"gauge@npm:^3.0.0": - version: 3.0.2 - resolution: "gauge@npm:3.0.2" - dependencies: - aproba: "npm:^1.0.3 || ^2.0.0" - color-support: "npm:^1.1.2" - console-control-strings: "npm:^1.0.0" - has-unicode: "npm:^2.0.1" - object-assign: "npm:^4.1.1" - signal-exit: "npm:^3.0.0" - string-width: "npm:^4.2.3" - strip-ansi: "npm:^6.0.1" - wide-align: "npm:^1.1.2" - checksum: 75230ccaf216471e31025c7d5fcea1629596ca20792de50c596eb18ffb14d8404f927cd55535aab2eeecd18d1e11bd6f23ec3c2e9878d2dda1dc74bccc34b913 + define-properties: "npm:^1.1.3" + es-abstract: "npm:^1.19.0" + functions-have-names: "npm:^1.2.2" + checksum: acd21d733a9b649c2c442f067567743214af5fa248dbeee69d8278ce7df3329ea5abac572be9f7470b4ec1cd4d8f1040e3c5caccf98ebf2bf861a0deab735c27 + languageName: node + linkType: hard + +"functions-have-names@npm:^1.2.2, functions-have-names@npm:^1.2.3": + version: 1.2.3 + resolution: "functions-have-names@npm:1.2.3" + checksum: c3f1f5ba20f4e962efb71344ce0a40722163e85bee2101ce25f88214e78182d2d2476aa85ef37950c579eb6cf6ee811c17b3101bb84004bb75655f3e33f3fdb5 languageName: node linkType: hard @@ -8455,21 +9472,21 @@ __metadata: string-width: "npm:^4.2.3" strip-ansi: "npm:^6.0.1" wide-align: "npm:^1.1.5" - checksum: ef10d7981113d69225135f994c9f8c4369d945e64a8fc721d655a3a38421b738c9fe899951721d1b47b73c41fdb5404ac87cc8903b2ecbed95d2800363e7e58c + checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d languageName: node linkType: hard "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" - checksum: 782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 + checksum: a7437e58c6be12aa6c90f7730eac7fa9833dc78872b4ad2963d2031b00a3367a93f98aec75f9aaac7220848e4026d67a8655e870b24f20a543d103c0d65952ec languageName: node linkType: hard "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" - checksum: c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde + checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 languageName: node linkType: hard @@ -8481,35 +9498,42 @@ __metadata: has: "npm:^1.0.3" has-proto: "npm:^1.0.1" has-symbols: "npm:^1.0.3" - checksum: 49eab47f9de8f1a4f9b458b8b74ee5199fb2614414a91973eb175e07db56b52b6df49b255cc7ff704cb0786490fb93bfe8f2ad138b590a8de09b47116a366bc9 + checksum: 5b61d88552c24b0cf6fa2d1b3bc5459d7306f699de060d76442cce49a4721f52b8c560a33ab392cf5575b7810277d54ded9d4d39a1ea61855619ebc005aa7e5f + languageName: node + linkType: hard + +"get-nonce@npm:^1.0.0": + version: 1.0.1 + resolution: "get-nonce@npm:1.0.1" + checksum: e2614e43b4694c78277bb61b0f04583d45786881289285c73770b07ded246a98be7e1f78b940c80cbe6f2b07f55f0b724e6db6fd6f1bcbd1e8bdac16521074ed languageName: node linkType: hard "get-npm-tarball-url@npm:^2.0.3": version: 2.0.3 resolution: "get-npm-tarball-url@npm:2.0.3" - checksum: fdf7a830d2602dd3d86285f412c9b2984ffe6ce854e1854e9548ea2b2f09f663b83791a31703552f8c72266d67c72e94c70f8d50a886fe5179d2f07a383660d8 + checksum: 8ad48a6f1126697665e12ebf053e0d1c3b15b3c4f29ea6c458387ac68d044ea1c08f0f2eb5c0fe35447fdd2da4f2fb5c9882feb5a2ea195c773f94e762c9b886 languageName: node linkType: hard "get-package-type@npm:^0.1.0": version: 0.1.0 resolution: "get-package-type@npm:0.1.0" - checksum: e34cdf447fdf1902a1f6d5af737eaadf606d2ee3518287abde8910e04159368c268568174b2e71102b87b26c2020486f126bfca9c4fb1ceb986ff99b52ecd1be + checksum: bba0811116d11e56d702682ddef7c73ba3481f114590e705fc549f4d868972263896af313c57a25c076e3c0d567e11d919a64ba1b30c879be985fc9d44f96148 languageName: node linkType: hard "get-port@npm:^5.1.1": version: 5.1.1 resolution: "get-port@npm:5.1.1" - checksum: 2873877a469b24e6d5e0be490724a17edb39fafc795d1d662e7bea951ca649713b4a50117a473f9d162312cb0e946597bd0e049ed2f866e79e576e8e213d3d1c + checksum: 0162663ffe5c09e748cd79d97b74cd70e5a5c84b760a475ce5767b357fb2a57cb821cee412d646aa8a156ed39b78aab88974eddaa9e5ee926173c036c0713787 languageName: node linkType: hard "get-stream@npm:^6.0.0": version: 6.0.1 resolution: "get-stream@npm:6.0.1" - checksum: 49825d57d3fd6964228e6200a58169464b8e8970489b3acdc24906c782fb7f01f9f56f8e6653c4a50713771d6658f7cfe051e5eb8c12e334138c9c918b296341 + checksum: e04ecece32c92eebf5b8c940f51468cd53554dcbb0ea725b2748be583c9523d00128137966afce410b9b051eb2ef16d657cd2b120ca8edafcf5a65e81af63cad languageName: node linkType: hard @@ -8519,14 +9543,14 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" get-intrinsic: "npm:^1.1.1" - checksum: 23bc3b44c221cdf7669a88230c62f4b9e30393b61eb21ba4400cb3e346801bd8f95fe4330ee78dbae37aecd874646d53e3e76a17a654d0c84c77f6690526d6bb + checksum: 9ceff8fe968f9270a37a1f73bf3f1f7bda69ca80f4f80850670e0e7b9444ff99323f7ac52f96567f8b5f5fbe7ac717a0d81d3407c7313e82810c6199446a5247 languageName: node linkType: hard "get-value@npm:^2.0.3, get-value@npm:^2.0.6": version: 2.0.6 resolution: "get-value@npm:2.0.6" - checksum: f069c132791b357c8fc4adfe9e2929b0a2c6e95f98ca7bc6fcbc27f8a302e552f86b4ae61ec56d9e9ac2544b93b6a39743d479866a37b43fcc104088ba74f0d9 + checksum: 5c3b99cb5398ea8016bf46ff17afc5d1d286874d2ad38ca5edb6e87d75c0965b0094cb9a9dddef2c59c23d250702323539a7fbdd870620db38c7e7d7ec87c1eb languageName: node linkType: hard @@ -8543,14 +9567,14 @@ __metadata: tar: "npm:^6.1.13" bin: giget: dist/cli.mjs - checksum: fc76d1042df3027c468f74320f7333ce3f99a84b7cd701683cffc386a35c53699a5c32b816b635f3cdf12956c3e85df4592ffbb31f01b8da6a8d943521c9e2e4 + checksum: 76ad0f7e792ee95dd6c4e1096697fdcce61a2a3235a6c21761fc3e0d1053342074ce71c80059d6d4363fd34152e5d7b2e58221412f300c852ff7d4a12d0321fe languageName: node linkType: hard "github-slugger@npm:^1.0.0": version: 1.5.0 resolution: "github-slugger@npm:1.5.0" - checksum: 116f99732925f939cbfd6f2e57db1aa7e111a460db0d103e3b3f2fce6909d44311663d4542350706cad806345b9892358cc3b153674f88eeae77f43380b3bfca + checksum: c70988224578b3bdaa25df65973ffc8c24594a77a28550c3636e495e49d17aef5cdb04c04fa3f1744babef98c61eecc6a43299a13ea7f3cc33d680bf9053ffbe languageName: node linkType: hard @@ -8559,7 +9583,7 @@ __metadata: resolution: "glob-parent@npm:5.1.2" dependencies: is-glob: "npm:^4.0.1" - checksum: cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee + checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e languageName: node linkType: hard @@ -8568,7 +9592,7 @@ __metadata: resolution: "glob-parent@npm:6.0.2" dependencies: is-glob: "npm:^4.0.3" - checksum: 317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 + checksum: c13ee97978bef4f55106b71e66428eb1512e71a7466ba49025fc2aec59a5bfb0954d5abd58fc5ee6c9b076eef4e1f6d3375c2e964b88466ca390da4419a786a8 languageName: node linkType: hard @@ -8579,25 +9603,29 @@ __metadata: "@types/glob": "npm:^7.1.3" peerDependencies: glob: ^7.1.6 - checksum: 3eb01bed2901539365df6a4d27800afb8788840647d01f9bf3500b3de756597f2ff4b8c823971ace34db228c83159beca459dc42a70968d4e9c8200ed2cc96bd - languageName: node - linkType: hard - -"glob-promise@npm:^6.0.2": - version: 6.0.3 - resolution: "glob-promise@npm:6.0.3" - dependencies: - "@types/glob": "npm:^8.0.0" - peerDependencies: - glob: ^8.0.3 - checksum: f6b4f318449a2ed4c4a511921d5ec311b78c1f6e75e8c1479791b7576bf4c0ad72ed5d2ee95e60cafc037633c9295603191fb1987b529055a116bc051f30d43a + checksum: c1a3d95f7c8393e4151d4899ec4e42bb2e8237160f840ad1eccbe9247407da8b6c13e28f463022e011708bc40862db87b9b77236d35afa3feb8aa86d518f2dfe languageName: node linkType: hard "glob-to-regexp@npm:^0.4.1": version: 0.4.1 resolution: "glob-to-regexp@npm:0.4.1" - checksum: 0486925072d7a916f052842772b61c3e86247f0a80cc0deb9b5a3e8a1a9faad5b04fb6f58986a09f34d3e96cd2a22a24b7e9882fb1cf904c31e9a310de96c429 + checksum: e795f4e8f06d2a15e86f76e4d92751cf8bbfcf0157cea5c2f0f35678a8195a750b34096b1256e436f0cebc1883b5ff0888c47348443e69546a5a87f9e1eb1167 + languageName: node + linkType: hard + +"glob@npm:^10.0.0": + version: 10.3.10 + resolution: "glob@npm:10.3.10" + dependencies: + foreground-child: ^3.1.0 + jackspeak: ^2.3.5 + minimatch: ^9.0.1 + minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 + path-scurry: ^1.10.1 + bin: + glob: dist/esm/bin.mjs + checksum: 4f2fe2511e157b5a3f525a54092169a5f92405f24d2aed3142f4411df328baca13059f4182f1db1bf933e2c69c0bd89e57ae87edd8950cba8c7ccbe84f721cf3 languageName: node linkType: hard @@ -8612,11 +9640,11 @@ __metadata: path-scurry: "npm:^1.10.1" bin: glob: dist/cjs/src/bin.js - checksum: 50effa4208762e508def5688e4d88242db80b5913f65e9c5d5aefb707c59e66a27e845fbf18127157189f6ed0f055e2c94d7112c97a065b9cbfe002e1b26d330 + checksum: 29190d3291f422da0cb40b77a72fc8d2c51a36524e99b8bf412548b7676a6627489528b57250429612b6eec2e6fe7826d328451d3e694a9d15e575389308ec53 languageName: node linkType: hard -"glob@npm:^7.0.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.2.0": +"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.2.0": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -8626,27 +9654,14 @@ __metadata: minimatch: "npm:^3.1.1" once: "npm:^1.3.0" path-is-absolute: "npm:^1.0.0" - checksum: 65676153e2b0c9095100fe7f25a778bf45608eeb32c6048cf307f579649bcc30353277b3b898a3792602c65764e5baa4f643714dfbdfd64ea271d210c7a425fe - languageName: node - linkType: hard - -"glob@npm:^8.1.0": - version: 8.1.0 - resolution: "glob@npm:8.1.0" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^5.0.1" - once: "npm:^1.3.0" - checksum: cb0b5cab17a59c57299376abe5646c7070f8acb89df5595b492dba3bfb43d301a46c01e5695f01154e6553168207cb60d4eaf07d3be4bc3eb9b0457c5c561d0f + checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 languageName: node linkType: hard "globals@npm:^11.1.0": version: 11.12.0 resolution: "globals@npm:11.12.0" - checksum: 758f9f258e7b19226bd8d4af5d3b0dcf7038780fb23d82e6f98932c44e239f884847f1766e8fa9cc5635ccb3204f7fa7314d4408dd4002a5e8ea827b4018f0a1 + checksum: 67051a45eca3db904aee189dfc7cd53c20c7d881679c93f6146ddd4c9f4ab2268e68a919df740d39c71f4445d2b38ee360fc234428baea1dbdfe68bbcb46979e languageName: node linkType: hard @@ -8655,7 +9670,7 @@ __metadata: resolution: "globals@npm:13.20.0" dependencies: type-fest: "npm:^0.20.2" - checksum: 9a028f136f1e7a3574689f430f7d57faa0d699c4c7e92ade00b02882a892be31c314d50dff07b48e607283013117bb8a997406d03a1f7ab4a33a005eb16efd6c + checksum: ad1ecf914bd051325faad281d02ea2c0b1df5d01bd94d368dcc5513340eac41d14b3c61af325768e3c7f8d44576e72780ec0b6f2d366121f8eec6e03c3a3b97a languageName: node linkType: hard @@ -8664,7 +9679,7 @@ __metadata: resolution: "globalthis@npm:1.0.3" dependencies: define-properties: "npm:^1.1.3" - checksum: 0db6e9af102a5254630351557ac15e6909bc7459d3e3f6b001e59fe784c96d31108818f032d9095739355a88467459e6488ff16584ee6250cd8c27dec05af4b0 + checksum: fbd7d760dc464c886d0196166d92e5ffb4c84d0730846d6621a39fbbc068aeeb9c8d1421ad330e94b7bca4bb4ea092f5f21f3d36077812af5d098b4dc006c998 languageName: node linkType: hard @@ -8678,14 +9693,14 @@ __metadata: ignore: "npm:^5.2.0" merge2: "npm:^1.4.1" slash: "npm:^3.0.0" - checksum: b39511b4afe4bd8a7aead3a27c4ade2b9968649abab0a6c28b1a90141b96ca68ca5db1302f7c7bd29eab66bf51e13916b8e0a3d0ac08f75e1e84a39b35691189 + checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 languageName: node linkType: hard "globrex@npm:^0.1.2": version: 0.1.2 resolution: "globrex@npm:0.1.2" - checksum: a54c029520cf58bda1d8884f72bd49b4cd74e977883268d931fd83bcbd1a9eb96d57c7dbd4ad80148fb9247467ebfb9b215630b2ed7563b2a8de02e1ff7f89d1 + checksum: adca162494a176ce9ecf4dd232f7b802956bb1966b37f60c15e49d2e7d961b66c60826366dc2649093cad5a0d69970cfa8875bd1695b5a1a2f33dcd2aa88da3c languageName: node linkType: hard @@ -8694,21 +9709,21 @@ __metadata: resolution: "gopd@npm:1.0.1" dependencies: get-intrinsic: "npm:^1.1.3" - checksum: 505c05487f7944c552cee72087bf1567debb470d4355b1335f2c262d218ebbff805cd3715448fe29b4b380bae6912561d0467233e4165830efd28da241418c63 + checksum: a5ccfb8806e0917a94e0b3de2af2ea4979c1da920bc381667c260e00e7cafdbe844e2cb9c5bcfef4e5412e8bf73bab837285bc35c7ba73aaaf0134d4583393a6 languageName: node linkType: hard "graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" - checksum: 386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 + checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 languageName: node linkType: hard "grapheme-splitter@npm:^1.0.4": version: 1.0.4 resolution: "grapheme-splitter@npm:1.0.4" - checksum: 108415fb07ac913f17040dc336607772fcea68c7f495ef91887edddb0b0f5ff7bc1d1ab181b125ecb2f0505669ef12c9a178a3bbd2dd8e042d8c5f1d7c90331a + checksum: 0c22ec54dee1b05cd480f78cf14f732cb5b108edc073572c4ec205df4cd63f30f8db8025afc5debc8835a8ddeacf648a1c7992fe3dcd6ad38f9a476d84906620 languageName: node linkType: hard @@ -8724,7 +9739,7 @@ __metadata: through2: "npm:^2.0.3" bin: gunzip-maybe: bin.js - checksum: 42798a8061759885c2084e1804e51313d14f2dc9cf6c137e222953ec802f914e592d6f9dbf6ad67f4e78eb036e86db017d9c7c93bb23e90cd5ae09326296ed77 + checksum: bc4d4977c24a2860238df271de75d53dd72a359d19f1248d1c613807dc221d3b8ae09624e3085c8106663e3e1b59db62a85b261d1138c2cc24efad9df577d4e1 languageName: node linkType: hard @@ -8742,14 +9757,14 @@ __metadata: optional: true bin: handlebars: bin/handlebars - checksum: 4c0913fc0018a2a2e358ee94e4fe83f071762b8bec51a473d187e6642e94e569843adcf550ffe329554c63ad450c062f3a05447bd2e3fff5ebfe698e214225c6 + checksum: 1e79a43f5e18d15742977cb987923eab3e2a8f44f2d9d340982bcb69e1735ed049226e534d7c1074eaddaf37e4fb4f471a8adb71cddd5bc8cf3f894241df5cee languageName: node linkType: hard "harmony-reflect@npm:^1.4.6": version: 1.6.2 resolution: "harmony-reflect@npm:1.6.2" - checksum: fa5b251fbeff0e2d925f0bfb5ffe39e0627639e998c453562d6a39e41789c15499649dc022178c807cf99bfb97e7b974bbbc031ba82078a26be7b098b9bc2b1a + checksum: 2e5bae414cd2bfae5476147f9935dc69ee9b9a413206994dcb94c5b3208d4555da3d4313aff6fd14bd9991c1e3ef69cdda5c8fac1eb1d7afc064925839339b8c languageName: node linkType: hard @@ -8758,35 +9773,35 @@ __metadata: resolution: "has-ansi@npm:2.0.0" dependencies: ansi-regex: "npm:^2.0.0" - checksum: f54e4887b9f8f3c4bfefd649c48825b3c093987c92c27880ee9898539e6f01aed261e82e73153c3f920fde0db5bf6ebd58deb498ed1debabcb4bc40113ccdf05 + checksum: 1b51daa0214440db171ff359d0a2d17bc20061164c57e76234f614c91dbd2a79ddd68dfc8ee73629366f7be45a6df5f2ea9de83f52e1ca24433f2cc78c35d8ec languageName: node linkType: hard "has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": version: 1.0.2 resolution: "has-bigints@npm:1.0.2" - checksum: 724eb1485bfa3cdff6f18d95130aa190561f00b3fcf9f19dc640baf8176b5917c143b81ec2123f8cddb6c05164a198c94b13e1377c497705ccc8e1a80306e83b + checksum: 390e31e7be7e5c6fe68b81babb73dfc35d413604d7ee5f56da101417027a4b4ce6a27e46eff97ad040c835b5d228676eae99a9b5c3bc0e23c8e81a49241ff45b languageName: node linkType: hard "has-flag@npm:^1.0.0": version: 1.0.0 resolution: "has-flag@npm:1.0.0" - checksum: d0ad4bebbbc005edccfa1e2c0600c89375be5663d23f49a129e0f817187405748b0b515abfc5b3c209c92692e39bb0481c83c0ee4df69433d6ffd0242183100b + checksum: ce3f8ae978e70f16e4bbe17d3f0f6d6c0a3dd3b62a23f97c91d0fda9ed8e305e13baf95cc5bee4463b9f25ac9f5255de113165c5fb285e01b8065b2ac079b301 languageName: node linkType: hard "has-flag@npm:^3.0.0": version: 3.0.0 resolution: "has-flag@npm:3.0.0" - checksum: 1c6c83b14b8b1b3c25b0727b8ba3e3b647f99e9e6e13eb7322107261de07a4c1be56fc0d45678fc376e09772a3a1642ccdaf8fc69bdf123b6c086598397ce473 + checksum: 4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b languageName: node linkType: hard "has-flag@npm:^4.0.0": version: 4.0.0 resolution: "has-flag@npm:4.0.0" - checksum: 2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 + checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad languageName: node linkType: hard @@ -8795,21 +9810,21 @@ __metadata: resolution: "has-property-descriptors@npm:1.0.0" dependencies: get-intrinsic: "npm:^1.1.1" - checksum: d4ca882b6960d6257bd28baa3ddfa21f068d260411004a093b30ca357c740e11e985771c85216a6d1eef4161e862657f48c4758ec8ab515223b3895200ad164b + checksum: a6d3f0a266d0294d972e354782e872e2fe1b6495b321e6ef678c9b7a06a40408a6891817350c62e752adced73a94ac903c54734fee05bf65b1905ee1368194bb languageName: node linkType: hard "has-proto@npm:^1.0.1": version: 1.0.1 resolution: "has-proto@npm:1.0.1" - checksum: c8a8fe411f810b23a564bd5546a8f3f0fff6f1b692740eb7a2fdc9df716ef870040806891e2f23ff4653f1083e3895bf12088703dd1a0eac3d9202d3a4768cd0 + checksum: febc5b5b531de8022806ad7407935e2135f1cc9e64636c3916c6842bd7995994ca3b29871ecd7954bd35f9e2986c17b3b227880484d22259e2f8e6ce63fd383e languageName: node linkType: hard "has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3": version: 1.0.3 resolution: "has-symbols@npm:1.0.3" - checksum: e6922b4345a3f37069cdfe8600febbca791c94988c01af3394d86ca3360b4b93928bbf395859158f88099cb10b19d98e3bbab7c9ff2c1bd09cf665ee90afa2c3 + checksum: a054c40c631c0d5741a8285010a0777ea0c068f99ed43e5d6eb12972da223f8af553a455132fdb0801bdcfa0e0f443c0c03a68d8555aa529b3144b446c3f2410 languageName: node linkType: hard @@ -8818,14 +9833,14 @@ __metadata: resolution: "has-tostringtag@npm:1.0.0" dependencies: has-symbols: "npm:^1.0.2" - checksum: 1cdba76b7d13f65198a92b8ca1560ba40edfa09e85d182bf436d928f3588a9ebd260451d569f0ed1b849c4bf54f49c862aa0d0a77f9552b1855bb6deb526c011 + checksum: cc12eb28cb6ae22369ebaad3a8ab0799ed61270991be88f208d508076a1e99abe4198c965935ce85ea90b60c94ddda73693b0920b58e7ead048b4a391b502c1c languageName: node linkType: hard "has-unicode@npm:^2.0.1": version: 2.0.1 resolution: "has-unicode@npm:2.0.1" - checksum: ebdb2f4895c26bb08a8a100b62d362e49b2190bcfd84b76bc4be1a3bd4d254ec52d0dd9f2fbcc093fc5eb878b20c52146f9dfd33e2686ed28982187be593b47c + checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 languageName: node linkType: hard @@ -8836,7 +9851,7 @@ __metadata: get-value: "npm:^2.0.3" has-values: "npm:^0.1.4" isobject: "npm:^2.0.0" - checksum: 7a7c2e9d07bc9742c81806150adb154d149bc6155267248c459cd1ce2a64b0759980d26213260e4b7599c8a3754551179f155ded88d0533a0d2bc7bc29028432 + checksum: 29e2a1e6571dad83451b769c7ce032fce6009f65bccace07c2962d3ad4d5530b6743d8f3229e4ecf3ea8e905d23a752c5f7089100c1f3162039fa6dc3976558f languageName: node linkType: hard @@ -8847,14 +9862,14 @@ __metadata: get-value: "npm:^2.0.6" has-values: "npm:^1.0.0" isobject: "npm:^3.0.0" - checksum: 17cdccaf50f8aac80a109dba2e2ee5e800aec9a9d382ef9deab66c56b34269e4c9ac720276d5ffa722764304a1180ae436df077da0dd05548cfae0209708ba4d + checksum: b9421d354e44f03d3272ac39fd49f804f19bc1e4fa3ceef7745df43d6b402053f828445c03226b21d7d934a21ac9cf4bc569396dc312f496ddff873197bbd847 languageName: node linkType: hard "has-values@npm:^0.1.4": version: 0.1.4 resolution: "has-values@npm:0.1.4" - checksum: a8f00ad862c20289798c35243d5bd0b0a97dd44b668c2204afe082e0265f2d0bf3b89fc8cc0ef01a52b49f10aa35cf85c336ee3a5f1cac96ed490f5e901cdbf2 + checksum: ab1c4bcaf811ccd1856c11cfe90e62fca9e2b026ebe474233a3d282d8d67e3b59ed85b622c7673bac3db198cb98bd1da2b39300a2f98e453729b115350af49bc languageName: node linkType: hard @@ -8864,7 +9879,7 @@ __metadata: dependencies: is-number: "npm:^3.0.0" kind-of: "npm:^4.0.0" - checksum: a6f2a1cc6b2e43eacc68e62e71ad6890def7f4b13d2ef06b4ad3ee156c23e470e6df144b9b467701908e17633411f1075fdff0cab45fb66c5e0584d89b25f35e + checksum: 77e6693f732b5e4cf6c38dfe85fdcefad0fab011af74995c3e83863fabf5e3a836f406d83565816baa0bc0a523c9410db8b990fe977074d61aeb6d8f4fcffa11 languageName: node linkType: hard @@ -8873,14 +9888,14 @@ __metadata: resolution: "has@npm:1.0.3" dependencies: function-bind: "npm:^1.1.1" - checksum: e1da0d2bd109f116b632f27782cf23182b42f14972ca9540e4c5aa7e52647407a0a4a76937334fddcb56befe94a3494825ec22b19b51f5e5507c3153fd1a5e1b + checksum: b9ad53d53be4af90ce5d1c38331e712522417d017d5ef1ebd0507e07c2fbad8686fffb8e12ddecd4c39ca9b9b47431afbb975b8abf7f3c3b82c98e9aad052792 languageName: node linkType: hard "hast-util-parse-selector@npm:^2.0.0": version: 2.2.5 resolution: "hast-util-parse-selector@npm:2.2.5" - checksum: 29b7ee77960ded6a99d30c287d922243071cc07b39f2006f203bd08ee54eb8f66bdaa86ef6527477c766e2382d520b60ee4e4087f189888c35d8bcc020173648 + checksum: 22ee4afbd11754562144cb3c4f3ec52524dafba4d90ee52512902d17cf11066d83b38f7bdf6ca571bbc2541f07ba30db0d234657b6ecb8ca4631587466459605 languageName: node linkType: hard @@ -8893,7 +9908,7 @@ __metadata: hast-util-parse-selector: "npm:^2.0.0" property-information: "npm:^5.0.0" space-separated-tokens: "npm:^1.0.0" - checksum: f76d9cf373cb075c8523c8ad52709f09f7e02b7c9d3152b8d35c65c265b9f1878bed6023f215a7d16523921036d40a7da292cb6f4399af9b5eccac2a5a5eb330 + checksum: 5e50b85af0d2cb7c17979cb1ddca75d6b96b53019dd999b39e7833192c9004201c3cee6445065620ea05d0087d9ae147a4844e582d64868be5bc6b0232dfe52d languageName: node linkType: hard @@ -8902,14 +9917,14 @@ __metadata: resolution: "he@npm:1.2.0" bin: he: bin/he - checksum: a27d478befe3c8192f006cdd0639a66798979dfa6e2125c6ac582a19a5ebfec62ad83e8382e6036170d873f46e4536a7e795bf8b95bf7c247f4cc0825ccc8c17 + checksum: 3d4d6babccccd79c5c5a3f929a68af33360d6445587d628087f39a965079d84f18ce9c3d3f917ee1e3978916fc833bb8b29377c3b403f919426f91bc6965e7a7 languageName: node linkType: hard "highlight.js@npm:^10.4.1, highlight.js@npm:~10.7.0": version: 10.7.3 resolution: "highlight.js@npm:10.7.3" - checksum: 073837eaf816922427a9005c56c42ad8786473dc042332dfe7901aa065e92bc3d94ebf704975257526482066abb2c8677cc0326559bb8621e046c21c5991c434 + checksum: defeafcd546b535d710d8efb8e650af9e3b369ef53e28c3dc7893eacfe263200bba4c5fcf43524ae66d5c0c296b1af0870523ceae3e3104d24b7abf6374a4fea languageName: node linkType: hard @@ -8918,14 +9933,14 @@ __metadata: resolution: "hoist-non-react-statics@npm:3.3.2" dependencies: react-is: "npm:^16.7.0" - checksum: fe0889169e845d738b59b64badf5e55fa3cf20454f9203d1eb088df322d49d4318df774828e789898dcb280e8a5521bb59b3203385662ca5e9218a6ca5820e74 + checksum: b1538270429b13901ee586aa44f4cc3ecd8831c061d06cb8322e50ea17b3f5ce4d0e2e66394761e6c8e152cd8c34fb3b4b690116c6ce2bd45b18c746516cb9e8 languageName: node linkType: hard "hosted-git-info@npm:^2.1.4": version: 2.8.9 resolution: "hosted-git-info@npm:2.8.9" - checksum: 317cbc6b1bbbe23c2a40ae23f3dafe9fa349ce42a89a36f930e3f9c0530c179a3882d2ef1e4141a4c3674d6faaea862138ec55b43ad6f75e387fda2483a13c70 + checksum: c955394bdab888a1e9bb10eb33029e0f7ce5a2ac7b3f158099dc8c486c99e73809dca609f5694b223920ca2174db33d32b12f9a2a47141dc59607c29da5a62dd languageName: node linkType: hard @@ -8935,7 +9950,7 @@ __metadata: dependencies: domhandler: "npm:5.0.3" htmlparser2: "npm:9.0.0" - checksum: e8553406993ff412fb4e31453f587586145f300d44d3d8e4e77c392811b122bbb33fd0cca53e6216e60d8deaf7c2deb7ef2274e9229f3a6d96c32fff2f0ca09b + checksum: 95e483b2c945e1158e102e4eb69768124b06c94cf3c0abff8e9b02e146b7391dcdd620df8d54331efb9952c9187e0352ea436226e9ba5f26a0cc3cfe85853d4b languageName: node linkType: hard @@ -8944,14 +9959,14 @@ __metadata: resolution: "html-encoding-sniffer@npm:3.0.0" dependencies: whatwg-encoding: "npm:^2.0.0" - checksum: b17b3b0fb5d061d8eb15121c3b0b536376c3e295ecaf09ba48dd69c6b6c957839db124fe1e2b3f11329753a4ee01aa7dedf63b7677999e86da17fbbdd82c5386 + checksum: 8d806aa00487e279e5ccb573366a951a9f68f65c90298eac9c3a2b440a7ffe46615aff2995a2f61c6746c639234e6179a97e18ca5ccbbf93d3725ef2099a4502 languageName: node linkType: hard "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" - checksum: 208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0 + checksum: d2df2da3ad40ca9ee3a39c5cc6475ef67c8f83c234475f24d8e9ce0dc80a2c82df8e1d6fa78ddd1e9022a586ea1bd247a615e80a5cd9273d90111ddda7d9e974 languageName: node linkType: hard @@ -8965,14 +9980,14 @@ __metadata: style-to-js: "npm:1.1.3" peerDependencies: react: 0.14 || 15 || 16 || 17 || 18 - checksum: a1bc1060f1d79d8b2c4b88941533af18662261942b529f4eb4f6d7553d13b7540be323d31c645a334f6c707ba2bf5409bc3fa074e9df22f0992214a6ea76ed0b + checksum: e9ac022076bf0efbb9f8488c5adc41dd8bc8757cd1f01ba1812a758deb0d9eea5a657e6fde6e6cd694b4e232ed5e4757e12c9fc5ab0ed457feede002fade04c9 languageName: node linkType: hard "html-tags@npm:^3.1.0": version: 3.3.1 resolution: "html-tags@npm:3.3.1" - checksum: 680165e12baa51bad7397452d247dbcc5a5c29dac0e6754b1187eee3bf26f514bc1907a431dd2f7eb56207611ae595ee76a0acc8eaa0d931e72c791dd6463d79 + checksum: b4ef1d5a76b678e43cce46e3783d563607b1d550cab30b4f511211564574770aa8c658a400b100e588bc60b8234e59b35ff72c7851cc28f3b5403b13a2c6cbce languageName: node linkType: hard @@ -8984,7 +9999,7 @@ __metadata: domhandler: "npm:^5.0.3" domutils: "npm:^3.1.0" entities: "npm:^4.5.0" - checksum: 100d24059a267068c6e73b4df7b123936ad39c86203c42c43935a84965be566a4162402355ba48889c8b7a42b55f8843e673ee2b5d21f0fd67c08f074d921068 + checksum: a234c3add821cae8308ca61ce4b8ad3e88af83cf9c3c2003059adc89c46a06ffc39cc2a92b39af8d16c3705e1055df6769d80877acb6529983867f0d7e74098d languageName: node linkType: hard @@ -8998,14 +10013,14 @@ __metadata: entities: "npm:^1.1.1" inherits: "npm:^2.0.1" readable-stream: "npm:^3.1.1" - checksum: b1424536ff062088501efa06a2afd478545d3134a5ad2e28bbe02dc2d092784982286b90f1c87fa3d86692958dbfb8936352dfd71d1cb2ff7cb61208c00fcdb1 + checksum: 6875f7dd875aa10be17d9b130e3738cd8ed4010b1f2edaf4442c82dfafe9d9336b155870dcc39f38843cbf7fef5e4fcfdf0c4c1fd4db3a1b91a1e0ee8f6c3475 languageName: node linkType: hard "http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" - checksum: ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc + checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 languageName: node linkType: hard @@ -9018,7 +10033,7 @@ __metadata: setprototypeof: "npm:1.2.0" statuses: "npm:2.0.1" toidentifier: "npm:1.0.1" - checksum: fc6f2715fe188d091274b5ffc8b3657bd85c63e969daa68ccb77afb05b071a4b62841acb7a21e417b5539014dff2ebf9550f0b14a9ff126f2734a7c1387f8e19 + checksum: 9b0a3782665c52ce9dc658a0d1560bcb0214ba5699e4ea15aefb2a496e2ca83db03ebc42e1cce4ac1f413e4e0d2d736a3fd755772c556a9a06853ba2a0b7d920 languageName: node linkType: hard @@ -9029,7 +10044,7 @@ __metadata: "@tootallnate/once": "npm:2" agent-base: "npm:6" debug: "npm:4" - checksum: 32a05e413430b2c1e542e5c74b38a9f14865301dd69dff2e53ddb684989440e3d2ce0c4b64d25eb63cf6283e6265ff979a61cf93e3ca3d23047ddfdc8df34a32 + checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 languageName: node linkType: hard @@ -9039,7 +10054,7 @@ __metadata: dependencies: agent-base: "npm:5" debug: "npm:4" - checksum: fbba3e037ec04e1850e867064a763b86dd884baae9c5f4ad380504e321068c9e9b5de79cf2f3a28ede7c36036dce905b58d9f51703c5b3884d887114f4887f77 + checksum: 19471d5aae3e747b1c98b17556647e2a1362e68220c6b19585a8527498f32e62e03c41d2872d059d8720d56846bd7460a80ac06f876bccfa786468ff40dd5eef languageName: node linkType: hard @@ -9049,14 +10064,14 @@ __metadata: dependencies: agent-base: "npm:6" debug: "npm:4" - checksum: 6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1 + checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 languageName: node linkType: hard "human-signals@npm:^2.1.0": version: 2.1.0 resolution: "human-signals@npm:2.1.0" - checksum: 695edb3edfcfe9c8b52a76926cd31b36978782062c0ed9b1192b36bebc75c4c87c82e178dfcb0ed0fc27ca59d434198aac0bd0be18f5781ded775604db22304a + checksum: b87fd89fce72391625271454e70f67fe405277415b48bcc0117ca73d31fa23a4241787afdc8d67f5a116cf37258c052f59ea82daffa72364d61351423848e3b8 languageName: node linkType: hard @@ -9065,7 +10080,7 @@ __metadata: resolution: "humanize-ms@npm:1.2.1" dependencies: ms: "npm:^2.0.0" - checksum: f34a2c20161d02303c2807badec2f3b49cbfbbb409abd4f95a07377ae01cfe6b59e3d15ac609cffcd8f2521f0eb37b7e1091acf65da99aa2a4f1ad63c21e7e7a + checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 languageName: node linkType: hard @@ -9074,7 +10089,7 @@ __metadata: resolution: "hunspell-spellchecker@npm:1.0.2" bin: hunspell-tojson: ./bin/hunspell-tojson.js - checksum: 61f6ec11ce65470ae4bba9406fedf2b36dfd0d6a39d56817de9dd5e48847517af9e7719cdf23368af1f33254e60f15be6323707addb66a2b7cb7e2c5c5e60b14 + checksum: 098e00a705b1b8975924ccef1b23e1d63acc139a493a392bb55f887926c518b2edae01f9a697cffa73346160c562f89610f80d354360a2cb637a67f7c54f8227 languageName: node linkType: hard @@ -9083,7 +10098,7 @@ __metadata: resolution: "husky@npm:8.0.3" bin: husky: lib/bin.js - checksum: 6722591771c657b91a1abb082e07f6547eca79144d678e586828ae806499d90dce2a6aee08b66183fd8b085f19d20e0990a2ad396961746b4c8bd5bdb619d668 + checksum: 837bc7e4413e58c1f2946d38fb050f5d7324c6f16b0fd66411ffce5703b294bd21429e8ba58711cd331951ee86ed529c5be4f76805959ff668a337dbfa82a1b0 languageName: node linkType: hard @@ -9092,7 +10107,7 @@ __metadata: resolution: "iconv-lite@npm:0.4.24" dependencies: safer-buffer: "npm:>= 2.1.2 < 3" - checksum: c6886a24cc00f2a059767440ec1bc00d334a89f250db8e0f7feb4961c8727118457e27c495ba94d082e51d3baca378726cd110aaf7ded8b9bbfd6a44760cf1d4 + checksum: bd9f120f5a5b306f0bc0b9ae1edeb1577161503f5f8252a20f1a9e56ef8775c9959fd01c55f2d3a39d9a8abaf3e30c1abeb1895f367dcbbe0a8fd1c9ca01c4f6 languageName: node linkType: hard @@ -9101,7 +10116,7 @@ __metadata: resolution: "iconv-lite@npm:0.6.3" dependencies: safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 + checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf languageName: node linkType: hard @@ -9110,21 +10125,21 @@ __metadata: resolution: "identity-obj-proxy@npm:3.0.0" dependencies: harmony-reflect: "npm:^1.4.6" - checksum: a3fc4de0042d7b45bf8652d5596c80b42139d8625c9cd6a8834e29e1b6dce8fccabd1228e08744b78677a19ceed7201a32fed8ca3dc3e4852e8fee24360a6cfc + checksum: 97559f8ea2aeaa1a880d279d8c49550dce01148321e00a2102cda5ddf9ce622fa1d7f3efc7bed63458af78889de888fdaebaf31c816312298bb3fdd0ef8aaf2c languageName: node linkType: hard "ieee754@npm:^1.1.13": version: 1.2.1 resolution: "ieee754@npm:1.2.1" - checksum: b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb + checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e languageName: node linkType: hard "ignore@npm:^5.2.0": version: 5.2.4 resolution: "ignore@npm:5.2.4" - checksum: 7c7cd90edd9fea6e037f9b9da4b01bf0a86b198ce78345f9bbd983929d68ff14830be31111edc5d70c264921f4962404d75b7262b4d9cc3bc12381eccbd03096 + checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef languageName: node linkType: hard @@ -9133,21 +10148,21 @@ __metadata: resolution: "image-size@npm:0.5.5" bin: image-size: bin/image-size.js - checksum: 655204163af06732f483a9fe7cce9dff4a29b7b2e88f5c957a5852e8143fa750f5e54b1955a2ca83de99c5220dbd680002d0d4e09140b01433520f4d5a0b1f4c + checksum: 6709d5cb73e96d5097ae5e9aa746dd36d6a9c8cf645e7eecac72ea07dbd6f312a65183752762fa92e2f3b698d4ed8d85dd55bf5207b6367245996bd16576d8fe languageName: node linkType: hard "immer@npm:^9.0.21": version: 9.0.21 resolution: "immer@npm:9.0.21" - checksum: 03ea3ed5d4d72e8bd428df4a38ad7e483ea8308e9a113d3b42e0ea2cc0cc38340eb0a6aca69592abbbf047c685dbda04e3d34bf2ff438ab57339ed0a34cc0a05 + checksum: 70e3c274165995352f6936695f0ef4723c52c92c92dd0e9afdfe008175af39fa28e76aafb3a2ca9d57d1fb8f796efc4dd1e1cc36f18d33fa5b74f3dfb0375432 languageName: node linkType: hard "immutable@npm:^4.0.0": version: 4.3.1 resolution: "immutable@npm:4.3.1" - checksum: 7dbe08e9568d83ddcc4eae0116385fd5642c77e4cf03c222f9d667733bfd1870d574f487c85d78ed12f55f2358372bea156732008569531f3a4740f2ce114d0e + checksum: a3a5ba29bd43f3f9a2e4d599763d7455d11a0ea57e50bf43f2836672fc80003e90d69f2a4f5b589f1f3d6986faf97f08ce1e253583740dd33c00adebab88b217 languageName: node linkType: hard @@ -9157,7 +10172,7 @@ __metadata: dependencies: parent-module: "npm:^1.0.0" resolve-from: "npm:^4.0.0" - checksum: 7f882953aa6b740d1f0e384d0547158bc86efbf2eea0f1483b8900a6f65c5a5123c2cf09b0d542cc419d0b98a759ecaeb394237e97ea427f2da221dc3cd80cc3 + checksum: 2cacfad06e652b1edc50be650f7ec3be08c5e5a6f6d12d035c440a42a8cc028e60a5b99ca08a77ab4d6b1346da7d971915828f33cdab730d3d42f08242d09baa languageName: node linkType: hard @@ -9169,21 +10184,21 @@ __metadata: resolve-cwd: "npm:^3.0.0" bin: import-local-fixture: fixtures/cli.js - checksum: c67ecea72f775fe8684ca3d057e54bdb2ae28c14bf261d2607c269c18ea0da7b730924c06262eca9aed4b8ab31e31d65bc60b50e7296c85908a56e2f7d41ecd2 + checksum: bfcdb63b5e3c0e245e347f3107564035b128a414c4da1172a20dc67db2504e05ede4ac2eee1252359f78b0bfd7b19ef180aec427c2fce6493ae782d73a04cddd languageName: node linkType: hard "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" - checksum: 8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 + checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 languageName: node linkType: hard "indent-string@npm:^4.0.0": version: 4.0.0 resolution: "indent-string@npm:4.0.0" - checksum: 1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f + checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 languageName: node linkType: hard @@ -9193,21 +10208,21 @@ __metadata: dependencies: once: "npm:^1.3.0" wrappy: "npm:1" - checksum: 7faca22584600a9dc5b9fca2cd5feb7135ac8c935449837b315676b4c90aa4f391ec4f42240178244b5a34e8bede1948627fda392ca3191522fc46b34e985ab2 + checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd languageName: node linkType: hard "inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" - checksum: 4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 + checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 languageName: node linkType: hard "inline-style-parser@npm:0.1.1": version: 0.1.1 resolution: "inline-style-parser@npm:0.1.1" - checksum: 08832a533f51a1e17619f2eabf2f5ec5e956d6dcba1896351285c65df022c9420de61d73256e1dca8015a52abf96cc84ddc3b73b898b22de6589d3962b5e501b + checksum: 5d545056a3e1f2bf864c928a886a0e1656a3517127d36917b973de581bd54adc91b4bf1febcb0da054f204b4934763f1a4e09308b4d55002327cf1d48ac5d966 languageName: node linkType: hard @@ -9218,35 +10233,37 @@ __metadata: get-intrinsic: "npm:^1.2.0" has: "npm:^1.0.3" side-channel: "npm:^1.0.4" - checksum: 66d8a66b4b5310c042e8ad00ce895dc55cb25165a3a7da0d7862ca18d69d3b1ba86511b4bf3baf4273d744d3f6e9154574af45189ef11135a444945309e39e4a + checksum: 97e84046bf9e7574d0956bd98d7162313ce7057883b6db6c5c7b5e5f05688864b0978ba07610c726d15d66544ffe4b1050107d93f8a39ebc59b15d8b429b497a languageName: node linkType: hard -"interpret@npm:^1.0.0": - version: 1.4.0 - resolution: "interpret@npm:1.4.0" - checksum: 08c5ad30032edeec638485bc3f6db7d0094d9b3e85e0f950866600af3c52e9fd69715416d29564731c479d9f4d43ff3e4d302a178196bdc0e6837ec147640450 +"invariant@npm:^2.2.4": + version: 2.2.4 + resolution: "invariant@npm:2.2.4" + dependencies: + loose-envify: ^1.0.0 + checksum: cc3182d793aad82a8d1f0af697b462939cb46066ec48bbf1707c150ad5fad6406137e91a262022c269702e01621f35ef60269f6c0d7fd178487959809acdfb14 languageName: node linkType: hard "ip@npm:^2.0.0": version: 2.0.0 resolution: "ip@npm:2.0.0" - checksum: 8d186cc5585f57372847ae29b6eba258c68862055e18a75cc4933327232cb5c107f89800ce29715d542eef2c254fbb68b382e780a7414f9ee7caf60b7a473958 + checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 languageName: node linkType: hard "ipaddr.js@npm:1.9.1": version: 1.9.1 resolution: "ipaddr.js@npm:1.9.1" - checksum: 0486e775047971d3fdb5fb4f063829bac45af299ae0b82dcf3afa2145338e08290563a2a70f34b732d795ecc8311902e541a8530eeb30d75860a78ff4e94ce2a + checksum: f88d3825981486f5a1942414c8d77dd6674dd71c065adcfa46f578d677edcb99fda25af42675cb59db492fdf427b34a5abfcde3982da11a8fd83a500b41cfe77 languageName: node linkType: hard "is-absolute-url@npm:^3.0.0": version: 3.0.3 resolution: "is-absolute-url@npm:3.0.3" - checksum: 04c415974c32e73a83d3a21a9bea18fc4e2c14fbe6bbd64832cf1e67a75ade2af0e900f552f0b8a447f1305f5ffc9d143ccd8d005dbe715d198c359d342b86f0 + checksum: 5159b51d065d9ad29e16a2f78d6c0e41c43227caf90a45e659c54ea6fd50ef0595b1871ce392e84b1df7cfdcad9a8e66eec0813a029112188435abf115accb16 languageName: node linkType: hard @@ -9255,7 +10272,7 @@ __metadata: resolution: "is-accessor-descriptor@npm:0.1.6" dependencies: kind-of: "npm:^3.0.2" - checksum: f2c314b314ec6e8a6e559351bff3c7ee9aed7a5e9c6f61dd8cb9e1382c8bfe33dca3f0e0af13daf9ded9e6e66390ff23b4acfb615d7a249009a51506a7b0f151 + checksum: 3d629a086a9585bc16a83a8e8a3416f400023301855cafb7ccc9a1d63145b7480f0ad28877dcc2cce09492c4ec1c39ef4c071996f24ee6ac626be4217b8ffc8a languageName: node linkType: hard @@ -9264,14 +10281,14 @@ __metadata: resolution: "is-accessor-descriptor@npm:1.0.0" dependencies: kind-of: "npm:^6.0.0" - checksum: d68edafd8ef133e9003837f3c80f4e5b82b12ab5456c772d1796857671ae83e3a426ed225a28a7e35bceabbce68c1f1ffdabf47e6d53f5a4d6c4558776ad3c20 + checksum: 8e475968e9b22f9849343c25854fa24492dbe8ba0dea1a818978f9f1b887339190b022c9300d08c47fe36f1b913d70ce8cbaca00369c55a56705fdb7caed37fe languageName: node linkType: hard "is-alphabetical@npm:^1.0.0": version: 1.0.4 resolution: "is-alphabetical@npm:1.0.4" - checksum: 1505b1de5a1fd74022c05fb21b0e683a8f5229366bac8dc4d34cf6935bcfd104d1125a5e6b083fb778847629f76e5bdac538de5367bdf2b927a1356164e23985 + checksum: 6508cce44fd348f06705d377b260974f4ce68c74000e7da4045f0d919e568226dc3ce9685c5a2af272195384df6930f748ce9213fc9f399b5d31b362c66312cb languageName: node linkType: hard @@ -9281,7 +10298,7 @@ __metadata: dependencies: is-alphabetical: "npm:^1.0.0" is-decimal: "npm:^1.0.0" - checksum: d623abae7130a7015c6bf33d99151d4e7005572fd170b86568ff4de5ae86ac7096608b87dd4a1d4dbbd497e392b6396930ba76c9297a69455909cebb68005905 + checksum: e2e491acc16fcf5b363f7c726f666a9538dba0a043665740feb45bba1652457a73441e7c5179c6768a638ed396db3437e9905f403644ec7c468fb41f4813d03f languageName: node linkType: hard @@ -9291,7 +10308,7 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" has-tostringtag: "npm:^1.0.0" - checksum: 5ff1f341ee4475350adfc14b2328b38962564b7c2076be2f5bac7bd9b61779efba99b9f844a7b82ba7654adccf8e8eb19d1bb0cc6d1c1a085e498f6793d4328f + checksum: 7f02700ec2171b691ef3e4d0e3e6c0ba408e8434368504bb593d0d7c891c0dbfda6d19d30808b904a6cb1929bca648c061ba438c39f296c2a8ca083229c49f27 languageName: node linkType: hard @@ -9302,14 +10319,14 @@ __metadata: call-bind: "npm:^1.0.2" get-intrinsic: "npm:^1.2.0" is-typed-array: "npm:^1.1.10" - checksum: 40ed13a5f5746ac3ae2f2e463687d9b5a3f5fd0086f970fb4898f0253c2a5ec2e3caea2d664dd8f54761b1c1948609702416921a22faebe160c7640a9217c80e + checksum: dcac9dda66ff17df9cabdc58214172bf41082f956eab30bb0d86bc0fab1e44b690fc8e1f855cf2481245caf4e8a5a006a982a71ddccec84032ed41f9d8da8c14 languageName: node linkType: hard "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" - checksum: e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729 + checksum: eef4417e3c10e60e2c810b6084942b3ead455af16c4509959a27e490e7aee87cfb3f38e01bbde92220b528a0ee1a18d52b787e1458ee86174d8c7f0e58cd488f languageName: node linkType: hard @@ -9318,7 +10335,7 @@ __metadata: resolution: "is-bigint@npm:1.0.4" dependencies: has-bigints: "npm:^1.0.1" - checksum: eb9c88e418a0d195ca545aff2b715c9903d9b0a5033bc5922fec600eb0c3d7b1ee7f882dbf2e0d5a6e694e42391be3683e4368737bd3c4a77f8ac293e7773696 + checksum: c56edfe09b1154f8668e53ebe8252b6f185ee852a50f9b41e8d921cb2bed425652049fbe438723f6cb48a63ca1aa051e948e7e401e093477c99c84eba244f666 languageName: node linkType: hard @@ -9327,7 +10344,7 @@ __metadata: resolution: "is-binary-path@npm:2.1.0" dependencies: binary-extensions: "npm:^2.0.0" - checksum: a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 + checksum: 84192eb88cff70d320426f35ecd63c3d6d495da9d805b19bc65b518984b7c0760280e57dbf119b7e9be6b161784a5a673ab2c6abe83abb5198a432232ad5b35c languageName: node linkType: hard @@ -9337,21 +10354,21 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" has-tostringtag: "npm:^1.0.0" - checksum: 6090587f8a8a8534c0f816da868bc94f32810f08807aa72fa7e79f7e11c466d281486ffe7a788178809c2aa71fe3e700b167fe80dd96dad68026bfff8ebf39f7 + checksum: c03b23dbaacadc18940defb12c1c0e3aaece7553ef58b162a0f6bba0c2a7e1551b59f365b91e00d2dbac0522392d576ef322628cb1d036a0fe51eb466db67222 languageName: node linkType: hard "is-buffer@npm:^1.1.5": version: 1.1.6 resolution: "is-buffer@npm:1.1.6" - checksum: ae18aa0b6e113d6c490ad1db5e8df9bdb57758382b313f5a22c9c61084875c6396d50bbf49315f5b1926d142d74dfb8d31b40d993a383e0a158b15fea7a82234 + checksum: 4a186d995d8bbf9153b4bd9ff9fd04ae75068fe695d29025d25e592d9488911eeece84eefbd8fa41b8ddcc0711058a71d4c466dcf6f1f6e1d83830052d8ca707 languageName: node linkType: hard "is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.7": version: 1.2.7 resolution: "is-callable@npm:1.2.7" - checksum: ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f + checksum: 61fd57d03b0d984e2ed3720fb1c7a897827ea174bd44402878e059542ea8c4aeedee0ea0985998aa5cc2736b2fa6e271c08587addb5b3959ac52cf665173d1ac languageName: node linkType: hard @@ -9360,7 +10377,7 @@ __metadata: resolution: "is-core-module@npm:2.12.1" dependencies: has: "npm:^1.0.3" - checksum: ff1d0dfc0b7851310d289398e416eb92ae8a9ac7ea8b8b9737fa8c0725f5a78c5f3db6edd4dff38c9ed731f3aaa1f6410a320233fcb52a2c8f1cf58eebf10a4b + checksum: f04ea30533b5e62764e7b2e049d3157dc0abd95ef44275b32489ea2081176ac9746ffb1cdb107445cf1ff0e0dfcad522726ca27c27ece64dadf3795428b8e468 languageName: node linkType: hard @@ -9369,7 +10386,7 @@ __metadata: resolution: "is-data-descriptor@npm:0.1.4" dependencies: kind-of: "npm:^3.0.2" - checksum: 32fda7e966b2c1f093230d5ef2aad1bb86e43e7280da50961e38ec31dbd8a50570a2911fd45277d321074a0762adc98e8462bb62820462594128857225e90d21 + checksum: 5c622e078ba933a78338ae398a3d1fc5c23332b395312daf4f74bab4afb10d061cea74821add726cb4db8b946ba36217ee71a24fe71dd5bca4632edb7f6aad87 languageName: node linkType: hard @@ -9378,7 +10395,7 @@ __metadata: resolution: "is-data-descriptor@npm:1.0.0" dependencies: kind-of: "npm:^6.0.0" - checksum: bed31385d7d1a0dbb2ab3077faf2188acf42609192dca4e320ed7b3dc14a9d70c00658956cdaa2c0402be136c6b56e183973ad81b730fd90ab427fb6fd3608be + checksum: e705e6816241c013b05a65dc452244ee378d1c3e3842bd140beabe6e12c0d700ef23c91803f971aa7b091fb0573c5da8963af34a2b573337d87bc3e1f53a4e6d languageName: node linkType: hard @@ -9387,21 +10404,21 @@ __metadata: resolution: "is-date-object@npm:1.0.5" dependencies: has-tostringtag: "npm:^1.0.0" - checksum: eed21e5dcc619c48ccef804dfc83a739dbb2abee6ca202838ee1bd5f760fe8d8a93444f0d49012ad19bb7c006186e2884a1b92f6e1c056da7fd23d0a9ad5992e + checksum: baa9077cdf15eb7b58c79398604ca57379b2fc4cf9aa7a9b9e295278648f628c9b201400c01c5e0f7afae56507d741185730307cbe7cad3b9f90a77e5ee342fc languageName: node linkType: hard "is-decimal@npm:^1.0.0": version: 1.0.4 resolution: "is-decimal@npm:1.0.4" - checksum: a4ad53c4c5c4f5a12214e7053b10326711f6a71f0c63ba1314a77bd71df566b778e4ebd29f9fb6815f07a4dc50c3767fb19bd6fc9fa05e601410f1d64ffeac48 + checksum: ed483a387517856dc395c68403a10201fddcc1b63dc56513fbe2fe86ab38766120090ecdbfed89223d84ca8b1cd28b0641b93cb6597b6e8f4c097a7c24e3fb96 languageName: node linkType: hard "is-deflate@npm:^1.0.0": version: 1.0.0 resolution: "is-deflate@npm:1.0.0" - checksum: 35f7ffcbef3549dd8a4d8df5dc09b4f4656a0fc88326e8b5201cda54114a9c2d8efb689d87c16f3f35c95bd71dcf13dc790d62b7504745b42c53ab4b40238f5a + checksum: c2f9f2d3db79ac50c5586697d1e69a55282a2b0cc5e437b3c470dd47f24e40b6216dcd7e024511e21381607bf57afa019343e3bd0e08a119032818b596004262 languageName: node linkType: hard @@ -9412,7 +10429,7 @@ __metadata: is-accessor-descriptor: "npm:^0.1.6" is-data-descriptor: "npm:^0.1.4" kind-of: "npm:^5.0.0" - checksum: 6b8f5617b764ef8c6be3d54830184357e6cdedd8e0eddf1b97d0658616ac170bfdbc7c1ad00e0aa9f5b767acdb9d6c63d4df936501784b34936bd0f9acf3b665 + checksum: 0f780c1b46b465f71d970fd7754096ffdb7b69fd8797ca1f5069c163eaedcd6a20ec4a50af669075c9ebcfb5266d2e53c8b227e485eefdb0d1fee09aa1dd8ab6 languageName: node linkType: hard @@ -9423,7 +10440,7 @@ __metadata: is-accessor-descriptor: "npm:^1.0.0" is-data-descriptor: "npm:^1.0.0" kind-of: "npm:^6.0.2" - checksum: a05169c7a87feb88fc155e3ada469090cfabb5a548a3f794358b511cc47a0871b8b95e7345be4925a22ef3df585c3923b31943b3ad6255ce563a9d97f2e221e0 + checksum: 2ed623560bee035fb67b23e32ce885700bef8abe3fbf8c909907d86507b91a2c89a9d3a4d835a4d7334dd5db0237a0aeae9ca109c1e4ef1c0e7b577c0846ab5a languageName: node linkType: hard @@ -9432,14 +10449,14 @@ __metadata: resolution: "is-docker@npm:2.2.1" bin: is-docker: cli.js - checksum: e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc + checksum: 3fef7ddbf0be25958e8991ad941901bf5922ab2753c46980b60b05c1bf9c9c2402d35e6dc32e4380b980ef5e1970a5d9d5e5aa2e02d77727c3b6b5e918474c56 languageName: node linkType: hard "is-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1": version: 0.1.1 resolution: "is-extendable@npm:0.1.1" - checksum: dd5ca3994a28e1740d1e25192e66eed128e0b2ff161a7ea348e87ae4f616554b486854de423877a2a2c171d5f7cd6e8093b91f54533bc88a59ee1c9838c43879 + checksum: 3875571d20a7563772ecc7a5f36cb03167e9be31ad259041b4a8f73f33f885441f778cee1f1fe0085eb4bc71679b9d8c923690003a36a6a5fdf8023e6e3f0672 languageName: node linkType: hard @@ -9448,28 +10465,28 @@ __metadata: resolution: "is-extendable@npm:1.0.1" dependencies: is-plain-object: "npm:^2.0.4" - checksum: 1d6678a5be1563db6ecb121331c819c38059703f0179f52aa80c242c223ee9c6b66470286636c0e63d7163e4d905c0a7d82a096e0b5eaeabb51b9f8d0af0d73f + checksum: db07bc1e9de6170de70eff7001943691f05b9d1547730b11be01c0ebfe67362912ba743cf4be6fd20a5e03b4180c685dad80b7c509fe717037e3eee30ad8e84f languageName: node linkType: hard "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" - checksum: 5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 + checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 languageName: node linkType: hard "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc + checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 languageName: node linkType: hard "is-generator-fn@npm:^2.0.0": version: 2.1.0 resolution: "is-generator-fn@npm:2.1.0" - checksum: 2957cab387997a466cd0bf5c1b6047bd21ecb32bdcfd8996b15747aa01002c1c88731802f1b3d34ac99f4f6874b626418bd118658cf39380fe5fff32a3af9c4d + checksum: a6ad5492cf9d1746f73b6744e0c43c0020510b59d56ddcb78a91cbc173f09b5e6beff53d75c9c5a29feb618bfef2bf458e025ecf3a57ad2268e2fb2569f56215 languageName: node linkType: hard @@ -9478,7 +10495,7 @@ __metadata: resolution: "is-generator-function@npm:1.0.10" dependencies: has-tostringtag: "npm:^1.0.0" - checksum: df03514df01a6098945b5a0cfa1abff715807c8e72f57c49a0686ad54b3b74d394e2d8714e6f709a71eb00c9630d48e73ca1796c1ccc84ac95092c1fecc0d98b + checksum: d54644e7dbaccef15ceb1e5d91d680eb5068c9ee9f9eb0a9e04173eb5542c9b51b5ab52c5537f5703e48d5fddfd376817c1ca07a84a407b7115b769d4bdde72b languageName: node linkType: hard @@ -9487,52 +10504,59 @@ __metadata: resolution: "is-glob@npm:4.0.3" dependencies: is-extglob: "npm:^2.1.1" - checksum: 17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a + checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 languageName: node linkType: hard "is-gzip@npm:^1.0.0": version: 1.0.0 resolution: "is-gzip@npm:1.0.0" - checksum: cbc1db080c636a6fb0f7346e3076f8276a29a9d8b52ae67c1971a8131c43f308e98ed227d1a6f49970e6c6ebabee0568e60aed7a3579dd4e1817cddf2faaf9b7 + checksum: 0d28931c1f445fa29c900cf9f48e06e9d1d477a3bf7bd7332e7ce68f1333ccd8cb381de2f0f62a9a262d9c0912608a9a71b4a40e788e201b3dbd67072bb20d86 languageName: node linkType: hard "is-hexadecimal@npm:^1.0.0": version: 1.0.4 resolution: "is-hexadecimal@npm:1.0.4" - checksum: ec4c64e5624c0f240922324bc697e166554f09d3ddc7633fc526084502626445d0a871fbd8cae52a9844e83bd0bb414193cc5a66806d7b2867907003fc70c5ea + checksum: a452e047587b6069332d83130f54d30da4faf2f2ebaa2ce6d073c27b5703d030d58ed9e0b729c8e4e5b52c6f1dab26781bb77b7bc6c7805f14f320e328ff8cd5 + languageName: node + linkType: hard + +"is-interactive@npm:^1.0.0": + version: 1.0.0 + resolution: "is-interactive@npm:1.0.0" + checksum: 824808776e2d468b2916cdd6c16acacebce060d844c35ca6d82267da692e92c3a16fdba624c50b54a63f38bdc4016055b6f443ce57d7147240de4f8cdabaf6f9 languageName: node linkType: hard "is-lambda@npm:^1.0.1": version: 1.0.1 resolution: "is-lambda@npm:1.0.1" - checksum: 85fee098ae62ba6f1e24cf22678805473c7afd0fb3978a3aa260e354cb7bcb3a5806cf0a98403188465efedec41ab4348e8e4e79305d409601323855b3839d4d + checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 languageName: node linkType: hard "is-map@npm:^2.0.1, is-map@npm:^2.0.2": version: 2.0.2 resolution: "is-map@npm:2.0.2" - checksum: 119ff9137a37fd131a72fab3f4ab8c9d6a24b0a1ee26b4eff14dc625900d8675a97785eea5f4174265e2006ed076cc24e89f6e57ebd080a48338d914ec9168a5 + checksum: ace3d0ecd667bbdefdb1852de601268f67f2db725624b1958f279316e13fecb8fa7df91fd60f690d7417b4ec180712f5a7ee967008e27c65cfd475cc84337728 languageName: node linkType: hard -"is-nan@npm:^1.2.1": +"is-nan@npm:^1.2.1, is-nan@npm:^1.3.2": version: 1.3.2 resolution: "is-nan@npm:1.3.2" dependencies: call-bind: "npm:^1.0.0" define-properties: "npm:^1.1.3" - checksum: 8bfb286f85763f9c2e28ea32e9127702fe980ffd15fa5d63ade3be7786559e6e21355d3625dd364c769c033c5aedf0a2ed3d4025d336abf1b9241e3d9eddc5b0 + checksum: 5dfadcef6ad12d3029d43643d9800adbba21cf3ce2ec849f734b0e14ee8da4070d82b15fdb35138716d02587c6578225b9a22779cab34888a139cc43e4e3610a languageName: node linkType: hard "is-negative-zero@npm:^2.0.2": version: 2.0.2 resolution: "is-negative-zero@npm:2.0.2" - checksum: eda024c158f70f2017f3415e471b818d314da5ef5be68f801b16314d4a4b6304a74cbed778acf9e2f955bb9c1c5f2935c1be0c7c99e1ad12286f45366217b6a3 + checksum: f3232194c47a549da60c3d509c9a09be442507616b69454716692e37ae9f37c4dea264fb208ad0c9f3efd15a796a46b79df07c7e53c6227c32170608b809149a languageName: node linkType: hard @@ -9541,7 +10565,7 @@ __metadata: resolution: "is-number-object@npm:1.0.7" dependencies: has-tostringtag: "npm:^1.0.0" - checksum: aad266da1e530f1804a2b7bd2e874b4869f71c98590b3964f9d06cc9869b18f8d1f4778f838ecd2a11011bce20aeecb53cb269ba916209b79c24580416b74b1b + checksum: d1e8d01bb0a7134c74649c4e62da0c6118a0bfc6771ea3c560914d52a627873e6920dd0fd0ebc0e12ad2ff4687eac4c308f7e80320b973b2c8a2c8f97a7524f7 languageName: node linkType: hard @@ -9550,42 +10574,42 @@ __metadata: resolution: "is-number@npm:3.0.0" dependencies: kind-of: "npm:^3.0.2" - checksum: e639c54640b7f029623df24d3d103901e322c0c25ea5bde97cd723c2d0d4c05857a8364ab5c58d963089dbed6bf1d0ffe975cb6aef917e2ad0ccbca653d31b4f + checksum: 0c62bf8e9d72c4dd203a74d8cfc751c746e75513380fef420cda8237e619a988ee43e678ddb23c87ac24d91ac0fe9f22e4ffb1301a50310c697e9d73ca3994e9 languageName: node linkType: hard "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" - checksum: b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 + checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a languageName: node linkType: hard "is-path-cwd@npm:^2.2.0": version: 2.2.0 resolution: "is-path-cwd@npm:2.2.0" - checksum: afce71533a427a759cd0329301c18950333d7589533c2c90205bd3fdcf7b91eb92d1940493190567a433134d2128ec9325de2fd281e05be1920fbee9edd22e0a + checksum: 46a840921bb8cc0dc7b5b423a14220e7db338072a4495743a8230533ce78812dc152548c86f4b828411fe98c5451959f07cf841c6a19f611e46600bd699e8048 languageName: node linkType: hard "is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" - checksum: cf7d4ac35fb96bab6a1d2c3598fe5ebb29aafb52c0aaa482b5a3ed9d8ba3edc11631e3ec2637660c44b3ce0e61a08d54946e8af30dec0b60a7c27296c68ffd05 + checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 languageName: node linkType: hard "is-plain-obj@npm:^1.1": version: 1.1.0 resolution: "is-plain-obj@npm:1.1.0" - checksum: daaee1805add26f781b413fdf192fc91d52409583be30ace35c82607d440da63cc4cac0ac55136716688d6c0a2c6ef3edb2254fecbd1fe06056d6bd15975ee8c + checksum: 0ee04807797aad50859652a7467481816cbb57e5cc97d813a7dcd8915da8195dc68c436010bf39d195226cde6a2d352f4b815f16f26b7bf486a5754290629931 languageName: node linkType: hard "is-plain-object@npm:5.0.0": version: 5.0.0 resolution: "is-plain-object@npm:5.0.0" - checksum: 893e42bad832aae3511c71fd61c0bf61aa3a6d853061c62a307261842727d0d25f761ce9379f7ba7226d6179db2a3157efa918e7fe26360f3bf0842d9f28942c + checksum: e32d27061eef62c0847d303125440a38660517e586f2f3db7c9d179ae5b6674ab0f469d519b2e25c147a1a3bc87156d0d5f4d8821e0ce4a9ee7fe1fcf11ce45c languageName: node linkType: hard @@ -9594,14 +10618,14 @@ __metadata: resolution: "is-plain-object@npm:2.0.4" dependencies: isobject: "npm:^3.0.1" - checksum: f050fdd5203d9c81e8c4df1b3ff461c4bc64e8b5ca383bcdde46131361d0a678e80bcf00b5257646f6c636197629644d53bd8e2375aea633de09a82d57e942f4 + checksum: 2a401140cfd86cabe25214956ae2cfee6fbd8186809555cd0e84574f88de7b17abacb2e477a6a658fa54c6083ecbda1e6ae404c7720244cd198903848fca70ca languageName: node linkType: hard "is-potential-custom-element-name@npm:^1.0.1": version: 1.0.1 resolution: "is-potential-custom-element-name@npm:1.0.1" - checksum: b73e2f22bc863b0939941d369486d308b43d7aef1f9439705e3582bfccaa4516406865e32c968a35f97a99396dac84e2624e67b0a16b0a15086a785e16ce7db9 + checksum: ced7bbbb6433a5b684af581872afe0e1767e2d1146b2207ca0068a648fb5cab9d898495d1ac0583524faaf24ca98176a7d9876363097c2d14fee6dd324f3a1ab languageName: node linkType: hard @@ -9611,14 +10635,14 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" has-tostringtag: "npm:^1.0.0" - checksum: bb72aae604a69eafd4a82a93002058c416ace8cde95873589a97fc5dac96a6c6c78a9977d487b7b95426a8f5073969124dd228f043f9f604f041f32fcc465fc1 + checksum: 362399b33535bc8f386d96c45c9feb04cf7f8b41c182f54174c1a45c9abbbe5e31290bbad09a458583ff6bf3b2048672cdb1881b13289569a7c548370856a652 languageName: node linkType: hard "is-set@npm:^2.0.1, is-set@npm:^2.0.2": version: 2.0.2 resolution: "is-set@npm:2.0.2" - checksum: 5f8bd1880df8c0004ce694e315e6e1e47a3452014be792880bb274a3b2cdb952fdb60789636ca6e084c7947ca8b7ae03ccaf54c93a7fcfed228af810559e5432 + checksum: b64343faf45e9387b97a6fd32be632ee7b269bd8183701f3b3f5b71a7cf00d04450ed8669d0bd08753e08b968beda96fca73a10fd0ff56a32603f64deba55a57 languageName: node linkType: hard @@ -9627,14 +10651,14 @@ __metadata: resolution: "is-shared-array-buffer@npm:1.0.2" dependencies: call-bind: "npm:^1.0.2" - checksum: cfeee6f171f1b13e6cbc6f3b6cc44e192b93df39f3fcb31aa66ffb1d2df3b91e05664311659f9701baba62f5e98c83b0673c628e7adc30f55071c4874fcdccec + checksum: 9508929cf14fdc1afc9d61d723c6e8d34f5e117f0bffda4d97e7a5d88c3a8681f633a74f8e3ad1fe92d5113f9b921dc5ca44356492079612f9a247efbce7032a languageName: node linkType: hard "is-stream@npm:^2.0.0": version: 2.0.1 resolution: "is-stream@npm:2.0.1" - checksum: 7c284241313fc6efc329b8d7f08e16c0efeb6baab1b4cd0ba579eb78e5af1aa5da11e68559896a2067cd6c526bd29241dda4eb1225e627d5aa1a89a76d4635a5 + checksum: b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 languageName: node linkType: hard @@ -9643,7 +10667,7 @@ __metadata: resolution: "is-string@npm:1.0.7" dependencies: has-tostringtag: "npm:^1.0.0" - checksum: 905f805cbc6eedfa678aaa103ab7f626aac9ebbdc8737abb5243acaa61d9820f8edc5819106b8fcd1839e33db21de9f0116ae20de380c8382d16dc2a601921f6 + checksum: 323b3d04622f78d45077cf89aab783b2f49d24dc641aa89b5ad1a72114cfeff2585efc8c12ef42466dff32bde93d839ad321b26884cf75e5a7892a938b089989 languageName: node linkType: hard @@ -9652,7 +10676,7 @@ __metadata: resolution: "is-symbol@npm:1.0.4" dependencies: has-symbols: "npm:^1.0.2" - checksum: 9381dd015f7c8906154dbcbf93fad769de16b4b961edc94f88d26eb8c555935caa23af88bda0c93a18e65560f6d7cca0fd5a3f8a8e1df6f1abbb9bead4502ef7 + checksum: 92805812ef590738d9de49d677cd17dfd486794773fb6fa0032d16452af46e9b91bb43ffe82c983570f015b37136f4b53b28b8523bfb10b0ece7a66c31a54510 languageName: node linkType: hard @@ -9665,14 +10689,21 @@ __metadata: for-each: "npm:^0.3.3" gopd: "npm:^1.0.1" has-tostringtag: "npm:^1.0.0" - checksum: b71268a2e5f493f2b95af4cbfe7a65254a822f07d57f20c18f084347cd45f11810915fe37d7a6831fe4b81def24621a042fd1169ec558c50f830b591bc8c1f66 + checksum: aac6ecb59d4c56a1cdeb69b1f129154ef462bbffe434cb8a8235ca89b42f258b7ae94073c41b3cb7bce37f6a1733ad4499f07882d5d5093a7ba84dfc4ebb8017 + languageName: node + linkType: hard + +"is-unicode-supported@npm:^0.1.0": + version: 0.1.0 + resolution: "is-unicode-supported@npm:0.1.0" + checksum: a2aab86ee7712f5c2f999180daaba5f361bdad1efadc9610ff5b8ab5495b86e4f627839d085c6530363c6d6d4ecbde340fb8e54bdb83da4ba8e0865ed5513c52 languageName: node linkType: hard "is-weakmap@npm:^2.0.1": version: 2.0.1 resolution: "is-weakmap@npm:2.0.1" - checksum: 9c9fec9efa7bf5030a4a927f33fff2a6976b93646259f92b517d3646c073cc5b98283a162ce75c412b060a46de07032444b530f0a4c9b6e012ef8f1741c3a987 + checksum: 1222bb7e90c32bdb949226e66d26cb7bce12e1e28e3e1b40bfa6b390ba3e08192a8664a703dff2a00a84825f4e022f9cd58c4599ff9981ab72b1d69479f4f7f6 languageName: node linkType: hard @@ -9681,7 +10712,7 @@ __metadata: resolution: "is-weakref@npm:1.0.2" dependencies: call-bind: "npm:^1.0.2" - checksum: 1545c5d172cb690c392f2136c23eec07d8d78a7f57d0e41f10078aa4f5daf5d7f57b6513a67514ab4f073275ad00c9822fc8935e00229d0a2089e1c02685d4b1 + checksum: 95bd9a57cdcb58c63b1c401c60a474b0f45b94719c30f548c891860f051bc2231575c290a6b420c6bc6e7ed99459d424c652bd5bf9a1d5259505dc35b4bf83de languageName: node linkType: hard @@ -9691,44 +10722,44 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" get-intrinsic: "npm:^1.1.1" - checksum: ef5136bd446ae4603229b897f73efd0720c6ab3ec6cc05c8d5c4b51aa9f95164713c4cad0a22ff1fedf04865ff86cae4648bc1d5eead4b6388e1150525af1cc1 + checksum: 5d8698d1fa599a0635d7ca85be9c26d547b317ed8fd83fc75f03efbe75d50001b5eececb1e9971de85fcde84f69ae6f8346bc92d20d55d46201d328e4c74a367 languageName: node linkType: hard "is-windows@npm:^1.0.2": version: 1.0.2 resolution: "is-windows@npm:1.0.2" - checksum: b32f418ab3385604a66f1b7a3ce39d25e8881dee0bd30816dc8344ef6ff9df473a732bcc1ec4e84fe99b2f229ae474f7133e8e93f9241686cfcf7eebe53ba7a5 + checksum: 438b7e52656fe3b9b293b180defb4e448088e7023a523ec21a91a80b9ff8cdb3377ddb5b6e60f7c7de4fa8b63ab56e121b6705fe081b3cf1b828b0a380009ad7 languageName: node linkType: hard -"is-wsl@npm:^2.1.1, is-wsl@npm:^2.2.0": +"is-wsl@npm:^2.2.0": version: 2.2.0 resolution: "is-wsl@npm:2.2.0" dependencies: is-docker: "npm:^2.0.0" - checksum: a6fa2d370d21be487c0165c7a440d567274fbba1a817f2f0bfa41cc5e3af25041d84267baa22df66696956038a43973e72fca117918c91431920bdef490fa25e + checksum: 20849846ae414997d290b75e16868e5261e86ff5047f104027026fd61d8b5a9b0b3ade16239f35e1a067b3c7cc02f70183cb661010ed16f4b6c7c93dad1b19d8 languageName: node linkType: hard "isarray@npm:1.0.0, isarray@npm:~1.0.0": version: 1.0.0 resolution: "isarray@npm:1.0.0" - checksum: 18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d + checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab languageName: node linkType: hard "isarray@npm:^2.0.5": version: 2.0.5 resolution: "isarray@npm:2.0.5" - checksum: 4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd + checksum: bd5bbe4104438c4196ba58a54650116007fa0262eccef13a4c55b2e09a5b36b59f1e75b9fcc49883dd9d4953892e6fc007eef9e9155648ceea036e184b0f930a languageName: node linkType: hard "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" - checksum: 228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d + checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 languageName: node linkType: hard @@ -9737,31 +10768,21 @@ __metadata: resolution: "isobject@npm:2.1.0" dependencies: isarray: "npm:1.0.0" - checksum: c4cafec73b3b2ee11be75dff8dafd283b5728235ac099b07d7873d5182553a707768e208327bbc12931b9422d8822280bf88d894a0024ff5857b3efefb480e7b + checksum: 811c6f5a866877d31f0606a88af4a45f282544de886bf29f6a34c46616a1ae2ed17076cc6bf34c0128f33eecf7e1fcaa2c82cf3770560d3e26810894e96ae79f languageName: node linkType: hard "isobject@npm:^3.0.0, isobject@npm:^3.0.1": version: 3.0.1 resolution: "isobject@npm:3.0.1" - checksum: 03344f5064a82f099a0cd1a8a407f4c0d20b7b8485e8e816c39f249e9416b06c322e8dec5b842b6bb8a06de0af9cb48e7bc1b5352f0fadc2f0abac033db3d4db - languageName: node - linkType: hard - -"isomorphic-unfetch@npm:^3.1.0": - version: 3.1.0 - resolution: "isomorphic-unfetch@npm:3.1.0" - dependencies: - node-fetch: "npm:^2.6.1" - unfetch: "npm:^4.2.0" - checksum: d3b61fca06304db692b7f76bdfd3a00f410e42cfa7403c3b250546bf71589d18cf2f355922f57198e4cc4a9872d3647b20397a5c3edf1a347c90d57c83cf2a89 + checksum: db85c4c970ce30693676487cca0e61da2ca34e8d4967c2e1309143ff910c207133a969f9e4ddb2dc6aba670aabce4e0e307146c310350b298e74a31f7d464703 languageName: node linkType: hard "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": version: 3.2.0 resolution: "istanbul-lib-coverage@npm:3.2.0" - checksum: 10ecb00a50cac2f506af8231ce523ffa1ac1310db0435c8ffaabb50c1d72539906583aa13c84f8835dc103998b9989edc3c1de989d2e2a96a91a9ba44e5db6b9 + checksum: a2a545033b9d56da04a8571ed05c8120bf10e9bce01cf8633a3a2b0d1d83dff4ac4fe78d6d5673c27fc29b7f21a41d75f83a36be09f82a61c367b56aa73c1ff9 languageName: node linkType: hard @@ -9774,7 +10795,7 @@ __metadata: "@istanbuljs/schema": "npm:^0.1.2" istanbul-lib-coverage: "npm:^3.2.0" semver: "npm:^6.3.0" - checksum: 8a1bdf3e377dcc0d33ec32fe2b6ecacdb1e4358fd0eb923d4326bb11c67622c0ceb99600a680f3dad5d29c66fc1991306081e339b4d43d0b8a2ab2e1d910a6ee + checksum: bf16f1803ba5e51b28bbd49ed955a736488381e09375d830e42ddeb403855b2006f850711d95ad726f2ba3f1ae8e7366de7e51d2b9ac67dc4d80191ef7ddf272 languageName: node linkType: hard @@ -9785,7 +10806,7 @@ __metadata: istanbul-lib-coverage: "npm:^3.0.0" make-dir: "npm:^3.0.0" supports-color: "npm:^7.1.0" - checksum: 81b0d5187c7603ed71bdea0b701a7329f8146549ca19aa26d91b4a163aea756f9d55c1a6dc1dcd087e24dfcb99baa69e266a68644fbfd5dc98107d6f6f5948d2 + checksum: 3f29eb3f53c59b987386e07fe772d24c7f58c6897f34c9d7a296f4000de7ae3de9eb95c3de3df91dc65b134c84dee35c54eee572a56243e8907c48064e34ff1b languageName: node linkType: hard @@ -9796,17 +10817,17 @@ __metadata: debug: "npm:^4.1.1" istanbul-lib-coverage: "npm:^3.0.0" source-map: "npm:^0.6.1" - checksum: 19e4cc405016f2c906dff271a76715b3e881fa9faeb3f09a86cb99b8512b3a5ed19cadfe0b54c17ca0e54c1142c9c6de9330d65506e35873994e06634eebeb66 + checksum: 21ad3df45db4b81852b662b8d4161f6446cd250c1ddc70ef96a585e2e85c26ed7cd9c2a396a71533cfb981d1a645508bc9618cae431e55d01a0628e7dec62ef2 languageName: node linkType: hard -"istanbul-reports@npm:^3.1.3, istanbul-reports@npm:^3.1.4": +"istanbul-reports@npm:^3.1.3": version: 3.1.5 resolution: "istanbul-reports@npm:3.1.5" dependencies: html-escaper: "npm:^2.0.0" istanbul-lib-report: "npm:^3.0.0" - checksum: 3a147171bffdbd3034856410b6ec81637871d17d10986513328fec23df6b666f66bd08ea480f5b7a5b9f7e8abc30f3e3c2e7d1b661fc57cdc479aaaa677b1011 + checksum: 7867228f83ed39477b188ea07e7ccb9b4f5320b6f73d1db93a0981b7414fa4ef72d3f80c4692c442f90fc250d9406e71d8d7ab65bb615cb334e6292b73192b89 languageName: node linkType: hard @@ -9819,7 +10840,20 @@ __metadata: dependenciesMeta: "@pkgjs/parseargs": optional: true - checksum: 510860a5d1eaf12cba509a09a8f7d1696090bfa7c8ae75c6d9c836890d2897409f3b3dd91039cf0020627d6eba8c024f571ae4d78bd956162b07794ddfb9dd62 + checksum: e29291c0d0f280a063fa18fbd1e891ab8c2d7519fd34052c0ebde38538a15c603140d60c2c7f432375ff7ee4c5f1c10daa8b2ae19a97c3d4affe308c8360c1df + languageName: node + linkType: hard + +"jackspeak@npm:^2.3.5": + version: 2.3.6 + resolution: "jackspeak@npm:2.3.6" + dependencies: + "@isaacs/cliui": ^8.0.2 + "@pkgjs/parseargs": ^0.11.0 + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 57d43ad11eadc98cdfe7496612f6bbb5255ea69fe51ea431162db302c2a11011642f50cfad57288bd0aea78384a0612b16e131944ad8ecd09d619041c8531b54 languageName: node linkType: hard @@ -9833,7 +10867,7 @@ __metadata: minimatch: "npm:^3.1.2" bin: jake: bin/cli.js - checksum: 89326d01a8bc110d02d973729a66394c79a34b34461116f5c530a2a2dbc30265683fe6737928f75df9178e9d369ff1442f5753fb983d525e740eefdadc56a103 + checksum: a23fd2273fb13f0d0d845502d02c791fd55ef5c6a2d207df72f72d8e1eac6d2b8ffa6caf660bc8006b3242e0daaa88a3ecc600194d72b5c6016ad56e9cd43553 languageName: node linkType: hard @@ -9843,7 +10877,7 @@ __metadata: dependencies: execa: "npm:^5.0.0" p-limit: "npm:^3.1.0" - checksum: 96334c78507a13c0f11f1360d893ade78fba7fd169825ca4acf7565156ceddd89b952be81c00378fa87ab642d3f44902c34a20f21b561e985e79f6e81fa7e9a8 + checksum: a67a7cb3c11f8f92bd1b7c79e84f724cbd11a9ad51f3cdadafe3ce7ee3c79ee50dbea128f920f5fddc807e9e4e83f5462143094391feedd959a77dd20ab96cf3 languageName: node linkType: hard @@ -9871,7 +10905,7 @@ __metadata: pure-rand: "npm:^6.0.0" slash: "npm:^3.0.0" stack-utils: "npm:^2.0.3" - checksum: 9321dfabfa6fe41d4495f4fd21d1a840baacdfe9f0cc7c2346b89cd4f775ee37cc839c6d6aaac415059852bbdfafca1ed8c392999f7fbd152d6b231ca0920d1d + checksum: f3e39a74b601929448df92037f0599978d4d7a4b8f636f64e8020533d2d2b2f669d6729c80c6efed69341ca26753e5061e9787a0acd6c70af2127a94375ebb76 languageName: node linkType: hard @@ -9898,7 +10932,7 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: 37850378efcb5bea2d000d4c78eac5af871bcd53d3f8e60902f33f116ec847f9a3641ca78f1ca046b4c1c6e2031e084d78b01eba3592788b3e3c983c0d5a4b21 + checksum: f5854ffea977b9a12520ea71f8d0cc8a626cbb93d7e1e6eea18a2a1f2b25f70f1b6b08a89f11b4dc7dd36a1776a9ac2cf8ec5c7998086f913ee690c06c07c949 languageName: node linkType: hard @@ -9936,7 +10970,7 @@ __metadata: optional: true ts-node: optional: true - checksum: 6f3c3ac7587b651d22b199fdc3c4ad17a08397c2fcae05543a7a81e03a7e12355aaa3c75ce39e6df5c8fd8efcd65518cf05f528f7724cb8df17aa4e44dd74ecf + checksum: 3a30afeb28cc5658ef9cd95f2551ab8a29641bb6d377eb239cba8e7522eb4611c9a98cdcf173d87f5ad7b5e1ad242c3cd5434a260107bd3c7e8305d05023e05c languageName: node linkType: hard @@ -9948,7 +10982,7 @@ __metadata: diff-sequences: "npm:^29.4.3" jest-get-type: "npm:^29.4.3" pretty-format: "npm:^29.6.1" - checksum: f067d977937744df7dd8a269e2948620e4bcb35ff70d9ea1d0fe75a47fa603ce3edc350961b671c94f8de5adb65d6bdeb0002569b59983fba56f02dd4b47d171 + checksum: c6350178ca27d92c7fd879790fb2525470c1ff1c5d29b1834a240fecd26c6904fb470ebddb98dc96dd85389c56c3b50e6965a1f5203e9236d213886ed9806219 languageName: node linkType: hard @@ -9957,7 +10991,7 @@ __metadata: resolution: "jest-docblock@npm:29.4.3" dependencies: detect-newline: "npm:^3.0.0" - checksum: 25cdea8fe77ff09d958abd347e26dcd8766ca69d9935bc626a89d694c91d33be06d4c088b02e4b3f143f532f726a10dff0bfe1e2387a0972a95addf5d64ed407 + checksum: e0e9df1485bb8926e5b33478cdf84b3387d9caf3658e7dc1eaa6dc34cb93dea0d2d74797f6e940f0233a88f3dadd60957f2288eb8f95506361f85b84bf8661df languageName: node linkType: hard @@ -9970,7 +11004,7 @@ __metadata: jest-get-type: "npm:^29.4.3" jest-util: "npm:^29.6.1" pretty-format: "npm:^29.6.1" - checksum: b2cbea027a7d68c6a22afff1d460c866389e5c3ec1fece930b3fa79df24fb39f3ca258679de9ca0c2af4a6a70e5aa542ff6779f32d21289bdf981a7c1470aa0e + checksum: 9d2ea7ed5326ee8c22523b22c66c85fe73754ea39f9b389881956508ee441392c61072a5fbf673e39beddd31d011bb94acae3edc77053ba4f9aa5c060114a5c8 languageName: node linkType: hard @@ -9991,7 +11025,7 @@ __metadata: peerDependenciesMeta: canvas: optional: true - checksum: 972a1bdfb1d508a359951ec11ade5dfad7cfabea0ab9f7746737ba10e0c6381e34f2b4acb03c7e5eb623611813310dfb0775eb0607c5537b7618234d04aab2ac + checksum: 3df7fc85275711f20b483ac8cd8c04500704ed0f69791eb55c574b38f5a39470f03d775cf20c1025bc1884916ac0573aa2fa4db1bb74225bc7fdd95ba97ad0da languageName: node linkType: hard @@ -10005,14 +11039,14 @@ __metadata: "@types/node": "npm:*" jest-mock: "npm:^29.6.1" jest-util: "npm:^29.6.1" - checksum: 2e168708553f45c2afc42234dd78c4677d1bd34a11e0c8d43e8ca6da8e68cd55acb2215cdfc46cba8c5b1dbc0061783006ecbc214a02a5ae962602f80232d7fc + checksum: a50287e1ff29d131646bd09acc3222ac6ea0ad61e86bf73851d318ef2be0633a421b8558c4a15ddc67e0ffcfc32da7f6a0d8a2ddbfa85453837899dec88d256c languageName: node linkType: hard "jest-get-type@npm:^29.4.3": version: 29.4.3 resolution: "jest-get-type@npm:29.4.3" - checksum: 874b0ced6b1cc677ff7fcf0dc86d02674617a7d0b73d47097604fb3ca460178d16104efdd3837e8b8bf0520ad5d210838c07483b058802b457b8413e60628fd0 + checksum: 6ac7f2dde1c65e292e4355b6c63b3a4897d7e92cb4c8afcf6d397f2682f8080e094c8b0b68205a74d269882ec06bf696a9de6cd3e1b7333531e5ed7b112605ce languageName: node linkType: hard @@ -10035,7 +11069,7 @@ __metadata: dependenciesMeta: fsevents: optional: true - checksum: 6d100cd80c89d2c45175e6504eafe40ba4dfb1e77a4e204204a5f2905a4840e73ff66cee187b39e33a1af2406831a48f1f945efdf872071e19ac417eb0a3aac1 + checksum: 7c74d5a0f6aafa9f4e60fae7949d4774770c0243fb529c24f2f4c81229db479fa318dc8b81e8d226865aef1d600af10bd8404dd208e802318434b46f75d5d869 languageName: node linkType: hard @@ -10045,7 +11079,7 @@ __metadata: dependencies: jest-get-type: "npm:^29.4.3" pretty-format: "npm:^29.6.1" - checksum: 17e702b3a790e37dd76b93e2f782de228bb332030e478264f2eb081e1d13907f414a6ec2271b173b2516e7faa4c7b0ddd1c9c5ae9b9293ed921a9ee943fafd1a + checksum: 5122d40c248effaede4c9ee3a99046a3f30088fef7bfc4af534678b432455161399357af46deb6423de7e05c6597920d6ee8cd570e26048886a90d541334f8c8 languageName: node linkType: hard @@ -10057,7 +11091,7 @@ __metadata: jest-diff: "npm:^29.6.1" jest-get-type: "npm:^29.4.3" pretty-format: "npm:^29.6.1" - checksum: 4425bcb900bd25dbd679c220ef978f80aab11a7b6bed0e178cf8fe3c7167ecefdb6f522e3cf3e877a622160f781cea02aac43a3e243dc8afca917e90418434b8 + checksum: d2efa6aed6e4820758b732b9fefd315c7fa4508ee690da656e1c5ac4c1a0f4cee5b04c9719ee1fda9aeb883b4209186c145089ced521e715b9fa70afdfa4a9c6 languageName: node linkType: hard @@ -10074,7 +11108,7 @@ __metadata: pretty-format: "npm:^29.6.1" slash: "npm:^3.0.0" stack-utils: "npm:^2.0.3" - checksum: 7a34c7ee4efada36aa385a07e1d22f8b6183dda37f7bca15fcf2e9575e9b91ce6ea88429a0b749bc59d934327492e622913d7cd9ab23ca78c29353184795a68d + checksum: 3e7cb2ff087fe72255292e151d24e4fbb4cd6134885c0a67a4b302f233fe4110bf7580b176f427f05ad7550eb878ed94237209785d09d659a7d171ffa59c068f languageName: node linkType: hard @@ -10084,7 +11118,7 @@ __metadata: dependencies: "@jest/types": "npm:^27.5.1" "@types/node": "npm:*" - checksum: 6ad58454b37ee3f726930b07efbf40a7c79d2d2d9c7b226708b4b550bc0904de93bcacf714105d11952a5c0bc855e5d59145c8c9dbbb4e69b46e7367abf53b52 + checksum: f5b5904bb1741b4a1687a5f492535b7b1758dc26534c72a5423305f8711292e96a601dec966df81bb313269fb52d47227e29f9c2e08324d79529172f67311be0 languageName: node linkType: hard @@ -10095,7 +11129,7 @@ __metadata: "@jest/types": "npm:^29.6.1" "@types/node": "npm:*" jest-util: "npm:^29.6.1" - checksum: 26e666787d04f341887d7612b2ada7a9c86868dac319056dac46709a00fc2ee694e7a64fad8f0d5450690d779ddaacaff7a35aaf1716a165b3e1eaf56d0aa300 + checksum: 5e902f1a7eba1eb1a64eb6c19947fe1316834359d9869d0e2644d8979b9cad0465885dc4c9909c471888cddeea835c938cec6263d386d3d1aad720fc74e52ea1 languageName: node linkType: hard @@ -10107,14 +11141,14 @@ __metadata: peerDependenciesMeta: jest-resolve: optional: true - checksum: 86eec0c78449a2de733a6d3e316d49461af6a858070e113c97f75fb742a48c2396ea94150cbca44159ffd4a959f743a47a8b37a792ef6fdad2cf0a5cba973fac + checksum: db1a8ab2cb97ca19c01b1cfa9a9c8c69a143fde833c14df1fab0766f411b1148ff0df878adea09007ac6a2085ec116ba9a996a6ad104b1e58c20adbf88eed9b2 languageName: node linkType: hard "jest-regex-util@npm:^29.4.3": version: 29.4.3 resolution: "jest-regex-util@npm:29.4.3" - checksum: a7a4508bda47c5177e7337fb6fb22e9adab414ba141f224c9992c86973da1ccf5c69040e63636090ad26ef3a123d28bec950fa99496c157444b4f847e5e5a670 + checksum: 96fc7fc28cd4dd73a63c13a526202c4bd8b351d4e5b68b1a2a2c88da3308c2a16e26feaa593083eb0bac38cca1aa9dd05025412e7de013ba963fb8e66af22b8a languageName: node linkType: hard @@ -10124,7 +11158,7 @@ __metadata: dependencies: jest-regex-util: "npm:^29.4.3" jest-snapshot: "npm:^29.6.1" - checksum: 330fdc103dd1c01ae73e9e4fc4ae11d341569187a82c09aea41d50cdf9e5353d00b0405177db020b3af76cb0e402c98f2dab129afde7bcd5d99f5123d6182321 + checksum: cee0a0fe53fd4531492a526b6ccd32377baad1eff6e6c124f04e9dc920219fd23fd39be88bb9551ee68d5fe92a3af627b423c9bc65a2aa0ac8a223c0e74dbbbb languageName: node linkType: hard @@ -10141,7 +11175,7 @@ __metadata: resolve: "npm:^1.20.0" resolve.exports: "npm:^2.0.0" slash: "npm:^3.0.0" - checksum: 809ee25be7a97ed33755dbe536617cb83a0a8218c81310f5927f1a2f9e82e48353d60a5b0b630b6c25bc66825d0b2197c6c569d043a8431bae01ba6e226b5a57 + checksum: 9ce979a0f4a751bea58caea76415112df2a3f4d58e294019872244728aadd001f0ec20c873a3c805dd8f7c762143b3c14d00f87d124ed87c9981fbf8723090ef languageName: node linkType: hard @@ -10170,7 +11204,7 @@ __metadata: jest-worker: "npm:^29.6.1" p-limit: "npm:^3.1.0" source-map-support: "npm:0.5.13" - checksum: 69d4f22c06d06498ffacf658460c3b40d87d77ac924a9f1e5c176f56e49d696b86234473463a764bd227f056d6e4e3852a2e10f95c74d5861d7fc4c17101ab55 + checksum: 0e4dbda26669ae31fee32f8a62b3119bba510f2d17a098d6157b48a73ed2fc9842405bf893f3045c12b3632c7c0e3399fb22684b18ab5566aff4905b26c79a9a languageName: node linkType: hard @@ -10200,7 +11234,7 @@ __metadata: jest-util: "npm:^29.6.1" slash: "npm:^3.0.0" strip-bom: "npm:^4.0.0" - checksum: 79850c21fb630cb35fe23e7688daa67d387735cf2912febcd95ef4195bcc4931699d28e3b16e705fa8c2843fca958524133b1fa3fe0361bc2dac17192b40125b + checksum: 7c360c9694467d996f3d6d914fefa0e7bda554adda8c2b9fba31546dba663d71a64eda103ff68120a2422f3c16db8f0bc2c445923fe8fb934f37e53ef74fb429 languageName: node linkType: hard @@ -10229,7 +11263,7 @@ __metadata: natural-compare: "npm:^1.4.0" pretty-format: "npm:^29.6.1" semver: "npm:^7.5.3" - checksum: 1322fb9b23e7316b5f83d467ce2f46a65fdfa84a67e0000825fd9ef4910e66bdc732cb16e6da406f94c18905b2a8c6bbc29000c79f31e1e3eeb57508ac233bb4 + checksum: e8f69d1fd4a29d354d4dca9eb2a22674b300f8ef509e4f1e75337c880414a00d2bdc9d3849a6855dbb5a76bfbe74603f33435378a3877e69f0838e4cc2244350 languageName: node linkType: hard @@ -10243,7 +11277,7 @@ __metadata: ci-info: "npm:^3.2.0" graceful-fs: "npm:^4.2.9" picomatch: "npm:^2.2.3" - checksum: c4765afe8769239aef6a76aa69d9c98d383e171e4745eb65c4abb2e776f7965ab762c758f740bf726ebab428bc52b099c23f37e93dc30cf1ec46b915543f80af + checksum: fc553556c1350c443449cadaba5fb9d604628e8b5ceb6ceaf4e7e08975b24277d0a14bf2e0f956024e03c23e556fcb074659423422a06fbedf2ab52978697ac7 languageName: node linkType: hard @@ -10257,7 +11291,7 @@ __metadata: jest-get-type: "npm:^29.4.3" leven: "npm:^3.1.0" pretty-format: "npm:^29.6.1" - checksum: 4f6889852b0167f9087c3a67b598365be0807d4e8cce77e246b97df3e3cd1c13d3c98c18de07080d670c9e52b81b81d0ee48fa0544eddc987d32796f50f86371 + checksum: d2491f3f33d9bbc2dcaaa6acbff26f257b59c5eeceb65a52a9c1cec2f679b836ec2a4658b7004c0ef9d90cd0d9bd664e41d5ed6900f932bea742dd8e6b85e7f1 languageName: node linkType: hard @@ -10273,7 +11307,7 @@ __metadata: emittery: "npm:^0.13.1" jest-util: "npm:^29.6.1" string-length: "npm:^4.0.1" - checksum: bf007eb358f27c4f180202a8ec4bae2948a9563a84da073a185375b6a5251fe6cf9bf3f02f0682d2b8c343bcc5c1c2f185703009b6a47883ef1daeefed55881c + checksum: 69bd5a602284fdce6eba5486c5c57aca6b511d91cb0907c34c104d6dd931e18ce67baa7f8e280fa473e5d81ea3e7b9e7d94f712c37ab0b3b8cc2aec30676955d languageName: node linkType: hard @@ -10285,7 +11319,7 @@ __metadata: jest-util: "npm:^29.6.1" merge-stream: "npm:^2.0.0" supports-color: "npm:^8.0.0" - checksum: 15a5c699e6074401aac85bcc869e3be95353767f127fd41cccc97c9b38e62596a1ec336866eab180beec305da2cc7da75a663f3a5ddf63b6838ff839ef5073ec + checksum: 0af309ea4db17c4c47e84a9246f907960a15577683c005fdeafc8f3c06bc455136f95a6f28fa2a3e924b767eb4dacd9b40915a7707305f88586f099af3ac27a8 languageName: node linkType: hard @@ -10304,35 +11338,35 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: 32e29cfa2373530ed323ea65dfb4fd5172026349be48ebb7a2dc5660adadd1c68f6b0fe2b67cc3ee723cc34e2d4552a852730ac787251b406cf58e37a90f6dac + checksum: a8ff2eb0f421623412236e23cbe67c638127fffde466cba9606bc0c0553b4c1e5cb116d7e0ef990b5d1712851652c8ee461373b578df50857fe635b94ff455d5 languageName: node linkType: hard "js-base64@npm:3.7.5": version: 3.7.5 resolution: "js-base64@npm:3.7.5" - checksum: 641f4979fc5cf90b897e265a158dfcbef483219c76bc9a755875cb03ff73efdb1bd468a42e0343e05a3af7226f9d333c08ee4bb10f42a4c526988845ce1dcf1b + checksum: 67a78c8b1c47b73f1c6fba1957e9fe6fd9dc78ac93ac46cc2e43472dcb9cf150d126fb0e593192e88e0497354fa634d17d255add7cc6ee3c7b4d29870faa8e18 languageName: node linkType: hard "js-base64@npm:^2.1.9": version: 2.6.4 resolution: "js-base64@npm:2.6.4" - checksum: 95d93c4eca0bbe0f2d5ffe8682d9acd23051e5c0ad71873ff5a48dd46a5f19025de9f7b36e63fa3f02f342ae4a8ca4c56e7b590d7300ebb6639ce09675e0fd02 + checksum: 5f4084078d6c46f8529741d110df84b14fac3276b903760c21fa8cc8521370d607325dfe1c1a9fbbeaae1ff8e602665aaeef1362427d8fef704f9e3659472ce8 languageName: node linkType: hard "js-sdsl@npm:^4.1.4": version: 4.4.1 resolution: "js-sdsl@npm:4.4.1" - checksum: b71da96fab9e57fdfb559349f50df5a1bc4ae0bf7655280b7b64ef7e349c32753be536c0c682a6a6b2d30e179cda9b8d7f5b451f7070a2fed6b829cfd8f95870 + checksum: ba445b53531f2f353f8f66ed8c7edc7942c9bac68707161aa70528fa8ee9a89805d170cff171aa40bdac1aed5dfe97dce6f929e6f759a487ed619387a5ea1365 languageName: node linkType: hard "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" - checksum: e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed + checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 languageName: node linkType: hard @@ -10344,7 +11378,7 @@ __metadata: esprima: "npm:^4.0.0" bin: js-yaml: bin/js-yaml.js - checksum: 6746baaaeac312c4db8e75fa22331d9a04cccb7792d126ed8ce6a0bbcfef0cedaddd0c5098fade53db067c09fe00aa1c957674b4765610a8b06a5a189e46433b + checksum: bef146085f472d44dee30ec34e5cf36bf89164f5d585435a3d3da89e52622dff0b188a580e4ad091c3341889e14cb88cac6e4deb16dc5b1e9623bb0601fc255c languageName: node linkType: hard @@ -10355,38 +11389,42 @@ __metadata: argparse: "npm:^2.0.1" bin: js-yaml: bin/js-yaml.js - checksum: 184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f + checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a languageName: node linkType: hard -"jscodeshift@npm:^0.14.0": - version: 0.14.0 - resolution: "jscodeshift@npm:0.14.0" - dependencies: - "@babel/core": "npm:^7.13.16" - "@babel/parser": "npm:^7.13.16" - "@babel/plugin-proposal-class-properties": "npm:^7.13.0" - "@babel/plugin-proposal-nullish-coalescing-operator": "npm:^7.13.8" - "@babel/plugin-proposal-optional-chaining": "npm:^7.13.12" - "@babel/plugin-transform-modules-commonjs": "npm:^7.13.8" - "@babel/preset-flow": "npm:^7.13.13" - "@babel/preset-typescript": "npm:^7.13.0" - "@babel/register": "npm:^7.13.16" - babel-core: "npm:^7.0.0-bridge.0" - chalk: "npm:^4.1.2" - flow-parser: "npm:0.*" - graceful-fs: "npm:^4.2.4" - micromatch: "npm:^4.0.4" - neo-async: "npm:^2.5.0" - node-dir: "npm:^0.1.17" - recast: "npm:^0.21.0" - temp: "npm:^0.8.4" - write-file-atomic: "npm:^2.3.0" +"jscodeshift@npm:^0.15.1": + version: 0.15.1 + resolution: "jscodeshift@npm:0.15.1" + dependencies: + "@babel/core": ^7.23.0 + "@babel/parser": ^7.23.0 + "@babel/plugin-transform-class-properties": ^7.22.5 + "@babel/plugin-transform-modules-commonjs": ^7.23.0 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.22.11 + "@babel/plugin-transform-optional-chaining": ^7.23.0 + "@babel/plugin-transform-private-methods": ^7.22.5 + "@babel/preset-flow": ^7.22.15 + "@babel/preset-typescript": ^7.23.0 + "@babel/register": ^7.22.15 + babel-core: ^7.0.0-bridge.0 + chalk: ^4.1.2 + flow-parser: 0.* + graceful-fs: ^4.2.4 + micromatch: ^4.0.4 + neo-async: ^2.5.0 + node-dir: ^0.1.17 + recast: ^0.23.3 + temp: ^0.8.4 + write-file-atomic: ^2.3.0 peerDependencies: "@babel/preset-env": ^7.1.6 + peerDependenciesMeta: + "@babel/preset-env": + optional: true bin: jscodeshift: bin/jscodeshift.js - checksum: dab63bdb4b7e67d79634fcd3f5dc8b227146e9f68aa88700bc49c5a45b6339d05bd934a98aa53d29abd04f81237d010e7e037799471b2aab66ec7b9a7d752786 + checksum: d760dee2b634fa8a4610bdbdf787ce117a9a6bcc73e9ae55a38be77e380698d928d34a375a93ed4685e8bbdecfbd3cdbb87eb4b7e22fc58381db3d59fb554687 languageName: node linkType: hard @@ -10425,7 +11463,7 @@ __metadata: peerDependenciesMeta: canvas: optional: true - checksum: b109073bb826a966db7828f46cb1d7371abecd30f182b143c52be5fe1ed84513bbbe995eb3d157241681fcd18331381e61e3dc004d4949f3a63bca02f6214902 + checksum: 6e2ae21db397133a061b270c26d2dbc0b9051733ea3b896a7ece78d79f475ff0974f766a413c1198a79c793159119169f2335ddb23150348fbfdcfa6f3105536 languageName: node linkType: hard @@ -10434,7 +11472,7 @@ __metadata: resolution: "jsesc@npm:2.5.2" bin: jsesc: bin/jsesc - checksum: dbf59312e0ebf2b4405ef413ec2b25abb5f8f4d9bc5fb8d9f90381622ebca5f2af6a6aa9a8578f65903f9e33990a6dc798edd0ce5586894bf0e9e31803a1de88 + checksum: 4dc190771129e12023f729ce20e1e0bfceac84d73a85bc3119f7f938843fe25a4aeccb54b6494dce26fcf263d815f5f31acdefac7cc9329efb8422a4f4d9fa9d languageName: node linkType: hard @@ -10443,42 +11481,42 @@ __metadata: resolution: "jsesc@npm:0.5.0" bin: jsesc: bin/jsesc - checksum: f93792440ae1d80f091b65f8ceddf8e55c4bb7f1a09dee5dcbdb0db5612c55c0f6045625aa6b7e8edb2e0a4feabd80ee48616dbe2d37055573a84db3d24f96d9 + checksum: b8b44cbfc92f198ad972fba706ee6a1dfa7485321ee8c0b25f5cedd538dcb20cde3197de16a7265430fce8277a12db066219369e3d51055038946039f6e20e17 languageName: node linkType: hard "json-parse-even-better-errors@npm:^2.3.0": version: 2.3.1 resolution: "json-parse-even-better-errors@npm:2.3.1" - checksum: 140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 + checksum: 798ed4cf3354a2d9ccd78e86d2169515a0097a5c133337807cdf7f1fc32e1391d207ccfc276518cc1d7d8d4db93288b8a50ba4293d212ad1336e52a8ec0a941f languageName: node linkType: hard "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" - checksum: 108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce + checksum: 7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b languageName: node linkType: hard "json-schema-traverse@npm:^1.0.0": version: 1.0.0 resolution: "json-schema-traverse@npm:1.0.0" - checksum: 71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6 + checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad languageName: node linkType: hard "json-schema@npm:0.4.0": version: 0.4.0 resolution: "json-schema@npm:0.4.0" - checksum: d4a637ec1d83544857c1c163232f3da46912e971d5bf054ba44fdb88f07d8d359a462b4aec46f2745efbc57053365608d88bc1d7b1729f7b4fc3369765639ed3 + checksum: 66389434c3469e698da0df2e7ac5a3281bcff75e797a5c127db7c5b56270e01ae13d9afa3c03344f76e32e81678337a8c912bdbb75101c62e487dc3778461d72 languageName: node linkType: hard "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 + checksum: cff44156ddce9c67c44386ad5cddf91925fe06b1d217f2da9c4910d01f358c6e3989c4d5a02683c7a5667f9727ff05831f7aa8ae66c8ff691c556f0884d49215 languageName: node linkType: hard @@ -10489,16 +11527,16 @@ __metadata: minimist: "npm:^1.2.0" bin: json5: lib/cli.js - checksum: 9ee316bf21f000b00752e6c2a3b79ecf5324515a5c60ee88983a1910a45426b643a4f3461657586e8aeca87aaf96f0a519b0516d2ae527a6c3e7eed80f68717f + checksum: 866458a8c58a95a49bef3adba929c625e82532bcff1fe93f01d29cb02cac7c3fe1f4b79951b7792c2da9de0b32871a8401a6e3c5b36778ad852bf5b8a61165d7 languageName: node linkType: hard -"json5@npm:^2.2.2": +"json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: json5: lib/cli.js - checksum: 5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c + checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 languageName: node linkType: hard @@ -10511,7 +11549,7 @@ __metadata: dependenciesMeta: graceful-fs: optional: true - checksum: 4f95b5e8a5622b1e9e8f33c96b7ef3158122f595998114d1e7f03985649ea99cb3cd99ce1ed1831ae94c8c8543ab45ebd044207612f31a56fd08462140e46865 + checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 languageName: node linkType: hard @@ -10523,7 +11561,7 @@ __metadata: array.prototype.flat: "npm:^1.3.1" object.assign: "npm:^4.1.4" object.values: "npm:^1.1.6" - checksum: 6761ccd830deab6a4cb8ca182c7b3627f4478138b6f4e2b680afc2b5e954635feb460ff75218b67f8694a9f8a0da6f0833a013e34961a16fbe4457fb34a0a7b2 + checksum: a6a00d324e38f0d47e04f973d79670248a663422a4dccdc02efd6f1caf1c00042fb0aafcff1023707c85dea6f013d435b90db67c1c6841bf345628f0a720d8b3 languageName: node linkType: hard @@ -10532,7 +11570,7 @@ __metadata: resolution: "kind-of@npm:3.2.2" dependencies: is-buffer: "npm:^1.1.5" - checksum: 7e34bc29d4b02c997f92f080de34ebb92033a96736bbb0bb2410e033a7e5ae6571f1fa37b2d7710018f95361473b816c604234197f4f203f9cf149d8ef1574d9 + checksum: e898df8ca2f31038f27d24f0b8080da7be274f986bc6ed176f37c77c454d76627619e1681f6f9d2e8d2fd7557a18ecc419a6bb54e422abcbb8da8f1a75e4b386 languageName: node linkType: hard @@ -10541,35 +11579,35 @@ __metadata: resolution: "kind-of@npm:4.0.0" dependencies: is-buffer: "npm:^1.1.5" - checksum: d6c44c75ee36898142dfc7106afbd50593216c37f96acb81a7ab33ca1a6938ce97d5692b8fc8fccd035f83811a9d97749d68771116441a48eedd0b68e2973165 + checksum: 1b9e7624a8771b5a2489026e820f3bbbcc67893e1345804a56b23a91e9069965854d2a223a7c6ee563c45be9d8c6ff1ef87f28ed5f0d1a8d00d9dcbb067c529f languageName: node linkType: hard "kind-of@npm:^5.0.0, kind-of@npm:^5.0.2": version: 5.1.0 resolution: "kind-of@npm:5.1.0" - checksum: fe85b7a2ed4b4d5a12e16e01d00d5c336e1760842fe0da38283605b9880c984288935e87b13138909e4d23d2d197a1d492f7393c6638d2c0fab8a900c4fb0392 + checksum: f2a0102ae0cf19c4a953397e552571bad2b588b53282874f25fca7236396e650e2db50d41f9f516bd402536e4df968dbb51b8e69e4d5d4a7173def78448f7bab languageName: node linkType: hard "kind-of@npm:^6.0.0, kind-of@npm:^6.0.2": version: 6.0.3 resolution: "kind-of@npm:6.0.3" - checksum: 61cdff9623dabf3568b6445e93e31376bee1cdb93f8ba7033d86022c2a9b1791a1d9510e026e6465ebd701a6dd2f7b0808483ad8838341ac52f003f512e0b4c4 + checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b languageName: node linkType: hard "kleur@npm:^3.0.3": version: 3.0.3 resolution: "kleur@npm:3.0.3" - checksum: cd3a0b8878e7d6d3799e54340efe3591ca787d9f95f109f28129bdd2915e37807bf8918bb295ab86afb8c82196beec5a1adcaf29042ce3f2bd932b038fe3aa4b + checksum: df82cd1e172f957bae9c536286265a5cdbd5eeca487cb0a3b2a7b41ef959fc61f8e7c0e9aeea9c114ccf2c166b6a8dd45a46fd619c1c569d210ecd2765ad5169 languageName: node linkType: hard "language-subtag-registry@npm:~0.3.2": version: 0.3.22 resolution: "language-subtag-registry@npm:0.3.22" - checksum: d1e09971260a7cd3b9fdeb190d33af0b6e99c8697013537d9aaa15f7856d9d83aee128ba8078e219df0a7cf4b8dd18d1a0c188f6543b500d92a2689d2d114b70 + checksum: 8ab70a7e0e055fe977ac16ea4c261faec7205ac43db5e806f72e5b59606939a3b972c4bd1e10e323b35d6ffa97c3e1c4c99f6553069dad2dfdd22020fa3eb56a languageName: node linkType: hard @@ -10578,7 +11616,7 @@ __metadata: resolution: "language-tags@npm:1.0.5" dependencies: language-subtag-registry: "npm:~0.3.2" - checksum: 04215e821af9a8f1bc6c99ab5aa0a316c3fe1912ca3337eb28596316064bddd8edd22f2883d866069ebdf01b2002e504a760a336b2c728b6d30514e86744f76c + checksum: c81b5d8b9f5f9cfd06ee71ada6ddfe1cf83044dd5eeefcd1e420ad491944da8957688db4a0a9bc562df4afdc2783425cbbdfd152c01d93179cf86888903123cf languageName: node linkType: hard @@ -10589,14 +11627,14 @@ __metadata: app-root-dir: "npm:^1.0.2" dotenv: "npm:^16.0.0" dotenv-expand: "npm:^10.0.0" - checksum: 3bc4fe649c46c4a20561ca1fd10cd1df641d2c6c42c61af6c65a5fe0546cb548f449e13e6c7440be445c9fe5b4973c25f499e7d899b8704b7b9bd0ec85bbfe2d + checksum: 196e0d701100144fbfe078d604a477573413ebf38dfe8d543748605e6a7074978508a3bb9f8135acd319db4fa947eef78836497163617d15a22163c59a00996b languageName: node linkType: hard "leven@npm:^3.1.0": version: 3.1.0 resolution: "leven@npm:3.1.0" - checksum: cd778ba3fbab0f4d0500b7e87d1f6e1f041507c56fdcd47e8256a3012c98aaee371d4c15e0a76e0386107af2d42e2b7466160a2d80688aaa03e66e49949f42df + checksum: 638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 languageName: node linkType: hard @@ -10606,14 +11644,14 @@ __metadata: dependencies: prelude-ls: "npm:^1.2.1" type-check: "npm:~0.4.0" - checksum: effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e + checksum: 12c5021c859bd0f5248561bf139121f0358285ec545ebf48bb3d346820d5c61a4309535c7f387ed7d84361cf821e124ce346c6b7cef8ee09a67c1473b46d0fc4 languageName: node linkType: hard "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" - checksum: 3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d + checksum: 0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 languageName: node linkType: hard @@ -10624,7 +11662,7 @@ __metadata: big.js: "npm:^5.2.2" emojis-list: "npm:^3.0.0" json5: "npm:^1.0.1" - checksum: 2b726088b5526f7605615e3e28043ae9bbd2453f4a85898e1151f3c39dbf7a2b65d09f3996bc588d92ac7e717ded529d3e1ea3ea42c433393be84a58234a2f53 + checksum: eb6fb622efc0ffd1abdf68a2022f9eac62bef8ec599cf8adb75e94d1d338381780be6278534170e99edc03380a6d29bc7eb1563c89ce17c5fed3a0b17f1ad804 languageName: node linkType: hard @@ -10634,7 +11672,7 @@ __metadata: dependencies: p-locate: "npm:^3.0.0" path-exists: "npm:^3.0.0" - checksum: 3db394b7829a7fe2f4fbdd25d3c4689b85f003c318c5da4052c7e56eed697da8f1bce5294f685c69ff76e32cba7a33629d94396976f6d05fb7f4c755c5e2ae8b + checksum: 53db3996672f21f8b0bf2a2c645ae2c13ffdae1eeecfcd399a583bce8516c0b88dcb4222ca6efbbbeb6949df7e46860895be2c02e8d3219abd373ace3bfb4e11 languageName: node linkType: hard @@ -10643,7 +11681,7 @@ __metadata: resolution: "locate-path@npm:5.0.0" dependencies: p-locate: "npm:^4.1.0" - checksum: 33a1c5247e87e022f9713e6213a744557a3e9ec32c5d0b5efb10aa3a38177615bf90221a5592674857039c1a0fd2063b82f285702d37b792d973e9e72ace6c59 + checksum: 83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 languageName: node linkType: hard @@ -10652,39 +11690,49 @@ __metadata: resolution: "locate-path@npm:6.0.0" dependencies: p-locate: "npm:^5.0.0" - checksum: d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 + checksum: 72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a languageName: node linkType: hard "lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "lodash.debounce@npm:4.0.8" - checksum: 762998a63e095412b6099b8290903e0a8ddcb353ac6e2e0f2d7e7d03abd4275fe3c689d88960eb90b0dde4f177554d51a690f22a343932ecbc50a5d111849987 + checksum: a3f527d22c548f43ae31c861ada88b2637eb48ac6aa3eb56e82d44917971b8aa96fbb37aa60efea674dc4ee8c42074f90f7b1f772e9db375435f6c83a19b3bc6 languageName: node linkType: hard "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" - checksum: 402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 + checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005 languageName: node linkType: hard "lodash@npm:^4.17.15, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" - checksum: d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c + checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 + languageName: node + linkType: hard + +"log-symbols@npm:^4.1.0": + version: 4.1.0 + resolution: "log-symbols@npm:4.1.0" + dependencies: + chalk: ^4.1.0 + is-unicode-supported: ^0.1.0 + checksum: fce1497b3135a0198803f9f07464165e9eb83ed02ceb2273930a6f8a508951178d8cf4f0378e9d28300a2ed2bc49050995d2bd5f53ab716bb15ac84d58c6ef74 languageName: node linkType: hard -"loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": +"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" dependencies: js-tokens: "npm:^3.0.0 || ^4.0.0" bin: loose-envify: cli.js - checksum: 655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e + checksum: 6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 languageName: node linkType: hard @@ -10694,7 +11742,7 @@ __metadata: dependencies: fault: "npm:^1.0.0" highlight.js: "npm:~10.7.0" - checksum: 728bce6f6fe8b157f48d3324e597f452ce0eed2ccff1c0f41a9047380f944e971eb45bceb31f08fbb64d8f338dabb166f10049b35b92c7ec5cf0241d6adb3dea + checksum: 14a1815d6bae202ddee313fc60f06d46e5235c02fa483a77950b401d85b4c1e12290145ccd17a716b07f9328bd5864aa2d402b6a819ff3be7c833d9748ff8ba7 languageName: node linkType: hard @@ -10703,7 +11751,7 @@ __metadata: resolution: "lru-cache@npm:5.1.1" dependencies: yallist: "npm:^3.0.2" - checksum: 89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 + checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb languageName: node linkType: hard @@ -10712,21 +11760,21 @@ __metadata: resolution: "lru-cache@npm:6.0.0" dependencies: yallist: "npm:^4.0.0" - checksum: cb53e582785c48187d7a188d3379c181b5ca2a9c78d2bce3e7dee36f32761d1c42983da3fe12b55cb74e1779fa94cdc2e5367c028a9b35317184ede0c07a30a9 + checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 languageName: node linkType: hard "lru-cache@npm:^7.7.1": version: 7.18.3 resolution: "lru-cache@npm:7.18.3" - checksum: b3a452b491433db885beed95041eb104c157ef7794b9c9b4d647be503be91769d11206bb573849a16b4cc0d03cbd15ffd22df7960997788b74c1d399ac7a4fed + checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 languageName: node linkType: hard "lru-cache@npm:^9.1.1 || ^10.0.0": version: 10.0.0 resolution: "lru-cache@npm:10.0.0" - checksum: 347b7b391091e9f91182b6f683ce04329932a542376a2d7d300637213b99f06c222a3bb0f0db59adf246dac6cef1bb509cab352451a96621d07c41b10a20495f + checksum: 18f101675fe283bc09cda0ef1e3cc83781aeb8373b439f086f758d1d91b28730950db785999cd060d3c825a8571c03073e8c14512b6655af2188d623031baf50 languageName: node linkType: hard @@ -10735,7 +11783,7 @@ __metadata: resolution: "lz-string@npm:1.5.0" bin: lz-string: bin/bin.js - checksum: 36128e4de34791838abe979b19927c26e67201ca5acf00880377af7d765b38d1c60847e01c5ec61b1a260c48029084ab3893a3925fd6e48a04011364b089991b + checksum: 1ee98b4580246fd90dd54da6e346fb1caefcf05f677c686d9af237a157fdea3fd7c83a4bc58f858cd5b10a34d27afe0fdcbd0505a47e0590726a873dc8b8f65d languageName: node linkType: hard @@ -10744,7 +11792,16 @@ __metadata: resolution: "magic-string@npm:0.27.0" dependencies: "@jridgewell/sourcemap-codec": "npm:^1.4.13" - checksum: cddacfea14441ca57ae8a307bc3cf90bac69efaa4138dd9a80804cffc2759bf06f32da3a293fb13eaa96334b7d45b7768a34f1d226afae25d2f05b05a3bb37d8 + checksum: 273faaa50baadb7a2df6e442eac34ad611304fc08fe16e24fe2e472fd944bfcb73ffb50d2dc972dc04e92784222002af46868cb9698b1be181c81830fd95a13e + languageName: node + linkType: hard + +"magic-string@npm:^0.30.0": + version: 0.30.5 + resolution: "magic-string@npm:0.30.5" + dependencies: + "@jridgewell/sourcemap-codec": ^1.4.15 + checksum: da10fecff0c0a7d3faf756913ce62bd6d5e7b0402be48c3b27bfd651b90e29677e279069a63b764bcdc1b8ecdcdb898f29a5c5ec510f2323e8d62ee057a6eb18 languageName: node linkType: hard @@ -10754,7 +11811,7 @@ __metadata: dependencies: pify: "npm:^4.0.1" semver: "npm:^5.6.0" - checksum: ada869944d866229819735bee5548944caef560d7a8536ecbc6536edca28c72add47cc4f6fc39c54fb25d06b58da1f8994cf7d9df7dadea047064749efc085d8 + checksum: 043548886bfaf1820323c6a2997e6d2fa51ccc2586ac14e6f14634f7458b4db2daf15f8c310e2a0abd3e0cddc64df1890d8fc7263033602c47bb12cbfcf86aab languageName: node linkType: hard @@ -10763,7 +11820,7 @@ __metadata: resolution: "make-dir@npm:3.1.0" dependencies: semver: "npm:^6.0.0" - checksum: 56aaafefc49c2dfef02c5c95f9b196c4eb6988040cf2c712185c7fe5c99b4091591a7fc4d4eafaaefa70ff763a26f6ab8c3ff60b9e75ea19876f49b18667ecaa + checksum: 484200020ab5a1fdf12f393fe5f385fc8e4378824c940fba1729dcd198ae4ff24867bc7a5646331e50cead8abff5d9270c456314386e629acec6dff4b8016b78 languageName: node linkType: hard @@ -10786,7 +11843,7 @@ __metadata: promise-retry: "npm:^2.0.1" socks-proxy-agent: "npm:^7.0.0" ssri: "npm:^10.0.0" - checksum: c161bde51dbc03382f9fac091734526a64dd6878205db6c338f70d2133df797b5b5166bff3091cf7d4785869d4b21e99a58139c1790c2fb1b5eec00f528f5f0b + checksum: 7268bf274a0f6dcf0343829489a4506603ff34bd0649c12058753900b0eb29191dce5dba12680719a5d0a983d3e57810f594a12f3c18494e93a1fbc6348a4540 languageName: node linkType: hard @@ -10795,21 +11852,21 @@ __metadata: resolution: "makeerror@npm:1.0.12" dependencies: tmpl: "npm:1.0.5" - checksum: b0e6e599780ce6bab49cc413eba822f7d1f0dfebd1c103eaa3785c59e43e22c59018323cf9e1708f0ef5329e94a745d163fcbb6bff8e4c6742f9be9e86f3500c + checksum: b38a025a12c8146d6eeea5a7f2bf27d51d8ad6064da8ca9405fcf7bf9b54acd43e3b30ddd7abb9b1bfa4ddb266019133313482570ddb207de568f71ecfcf6060 languageName: node linkType: hard "map-cache@npm:^0.2.2": version: 0.2.2 resolution: "map-cache@npm:0.2.2" - checksum: 05e3eb005c1b80b9f949ca007687640e8c5d0fc88dc45c3c3ab4902a3bec79d66a58f3e3b04d6985d90cd267c629c7b46c977e9c34433e8c11ecfcbb9f0fa290 + checksum: 3067cea54285c43848bb4539f978a15dedc63c03022abeec6ef05c8cb6829f920f13b94bcaf04142fc6a088318e564c4785704072910d120d55dbc2e0c421969 languageName: node linkType: hard "map-or-similar@npm:^1.5.0": version: 1.5.0 resolution: "map-or-similar@npm:1.5.0" - checksum: 33c6ccfdc272992e33e4e99a69541a3e7faed9de3ac5bc732feb2500a9ee71d3f9d098980a70b7746e7eeb7f859ff7dfb8aa9b5ecc4e34170a32ab78cfb18def + checksum: f65c0d420e272d0fce4e24db35f6a08109218480bca1d61eaa442cbe6cf46270b840218d3b5e94e4bfcc2595f1d0a1fa5885df750b52aac9ab1d437b29dcce38 languageName: node linkType: hard @@ -10818,7 +11875,7 @@ __metadata: resolution: "map-visit@npm:1.0.0" dependencies: object-visit: "npm:^1.0.0" - checksum: fb3475e5311939a6147e339999113db607adc11c7c3cd3103e5e9dbf502898416ecba6b1c7c649c6d4d12941de00cee58b939756bdf20a9efe7d4fa5a5738b73 + checksum: c27045a5021c344fc19b9132eb30313e441863b2951029f8f8b66f79d3d8c1e7e5091578075a996f74e417479506fe9ede28c44ca7bc351a61c9d8073daec36a languageName: node linkType: hard @@ -10827,7 +11884,7 @@ __metadata: resolution: "markdown-to-jsx@npm:7.2.1" peerDependencies: react: ">= 0.14.0" - checksum: 002ba7c723853c456a4902976d5f5a15d9585bd75dc6ab3add783b4a346e3372327c4fffd7843f30fd5b6550c5fd97e7142330521a5886f8b770db4c61558d61 + checksum: 0c8c715229044401ea48c2fc26c2554464100074959dafacdd9e4a0e849f0a190b02f39edb373bbdd95e38b8f910074b83b63d08752b8ae6be6ddcfb40ea50a0 languageName: node linkType: hard @@ -10836,28 +11893,28 @@ __metadata: resolution: "mdast-util-definitions@npm:4.0.0" dependencies: unist-util-visit: "npm:^2.0.0" - checksum: d81bb0b702f99878c8e8e4f66dd7f6f673ab341f061b3d9487ba47dad28b584e02f16b4c42df23714eaac8a7dd8544ba7d77308fad8d4a9fd0ac92e2a7f56be9 + checksum: 2325f20b82b3fb8cb5fda77038ee0bbdd44f82cfca7c48a854724b58bc1fe5919630a3ce7c45e210726df59d46c881d020b2da7a493bfd1ee36eb2bbfef5d78e languageName: node linkType: hard "mdast-util-to-string@npm:^1.0.0": version: 1.1.0 resolution: "mdast-util-to-string@npm:1.1.0" - checksum: 5dad9746ec0839792a8a35f504564e8d2b8c30013652410306c111963d33f1ee7b5477aa64ed77b64e13216363a29395809875ffd80e2031a08614657628a121 + checksum: eec1eb283f3341376c8398b67ce512a11ab3e3191e3dbd5644d32a26784eac8d5f6d0b0fb81193af00d75a2c545cde765c8b03e966bd890076efb5d357fb4fe2 languageName: node linkType: hard "mdn-data@npm:2.0.14": version: 2.0.14 resolution: "mdn-data@npm:2.0.14" - checksum: 67241f8708c1e665a061d2b042d2d243366e93e5bf1f917693007f6d55111588b952dcbfd3ea9c2d0969fb754aad81b30fdcfdcc24546495fc3b24336b28d4bd + checksum: 9d0128ed425a89f4cba8f787dca27ad9408b5cb1b220af2d938e2a0629d17d879a34d2cb19318bdb26c3f14c77dd5dfbae67211f5caaf07b61b1f2c5c8c7dc16 languageName: node linkType: hard "media-typer@npm:0.3.0": version: 0.3.0 resolution: "media-typer@npm:0.3.0" - checksum: d160f31246907e79fed398470285f21bafb45a62869dc469b1c8877f3f064f5eabc4bcc122f9479b8b605bc5c76187d7871cf84c4ee3ecd3e487da1993279928 + checksum: af1b38516c28ec95d6b0826f6c8f276c58aec391f76be42aa07646b4e39d317723e869700933ca6995b056db4b09a78c92d5440dc23657e6764be5d28874bba1 languageName: node linkType: hard @@ -10866,14 +11923,14 @@ __metadata: resolution: "memoizerific@npm:1.11.3" dependencies: map-or-similar: "npm:^1.5.0" - checksum: 661bf69b7afbfad57f0208f0c63324f4c96087b480708115b78ee3f0237d86c7f91347f6db31528740b2776c2e34c709bcb034e1e910edee2270c9603a0a469e + checksum: d51bdc3ed8c39b4b73845c90eb62d243ddf21899914352d0c303f5e1d477abcb192f4c605e008caa4a31d823225eeb22a99ba5ee825fb88d0c33382db3aee95a languageName: node linkType: hard "merge-descriptors@npm:1.0.1": version: 1.0.1 resolution: "merge-descriptors@npm:1.0.1" - checksum: b67d07bd44cfc45cebdec349bb6e1f7b077ee2fd5beb15d1f7af073849208cb6f144fe403e29a36571baf3f4e86469ac39acf13c318381e958e186b2766f54ec + checksum: 5abc259d2ae25bb06d19ce2b94a21632583c74e2a9109ee1ba7fd147aa7362b380d971e0251069f8b3eb7d48c21ac839e21fa177b335e82c76ec172e30c31a26 languageName: node linkType: hard @@ -10882,28 +11939,28 @@ __metadata: resolution: "merge-options@npm:1.0.1" dependencies: is-plain-obj: "npm:^1.1" - checksum: 7be91e9d1cb8f78c903263ecd34e7895f1daf84aed77e8bd2d539ff593db55d0bca2ebe98b66c3f95d731add04b03f7dd77ad89dc198c3a7ea11ffd8e4aaef7e + checksum: 7e3d5d658879038cdc225107205dacd68fd8e22cf4f54fb37fd9e0687f7eb9efd7f0f2163577675325a3a72c9df0566e23911d0d8a2448ca8f83eee5199dd990 languageName: node linkType: hard "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" - checksum: 867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 + checksum: 6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 languageName: node linkType: hard "merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" - checksum: 254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb + checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 languageName: node linkType: hard "methods@npm:~1.1.2": version: 1.1.2 resolution: "methods@npm:1.1.2" - checksum: bdf7cc72ff0a33e3eede03708c08983c4d7a173f91348b4b1e4f47d4cdbf734433ad971e7d1e8c77247d9e5cd8adb81ea4c67b0a2db526b758b2233d7814b8b2 + checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a languageName: node linkType: hard @@ -10924,7 +11981,7 @@ __metadata: regex-not: "npm:^1.0.0" snapdragon: "npm:^0.8.1" to-regex: "npm:^3.0.1" - checksum: 55ee73d7f9bf3fa73e8482193cf2bb079fe09f56c65125eba319970c6feabacf6ad0680eb702d0bbf2adef8d956a6356c01ea39f51ad9864e8dbedbaa265ed3b + checksum: 4c28b7c9e49a510f62ced8ec70dde03871931bfdae8a594762404dddd7666f3acdf1d14cadddda609d8114648a702738a0f9672a31ac4e0f4896b9e4962c6bd6 languageName: node linkType: hard @@ -10934,14 +11991,14 @@ __metadata: dependencies: braces: "npm:^3.0.2" picomatch: "npm:^2.3.1" - checksum: 3d6505b20f9fa804af5d8c596cb1c5e475b9b0cd05f652c5b56141cf941bd72adaeb7a436fda344235cef93a7f29b7472efc779fcdb83b478eab0867b95cdeff + checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc languageName: node linkType: hard "mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2": version: 1.52.0 resolution: "mime-db@npm:1.52.0" - checksum: 0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa + checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f languageName: node linkType: hard @@ -10950,7 +12007,7 @@ __metadata: resolution: "mime-types@npm:2.1.35" dependencies: mime-db: "npm:1.52.0" - checksum: 82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 + checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 languageName: node linkType: hard @@ -10959,7 +12016,7 @@ __metadata: resolution: "mime@npm:1.6.0" bin: mime: cli.js - checksum: b92cd0adc44888c7135a185bfd0dddc42c32606401c72896a842ae15da71eb88858f17669af41e498b463cd7eb998f7b48939a25b08374c7924a9c8a6f8a81b0 + checksum: fef25e39263e6d207580bdc629f8872a3f9772c923c7f8c7e793175cee22777bbe8bba95e5d509a40aaa292d8974514ce634ae35769faa45f22d17edda5e8557 languageName: node linkType: hard @@ -10968,21 +12025,21 @@ __metadata: resolution: "mime@npm:2.6.0" bin: mime: cli.js - checksum: a7f2589900d9c16e3bdf7672d16a6274df903da958c1643c9c45771f0478f3846dcb1097f31eb9178452570271361e2149310931ec705c037210fc69639c8e6c + checksum: 1497ba7b9f6960694268a557eae24b743fd2923da46ec392b042469f4b901721ba0adcf8b0d3c2677839d0e243b209d76e5edcbd09cfdeffa2dfb6bb4df4b862 languageName: node linkType: hard "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" - checksum: b26f5479d7ec6cc2bce275a08f146cf78f5e7b661b18114e2506dd91ec7ec47e7a25bf4360e5438094db0560bcc868079fb3b1fb3892b833c1ecbf63f80c95a4 + checksum: d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a languageName: node linkType: hard -"min-indent@npm:^1.0.0": +"min-indent@npm:^1.0.0, min-indent@npm:^1.0.1": version: 1.0.1 resolution: "min-indent@npm:1.0.1" - checksum: 7e207bd5c20401b292de291f02913230cb1163abca162044f7db1d951fa245b174dc00869d40dd9a9f32a885ad6a5f3e767ee104cf278f399cb4e92d3f582d5c + checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 languageName: node linkType: hard @@ -10991,7 +12048,7 @@ __metadata: resolution: "minimatch@npm:3.1.2" dependencies: brace-expansion: "npm:^1.1.7" - checksum: 0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a languageName: node linkType: hard @@ -11000,7 +12057,7 @@ __metadata: resolution: "minimatch@npm:5.1.6" dependencies: brace-expansion: "npm:^2.0.1" - checksum: 3defdfd230914f22a8da203747c42ee3c405c39d4d37ffda284dac5e45b7e1f6c49aa8be606509002898e73091ff2a3bbfc59c2c6c71d4660609f63aa92f98e3 + checksum: 7564208ef81d7065a370f788d337cd80a689e981042cb9a1d0e6580b6c6a8c9279eba80010516e258835a988363f99f54a6f711a315089b8b42694f5da9d0d77 languageName: node linkType: hard @@ -11009,14 +12066,14 @@ __metadata: resolution: "minimatch@npm:9.0.3" dependencies: brace-expansion: "npm:^2.0.1" - checksum: 85f407dcd38ac3e180f425e86553911d101455ca3ad5544d6a7cec16286657e4f8a9aa6695803025c55e31e35a91a2252b5dc8e7d527211278b8b65b4dbd5eac + checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 languageName: node linkType: hard "minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" - checksum: 19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 + checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 languageName: node linkType: hard @@ -11025,7 +12082,7 @@ __metadata: resolution: "minipass-collect@npm:1.0.2" dependencies: minipass: "npm:^3.0.0" - checksum: 8f82bd1f3095b24f53a991b04b67f4c710c894e518b813f0864a31de5570441a509be1ca17e0bb92b047591a8fdbeb886f502764fefb00d2f144f4011791e898 + checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 languageName: node linkType: hard @@ -11040,7 +12097,7 @@ __metadata: dependenciesMeta: encoding: optional: true - checksum: 12e0fde7e8fdb1bd923b9243b4788e7d3df305c6ddb3b79ab2da4587fa608c126157c7f6dd43746e8063ee99ec5abbb898d0426c812e9c9b68260c4fea9b279a + checksum: af5ab2552a16fcf505d35fd7ffb84b57f4a0eeb269e6e1d9a2a75824dda48b36e527083250b7cca4a4def21d9544e2ade441e4730e233c0bc2133f6abda31e18 languageName: node linkType: hard @@ -11049,7 +12106,7 @@ __metadata: resolution: "minipass-flush@npm:1.0.5" dependencies: minipass: "npm:^3.0.0" - checksum: 2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd + checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf languageName: node linkType: hard @@ -11058,7 +12115,7 @@ __metadata: resolution: "minipass-pipeline@npm:1.2.4" dependencies: minipass: "npm:^3.0.0" - checksum: cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 + checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b languageName: node linkType: hard @@ -11067,7 +12124,7 @@ __metadata: resolution: "minipass-sized@npm:1.0.3" dependencies: minipass: "npm:^3.0.0" - checksum: 298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb + checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 languageName: node linkType: hard @@ -11076,21 +12133,21 @@ __metadata: resolution: "minipass@npm:3.3.6" dependencies: yallist: "npm:^4.0.0" - checksum: a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c + checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 languageName: node linkType: hard "minipass@npm:^5.0.0": version: 5.0.0 resolution: "minipass@npm:5.0.0" - checksum: a91d8043f691796a8ac88df039da19933ef0f633e3d7f0d35dcd5373af49131cf2399bfc355f41515dc495e3990369c3858cd319e5c2722b4753c90bf3152462 + checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea languageName: node linkType: hard "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": version: 7.0.2 resolution: "minipass@npm:7.0.2" - checksum: 5e800acfc9dc75eacac5c4969ab50210463a8afbe8b487de1ae681106e17eb93772513854b6a38462b200b5758af95eeeb481945e050ce76f575ff1150fff4b4 + checksum: 46776de732eb7cef2c7404a15fb28c41f5c54a22be50d47b03c605bf21f5c18d61a173c0a20b49a97e7a65f78d887245066410642551e45fffe04e9ac9e325bc languageName: node linkType: hard @@ -11100,7 +12157,7 @@ __metadata: dependencies: minipass: "npm:^3.0.0" yallist: "npm:^4.0.0" - checksum: 64fae024e1a7d0346a1102bb670085b17b7f95bf6cfdf5b128772ec8faf9ea211464ea4add406a3a6384a7d87a0cd1a96263692134323477b4fb43659a6cab78 + checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 languageName: node linkType: hard @@ -11110,14 +12167,14 @@ __metadata: dependencies: for-in: "npm:^1.0.2" is-extendable: "npm:^1.0.1" - checksum: cb39ffb73c377222391af788b4c83d1a6cecb2d9fceb7015384f8deb46e151a9b030c21ef59a79cb524d4557e3f74c7248ab948a62a6e7e296b42644863d183b + checksum: 820d5a51fcb7479f2926b97f2c3bb223546bc915e6b3a3eb5d906dda871bba569863595424a76682f2b15718252954644f3891437cb7e3f220949bed54b1750d languageName: node linkType: hard "mkdirp-classic@npm:^0.5.2": version: 0.5.3 resolution: "mkdirp-classic@npm:0.5.3" - checksum: 95371d831d196960ddc3833cc6907e6b8f67ac5501a6582f47dfae5eb0f092e9f8ce88e0d83afcae95d6e2b61a01741ba03714eeafb6f7a6e9dcc158ac85b168 + checksum: 3f4e088208270bbcc148d53b73e9a5bd9eef05ad2cbf3b3d0ff8795278d50dd1d11a8ef1875ff5aea3fa888931f95bfcb2ad5b7c1061cfefd6284d199e6776ac languageName: node linkType: hard @@ -11128,7 +12185,7 @@ __metadata: minimist: "npm:^1.2.6" bin: mkdirp: bin/cmd.js - checksum: e2e2be789218807b58abced04e7b49851d9e46e88a2f9539242cc8a92c9b5c3a0b9bab360bd3014e02a140fc4fbc58e31176c408b493f8a2a6f4986bd7527b01 + checksum: 0c91b721bb12c3f9af4b77ebf73604baf350e64d80df91754dc509491ae93bf238581e59c7188360cec7cb62fc4100959245a42cfe01834efedc5e9d068376c2 languageName: node linkType: hard @@ -11137,51 +12194,44 @@ __metadata: resolution: "mkdirp@npm:1.0.4" bin: mkdirp: bin/cmd.js - checksum: 46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf + checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f languageName: node linkType: hard "mri@npm:^1.2.0": version: 1.2.0 resolution: "mri@npm:1.2.0" - checksum: a3d32379c2554cf7351db6237ddc18dc9e54e4214953f3da105b97dc3babe0deb3ffe99cf409b38ea47cc29f9430561ba6b53b24ab8f9ce97a4b50409e4a50e7 + checksum: 83f515abbcff60150873e424894a2f65d68037e5a7fcde8a9e2b285ee9c13ac581b63cfc1e6826c4732de3aeb84902f7c1e16b7aff46cd3f897a0f757a894e85 languageName: node linkType: hard "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" - checksum: f8fda810b39fd7255bbdc451c46286e549794fcc700dc9cd1d25658bbc4dc2563a5de6fe7c60f798a16a60c6ceb53f033cb353f493f0cf63e5199b702943159d - languageName: node - linkType: hard - -"ms@npm:2.1.1": - version: 2.1.1 - resolution: "ms@npm:2.1.1" - checksum: 056140c631e740369fa21142417aba1bd629ab912334715216c666eb681c8f015c622dd4e38bc1d836b30852b05641331661703af13a0397eb0ca420fc1e75d9 + checksum: 0e6a22b8b746d2e0b65a430519934fefd41b6db0682e3477c10f60c76e947c4c0ad06f63ffdf1d78d335f83edee8c0aa928aa66a36c7cd95b69b26f468d527f4 languageName: node linkType: hard "ms@npm:2.1.2": version: 2.1.2 resolution: "ms@npm:2.1.2" - checksum: a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc + checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f languageName: node linkType: hard "ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1": version: 2.1.3 resolution: "ms@npm:2.1.3" - checksum: d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 + checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d languageName: node linkType: hard -"nanoid@npm:^3.3.1, nanoid@npm:^3.3.6": +"nanoid@npm:^3.3.6": version: 3.3.6 resolution: "nanoid@npm:3.3.6" bin: nanoid: bin/nanoid.cjs - checksum: 606b355960d0fcbe3d27924c4c52ef7d47d3b57208808ece73279420d91469b01ec1dce10fae512b6d4a8c5a5432b352b228336a8b2202a6ea68e67fa348e2ee + checksum: 7d0eda657002738aa5206107bd0580aead6c95c460ef1bdd0b1a87a9c7ae6277ac2e9b945306aaa5b32c6dcb7feaf462d0f552e7f8b5718abfc6ead5c94a71b3 languageName: node linkType: hard @@ -11200,65 +12250,65 @@ __metadata: regex-not: "npm:^1.0.0" snapdragon: "npm:^0.8.1" to-regex: "npm:^3.0.1" - checksum: 0f5cefa755ca2e20c86332821995effb24acb79551ddaf51c1b9112628cad234a0d8fd9ac6aa56ad1f8bfad6ff6ae86e851acb960943249d9fa44b091479953a + checksum: 54d4166d6ef08db41252eb4e96d4109ebcb8029f0374f9db873bd91a1f896c32ec780d2a2ea65c0b2d7caf1f28d5e1ea33746a470f32146ac8bba821d80d38d8 languageName: node linkType: hard "natural-compare-lite@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare-lite@npm:1.4.0" - checksum: f6cef26f5044515754802c0fc475d81426f3b90fe88c20fabe08771ce1f736ce46e0397c10acb569a4dd0acb84c7f1ee70676122f95d5bfdd747af3a6c6bbaa8 + checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225 languageName: node linkType: hard "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" - checksum: f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 + checksum: 23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d languageName: node linkType: hard "negotiator@npm:0.6.3, negotiator@npm:^0.6.3": version: 0.6.3 resolution: "negotiator@npm:0.6.3" - checksum: 3ec9fd413e7bf071c937ae60d572bc67155262068ed522cf4b3be5edbe6ddf67d095ec03a3a14ebf8fc8e95f8e1d61be4869db0dbb0de696f6b837358bd43fc2 + checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 languageName: node linkType: hard -"neo-async@npm:^2.5.0, neo-async@npm:^2.6.0, neo-async@npm:^2.6.1": +"neo-async@npm:^2.5.0, neo-async@npm:^2.6.0": version: 2.6.2 resolution: "neo-async@npm:2.6.2" - checksum: c2f5a604a54a8ec5438a342e1f356dff4bc33ccccdb6dc668d94fe8e5eccfc9d2c2eea6064b0967a767ba63b33763f51ccf2cd2441b461a7322656c1f06b3f5d + checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9 languageName: node linkType: hard -"node-dir@npm:^0.1.10, node-dir@npm:^0.1.17": +"node-dir@npm:^0.1.17": version: 0.1.17 resolution: "node-dir@npm:0.1.17" dependencies: minimatch: "npm:^3.0.2" - checksum: 16222e871708c405079ff8122d4a7e1d522c5b90fc8f12b3112140af871cfc70128c376e845dcd0044c625db0d2efebd2d852414599d240564db61d53402b4c1 + checksum: 29de9560e52cdac8d3f794d38d782f6799e13d4d11aaf96d3da8c28458e1c5e33bb5f8edfb42dc34172ec5516c50c5b8850c9e1526542616757a969267263328 languageName: node linkType: hard "node-fetch-native@npm:^1.0.2": version: 1.2.0 resolution: "node-fetch-native@npm:1.2.0" - checksum: 85faa0b7af6884fd615ddc05ec70f05d3818bef8ece43952c49dd849885b21fe7cef54f62cf17b9c0faadfe13498f667a996070d386918ab7017b46c725c5ff6 + checksum: f18d775523fc25b9fbec05a1da99cbf40214045bcaca82c8fd949b99148890c3cead4ab1764e26a92af600d14884d846481bcebf82d56815210624f836051a10 languageName: node linkType: hard -"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.7": - version: 2.6.12 - resolution: "node-fetch@npm:2.6.12" +"node-fetch@npm:^2.0.0": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" dependencies: - whatwg-url: "npm:^5.0.0" + whatwg-url: ^5.0.0 peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: encoding: optional: true - checksum: 10372e4b5ee07acadc15e6b2bc6fd8940582eea7b9b2a331f4e3665fdcd968498c1656f79f2fa572080ebb37ea80e1474a6478b3b36057ef901b63f4be8fd899 + checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 languageName: node linkType: hard @@ -11279,21 +12329,28 @@ __metadata: which: "npm:^2.0.2" bin: node-gyp: bin/node-gyp.js - checksum: e8dfbe2b02f23d056f69e01c409381963e92c71cafba6c9cfbf63b038f65ca19ab8183bb6891d080e59c4eb2cc425fc736f42e90afc0f0030ecd97bfc64fb7ad + checksum: 78b404e2e0639d64e145845f7f5a3cb20c0520cdaf6dda2f6e025e9b644077202ea7de1232396ba5bde3fee84cdc79604feebe6ba3ec84d464c85d407bb5da99 languageName: node linkType: hard "node-int64@npm:^0.4.0": version: 0.4.0 resolution: "node-int64@npm:0.4.0" - checksum: a6a4d8369e2f2720e9c645255ffde909c0fbd41c92ea92a5607fc17055955daac99c1ff589d421eee12a0d24e99f7bfc2aabfeb1a4c14742f6c099a51863f31a + checksum: d0b30b1ee6d961851c60d5eaa745d30b5c95d94bc0e74b81e5292f7c42a49e3af87f1eb9e89f59456f80645d679202537de751b7d72e9e40ceea40c5e449057e languageName: node linkType: hard "node-releases@npm:^2.0.12": version: 2.0.13 resolution: "node-releases@npm:2.0.13" - checksum: 2fb44bf70fc949d27f3a48a7fd1a9d1d603ddad4ccd091f26b3fb8b1da976605d919330d7388ccd55ca2ade0dc8b2e12841ba19ef249c8bb29bf82532d401af7 + checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 + languageName: node + linkType: hard + +"node-releases@npm:^2.0.14": + version: 2.0.14 + resolution: "node-releases@npm:2.0.14" + checksum: 59443a2f77acac854c42d321bf1b43dea0aef55cd544c6a686e9816a697300458d4e82239e2d794ea05f7bbbc8a94500332e2d3ac3f11f52e4b16cbe638b3c41 languageName: node linkType: hard @@ -11304,7 +12361,7 @@ __metadata: abbrev: "npm:^1.0.0" bin: nopt: bin/nopt.js - checksum: 837b52c330df16fcaad816b1f54fec6b2854ab1aa771d935c1603fbcf9b023bb073f1466b1b67f48ea4dce127ae675b85b9d9355700e9b109de39db490919786 + checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac languageName: node linkType: hard @@ -11316,14 +12373,14 @@ __metadata: resolve: "npm:^1.10.0" semver: "npm:2 || 3 || 4 || 5" validate-npm-package-license: "npm:^3.0.1" - checksum: 357cb1646deb42f8eb4c7d42c4edf0eec312f3628c2ef98501963cc4bbe7277021b2b1d977f982b2edce78f5a1014613ce9cf38085c3df2d76730481357ca504 + checksum: 7999112efc35a6259bc22db460540cae06564aa65d0271e3bdfa86876d08b0e578b7b5b0028ee61b23f1cae9fc0e7847e4edc0948d3068a39a2a82853efc8499 languageName: node linkType: hard "normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" - checksum: e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 + checksum: 88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 languageName: node linkType: hard @@ -11332,19 +12389,7 @@ __metadata: resolution: "npm-run-path@npm:4.0.1" dependencies: path-key: "npm:^3.0.0" - checksum: 6f9353a95288f8455cf64cbeb707b28826a7f29690244c1e4bb61ec573256e021b6ad6651b394eb1ccfd00d6ec50147253aba2c5fe58a57ceb111fad62c519ac - languageName: node - linkType: hard - -"npmlog@npm:^5.0.1": - version: 5.0.1 - resolution: "npmlog@npm:5.0.1" - dependencies: - are-we-there-yet: "npm:^2.0.0" - console-control-strings: "npm:^1.1.0" - gauge: "npm:^3.0.0" - set-blocking: "npm:^2.0.0" - checksum: 489ba519031013001135c463406f55491a17fc7da295c18a04937fe3a4d523fd65e88dd418a28b967ab743d913fdeba1e29838ce0ad8c75557057c481f7d49fa + checksum: 5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 languageName: node linkType: hard @@ -11356,7 +12401,7 @@ __metadata: console-control-strings: "npm:^1.1.0" gauge: "npm:^4.0.3" set-blocking: "npm:^2.0.0" - checksum: 0cacedfbc2f6139c746d9cd4a85f62718435ad0ca4a2d6459cd331dd33ae58206e91a0742c1558634efcde3f33f8e8e7fd3adf1bfe7978310cf00bd55cccf890 + checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a languageName: node linkType: hard @@ -11365,21 +12410,21 @@ __metadata: resolution: "nth-check@npm:2.1.1" dependencies: boolbase: "npm:^1.0.0" - checksum: 5fee7ff309727763689cfad844d979aedd2204a817fbaaf0e1603794a7c20db28548d7b024692f953557df6ce4a0ee4ae46cd8ebd9b36cfb300b9226b567c479 + checksum: 5afc3dafcd1573b08877ca8e6148c52abd565f1d06b1eb08caf982e3fa289a82f2cae697ffb55b5021e146d60443f1590a5d6b944844e944714a5b549675bcd3 languageName: node linkType: hard "nwsapi@npm:^2.2.2": version: 2.2.7 resolution: "nwsapi@npm:2.2.7" - checksum: 44be198adae99208487a1c886c0a3712264f7bbafa44368ad96c003512fed2753d4e22890ca1e6edb2690c3456a169f2a3c33bfacde1905cf3bf01c7722464db + checksum: cab25f7983acec7e23490fec3ef7be608041b460504229770e3bfcf9977c41d6fe58f518994d3bd9aa3a101f501089a3d4a63536f4ff8ae4b8c4ca23bdbfda4e languageName: node linkType: hard "object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" - checksum: 1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 + checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f languageName: node linkType: hard @@ -11390,14 +12435,14 @@ __metadata: copy-descriptor: "npm:^0.1.0" define-property: "npm:^0.2.5" kind-of: "npm:^3.0.3" - checksum: 79314b05e9d626159a04f1d913f4c4aba9eae8848511cf5f4c8e3b04bb3cc313b65f60357f86462c959a14c2d58380fedf89b6b32ecec237c452a5ef3900a293 + checksum: a9e35f07e3a2c882a7e979090360d1a20ab51d1fa19dfdac3aa8873b328a7c4c7683946ee97c824ae40079d848d6740a3788fa14f2185155dab7ed970a72c783 languageName: node linkType: hard "object-inspect@npm:^1.12.3, object-inspect@npm:^1.9.0": version: 1.12.3 resolution: "object-inspect@npm:1.12.3" - checksum: 752bb5f4dc595e214157ea8f442adb77bdb850ace762b078d151d8b6486331ab12364997a89ee6509be1023b15adf2b3774437a7105f8a5043dfda11ed622411 + checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db languageName: node linkType: hard @@ -11407,14 +12452,14 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.3" - checksum: 8c263fb03fc28f1ffb54b44b9147235c5e233dc1ca23768e7d2569740b5d860154d7cc29a30220fe28ed6d8008e2422aefdebfe987c103e1c5d190cf02d9d886 + checksum: 989b18c4cba258a6b74dc1d74a41805c1a1425bce29f6cabb50dcb1a6a651ea9104a1b07046739a49a5bb1bc49727bcb00efd5c55f932f6ea04ec8927a7901fe languageName: node linkType: hard "object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" - checksum: b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d + checksum: b363c5e7644b1e1b04aa507e88dcb8e3a2f52b6ffd0ea801e4c7a62d5aa559affe21c55a07fd4b1fd55fc03a33c610d73426664b20032405d7b92a1414c34d6a languageName: node linkType: hard @@ -11423,7 +12468,7 @@ __metadata: resolution: "object-visit@npm:1.0.1" dependencies: isobject: "npm:^3.0.0" - checksum: 086b475bda24abd2318d2b187c3e928959b89f5cb5883d6fe5a42d03719b61fc18e765f658de9ac8730e67ba9ff26d61e73d991215948ff9ecefe771e0071029 + checksum: b0ee07f5bf3bb881b881ff53b467ebbde2b37ebb38649d6944a6cd7681b32eedd99da9bd1e01c55facf81f54ed06b13af61aba6ad87f0052982995e09333f790 languageName: node linkType: hard @@ -11435,7 +12480,7 @@ __metadata: define-properties: "npm:^1.1.4" has-symbols: "npm:^1.0.3" object-keys: "npm:^1.1.1" - checksum: 2f286118c023e557757620e647b02e7c88d3d417e0c568fca0820de8ec9cca68928304854d5b03e99763eddad6e78a6716e2930f7e6372e4b9b843f3fd3056f3 + checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864 languageName: node linkType: hard @@ -11446,7 +12491,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 8782c71db3a068ccbae9e0541e6b4ac2c25dc67c63f97b7e6ad3c88271d7820197e7398e37747f96542ed47c27f0b81148cdf14c42df15dc22f64818ae7bb5bf + checksum: 0f8c47517e6a9a980241eafe3b73de11e59511883173c2b93d67424a008e47e11b77c80e431ad1d8a806f6108b225a1cab9223e53e555776c612a24297117d28 languageName: node linkType: hard @@ -11457,7 +12502,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: db6759ea68131cbdb70b1152f9984b49db03e81de4f6de079b39929bebd8b45501e5333ca2351991e07ee56f4651606c023396644e8f25c0806fa39a26c4c6e6 + checksum: 453c6d694180c0c30df451b60eaf27a5b9bca3fb43c37908fd2b78af895803dc631242bcf05582173afa40d8d0e9c96e16e8874b39471aa53f3ac1f98a085d85 languageName: node linkType: hard @@ -11467,7 +12512,7 @@ __metadata: dependencies: define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 419fc1c74a2aea7ebb4d49b79d5b1599a010b26c18eae35bd061ccdd013ccb749c499d8dd6ee21a91e6d7264ccc592573d0f13562970f76e25fc844d8c1b02ce + checksum: b936572536db0cdf38eb30afd2f1026a8b6f2cc5d2c4497c9d9bbb01eaf3e980dead4fd07580cfdd098e6383e5a9db8212d3ea0c6bdd2b5e68c60aa7e3b45566 languageName: node linkType: hard @@ -11476,7 +12521,7 @@ __metadata: resolution: "object.pick@npm:1.3.0" dependencies: isobject: "npm:^3.0.1" - checksum: cd316ec986e49895a28f2df9182de9cdeee57cd2a952c122aacc86344c28624fe002d9affc4f48b5014ec7c033da9942b08821ddb44db8c5bac5b3ec54bdc31e + checksum: 77fb6eed57c67adf75e9901187e37af39f052ef601cb4480386436561357eb9e459e820762f01fd02c5c1b42ece839ad393717a6d1850d848ee11fbabb3e580a languageName: node linkType: hard @@ -11487,7 +12532,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 3381204390f10c9f653a4875a50d221c67b5c16cb80a6ac06c706fc82a7cad8400857d4c7a0731193b0abb56b84fe803eabcf7addcf32de76397bbf207e68c66 + checksum: f6fff9fd817c24cfd8107f50fb33061d81cd11bacc4e3dbb3852e9ff7692fde4dbce823d4333ea27cd9637ef1b6690df5fbb61f1ed314fa2959598dc3ae23d8e languageName: node linkType: hard @@ -11496,14 +12541,14 @@ __metadata: resolution: "on-finished@npm:2.4.1" dependencies: ee-first: "npm:1.1.1" - checksum: 46fb11b9063782f2d9968863d9cbba33d77aa13c17f895f56129c274318b86500b22af3a160fe9995aa41317efcd22941b6eba747f718ced08d9a73afdb087b4 + checksum: d20929a25e7f0bb62f937a425b5edeb4e4cde0540d77ba146ec9357f00b0d497cdb3b9b05b9c8e46222407d1548d08166bff69cc56dfa55ba0e4469228920ff0 languageName: node linkType: hard "on-headers@npm:~1.0.2": version: 1.0.2 resolution: "on-headers@npm:1.0.2" - checksum: f649e65c197bf31505a4c0444875db0258e198292f34b884d73c2f751e91792ef96bb5cf89aa0f4fecc2e4dc662461dda606b1274b0e564f539cae5d2f5fc32f + checksum: 2bf13467215d1e540a62a75021e8b318a6cfc5d4fc53af8e8f84ad98dbcea02d506c6d24180cd62e1d769c44721ba542f3154effc1f7579a8288c9f7873ed8e5 languageName: node linkType: hard @@ -11512,37 +12557,27 @@ __metadata: resolution: "once@npm:1.4.0" dependencies: wrappy: "npm:1" - checksum: 5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 + checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 languageName: node linkType: hard -"onetime@npm:^5.1.2": +"onetime@npm:^5.1.0, onetime@npm:^5.1.2": version: 5.1.2 resolution: "onetime@npm:5.1.2" dependencies: mimic-fn: "npm:^2.1.0" - checksum: ffcef6fbb2692c3c40749f31ea2e22677a876daea92959b8a80b521d95cca7a668c884d8b2045d1d8ee7d56796aa405c405462af112a1477594cc63531baeb8f - languageName: node - linkType: hard - -"open@npm:^7.0.3": - version: 7.4.2 - resolution: "open@npm:7.4.2" - dependencies: - is-docker: "npm:^2.0.0" - is-wsl: "npm:^2.1.1" - checksum: 77573a6a68f7364f3a19a4c80492712720746b63680ee304555112605ead196afe91052bd3c3d165efdf4e9d04d255e87de0d0a77acec11ef47fd5261251813f + checksum: 2478859ef817fc5d4e9c2f9e5728512ddd1dbc9fb7829ad263765bb6d3b91ce699d6e2332eef6b7dff183c2f490bd3349f1666427eaba4469fba0ac38dfd0d34 languageName: node linkType: hard -"open@npm:^8.4.0": +"open@npm:^8.0.4, open@npm:^8.4.0": version: 8.4.2 resolution: "open@npm:8.4.2" dependencies: define-lazy-prop: "npm:^2.0.0" is-docker: "npm:^2.1.1" is-wsl: "npm:^2.2.0" - checksum: bb6b3a58401dacdb0aad14360626faf3fb7fba4b77816b373495988b724fb48941cad80c1b65d62bb31a17609b2cd91c41a181602caea597ca80dfbcc27e84c9 + checksum: 6388bfff21b40cb9bd8f913f9130d107f2ed4724ea81a8fd29798ee322b361ca31fa2cdfb491a5c31e43a3996cfe9566741238c7a741ada8d7af1cb78d85cf26 languageName: node linkType: hard @@ -11556,7 +12591,24 @@ __metadata: levn: "npm:^0.4.1" prelude-ls: "npm:^1.2.1" type-check: "npm:^0.4.0" - checksum: 66fba794d425b5be51353035cf3167ce6cfa049059cbb93229b819167687e0f48d2bc4603fcb21b091c99acb516aae1083624675b15c4765b2e4693a085e959c + checksum: 09281999441f2fe9c33a5eeab76700795365a061563d66b098923eb719251a42bdbe432790d35064d0816ead9296dbeb1ad51a733edf4167c96bd5d0882e428a + languageName: node + linkType: hard + +"ora@npm:^5.4.1": + version: 5.4.1 + resolution: "ora@npm:5.4.1" + dependencies: + bl: ^4.1.0 + chalk: ^4.1.0 + cli-cursor: ^3.1.0 + cli-spinners: ^2.5.0 + is-interactive: ^1.0.0 + is-unicode-supported: ^0.1.0 + log-symbols: ^4.1.0 + strip-ansi: ^6.0.0 + wcwidth: ^1.0.1 + checksum: 28d476ee6c1049d68368c0dc922e7225e3b5600c3ede88fade8052837f9ed342625fdaa84a6209302587c8ddd9b664f71f0759833cbdb3a4cf81344057e63c63 languageName: node linkType: hard @@ -11565,7 +12617,7 @@ __metadata: resolution: "p-limit@npm:2.3.0" dependencies: p-try: "npm:^2.0.0" - checksum: 8da01ac53efe6a627080fafc127c873da40c18d87b3f5d5492d465bb85ec7207e153948df6b9cbaeb130be70152f874229b8242ee2be84c0794082510af97f12 + checksum: 84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 languageName: node linkType: hard @@ -11574,7 +12626,7 @@ __metadata: resolution: "p-limit@npm:3.1.0" dependencies: yocto-queue: "npm:^0.1.0" - checksum: 9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a + checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 languageName: node linkType: hard @@ -11583,7 +12635,7 @@ __metadata: resolution: "p-locate@npm:3.0.0" dependencies: p-limit: "npm:^2.0.0" - checksum: 7b7f06f718f19e989ce6280ed4396fb3c34dabdee0df948376483032f9d5ec22fdf7077ec942143a75827bb85b11da72016497fc10dac1106c837ed593969ee8 + checksum: 83991734a9854a05fe9dbb29f707ea8a0599391f52daac32b86f08e21415e857ffa60f0e120bfe7ce0cc4faf9274a50239c7895fc0d0579d08411e513b83a4ae languageName: node linkType: hard @@ -11592,7 +12644,7 @@ __metadata: resolution: "p-locate@npm:4.1.0" dependencies: p-limit: "npm:^2.2.0" - checksum: 1b476ad69ad7f6059744f343b26d51ce091508935c1dbb80c4e0a2f397ffce0ca3a1f9f5cd3c7ce19d7929a09719d5c65fe70d8ee289c3f267cd36f2881813e9 + checksum: 513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 languageName: node linkType: hard @@ -11601,7 +12653,7 @@ __metadata: resolution: "p-locate@npm:5.0.0" dependencies: p-limit: "npm:^3.0.2" - checksum: 2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a + checksum: 1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3 languageName: node linkType: hard @@ -11610,21 +12662,21 @@ __metadata: resolution: "p-map@npm:4.0.0" dependencies: aggregate-error: "npm:^3.0.0" - checksum: 592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75 + checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c languageName: node linkType: hard "p-try@npm:^2.0.0": version: 2.2.0 resolution: "p-try@npm:2.2.0" - checksum: c36c19907734c904b16994e6535b02c36c2224d433e01a2f1ab777237f4d86e6289fd5fd464850491e940379d4606ed850c03e0f9ab600b0ebddb511312e177f + checksum: f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae languageName: node linkType: hard "pako@npm:~0.2.0": version: 0.2.9 resolution: "pako@npm:0.2.9" - checksum: 79c1806ebcf325b60ae599e4d7227c2e346d7b829dc20f5cf24cef07c934079dc3a61c5b3c8278a2f7a190c4a613e343ea11e5302dbe252efd11712df4b6b041 + checksum: 055f9487cd57fbb78df84315873bbdd089ba286f3499daed47d2effdc6253e981f5db6898c23486de76d4a781559f890d643bd3a49f70f1b4a18019c98aa5125 languageName: node linkType: hard @@ -11633,7 +12685,7 @@ __metadata: resolution: "parent-module@npm:1.0.1" dependencies: callsites: "npm:^3.0.0" - checksum: c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 + checksum: 6ba8b255145cae9470cf5551eb74be2d22281587af787a2626683a6c20fbb464978784661478dd2a3f1dad74d1e802d403e1b03c1a31fab310259eec8ac560ff languageName: node linkType: hard @@ -11647,7 +12699,7 @@ __metadata: is-alphanumerical: "npm:^1.0.0" is-decimal: "npm:^1.0.0" is-hexadecimal: "npm:^1.0.0" - checksum: f85a22c0ea406ff26b53fdc28641f01cc36fa49eb2e3135f02693286c89ef0bcefc2262d99b3688e20aac2a14fd10b75c518583e875c1b9fe3d1f937795e0854 + checksum: 7addfd3e7d747521afac33c8121a5f23043c6973809756920d37e806639b4898385d386fcf4b3c8e2ecf1bc28aac5ae97df0b112d5042034efbe80f44081ebce languageName: node linkType: hard @@ -11659,7 +12711,7 @@ __metadata: error-ex: "npm:^1.3.1" json-parse-even-better-errors: "npm:^2.3.0" lines-and-columns: "npm:^1.1.6" - checksum: 77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585 + checksum: 62085b17d64da57f40f6afc2ac1f4d95def18c4323577e1eced571db75d9ab59b297d1d10582920f84b15985cbfc6b6d450ccbf317644cfa176f3ed982ad87e2 languageName: node linkType: hard @@ -11668,56 +12720,56 @@ __metadata: resolution: "parse5@npm:7.1.2" dependencies: entities: "npm:^4.4.0" - checksum: 297d7af8224f4b5cb7f6617ecdae98eeaed7f8cbd78956c42785e230505d5a4f07cef352af10d3006fa5c1544b76b57784d3a22d861ae071bbc460c649482bf4 + checksum: 59465dd05eb4c5ec87b76173d1c596e152a10e290b7abcda1aecf0f33be49646ea74840c69af975d7887543ea45564801736356c568d6b5e71792fd0f4055713 languageName: node linkType: hard -"parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": +"parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" - checksum: 90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 + checksum: 407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 languageName: node linkType: hard "pascalcase@npm:^0.1.1": version: 0.1.1 resolution: "pascalcase@npm:0.1.1" - checksum: 48dfe90618e33810bf58211d8f39ad2c0262f19ad6354da1ba563935b5f429f36409a1fb9187c220328f7a4dc5969917f8e3e01ee089b5f1627b02aefe39567b + checksum: f83681c3c8ff75fa473a2bb2b113289952f802ff895d435edd717e7cb898b0408cbdb247117a938edcbc5d141020909846cc2b92c47213d764e2a94d2ad2b925 languageName: node linkType: hard "path-exists@npm:^3.0.0": version: 3.0.0 resolution: "path-exists@npm:3.0.0" - checksum: 17d6a5664bc0a11d48e2b2127d28a0e58822c6740bde30403f08013da599182289c56518bec89407e3f31d3c2b6b296a4220bc3f867f0911fee6952208b04167 + checksum: 96e92643aa34b4b28d0de1cd2eba52a1c5313a90c6542d03f62750d82480e20bfa62bc865d5cfc6165f5fcd5aeb0851043c40a39be5989646f223300021bae0a languageName: node linkType: hard "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" - checksum: 8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b + checksum: 505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 languageName: node linkType: hard "path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" - checksum: 127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078 + checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 languageName: node linkType: hard "path-key@npm:^3.0.0, path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" - checksum: 748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c + checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 languageName: node linkType: hard "path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" - checksum: 11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 + checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a languageName: node linkType: hard @@ -11727,28 +12779,28 @@ __metadata: dependencies: lru-cache: "npm:^9.1.1 || ^10.0.0" minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: e5dc78a7348d25eec61ab166317e9e9c7b46818aa2c2b9006c507a6ff48c672d011292d9662527213e558f5652ce0afcc788663a061d8b59ab495681840c0c1e + checksum: e2557cff3a8fb8bc07afdd6ab163a92587884f9969b05bbbaf6fe7379348bfb09af9ed292af12ed32398b15fb443e81692047b786d1eeb6d898a51eb17ed7d90 languageName: node linkType: hard "path-to-regexp@npm:0.1.7": version: 0.1.7 resolution: "path-to-regexp@npm:0.1.7" - checksum: 50a1ddb1af41a9e68bd67ca8e331a705899d16fb720a1ea3a41e310480948387daf603abb14d7b0826c58f10146d49050a1291ba6a82b78a382d1c02c0b8f905 + checksum: 69a14ea24db543e8b0f4353305c5eac6907917031340e5a8b37df688e52accd09e3cebfe1660b70d76b6bd89152f52183f28c74813dbf454ba1a01c82a38abce languageName: node linkType: hard "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" - checksum: 666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c + checksum: 5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 languageName: node linkType: hard "pathe@npm:^1.1.0": version: 1.1.1 resolution: "pathe@npm:1.1.1" - checksum: 3ae5a0529c3415d91c3ac9133f52cffea54a0dd46892fe059f4b80faf36fd207957d4594bdc87043b65d0761b1e5728f81f46bafff3b5302da4e2e48889b8c0e + checksum: 34ab3da2e5aa832ebc6a330ffe3f73d7ba8aec6e899b53b8ec4f4018de08e40742802deb12cf5add9c73b7bf719b62c0778246bd376ca62b0fb23e0dde44b759 languageName: node linkType: hard @@ -11759,42 +12811,42 @@ __metadata: buffer-from: "npm:^1.0.0" duplexify: "npm:^3.5.0" through2: "npm:^2.0.3" - checksum: 3c35d1951b8640036f93b1b5628a90f849e49ca4f2e6aba393ff4978413931d9c491c83f71a92f878d5ea4c670af0bba04dfcfb79b310ead22601db7c1420e36 + checksum: a0e09d6d1a8a01158a3334f20d6b1cdd91747eba24eb06a1d742eefb620385593121a76d4378cc81f77cdce6a66df0575a41041b1189c510254aec91878afc99 languageName: node linkType: hard "pend@npm:~1.2.0": version: 1.2.0 resolution: "pend@npm:1.2.0" - checksum: 8a87e63f7a4afcfb0f9f77b39bb92374afc723418b9cb716ee4257689224171002e07768eeade4ecd0e86f1fa3d8f022994219fb45634f2dbd78c6803e452458 + checksum: 6c72f5243303d9c60bd98e6446ba7d30ae29e3d56fdb6fae8767e8ba6386f33ee284c97efe3230a0d0217e2b1723b8ab490b1bbf34fcbb2180dbc8a9de47850d languageName: node linkType: hard "picocolors@npm:^1.0.0": version: 1.0.0 resolution: "picocolors@npm:1.0.0" - checksum: 20a5b249e331c14479d94ec6817a182fd7a5680debae82705747b2db7ec50009a5f6648d0621c561b0572703f84dbef0858abcbd5856d3c5511426afcb1961f7 + checksum: a2e8092dd86c8396bdba9f2b5481032848525b3dc295ce9b57896f931e63fc16f79805144321f72976383fc249584672a75cc18d6777c6b757603f372f745981 languageName: node linkType: hard "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.0, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" - checksum: 26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be + checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf languageName: node linkType: hard "pify@npm:^4.0.1": version: 4.0.1 resolution: "pify@npm:4.0.1" - checksum: 6f9d404b0d47a965437403c9b90eca8bb2536407f03de165940e62e72c8c8b75adda5516c6b9b23675a5877cc0bcac6bdfb0ef0e39414cd2476d5495da40e7cf + checksum: 9c4e34278cb09987685fa5ef81499c82546c033713518f6441778fbec623fc708777fe8ac633097c72d88470d5963094076c7305cafc7ad340aae27cfacd856b languageName: node linkType: hard -"pirates@npm:^4.0.4, pirates@npm:^4.0.5": +"pirates@npm:^4.0.4, pirates@npm:^4.0.6": version: 4.0.6 resolution: "pirates@npm:4.0.6" - checksum: 00d5fa51f8dded94d7429700fb91a0c1ead00ae2c7fd27089f0c5b63e6eca36197fe46384631872690a66f390c5e27198e99006ab77ae472692ab9c2ca903f36 + checksum: 46a65fefaf19c6f57460388a5af9ab81e3d7fd0e7bc44ca59d753cb5c4d0df97c6c6e583674869762101836d68675f027d60f841c105d72734df9dfca97cbcc6 languageName: node linkType: hard @@ -11803,7 +12855,7 @@ __metadata: resolution: "pkg-dir@npm:3.0.0" dependencies: find-up: "npm:^3.0.0" - checksum: 902a3d0c1f8ac43b1795fa1ba6ffeb37dfd53c91469e969790f6ed5e29ff2bdc50b63ba6115dc056d2efb4a040aa2446d512b3804bdafdf302f734fb3ec21847 + checksum: 70c9476ffefc77552cc6b1880176b71ad70bfac4f367604b2b04efd19337309a4eec985e94823271c7c0e83946fa5aeb18cd360d15d10a5d7533e19344bfa808 languageName: node linkType: hard @@ -11812,7 +12864,7 @@ __metadata: resolution: "pkg-dir@npm:4.2.0" dependencies: find-up: "npm:^4.0.0" - checksum: c56bda7769e04907a88423feb320babaed0711af8c436ce3e56763ab1021ba107c7b0cafb11cde7529f669cfc22bffcaebffb573645cbd63842ea9fb17cd7728 + checksum: 9863e3f35132bf99ae1636d31ff1e1e3501251d480336edb1c211133c8d58906bed80f154a1d723652df1fda91e01c7442c2eeaf9dc83157c7ae89087e43c8d6 languageName: node linkType: hard @@ -11821,7 +12873,7 @@ __metadata: resolution: "pkg-dir@npm:5.0.0" dependencies: find-up: "npm:^5.0.0" - checksum: 793a496d685dc55bbbdbbb22d884535c3b29241e48e3e8d37e448113a71b9e42f5481a61fdc672d7322de12fbb2c584dd3a68bf89b18fffce5c48a390f911bc5 + checksum: b167bb8dac7bbf22b1d5e30ec223e6b064b84b63010c9d49384619a36734caf95ed23ad23d4f9bd975e8e8082b60a83395f43a89bb192df53a7c25a38ecb57d9 languageName: node linkType: hard @@ -11830,14 +12882,14 @@ __metadata: resolution: "polished@npm:4.2.2" dependencies: "@babel/runtime": "npm:^7.17.8" - checksum: 1d054d1fea18ac7d921ca91504ffcf1ef0f505eda6acbfec6e205a98ebfea80b658664995deb35907dabc5f75f287dc2894812503a8aed28285bb91f25cf7400 + checksum: 97fb927dc55cd34aeb11b31ae2a3332463f114351c86e8aa6580d7755864a0120164fdc3770e6160c8b1775052f0eda14db9a6e34402cd4b08ab2d658a593725 languageName: node linkType: hard "posix-character-classes@npm:^0.1.0": version: 0.1.1 resolution: "posix-character-classes@npm:0.1.1" - checksum: cce88011548a973b4af58361cd8f5f7b5a6faff8eef0901565802f067bcabf82597e920d4c97c22068464be3cbc6447af589f6cc8a7d813ea7165be60a0395bc + checksum: dedb99913c60625a16050cfed2fb5c017648fc075be41ac18474e1c6c3549ef4ada201c8bd9bd006d36827e289c571b6092e1ef6e756cdbab2fd7046b25c6442 languageName: node linkType: hard @@ -11846,7 +12898,7 @@ __metadata: resolution: "postcss-prefix-selector@npm:1.16.0" peerDependencies: postcss: ">4 <9" - checksum: edc78fd0d8885ad77907044cb25afb6b49c81170810025afca47d6984f86479503a63293910cd4e9b296a7e5d876ab7473c481180774e7e7a55a6edf02746469 + checksum: 8bdf10628ec8b1679a4dbb9cd736a4742c5d9b8a878c35cebaad43d67e50a18ffeb34d15860374f18a89fe4c43f818f3386bdb3321f92bb35eec9ef640a46a76 languageName: node linkType: hard @@ -11858,7 +12910,7 @@ __metadata: js-base64: "npm:^2.1.9" source-map: "npm:^0.5.6" supports-color: "npm:^3.2.3" - checksum: 1f9f6673dd24d52f1ed33b800248e6ef752d6b6a092fe268021e398df0d7e0956f00fb961781647264d659240c3d67f5bfd3df9bf1b7af985aa996be619d30b1 + checksum: 0cb88e7c887b9b55d0362159846ec9fbf330892c5853b0e346929e723d215295ffae48d9a0f219f64f74767f9114802dc1b5cd21c327184f958b7efaa93dd629 languageName: node linkType: hard @@ -11869,7 +12921,7 @@ __metadata: nanoid: "npm:^3.3.6" picocolors: "npm:^1.0.0" source-map-js: "npm:^1.0.2" - checksum: aa2143cb5ed6eef6cb1d38236f158c5fe11bfd1f338c930cf4901f09586874e05fa006e3fd329ca51c61202c7e90d0705379e6310251c9311116e65cb6a08c18 + checksum: 9ed3ab8af43ad5210c28f56f916fd9b8c9f94fbeaebbf645dcf579bc28bdd8056c2a7ecc934668d399b81fedb6128f0c4b299f931e50454964bc911c25a3a0a2 languageName: node linkType: hard @@ -11879,7 +12931,7 @@ __metadata: dependencies: htmlparser2: "npm:^3.8.3" isobject: "npm:^2.1.0" - checksum: 14dc8db2233c8e3b1bf33e8a2e35676490c8b7aa25be085f189c652ae7064eeb8c1e8bb1092a5659481c85253e61d328c8492fb315d47941f1477ffacd1e22ef + checksum: 1111cced3ea995de4f72bedace828b733e7eefa953573202e596cac7c82b3ced6cae2849c00f2ed1bb801ff544f4cf85a7b94f5f23392727dc4e0a0b26a8b15f languageName: node linkType: hard @@ -11888,14 +12940,14 @@ __metadata: resolution: "posthtml-rename-id@npm:1.0.12" dependencies: escape-string-regexp: "npm:1.0.5" - checksum: 1dcd2067565554b743ef1ae133735c72123352ce7bd048d179ebccba411ed251a52579cf69bb4a4ab60ae046156f28fc96cf3a722aff8d23770b948c5bf7604d + checksum: 5bfb88f9063e1057c6f5342d7100584cdcb55f4344ed3cfd68db8249fb25cc06f89b048fbf170cfb64c9a771994a2c3e79457f3bcc49988611a59769fc0a3a6b languageName: node linkType: hard "posthtml-render@npm:^1.0.5, posthtml-render@npm:^1.0.6": version: 1.4.0 resolution: "posthtml-render@npm:1.4.0" - checksum: e916f8d3c09a0d750c46aeecb393e373521bb695d8640d405e711253bfba9fab72c9f89a59c7b8416f7cc749f349e356f46fcd09a6f6a3219c4ae0713c60147a + checksum: 68c5c85834d57d54bb797ae81a4ab74ad1d87f55e6a327dac9804fbed96214b57d437d7e255e9396184ab976ab7e77aed6efda9315c156ab25ef8ab2c095c16b languageName: node linkType: hard @@ -11907,7 +12959,7 @@ __metadata: posthtml: "npm:^0.9.2" posthtml-parser: "npm:^0.2.1" posthtml-render: "npm:^1.0.6" - checksum: 55a6b631a2fc3e5db62a50ae9cdaa402802272174eb72c172ed3dd8d486338c2666dbb9d5c7467a54cc05675b4152c90517fcd03caea9ba0e763c56a31a14372 + checksum: a9f88294dd7fe862a360a04d5e003fc250175bcb43f6fbd80f384f9daa6f39877a16026d00b39107a6201abe237fbfb591a0deea3bda19c606d493c96deff640 languageName: node linkType: hard @@ -11917,14 +12969,14 @@ __metadata: dependencies: posthtml-parser: "npm:^0.2.0" posthtml-render: "npm:^1.0.5" - checksum: d873eef686c140cfc5e19820293798e90a12c7c76a35934e8e1791dddbf22a00efc78bc9c03f74b8afdf736c08b942a594f796e56a29054bd89a736b9fd7433a + checksum: 1464440239cc8ab745b6682142f509acc3a8837ef01e0398d7f482221030cd06c39f396feb301c4d337c920ce3281788782870c35a11349551c3a418cdc55487 languageName: node linkType: hard "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" - checksum: b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd + checksum: cd192ec0d0a8e4c6da3bb80e4f62afe336df3f76271ac6deb0e6a36187133b6073a19e9727a1ff108cd8b9982e4768850d413baa71214dd80c7979617dca827a languageName: node linkType: hard @@ -11933,7 +12985,7 @@ __metadata: resolution: "prettier-linter-helpers@npm:1.0.0" dependencies: fast-diff: "npm:^1.1.2" - checksum: 81e0027d731b7b3697ccd2129470ed9913ecb111e4ec175a12f0fcfab0096516373bf0af2fef132af50cafb0a905b74ff57996d615f59512bb9ac7378fcc64ab + checksum: 00ce8011cf6430158d27f9c92cfea0a7699405633f7f1d4a45f07e21bf78e99895911cbcdc3853db3a824201a7c745bd49bfea8abd5fb9883e765a90f74f8392 languageName: node linkType: hard @@ -11942,7 +12994,7 @@ __metadata: resolution: "prettier@npm:2.8.8" bin: prettier: bin-prettier.js - checksum: 463ea8f9a0946cd5b828d8cf27bd8b567345cf02f56562d5ecde198b91f47a76b7ac9eae0facd247ace70e927143af6135e8cf411986b8cb8478784a4d6d724a + checksum: b49e409431bf129dd89238d64299ba80717b57ff5a6d1c1a8b1a28b590d998a34e083fa13573bc732bb8d2305becb4c9a4407f8486c81fa7d55100eb08263cf8 languageName: node linkType: hard @@ -11953,7 +13005,7 @@ __metadata: ansi-regex: "npm:^5.0.1" ansi-styles: "npm:^5.0.0" react-is: "npm:^17.0.1" - checksum: 0cbda1031aa30c659e10921fa94e0dd3f903ecbbbe7184a729ad66f2b6e7f17891e8c7d7654c458fa4ccb1a411ffb695b4f17bbcd3fe075fabe181027c4040ed + checksum: cf610cffcb793885d16f184a62162f2dd0df31642d9a18edf4ca298e909a8fe80bdbf556d5c9573992c102ce8bf948691da91bf9739bee0ffb6e79c8a8a6e088 languageName: node linkType: hard @@ -11964,49 +13016,49 @@ __metadata: "@jest/schemas": "npm:^29.6.0" ansi-styles: "npm:^5.0.0" react-is: "npm:^18.0.0" - checksum: decb4ca86b34e53a08e525d2b50be19ef4bffa4bb4122787740b012c11490311879de53dee8b669a82376b6fec06040ec546831f2c3ce0df963c00d743cce664 + checksum: 6f923a2379a37a425241dc223d76f671c73c4f37dba158050575a54095867d565c068b441843afdf3d7c37bed9df4bbadf46297976e60d4149972b779474203a languageName: node linkType: hard "pretty-hrtime@npm:^1.0.3": version: 1.0.3 resolution: "pretty-hrtime@npm:1.0.3" - checksum: 67cb3fc283a72252b49ac488647e6a01b78b7aa1b8f2061834aa1650691229081518ef3ca940f77f41cc8a8f02ba9eeb74b843481596670209e493062f2e89e0 + checksum: bae0e6832fe13c3de43d1a3d43df52bf6090499d74dc65a17f5552cb1a94f1f8019a23284ddf988c3c408a09678d743901e1d8f5b7a71bec31eeeac445bef371 languageName: node linkType: hard "prismjs@npm:^1.27.0": version: 1.29.0 resolution: "prismjs@npm:1.29.0" - checksum: d906c4c4d01b446db549b4f57f72d5d7e6ccaca04ecc670fb85cea4d4b1acc1283e945a9cbc3d81819084a699b382f970e02f9d1378e14af9808d366d9ed7ec6 + checksum: 007a8869d4456ff8049dc59404e32d5666a07d99c3b0e30a18bd3b7676dfa07d1daae9d0f407f20983865fd8da56de91d09cb08e6aa61f5bc420a27c0beeaf93 languageName: node linkType: hard "prismjs@npm:~1.27.0": version: 1.27.0 resolution: "prismjs@npm:1.27.0" - checksum: 841cbf53e837a42df9155c5ce1be52c4a0a8967ac916b52a27d066181a3578186c634e52d06d0547fb62b65c486b99b95f826dd54966619f9721b884f486b498 + checksum: 85c7f4a3e999073502cc9e1882af01e3709706369ec254b60bff1149eda701f40d02512acab956012dc7e61cfd61743a3a34c1bd0737e8dbacd79141e5698bbc languageName: node linkType: hard "process-nextick-args@npm:~2.0.0": version: 2.0.1 resolution: "process-nextick-args@npm:2.0.1" - checksum: bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 + checksum: 1d38588e520dab7cea67cbbe2efdd86a10cc7a074c09657635e34f035277b59fbb57d09d8638346bf7090f8e8ebc070c96fa5fd183b777fff4f5edff5e9466cf languageName: node linkType: hard "process@npm:^0.11.10": version: 0.11.10 resolution: "process@npm:0.11.10" - checksum: 40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3 + checksum: bfcce49814f7d172a6e6a14d5fa3ac92cc3d0c3b9feb1279774708a719e19acd673995226351a082a9ae99978254e320ccda4240ddc474ba31a76c79491ca7c3 languageName: node linkType: hard "progress@npm:^2.0.1": version: 2.0.3 resolution: "progress@npm:2.0.3" - checksum: 1697e07cb1068055dbe9fe858d242368ff5d2073639e652b75a7eb1f2a1a8d4afd404d719de23c7b48481a6aa0040686310e2dac2f53d776daa2176d3f96369c + checksum: f67403fe7b34912148d9252cb7481266a354bd99ce82c835f79070643bb3c6583d10dbcfda4d41e04bbc1d8437e9af0fb1e1f2135727878f5308682a579429b7 languageName: node linkType: hard @@ -12016,7 +13068,7 @@ __metadata: dependencies: err-code: "npm:^2.0.2" retry: "npm:^0.12.0" - checksum: 9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 + checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 languageName: node linkType: hard @@ -12026,7 +13078,7 @@ __metadata: dependencies: kleur: "npm:^3.0.3" sisteransi: "npm:^1.0.5" - checksum: 16f1ac2977b19fe2cf53f8411cc98db7a3c8b115c479b2ca5c82b5527cd937aa405fa04f9a5960abeb9daef53191b53b4d13e35c1f5d50e8718c76917c5f1ea4 + checksum: d8fd1fe63820be2412c13bfc5d0a01909acc1f0367e32396962e737cb2fc52d004f3302475d5ce7d18a1e8a79985f93ff04ee03007d091029c3f9104bffc007d languageName: node linkType: hard @@ -12037,7 +13089,7 @@ __metadata: loose-envify: "npm:^1.4.0" object-assign: "npm:^4.1.1" react-is: "npm:^16.13.1" - checksum: 59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077 + checksum: c056d3f1c057cb7ff8344c645450e14f088a915d078dcda795041765047fa080d38e5d626560ccaac94a4e16e3aa15f3557c1a9a8d1174530955e992c675e459 languageName: node linkType: hard @@ -12046,7 +13098,7 @@ __metadata: resolution: "property-information@npm:5.6.0" dependencies: xtend: "npm:^4.0.0" - checksum: d54b77c31dc13bb6819559080b2c67d37d94be7dc271f404f139a16a57aa96fcc0b3ad806d4a5baef9e031744853e4afe3df2e37275aacb1f78079bbb652c5af + checksum: fcf87c6542e59a8bbe31ca0b3255a4a63ac1059b01b04469680288998bcfa97f341ca989566adbb63975f4d85339030b82320c324a511532d390910d1c583893 languageName: node linkType: hard @@ -12056,21 +13108,21 @@ __metadata: dependencies: forwarded: "npm:0.2.0" ipaddr.js: "npm:1.9.1" - checksum: c3eed999781a35f7fd935f398b6d8920b6fb00bbc14287bc6de78128ccc1a02c89b95b56742bf7cf0362cc333c61d138532049c7dedc7a328ef13343eff81210 + checksum: 29c6990ce9364648255454842f06f8c46fcd124d3e6d7c5066df44662de63cdc0bad032e9bf5a3d653ff72141cc7b6019873d685708ac8210c30458ad99f2b74 languageName: node linkType: hard "proxy-from-env@npm:^1.0.0, proxy-from-env@npm:^1.1.0": version: 1.1.0 resolution: "proxy-from-env@npm:1.1.0" - checksum: fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b + checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 languageName: node linkType: hard "psl@npm:^1.1.33": version: 1.9.0 resolution: "psl@npm:1.9.0" - checksum: 6a3f805fdab9442f44de4ba23880c4eba26b20c8e8e0830eff1cb31007f6825dace61d17203c58bfe36946842140c97a1ba7f67bc63ca2d88a7ee052b65d97ab + checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d languageName: node linkType: hard @@ -12080,7 +13132,7 @@ __metadata: dependencies: end-of-stream: "npm:^1.1.0" once: "npm:^1.3.1" - checksum: f1fe8960f44d145f8617ea4c67de05392da4557052980314c8f85081aee26953bdcab64afad58a2b1df0e8ff7203e3710e848cbe81a01027978edc6e264db355 + checksum: e9f26a17be00810bff37ad0171edb35f58b242487b0444f92fb7d78bc7d61442fa9b9c5bd93a43fd8fd8ddd3cc75f1221f5e04c790f42907e5baab7cf5e2b931 languageName: node linkType: hard @@ -12090,7 +13142,7 @@ __metadata: dependencies: end-of-stream: "npm:^1.1.0" once: "npm:^1.3.1" - checksum: bbdeda4f747cdf47db97428f3a135728669e56a0ae5f354a9ac5b74556556f5446a46f720a8f14ca2ece5be9b4d5d23c346db02b555f46739934cc6c093a5478 + checksum: e42e9229fba14732593a718b04cb5e1cfef8254544870997e0ecd9732b189a48e1256e4e5478148ecb47c8511dca2b09eae56b4d0aad8009e6fac8072923cfc9 languageName: node linkType: hard @@ -12101,14 +13153,14 @@ __metadata: duplexify: "npm:^3.6.0" inherits: "npm:^2.0.3" pump: "npm:^2.0.0" - checksum: 0bcabf9e3dbf2d0cc1f9b84ac80d3c75386111caf8963bfd98817a1e2192000ac0ccc804ca6ccd5b2b8430fdb71347b20fb2f014fe3d41adbacb1b502a841c45 + checksum: 26ca412ec8d665bd0d5e185c1b8f627728eff603440d75d22a58e421e3c66eaf86ec6fc6a6efc54808ecef65979279fa8e99b109a23ec1fa8d79f37e6978c9bd languageName: node linkType: hard "punycode@npm:^2.1.0, punycode@npm:^2.1.1": version: 2.3.0 resolution: "punycode@npm:2.3.0" - checksum: 8e6f7abdd3a6635820049e3731c623bbef3fedbf63bbc696b0d7237fdba4cefa069bc1fa62f2938b0fbae057550df7b5318f4a6bcece27f1907fc75c54160bee + checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200 languageName: node linkType: hard @@ -12126,14 +13178,14 @@ __metadata: proxy-from-env: "npm:^1.0.0" rimraf: "npm:^2.6.1" ws: "npm:^6.1.0" - checksum: 29a73c2327e208e6528bac05f841b3340ee1a8d7bd59e7b235c9d8b3c0bf266804ad1aa901a0e4a1d66ce4202646f242988c3c5c4dfb105e9ad082bf4aae69be + checksum: 2ddb597ef1b2d162b4aa49833b977734129edf7c8fa558fc38c59d273e79aa1bd079481c642de87f7163665f7f37aa52683da2716bafb7d3cab68c262c36ec28 languageName: node linkType: hard "pure-rand@npm:^6.0.0": version: 6.0.2 resolution: "pure-rand@npm:6.0.2" - checksum: 0556bee2e16a8d081a2b7630d9cb4e5dafd4e6bd6e4c61de1cf1ef5974f127847523e3d0e62884f6f5d64b66a5e93b05bd8f37ed009f3a4fe5089899e05914aa + checksum: 79de33876a4f515d759c48e98d00756bbd916b4ea260cc572d7adfa4b62cace9952e89f0241d0410214554503d25061140fe325c66f845213d2b1728ba8d413e languageName: node linkType: hard @@ -12142,7 +13194,7 @@ __metadata: resolution: "qs@npm:6.11.0" dependencies: side-channel: "npm:^1.0.4" - checksum: 4e4875e4d7c7c31c233d07a448e7e4650f456178b9dd3766b7cfa13158fdb24ecb8c4f059fa91e820dc6ab9f2d243721d071c9c0378892dcdad86e9e9a27c68f + checksum: 6e1f29dd5385f7488ec74ac7b6c92f4d09a90408882d0c208414a34dd33badc1a621019d4c799a3df15ab9b1d0292f97c1dd71dc7c045e69f81a8064e5af7297 languageName: node linkType: hard @@ -12151,7 +13203,7 @@ __metadata: resolution: "qs@npm:6.11.2" dependencies: side-channel: "npm:^1.0.4" - checksum: 4f95d4ff18ed480befcafa3390022817ffd3087fc65f146cceb40fc5edb9fa96cb31f648cae2fa96ca23818f0798bd63ad4ca369a0e22702fcd41379b3ab6571 + checksum: e812f3c590b2262548647d62f1637b6989cc56656dc960b893fe2098d96e1bd633f36576f4cd7564dfbff9db42e17775884db96d846bebe4f37420d073ecdc0b languageName: node linkType: hard @@ -12161,35 +13213,35 @@ __metadata: dependencies: object-assign: "npm:^4.1.0" strict-uri-encode: "npm:^1.0.0" - checksum: 6181c343074c2049fbbcde63f87c1da5d3a49c6e34c8d94a61d692e886e0b8cd1ae4a4be00b598112bb9c4cb819e423ed503a5d246e4d24ecb0990d8bb21570b + checksum: 3b2bae6a8454cf0edf11cf1aa4d1f920398bbdabc1c39222b9bb92147e746fcd97faf00e56f494728fb66b2961b495ba0fde699d5d3bd06b11472d664b36c6cf languageName: node linkType: hard "querystringify@npm:^2.1.1": version: 2.2.0 resolution: "querystringify@npm:2.2.0" - checksum: 3258bc3dbdf322ff2663619afe5947c7926a6ef5fb78ad7d384602974c467fadfc8272af44f5eb8cddd0d011aae8fabf3a929a8eee4b86edcc0a21e6bd10f9aa + checksum: 5641ea231bad7ef6d64d9998faca95611ed4b11c2591a8cae741e178a974f6a8e0ebde008475259abe1621cb15e692404e6b6626e927f7b849d5c09392604b15 languageName: node linkType: hard "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" - checksum: 900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 + checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 languageName: node linkType: hard "ramda@npm:0.29.0": version: 0.29.0 resolution: "ramda@npm:0.29.0" - checksum: b00eaaf1c62b06a99affa1d583e256bd65ad27ab9d0ef512f55d7d93b842e7cd244a4a09179f61fdd8548362e409323867a2b0477cbd0626b5644eb6ac7c53da + checksum: 9ab26c06eb7545cbb7eebcf75526d6ee2fcaae19e338f165b2bf32772121e7b28192d6664d1ba222ff76188ba26ab307342d66e805dbb02c860560adc4d5dd57 languageName: node linkType: hard "range-parser@npm:~1.2.1": version: 1.2.1 resolution: "range-parser@npm:1.2.1" - checksum: 96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0 + checksum: 0a268d4fea508661cf5743dfe3d5f47ce214fd6b7dec1de0da4d669dd4ef3d2144468ebe4179049eff253d9d27e719c88dae55be64f954e80135a0cada804ec9 languageName: node linkType: hard @@ -12201,7 +13253,7 @@ __metadata: http-errors: "npm:2.0.0" iconv-lite: "npm:0.4.24" unpipe: "npm:1.0.0" - checksum: 5dad5a3a64a023b894ad7ab4e5c7c1ce34d3497fc7138d02f8c88a3781e68d8a55aa7d4fd3a458616fa8647cc228be314a1c03fb430a07521de78b32c4dd09d2 + checksum: 5362adff1575d691bb3f75998803a0ffed8c64eabeaa06e54b4ada25a0cd1b2ae7f4f5ec46565d1bec337e08b5ac90c76eaa0758de6f72a633f025d754dec29e languageName: node linkType: hard @@ -12213,7 +13265,7 @@ __metadata: peerDependencies: react: ^16.9.0 || ^17 || ^18 react-dom: ^16.9.0 || ^17 || ^18 - checksum: 53d2a695976e8380f9ae314cf4f4f0e894edef1858a5f13da58431ed6bbe63f0b9d4db9f0e25303b7ef55049f00d77bac247f39d13f8c9ac3bca0c459c573d5b + checksum: 77648dd51d746842326a5268cfb48290df225e11b13de587313603fb8452703ba34ea4b32afa8bf386067e179212ce670adca09c5d29943ea74d8c0e43b20430 languageName: node linkType: hard @@ -12223,7 +13275,7 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 48eb73cf71e10841c2a61b6b06ab81da9fffa9876134c239bfdebcf348ce2a47e56b146338e35dfb03512c85966bfc9a53844fc56bc50154e71f8daee59ff6f0 + checksum: e432b7cb0df57e8f0bcdc3b012d2e93fcbcb6092c9e0f85654788d5ebfc4442536d8cc35b2418061ba3c4afb8b7788cc101c606d86a1732407921de7a9244c8d languageName: node linkType: hard @@ -12235,7 +13287,7 @@ __metadata: prop-types: "npm:^15.8.1" peerDependencies: react: ^15.3.0 || 16 || 17 || 18 - checksum: de70d9f9c2d17cee207888ed791d4a042c300e5ca732503434d49e6745cff56c0d5ebcc82ab86237e9c2248e636d1d031b9f9cf9913ecec61d82a0e5ebc93881 + checksum: f00a4551b9b63c944a041a6ab46af5ef20ba1106b3bc25173e7ef9bffbfba17a613368682ab8820cfe8d4b3acc5335cd9ce20229145bcc1e6aa8d1db04c512e5 languageName: node linkType: hard @@ -12244,27 +13296,25 @@ __metadata: resolution: "react-docgen-typescript@npm:2.2.2" peerDependencies: typescript: ">= 4.3.x" - checksum: d31a061a21b5d4b67d4af7bc742541fd9e16254bd32861cd29c52565bc2175f40421a3550d52b6a6b0d0478e7cc408558eb0060a0bdd2957b02cfceeb0ee1e88 + checksum: a9826459ea44e818f21402728dd47f5cae60bd936574cefd4f90ad101ff3eebacd67b6e017b793309734ce62c037aa3072dbc855d2b0e29bad1a38cbf5bac115 languageName: node linkType: hard -"react-docgen@npm:6.0.0-alpha.3": - version: 6.0.0-alpha.3 - resolution: "react-docgen@npm:6.0.0-alpha.3" +"react-docgen@npm:^7.0.0": + version: 7.0.3 + resolution: "react-docgen@npm:7.0.3" dependencies: - "@babel/core": "npm:^7.7.5" - "@babel/generator": "npm:^7.12.11" - ast-types: "npm:^0.14.2" - commander: "npm:^2.19.0" - doctrine: "npm:^3.0.0" - estree-to-babel: "npm:^3.1.0" - neo-async: "npm:^2.6.1" - node-dir: "npm:^0.1.10" - resolve: "npm:^1.17.0" - strip-indent: "npm:^3.0.0" - bin: - react-docgen: bin/react-docgen.js - checksum: 284bba5528d5e9084c3ed36b2d2fec8fc5d55f3fb8ca544ec3a0d1ab98c39001ecb7db6e03a1088b82eb3d750c1343cde2fc9b7729540277eda40e10f38912d8 + "@babel/core": ^7.18.9 + "@babel/traverse": ^7.18.9 + "@babel/types": ^7.18.9 + "@types/babel__core": ^7.18.0 + "@types/babel__traverse": ^7.18.0 + "@types/doctrine": ^0.0.9 + "@types/resolve": ^1.20.2 + doctrine: ^3.0.0 + resolve: ^1.22.1 + strip-indent: ^4.0.0 + checksum: f5dbabd16a25b3c424c4962df4b4073d03ca124c3a5c99871f8436e30468854de115f959d0d5f03df77ad8dbe54f21e679fb48ba47bc125d61ae527bc5bcf0bf languageName: node linkType: hard @@ -12276,7 +13326,7 @@ __metadata: scheduler: "npm:^0.23.0" peerDependencies: react: ^18.2.0 - checksum: 66dfc5f93e13d0674e78ef41f92ed21dfb80f9c4ac4ac25a4b51046d41d4d2186abc915b897f69d3d0ebbffe6184e7c5876f2af26bfa956f179225d921be713a + checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc languageName: node linkType: hard @@ -12290,44 +13340,35 @@ __metadata: peerDependencies: react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 - checksum: 0d60a0ea758529c32a706d0c69d70b69fb94de3c46442fffdee34f08f51ffceddbb5395b41dfd1565895653e9f60f98ca525835be9d5db1f16d6b22be12f4cd4 - languageName: node - linkType: hard - -"react-inspector@npm:^6.0.0": - version: 6.0.2 - resolution: "react-inspector@npm:6.0.2" - peerDependencies: - react: ^16.8.4 || ^17.0.0 || ^18.0.0 - checksum: 8f9b23c21b4d95722e28c9455c2bf00fd9437347714382594461f98e5b9954d60864d0f4e74e881639b065e752a97ba52a65e39930c234072e5bff291bb02b5e + checksum: c3907cc4c1d3e9ecc8ca7727058ebcba6ec89848d9e07bfd2c77ee8f28f1ad99bf55e38359dec8a1125de83d41ac09a2874f53c41415edc86ffa9840fa1b7856 languageName: node linkType: hard "react-is@npm:18.1.0": version: 18.1.0 resolution: "react-is@npm:18.1.0" - checksum: 558874e4c3bd9805a9294426e090919ee6901be3ab07f80b997c36b5a01a8d691112802e7438d146f6c82fd6495d8c030f276ef05ec3410057f8740a8d723f8c + checksum: d206a0fe6790851bff168727bfb896de02c5591695afb0c441163e8630136a3e13ee1a7ddd59fdccddcc93968b4721ae112c10f790b194b03b35a3dc13a355ef languageName: node linkType: hard "react-is@npm:^16.13.1, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" - checksum: 33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 + checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f languageName: node linkType: hard "react-is@npm:^17.0.1": version: 17.0.2 resolution: "react-is@npm:17.0.2" - checksum: 2bdb6b93fbb1820b024b496042cce405c57e2f85e777c9aabd55f9b26d145408f9f74f5934676ffdc46f3dcff656d78413a6e43968e7b3f92eea35b3052e9053 + checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8 languageName: node linkType: hard "react-is@npm:^18.0.0": version: 18.2.0 resolution: "react-is@npm:18.2.0" - checksum: 6eb5e4b28028c23e2bfcf73371e72cd4162e4ac7ab445ddae2afe24e347a37d6dc22fae6e1748632cd43c6d4f9b8f86dcf26bf9275e1874f436d129952528ae0 + checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e languageName: node linkType: hard @@ -12339,7 +13380,7 @@ __metadata: peerDependencies: react: ^16.14.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 - checksum: ebcf895352f1f4a3c1ed0c9ff7a67886146723b02b8137f5f21b3a5b522992418dfea5cf8e40a55b1a55828a0721f7954a50cc59264f00a2cd2caa3416d34440 + checksum: 8f411d6dbdac8b902e4e3f33063b9956b4dbdbab344085c1758864e62c45603f3f971de2ca20016100b55b040e284b3653e186961bd12d10bdbfdf1f2a409dee languageName: node linkType: hard @@ -12349,21 +13390,21 @@ __metadata: peerDependencies: react: ^16.14.0 || ^17.0.0 react-dom: ^16.14.0 || ^17.0.0 - checksum: 5c61654a0a20086eef17f2f356bdcb17571bbc2eb94a084d97f3e4087878f2b038f1040e98e73a40e3caf3cf418175a23502a4e86488e186b3b0c349d1d8ca1a + checksum: a62d3e3afaa9fb103a0f5927c909ccfa7b95cadcc9ca648daefec261c6876d1e1af1831dbcb5128a3f27f1a99143acc2899a994cefb5271ef0a0d91c1f303016 languageName: node linkType: hard "react-merge-refs@npm:2.0.2": version: 2.0.2 resolution: "react-merge-refs@npm:2.0.2" - checksum: ebadd9517c442419f30091b5fd89808d8d906569e7b90b247d3940f3165c91c7efce4b57aca15ed6eaf41c5507fa344d613a9380d76c50e3540f422d71265d26 + checksum: 64758870d79ad52e6666d1d30cdecd5a72722edfd5c89808b41acdbd81a039f0c78b8b576f7ae247010468fc45cb57dd31f402693c64224439dbe0127f4389f3 languageName: node linkType: hard "react-property@npm:2.0.0": version: 2.0.0 resolution: "react-property@npm:2.0.0" - checksum: d783292999b8bcfc45c457ab00d60faed66a15ada2cd8a9e00db8573b04a7102e81f38fec724a052698b4d2a305e3bbaf49913fc733035674496b1eb40174d55 + checksum: 8a444df30ef0937689c7968dae2501a0ca523777169f450e1f7ef5beeb855d6509bd058bf612f6ed8f459aa35468335d356e50264492e1938586e59fdb988262 languageName: node linkType: hard @@ -12395,14 +13436,49 @@ __metadata: optional: true redux: optional: true - checksum: 0efeeb228ebd1c20b7f127b010959f6531608a9e7d7c0680f3f5801fe9e912a60e3735b85d004aceed6a12740cb9dd5594cd1ab227b8c2aa91aeb8d87b0dbe1e + checksum: 370676330727764d78f35e9c5a0ed0591d79482fe9b70fffcab4aa6bcccc6194e4f1ebd818b4b390351dea5557e70d3bd4d95d7a0ac9baa1f45d6bf2230ee713 languageName: node linkType: hard "react-refresh@npm:^0.14.0": version: 0.14.0 resolution: "react-refresh@npm:0.14.0" - checksum: b8ae07ad153357d77830928a7f1fc2df837aabefee907fa273ba04c7643f3b860e986f1d4b7ada9b721c8d79b8c24b5b911a314a1a2398b105f1b13d19ea2b8d + checksum: dc69fa8c993df512f42dd0f1b604978ae89bd747c0ed5ec595c0cc50d535fb2696619ccd98ae28775cc01d0a7c146a532f0f7fb81dc22e1977c242a4912312f4 + languageName: node + linkType: hard + +"react-remove-scroll-bar@npm:^2.3.3": + version: 2.3.4 + resolution: "react-remove-scroll-bar@npm:2.3.4" + dependencies: + react-style-singleton: ^2.2.1 + tslib: ^2.0.0 + peerDependencies: + "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: b5ce5f2f98d65c97a3e975823ae4043a4ba2a3b63b5ba284b887e7853f051b5cd6afb74abde6d57b421931c52f2e1fdbb625dc858b1cb5a32c27c14ab85649d4 + languageName: node + linkType: hard + +"react-remove-scroll@npm:2.5.5": + version: 2.5.5 + resolution: "react-remove-scroll@npm:2.5.5" + dependencies: + react-remove-scroll-bar: ^2.3.3 + react-style-singleton: ^2.2.1 + tslib: ^2.1.0 + use-callback-ref: ^1.3.0 + use-sidecar: ^1.1.2 + peerDependencies: + "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 2c7fe9cbd766f5e54beb4bec2e2efb2de3583037b23fef8fa511ab426ed7f1ae992382db5acd8ab5bfb030a4b93a06a2ebca41377d6eeaf0e6791bb0a59616a4 languageName: node linkType: hard @@ -12415,7 +13491,7 @@ __metadata: peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: be7433bc290e56c0dd3e1008d53a76cc9866bf460980658501880876420086f11810ec3355a3abcd79ac537d6a1351eda009fade841c266456d0e8df60967b76 + checksum: ba44ff37f2956bc18991f2eedb32a3fa46d35832f61ded6c5d167e853ca289868fca6635467866280c73bc3da00dce8437dbbec57da100c0a3e3e3850af00b83 languageName: node linkType: hard @@ -12426,7 +13502,24 @@ __metadata: "@remix-run/router": "npm:1.6.2" peerDependencies: react: ">=16.8" - checksum: a437606078d6096a6dfa322adf80d00ce153f20cd470ad888088c8da99f44477b963425c53f5461a540b909fc274154292ed80d636482dcdc58a423915ca1433 + checksum: e47f875dca70033a3b42704cb5ec076b60f9629a5cdc3be613707f3d5a5706123fb80301037455c285c6d5a1011b443e1784e0103969ebfac7071648d360c413 + languageName: node + linkType: hard + +"react-style-singleton@npm:^2.2.1": + version: 2.2.1 + resolution: "react-style-singleton@npm:2.2.1" + dependencies: + get-nonce: ^1.0.0 + invariant: ^2.2.4 + tslib: ^2.0.0 + peerDependencies: + "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 7ee8ef3aab74c7ae1d70ff34a27643d11ba1a8d62d072c767827d9ff9a520905223e567002e0bf6c772929d8ea1c781a3ba0cc4a563e92b1e3dc2eaa817ecbe8 languageName: node linkType: hard @@ -12441,7 +13534,7 @@ __metadata: refractor: "npm:^3.6.0" peerDependencies: react: ">= 0.14.0" - checksum: 2bf57a1ea151f688efc7eba355677577c9bb55f05f9df7ef86627aae42f63f505486cddf3f4a628aecc51ec75e89beb9533201570d03201c4bf7d69d61d2545d + checksum: c082b48f30f8ba8d0c55ed1d761910630860077c7ff5793c4c912adcb5760df06436ed0ad62be0de28113aac9ad2af55eccd995f8eee98df53382e4ced2072fb languageName: node linkType: hard @@ -12450,7 +13543,7 @@ __metadata: resolution: "react@npm:18.2.0" dependencies: loose-envify: "npm:^1.1.0" - checksum: b562d9b569b0cb315e44b48099f7712283d93df36b19a39a67c254c6686479d3980b7f013dc931f4a5a3ae7645eae6386b4aa5eea933baa54ecd0f9acb0902b8 + checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b languageName: node linkType: hard @@ -12461,7 +13554,7 @@ __metadata: find-up: "npm:^4.1.0" read-pkg: "npm:^5.2.0" type-fest: "npm:^0.8.1" - checksum: 82b3ac9fd7c6ca1bdc1d7253eb1091a98ff3d195ee0a45386582ce3e69f90266163c34121e6a0a02f1630073a6c0585f7880b3865efcae9c452fa667f02ca385 + checksum: e4e93ce70e5905b490ca8f883eb9e48b5d3cebc6cd4527c25a0d8f3ae2903bd4121c5ab9c5a3e217ada0141098eeb661313c86fa008524b089b8ed0b7f165e44 languageName: node linkType: hard @@ -12473,7 +13566,7 @@ __metadata: normalize-package-data: "npm:^2.5.0" parse-json: "npm:^5.0.0" type-fest: "npm:^0.6.0" - checksum: b51a17d4b51418e777029e3a7694c9bd6c578a5ab99db544764a0b0f2c7c0f58f8a6bc101f86a6fceb8ba6d237d67c89acf6170f6b98695d0420ddc86cf109fb + checksum: eb696e60528b29aebe10e499ba93f44991908c57d70f2d26f369e46b8b9afc208ef11b4ba64f67630f31df8b6872129e0a8933c8c53b7b4daf0eace536901222 languageName: node linkType: hard @@ -12488,7 +13581,7 @@ __metadata: safe-buffer: "npm:~5.1.1" string_decoder: "npm:~1.1.1" util-deprecate: "npm:~1.0.1" - checksum: 7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa + checksum: 65645467038704f0c8aaf026a72fbb588a9e2ef7a75cd57a01702ee9db1c4a1e4b03aaad36861a6a0926546a74d174149c8c207527963e0c2d3eee2f37678a42 languageName: node linkType: hard @@ -12499,7 +13592,7 @@ __metadata: inherits: "npm:^2.0.3" string_decoder: "npm:^1.1.1" util-deprecate: "npm:^1.0.1" - checksum: e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7 + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d languageName: node linkType: hard @@ -12508,19 +13601,7 @@ __metadata: resolution: "readdirp@npm:3.6.0" dependencies: picomatch: "npm:^2.2.1" - checksum: 6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b - languageName: node - linkType: hard - -"recast@npm:^0.21.0": - version: 0.21.5 - resolution: "recast@npm:0.21.5" - dependencies: - ast-types: "npm:0.15.2" - esprima: "npm:~4.0.0" - source-map: "npm:~0.6.1" - tslib: "npm:^2.0.1" - checksum: a45168c82195f24fa2c70293a624fece0069a2e8e8adb637f9963777735f81cb3bb62e55172db677ec3573b08b2daaf1eddd85b74da6fe0bd37c9b15eeaf94b4 + checksum: 1ced032e6e45670b6d7352d71d21ce7edf7b9b928494dcaba6f11fba63180d9da6cd7061ebc34175ffda6ff529f481818c962952004d273178acd70f7059b320 languageName: node linkType: hard @@ -12533,16 +13614,20 @@ __metadata: esprima: "npm:~4.0.0" source-map: "npm:~0.6.1" tslib: "npm:^2.0.1" - checksum: 2f2d0ce271b187e29f8ea15bf3c319e708376145aaef2797e9a9d3e337e12178bd0d05d607baf601bb607075fbc040ca51f2d58a8bd566d8069c8a9d4b334608 + checksum: b1340ab0a3a8e4bf206c6c7d54168f7019ed4138a53bc746df230c01f1b6672ce9d25dceb34896b6683622d3eede4e1f18b7d0b672f5aab54ba7762de949e317 languageName: node linkType: hard -"rechoir@npm:^0.6.2": - version: 0.6.2 - resolution: "rechoir@npm:0.6.2" +"recast@npm:^0.23.3": + version: 0.23.4 + resolution: "recast@npm:0.23.4" dependencies: - resolve: "npm:^1.1.6" - checksum: 22c4bb32f4934a9468468b608417194f7e3ceba9a508512125b16082c64f161915a28467562368eeb15dc16058eb5b7c13a20b9eb29ff9927d1ebb3b5aa83e84 + assert: ^2.0.0 + ast-types: ^0.16.1 + esprima: ~4.0.0 + source-map: ~0.6.1 + tslib: ^2.0.1 + checksum: edb63bbe0457e68c0f4892f55413000e92aa7c5c53f9e109ab975d1c801cd299a62511ea72734435791f4aea6f0edf560f6a275761f66b2b6069ff6d72686029 languageName: node linkType: hard @@ -12552,7 +13637,7 @@ __metadata: dependencies: indent-string: "npm:^4.0.0" strip-indent: "npm:^3.0.0" - checksum: d64a6b5c0b50eb3ddce3ab770f866658a2b9998c678f797919ceb1b586bab9259b311407280bd80b804e2a7c7539b19238ae6a2a20c843f1a7fcff21d48c2eae + checksum: fa1ef20404a2d399235e83cc80bd55a956642e37dd197b4b612ba7327bf87fa32745aeb4a1634b2bab25467164ab4ed9c15be2c307923dd08b0fe7c52431ae6b languageName: node linkType: hard @@ -12561,7 +13646,7 @@ __metadata: resolution: "redux-thunk@npm:2.4.2" peerDependencies: redux: ^4 - checksum: e202d6ef7dfa7df08ed24cb221aa89d6c84dbaa7d65fe90dbd8e826d0c10d801f48388f9a7598a4fd970ecbc93d335014570a61ca7bc8bf569eab5de77b31a3c + checksum: c7f757f6c383b8ec26152c113e20087818d18ed3edf438aaad43539e9a6b77b427ade755c9595c4a163b6ad3063adf3497e5fe6a36c68884eb1f1cfb6f049a5c languageName: node linkType: hard @@ -12570,7 +13655,7 @@ __metadata: resolution: "redux@npm:4.2.1" dependencies: "@babel/runtime": "npm:^7.9.2" - checksum: 136d98b3d5dbed1cd6279c8c18a6a74c416db98b8a432a46836bdd668475de6279a2d4fd9d1363f63904e00f0678a8a3e7fa532c897163340baf1e71bb42c742 + checksum: f63b9060c3a1d930ae775252bb6e579b42415aee7a23c4114e21a0b4ba7ec12f0ec76936c00f546893f06e139819f0e2855e0d55ebfce34ca9c026241a6950dd languageName: node linkType: hard @@ -12581,7 +13666,7 @@ __metadata: hastscript: "npm:^6.0.0" parse-entities: "npm:^2.0.0" prismjs: "npm:~1.27.0" - checksum: 63ab62393c8c2fd7108c2ea1eff721c0ad2a1a6eee60fdd1b47f4bb25cf298667dc97d041405b3e718b0817da12b37a86ed07ebee5bd2ca6405611f1bae456db + checksum: 39b01c4168c77c5c8486f9bf8907bbb05f257f15026057ba5728535815a2d90eed620468a4bfbb2b8ceefbb3ce3931a1be8b17152dbdbc8b0eef92450ff750a2 languageName: node linkType: hard @@ -12590,21 +13675,28 @@ __metadata: resolution: "regenerate-unicode-properties@npm:10.1.0" dependencies: regenerate: "npm:^1.4.2" - checksum: 17818ea6f67c5a4884b9e18842edc4b3838a12f62e24f843e80fbb6d8cb649274b5b86d98bb02075074e02021850e597a92ff6b58bbe5caba4bf5fd8e4e38b56 + checksum: b1a8929588433ab8b9dc1a34cf3665b3b472f79f2af6ceae00d905fc496b332b9af09c6718fb28c730918f19a00dc1d7310adbaa9b72a2ec7ad2f435da8ace17 languageName: node linkType: hard "regenerate@npm:^1.4.2": version: 1.4.2 resolution: "regenerate@npm:1.4.2" - checksum: f73c9eba5d398c818edc71d1c6979eaa05af7a808682749dd079f8df2a6d91a9b913db216c2c9b03e0a8ba2bba8701244a93f45211afbff691c32c7b275db1b8 + checksum: 3317a09b2f802da8db09aa276e469b57a6c0dd818347e05b8862959c6193408242f150db5de83c12c3fa99091ad95fb42a6db2c3329bfaa12a0ea4cbbeb30cb0 languageName: node linkType: hard "regenerator-runtime@npm:^0.13.11": version: 0.13.11 resolution: "regenerator-runtime@npm:0.13.11" - checksum: 12b069dc774001fbb0014f6a28f11c09ebfe3c0d984d88c9bced77fdb6fedbacbca434d24da9ae9371bfbf23f754869307fb51a4c98a8b8b18e5ef748677ca24 + checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 + languageName: node + linkType: hard + +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 9f57c93277b5585d3c83b0cf76be47b473ae8c6d9142a46ce8b0291a04bb2cf902059f0f8445dcabb3fb7378e5fe4bb4ea1e008876343d42e46d3b484534ce38 languageName: node linkType: hard @@ -12613,7 +13705,16 @@ __metadata: resolution: "regenerator-transform@npm:0.15.1" dependencies: "@babel/runtime": "npm:^7.8.4" - checksum: 6588e0c454e92ed6c2b3ed7ab24f61270aef47ae7052eceb5367cc15658948a2e84fdd6849f7c96e561d1f8a7474dc4c292166792e07498fdde226299b9ff374 + checksum: 2d15bdeadbbfb1d12c93f5775493d85874dbe1d405bec323da5c61ec6e701bc9eea36167483e1a5e752de9b2df59ab9a2dfff6bf3784f2b28af2279a673d29a4 + languageName: node + linkType: hard + +"regenerator-transform@npm:^0.15.2": + version: 0.15.2 + resolution: "regenerator-transform@npm:0.15.2" + dependencies: + "@babel/runtime": ^7.8.4 + checksum: 20b6f9377d65954980fe044cfdd160de98df415b4bff38fbade67b3337efaf078308c4fed943067cd759827cc8cfeca9cb28ccda1f08333b85d6a2acbd022c27 languageName: node linkType: hard @@ -12623,7 +13724,7 @@ __metadata: dependencies: extend-shallow: "npm:^3.0.2" safe-regex: "npm:^1.1.0" - checksum: a0f8d6045f63b22e9759db10e248369c443b41cedd7dba0922d002b66c2734bc2aef0d98c4d45772d1f756245f4c5203856b88b9624bba2a58708858a8d485d6 + checksum: 3081403de79559387a35ef9d033740e41818a559512668cef3d12da4e8a29ef34ee13c8ed1256b07e27ae392790172e8a15c8a06b72962fd4550476cde3d8f77 languageName: node linkType: hard @@ -12634,7 +13735,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.2.0" functions-have-names: "npm:^1.2.3" - checksum: 312b7966c5cd2e6837da4073e0e6450191e3c6e8f07276cbed35e170ea5606f91487b435eb3290593f8aed39b1191c44f5340e6e5392650feaf2b34a98378464 + checksum: c541687cdbdfff1b9a07f6e44879f82c66bbf07665f9a7544c5fd16acdb3ec8d1436caab01662d2fbcad403f3499d49ab0b77fbc7ef29ef961d98cc4bc9755b4 languageName: node linkType: hard @@ -12648,7 +13749,7 @@ __metadata: regjsparser: "npm:^0.9.1" unicode-match-property-ecmascript: "npm:^2.0.0" unicode-match-property-value-ecmascript: "npm:^2.1.0" - checksum: 7945d5ab10c8bbed3ca383d4274687ea825aee4ab93a9c51c6e31e1365edd5ea807f6908f800ba017b66c462944ba68011164e7055207747ab651f8111ef3770 + checksum: 95bb97088419f5396e07769b7de96f995f58137ad75fac5811fb5fe53737766dfff35d66a0ee66babb1eb55386ef981feaef392f9df6d671f3c124812ba24da2 languageName: node linkType: hard @@ -12659,7 +13760,7 @@ __metadata: jsesc: "npm:~0.5.0" bin: regjsparser: bin/parser - checksum: fe44fcf19a99fe4f92809b0b6179530e5ef313ff7f87df143b08ce9a2eb3c4b6189b43735d645be6e8f4033bfb015ed1ca54f0583bc7561bed53fd379feb8225 + checksum: 5e1b76afe8f1d03c3beaf9e0d935dd467589c3625f6d65fb8ffa14f224d783a0fed4bf49c2c1b8211043ef92b6117313419edf055a098ed8342e340586741afc languageName: node linkType: hard @@ -12672,7 +13773,7 @@ __metadata: mdast-util-definitions: "npm:^4.0.0" space-separated-tokens: "npm:^1.0.0" unist-util-visit: "npm:^2.0.0" - checksum: 5f0affc97e18ad3247e3b29449f4df98be5a75950cf0f0f13dd1755c4ef1065f9ab44626bba34d913d32bb92afd6f06a8e2f8068e83b48337f0b7a5d1f0cecfe + checksum: 48c4a41fe38916f79febb390b0c4deefe82b554dd36dc534262d851860d17fb6d15d78d515f29194e5fa48db5f01f4405a6f6dd077aaf32812a2efffb01700d7 languageName: node linkType: hard @@ -12683,56 +13784,56 @@ __metadata: github-slugger: "npm:^1.0.0" mdast-util-to-string: "npm:^1.0.0" unist-util-visit: "npm:^2.0.0" - checksum: 7cc2857936fce9c9c00b9c7d70de46d594cedf93bd8560fd006164dee7aacccdf472654ee35b33f4fb4bd0af882d89998c6d0c9088c2e95702a9fc15ebae002a + checksum: 81fff0dcfaf6d6117ef1293bb1d26c3e25483d99c65c22434298eed93583a89ea5d7b94063d9a7f47c0647a708ce84f00ff62d274503f248feec03c344cabb20 languageName: node linkType: hard "repeat-element@npm:^1.1.2": version: 1.1.4 resolution: "repeat-element@npm:1.1.4" - checksum: 81aa8d82bc845780803ef52df3533fa399974b99df571d0bb86e91f0ffca9ee4b9c4e8e5e72af087938cc28d2aef93d106a6d01da685d72ce96455b90a9f9f69 + checksum: 1edd0301b7edad71808baad226f0890ba709443f03a698224c9ee4f2494c317892dc5211b2ba8cbea7194a9ddbcac01e283bd66de0467ab24ee1fc1a3711d8a9 languageName: node linkType: hard "repeat-string@npm:^1.6.1": version: 1.6.1 resolution: "repeat-string@npm:1.6.1" - checksum: 87fa21bfdb2fbdedc44b9a5b118b7c1239bdd2c2c1e42742ef9119b7d412a5137a1d23f1a83dc6bb686f4f27429ac6f542e3d923090b44181bafa41e8ac0174d + checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0 languageName: node linkType: hard "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" - checksum: 83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99 + checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80 languageName: node linkType: hard "require-from-string@npm:^2.0.2": version: 2.0.2 resolution: "require-from-string@npm:2.0.2" - checksum: aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2 + checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b languageName: node linkType: hard "requireindex@npm:^1.1.0": version: 1.2.0 resolution: "requireindex@npm:1.2.0" - checksum: 7fb42aed73bf8de9acc4d6716cf07acc7fbe180e58729433bafcf702e76e7bb10e54f8266c06bfec62d752e0ac14d50e8758833de539e6f4e2cd642077866153 + checksum: 50d8b10a1ff1fdf6aea7a1870bc7bd238b0fb1917d8d7ca17fd03afc38a65dcd7a8a4eddd031f89128b5f0065833d5c92c4fef67f2c04e8624057fe626c9cf94 languageName: node linkType: hard "requires-port@npm:^1.0.0": version: 1.0.0 resolution: "requires-port@npm:1.0.0" - checksum: b2bfdd09db16c082c4326e573a82c0771daaf7b53b9ce8ad60ea46aa6e30aaf475fe9b164800b89f93b748d2c234d8abff945d2551ba47bf5698e04cd7713267 + checksum: eee0e303adffb69be55d1a214e415cf42b7441ae858c76dfc5353148644f6fd6e698926fc4643f510d5c126d12a705e7c8ed7e38061113bdf37547ab356797ff languageName: node linkType: hard "reselect@npm:^4.1.8": version: 4.1.8 resolution: "reselect@npm:4.1.8" - checksum: 06a305a504affcbb67dd0561ddc8306b35796199c7e15b38934c80606938a021eadcf68cfd58e7bb5e17786601c37602a3362a4665c7bf0a96c1041ceee9d0b7 + checksum: a4ac87cedab198769a29be92bc221c32da76cfdad6911eda67b4d3e7136dca86208c3b210e31632eae31ebd2cded18596f0dd230d3ccc9e978df22f233b5583e languageName: node linkType: hard @@ -12741,39 +13842,39 @@ __metadata: resolution: "resolve-cwd@npm:3.0.0" dependencies: resolve-from: "npm:^5.0.0" - checksum: e608a3ebd15356264653c32d7ecbc8fd702f94c6703ea4ac2fb81d9c359180cba0ae2e6b71faa446631ed6145454d5a56b227efc33a2d40638ac13f8beb20ee4 + checksum: 546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 languageName: node linkType: hard "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" - checksum: 8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 + checksum: f4ba0b8494846a5066328ad33ef8ac173801a51739eb4d63408c847da9a2e1c1de1e6cbbf72699211f3d13f8fc1325648b169bd15eb7da35688e30a5fb0e4a7f languageName: node linkType: hard "resolve-from@npm:^5.0.0": version: 5.0.0 resolution: "resolve-from@npm:5.0.0" - checksum: b21cb7f1fb746de8107b9febab60095187781137fd803e6a59a76d421444b1531b641bba5857f5dc011974d8a5c635d61cec49e6bd3b7fc20e01f0fafc4efbf2 + checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf languageName: node linkType: hard "resolve-url@npm:^0.2.1": version: 0.2.1 resolution: "resolve-url@npm:0.2.1" - checksum: c285182cfcddea13a12af92129ce0569be27fb0074ffaefbd3ba3da2eac2acecdfc996d435c4982a9fa2b4708640e52837c9153a5ab9255886a00b0b9e8d2a54 + checksum: 7b7035b9ed6e7bc7d289e90aef1eab5a43834539695dac6416ca6e91f1a94132ae4796bbd173cdacfdc2ade90b5f38a3fb6186bebc1b221cd157777a23b9ad14 languageName: node linkType: hard "resolve.exports@npm:^2.0.0": version: 2.0.2 resolution: "resolve.exports@npm:2.0.2" - checksum: cc4cffdc25447cf34730f388dca5021156ba9302a3bad3d7f168e790dc74b2827dff603f1bc6ad3d299bac269828dca96dd77e036dc9fba6a2a1807c47ab5c98 + checksum: 1c7778ca1b86a94f8ab4055d196c7d87d1874b96df4d7c3e67bbf793140f0717fd506dcafd62785b079cd6086b9264424ad634fb904409764c3509c3df1653f2 languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1": +"resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.20.0, resolve@npm:^1.22.1": version: 1.22.3 resolution: "resolve@npm:1.22.3" dependencies: @@ -12782,7 +13883,7 @@ __metadata: supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 5ebd90dc08467e7d9af8f89a67f127c90d77e58d3bfc65da5221699cc15679c5bae5e410e6795ee4b9f717cd711c495a52a3b650ce6720b0626de46e5074e796 + checksum: fb834b81348428cb545ff1b828a72ea28feb5a97c026a1cf40aa1008352c72811ff4d4e71f2035273dc536dcfcae20c13604ba6283c612d70fa0b6e44519c374 languageName: node linkType: hard @@ -12795,54 +13896,64 @@ __metadata: supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 1de92669e7c46cfe125294c66d5405e13288bb87b97e9bdab71693ceebbcc0255c789bde30e2834265257d330d8ff57414d7d88e3097d8f69951f3ce978bf045 + checksum: c438ac9a650f2030fd074219d7f12ceb983b475da2d89ad3d6dd05fbf6b7a0a8cd37d4d10b43cb1f632bc19f22246ab7f36ebda54d84a29bfb2910a0680906d3 languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin": +"resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@npm%3A^1.10.0#~builtin, resolve@patch:resolve@npm%3A^1.14.2#~builtin, resolve@patch:resolve@npm%3A^1.20.0#~builtin, resolve@patch:resolve@npm%3A^1.22.1#~builtin": version: 1.22.3 - resolution: "resolve@patch:resolve@npm%3A1.22.3#optional!builtin::version=1.22.3&hash=c3c19d" + resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=c3c19d" dependencies: is-core-module: "npm:^2.12.0" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 6267bdbbbb1da23975463e979dadf5135fcc40c4b9281c5af4581afa848ced98090ab4e2dbc9085e58f8ea48c0eb7c4fe94b1e8f55ebdd17a725d86982eb5288 + checksum: ad59734723b596d0891321c951592ed9015a77ce84907f89c9d9307dd0c06e11a67906a3e628c4cae143d3e44898603478af0ddeb2bba3f229a9373efe342665 languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^2.0.0-next.4#optional!builtin": +"resolve@patch:resolve@npm%3A^2.0.0-next.4#~builtin": version: 2.0.0-next.4 - resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#optional!builtin::version=2.0.0-next.4&hash=c3c19d" + resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=c3c19d" dependencies: is-core-module: "npm:^2.9.0" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: ed2bb51d616b9cd30fe85cf49f7a2240094d9fa01a221d361918462be81f683d1855b7f192391d2ab5325245b42464ca59690db5bd5dad0a326fc0de5974dd10 + checksum: 4bf9f4f8a458607af90518ff73c67a4bc1a38b5a23fef2bb0ccbd45e8be89820a1639b637b0ba377eb2be9eedfb1739a84cde24fe4cd670c8207d8fea922b011 + languageName: node + linkType: hard + +"restore-cursor@npm:^3.1.0": + version: 3.1.0 + resolution: "restore-cursor@npm:3.1.0" + dependencies: + onetime: ^5.1.0 + signal-exit: ^3.0.2 + checksum: f877dd8741796b909f2a82454ec111afb84eb45890eb49ac947d87991379406b3b83ff9673a46012fca0d7844bb989f45cc5b788254cf1a39b6b5a9659de0630 languageName: node linkType: hard "ret@npm:~0.1.10": version: 0.1.15 resolution: "ret@npm:0.1.15" - checksum: 01f77cad0f7ea4f955852c03d66982609893edc1240c0c964b4c9251d0f9fb6705150634060d169939b096d3b77f4c84d6b6098a5b5d340160898c8581f1f63f + checksum: d76a9159eb8c946586567bd934358dfc08a36367b3257f7a3d7255fdd7b56597235af23c6afa0d7f0254159e8051f93c918809962ebd6df24ca2a83dbe4d4151 languageName: node linkType: hard "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" - checksum: 59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe + checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c languageName: node linkType: hard "reusify@npm:^1.0.4": version: 1.0.4 resolution: "reusify@npm:1.0.4" - checksum: c19ef26e4e188f408922c46f7ff480d38e8dfc55d448310dfb518736b23ed2c4f547fb64a6ed5bdba92cd7e7ddc889d36ff78f794816d5e71498d645ef476107 + checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc languageName: node linkType: hard @@ -12853,7 +13964,7 @@ __metadata: glob: "npm:^7.1.3" bin: rimraf: ./bin.js - checksum: 4eef73d406c6940927479a3a9dee551e14a54faf54b31ef861250ac815172bade86cc6f7d64a4dc5e98b65e4b18a2e1c9ff3b68d296be0c748413f092bb0dd40 + checksum: cdc7f6eacb17927f2a075117a823e1c5951792c6498ebcce81ca8203454a811d4cf8900314154d3259bb8f0b42ab17f67396a8694a54cae3283326e57ad250cd languageName: node linkType: hard @@ -12864,7 +13975,7 @@ __metadata: glob: "npm:^7.1.3" bin: rimraf: bin.js - checksum: 9cb7757acb489bd83757ba1a274ab545eafd75598a9d817e0c3f8b164238dd90eba50d6b848bd4dcc5f3040912e882dc7ba71653e35af660d77b25c381d402e8 + checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 languageName: node linkType: hard @@ -12875,7 +13986,7 @@ __metadata: glob: "npm:^7.1.3" bin: rimraf: ./bin.js - checksum: f1e646f8c567795f2916aef7aadf685b543da6b9a53e482bb04b07472c7eef2b476045ba1e29f401c301c66b630b22b815ab31fdd60c5e1ae6566ff523debf45 + checksum: 3ea587b981a19016297edb96d1ffe48af7e6af69660e3b371dbfc73722a73a0b0e9be5c88089fbeeb866c389c1098e07f64929c7414290504b855f54f901ab10 languageName: node linkType: hard @@ -12889,7 +14000,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: c23ee8dcd34fe854afe06e1ec6d6017b200c523795a7c0f876494afd4a279f1d1232b3f274fea9438ac8ec4ebf6ce202f17316f790a94dba8173e213d2b98d19 + checksum: 7186beeba0e6fd33b37aa33ede7157e77af0a0be4b75d345a51dab4be5962a8e7a1c5ec8868e7c4cd361b456eb1b47bdb75e5db32ab37a546bed383d06b40384 languageName: node linkType: hard @@ -12903,7 +14014,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 421418687f5dcd7324f4387f203c6bfc7118b7ace789e30f5da022471c43e037a76f5fd93837052754eeeae798a4fb266ac05ccee1e594406d912a59af98dde9 + checksum: 6a2bf167b3587d4df709b37d149ad0300692cc5deb510f89ac7bdc77c8738c9546ae3de9322b0968e1ed2b0e984571f5f55aae28fa7de4cfcb1bc5402a4e2be6 languageName: node linkType: hard @@ -12912,28 +14023,21 @@ __metadata: resolution: "run-parallel@npm:1.2.0" dependencies: queue-microtask: "npm:^1.2.2" - checksum: 200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 - languageName: node - linkType: hard - -"safe-buffer@npm:5.1.1": - version: 5.1.1 - resolution: "safe-buffer@npm:5.1.1" - checksum: 1c233bd105deeba3c9a8911ed4ec24ba45adbb51fec02f7944a10a202c38e3df4ef2b524bdeb55f2e4f8c77c13b2959e2e2e6022e5d99acdd70633b5f7e138cf + checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d languageName: node linkType: hard "safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": version: 5.1.2 resolution: "safe-buffer@npm:5.1.2" - checksum: 780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 + checksum: f2f1f7943ca44a594893a852894055cf619c1fbcb611237fc39e461ae751187e7baf4dc391a72125e0ac4fb2d8c5c0b3c71529622e6a58f46b960211e704903c languageName: node linkType: hard "safe-buffer@npm:5.2.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" - checksum: 6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 + checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 languageName: node linkType: hard @@ -12944,7 +14048,7 @@ __metadata: call-bind: "npm:^1.0.2" get-intrinsic: "npm:^1.1.3" is-regex: "npm:^1.1.4" - checksum: 14a81a7e683f97b2d6e9c8be61fddcf8ed7a02f4e64a825515f96bb1738eb007145359313741d2704d28b55b703a0f6300c749dde7c1dbc13952a2b85048ede2 + checksum: bc566d8beb8b43c01b94e67de3f070fd2781685e835959bbbaaec91cc53381145ca91f69bd837ce6ec244817afa0a5e974fc4e40a2957f0aca68ac3add1ddd34 languageName: node linkType: hard @@ -12953,14 +14057,14 @@ __metadata: resolution: "safe-regex@npm:1.1.0" dependencies: ret: "npm:~0.1.10" - checksum: 547d58aa5184cbef368fd5ed5f28d20f911614748c5da6b35f53fd6626396707587251e6e3d1e3010fd3ff1212e413841b8825eaa5f317017ca62a30899af31a + checksum: 9a8bba57c87a841f7997b3b951e8e403b1128c1a4fd1182f40cc1a20e2d490593d7c2a21030fadfea320c8e859219019e136f678c6689ed5960b391b822f01d5 languageName: node linkType: hard "safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" - checksum: 7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 + checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 languageName: node linkType: hard @@ -12973,7 +14077,7 @@ __metadata: source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 19c3a945bd71d9c9ab3b01a97b0d218c92815b7f3e45a9bba37265b4c43e4ef12ab029c7257e02c1db2b85f7da91974af81e31d58940c9a54b50787ee4a50a3c + checksum: 1b1b3584b38a63dd94156b65f13b90e3f84b170a38c3d5e3fa578b7a32a37aeb349b4926b0eaf9448d48e955e86b1ee01b13993f19611dad8068af07a607c13b languageName: node linkType: hard @@ -12982,7 +14086,7 @@ __metadata: resolution: "saxes@npm:6.0.0" dependencies: xmlchars: "npm:^2.2.0" - checksum: 3847b839f060ef3476eb8623d099aa502ad658f5c40fd60c105ebce86d244389b0d76fcae30f4d0c728d7705ceb2f7e9b34bb54717b6a7dbedaf5dad2d9a4b74 + checksum: d3fa3e2aaf6c65ed52ee993aff1891fc47d5e47d515164b5449cbf5da2cbdc396137e55590472e64c5c436c14ae64a8a03c29b9e7389fc6f14035cf4e982ef3b languageName: node linkType: hard @@ -12991,7 +14095,7 @@ __metadata: resolution: "scheduler@npm:0.23.0" dependencies: loose-envify: "npm:^1.1.0" - checksum: b777f7ca0115e6d93e126ac490dbd82642d14983b3079f58f35519d992fa46260be7d6e6cede433a92db70306310c6f5f06e144f0e40c484199e09c1f7be53dd + checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a languageName: node linkType: hard @@ -13000,7 +14104,7 @@ __metadata: resolution: "semver@npm:5.7.2" bin: semver: bin/semver - checksum: e4cf10f86f168db772ae95d86ba65b3fd6c5967c94d97c708ccb463b778c2ee53b914cd7167620950fc07faf5a564e6efe903836639e512a1aa15fbc9667fa25 + checksum: fb4ab5e0dd1c22ce0c937ea390b4a822147a9c53dbd2a9a0132f12fe382902beef4fbf12cf51bb955248d8d15874ce8cd89532569756384f994309825f10b686 languageName: node linkType: hard @@ -13009,7 +14113,7 @@ __metadata: resolution: "semver@npm:6.3.1" bin: semver: bin/semver.js - checksum: e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d + checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 languageName: node linkType: hard @@ -13020,16 +14124,7 @@ __metadata: lru-cache: "npm:^6.0.0" bin: semver: bin/semver.js - checksum: 5160b06975a38b11c1ab55950cb5b8a23db78df88275d3d8a42ccf1f29e55112ac995b3a26a522c36e3b5f76b0445f1eef70d696b8c7862a2b4303d7b0e7609e - languageName: node - linkType: hard - -"semver@npm:~7.0.0": - version: 7.0.0 - resolution: "semver@npm:7.0.0" - bin: - semver: bin/semver.js - checksum: 7fd341680a967a0abfd66f3a7d36ba44e52ff5d3e799e9a6cdb01a68160b64ef09be82b4af05459effeecdd836f002c2462555d2821cd890dfdfe36a0d9f56a5 + checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 languageName: node linkType: hard @@ -13050,20 +14145,7 @@ __metadata: on-finished: "npm:2.4.1" range-parser: "npm:~1.2.1" statuses: "npm:2.0.1" - checksum: 0eb134d6a51fc13bbcb976a1f4214ea1e33f242fae046efc311e80aff66c7a43603e26a79d9d06670283a13000e51be6e0a2cb80ff0942eaf9f1cd30b7ae736a - languageName: node - linkType: hard - -"serve-favicon@npm:^2.5.0": - version: 2.5.0 - resolution: "serve-favicon@npm:2.5.0" - dependencies: - etag: "npm:~1.8.1" - fresh: "npm:0.5.2" - ms: "npm:2.1.1" - parseurl: "npm:~1.3.2" - safe-buffer: "npm:5.1.1" - checksum: 7244ced3c46f8dfde591dc801f1e21ebc8fa07c4870cbbaee3ce37104b3aad32858e674e251a8ed4837867ea0dd67cb734b485ae5a7b0895cb6022f8b8c79303 + checksum: 74fc07ebb58566b87b078ec63e5a3e41ecd987e4272ba67b7467e86c6ad51bc6b0b0154133b6d8b08a2ddda360464f71382f7ef864700f34844a76c8027817a8 languageName: node linkType: hard @@ -13075,14 +14157,14 @@ __metadata: escape-html: "npm:~1.0.3" parseurl: "npm:~1.3.3" send: "npm:0.18.0" - checksum: fa9f0e21a540a28f301258dfe1e57bb4f81cd460d28f0e973860477dd4acef946a1f41748b5bd41c73b621bea2029569c935faa38578fd34cd42a9b4947088ba + checksum: af57fc13be40d90a12562e98c0b7855cf6e8bd4c107fe9a45c212bf023058d54a1871b1c89511c3958f70626fff47faeb795f5d83f8cf88514dbaeb2b724464d languageName: node linkType: hard "set-blocking@npm:^2.0.0": version: 2.0.0 resolution: "set-blocking@npm:2.0.0" - checksum: 9f8c1b2d800800d0b589de1477c753492de5c1548d4ade52f57f1d1f5e04af5481554d75ce5e5c43d4004b80a3eb714398d6907027dc0534177b7539119f4454 + checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 languageName: node linkType: hard @@ -13094,14 +14176,14 @@ __metadata: is-extendable: "npm:^0.1.1" is-plain-object: "npm:^2.0.3" split-string: "npm:^3.0.1" - checksum: 4c40573c4f6540456e4b38b95f570272c4cfbe1d12890ad4057886da8535047cd772dfadf5b58e2e87aa244dfb4c57e3586f6716b976fc47c5144b6b09e1811b + checksum: 09a4bc72c94641aeae950eb60dc2755943b863780fcc32e441eda964b64df5e3f50603d5ebdd33394ede722528bd55ed43aae26e9df469b4d32e2292b427b601 languageName: node linkType: hard "setprototypeof@npm:1.2.0": version: 1.2.0 resolution: "setprototypeof@npm:1.2.0" - checksum: 68733173026766fa0d9ecaeb07f0483f4c2dc70ca376b3b7c40b7cda909f94b0918f6c5ad5ce27a9160bdfb475efaa9d5e705a11d8eaae18f9835d20976028bc + checksum: be18cbbf70e7d8097c97f713a2e76edf84e87299b40d085c6bf8b65314e994cc15e2e317727342fa6996e38e1f52c59720b53fe621e2eb593a6847bf0356db89 languageName: node linkType: hard @@ -13110,7 +14192,7 @@ __metadata: resolution: "shallow-clone@npm:3.0.1" dependencies: kind-of: "npm:^6.0.2" - checksum: 7bab09613a1b9f480c85a9823aebec533015579fa055ba6634aa56ba1f984380670eaf33b8217502931872aa1401c9fcadaa15f9f604d631536df475b05bcf1e + checksum: 39b3dd9630a774aba288a680e7d2901f5c0eae7b8387fc5c8ea559918b29b3da144b7bdb990d7ccd9e11be05508ac9e459ce51d01fd65e583282f6ffafcba2e7 languageName: node linkType: hard @@ -13119,27 +14201,14 @@ __metadata: resolution: "shebang-command@npm:2.0.0" dependencies: shebang-regex: "npm:^3.0.0" - checksum: a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e + checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa languageName: node linkType: hard "shebang-regex@npm:^3.0.0": version: 3.0.0 resolution: "shebang-regex@npm:3.0.0" - checksum: 1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 - languageName: node - linkType: hard - -"shelljs@npm:^0.8.5": - version: 0.8.5 - resolution: "shelljs@npm:0.8.5" - dependencies: - glob: "npm:^7.0.0" - interpret: "npm:^1.0.0" - rechoir: "npm:^0.6.2" - bin: - shjs: bin/shjs - checksum: feb25289a12e4bcd04c40ddfab51aff98a3729f5c2602d5b1a1b95f6819ec7804ac8147ebd8d9a85dfab69d501bcf92d7acef03247320f51c1552cec8d8e2382 + checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 languageName: node linkType: hard @@ -13150,51 +14219,51 @@ __metadata: call-bind: "npm:^1.0.0" get-intrinsic: "npm:^1.0.2" object-inspect: "npm:^1.9.0" - checksum: 054a5d23ee35054b2c4609b9fd2a0587760737782b5d765a9c7852264710cc39c6dcb56a9bbd6c12cd84071648aea3edb2359d2f6e560677eedadce511ac1da5 + checksum: 351e41b947079c10bd0858364f32bb3a7379514c399edb64ab3dce683933483fc63fb5e4efe0a15a2e8a7e3c436b6a91736ddb8d8c6591b0460a24bb4a1ee245 languageName: node linkType: hard -"signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": +"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" - checksum: 25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 + checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 languageName: node linkType: hard "signal-exit@npm:^4.0.1": version: 4.0.2 resolution: "signal-exit@npm:4.0.2" - checksum: 3c36ae214f4774b4a7cbbd2d090b2864f8da4dc3f9140ba5b76f38bea7605c7aa8042adf86e48ee8a0955108421873f9b0f20281c61b8a65da4d9c1c1de4929f + checksum: 41f5928431cc6e91087bf0343db786a6313dd7c6fd7e551dbc141c95bb5fb26663444fd9df8ea47c5d7fc202f60aa7468c3162a9365cbb0615fc5e1b1328fe31 languageName: node linkType: hard -"simple-update-notifier@npm:^1.0.0": - version: 1.1.0 - resolution: "simple-update-notifier@npm:1.1.0" +"simple-update-notifier@npm:^2.0.0": + version: 2.0.0 + resolution: "simple-update-notifier@npm:2.0.0" dependencies: - semver: "npm:~7.0.0" - checksum: 3cbbbc71a5d9a2924f0e3f42fbf3cbe1854bfe142203456b00d5233bdbbdeb5091b8067cd34fb00f81dbfbc29fc30dbb6e026b3d58ea0551e3f26c0e64082092 + semver: ^7.5.3 + checksum: 9ba00d38ce6a29682f64a46213834e4eb01634c2f52c813a9a7b8873ca49cdbb703696f3290f3b27dc067de6d9418b0b84bef22c3eb074acf352529b2d6c27fd languageName: node linkType: hard "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" - checksum: 230ac975cca485b7f6fe2b96a711aa62a6a26ead3e6fb8ba17c5a00d61b8bed0d7adc21f5626b70d7c33c62ff4e63933017a6462942c719d1980bb0b1207ad46 + checksum: aba6438f46d2bfcef94cf112c835ab395172c75f67453fe05c340c770d3c402363018ae1ab4172a1026a90c47eaccf3af7b6ff6fa749a680c2929bd7fa2b37a4 languageName: node linkType: hard "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" - checksum: e18488c6a42bdfd4ac5be85b2ced3ccd0224773baae6ad42cfbb9ec74fc07f9fa8396bd35ee638084ead7a2a0818eb5e7151111544d4731ce843019dab4be47b + checksum: 94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c languageName: node linkType: hard "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" - checksum: a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 + checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b languageName: node linkType: hard @@ -13205,7 +14274,7 @@ __metadata: define-property: "npm:^1.0.0" isobject: "npm:^3.0.0" snapdragon-util: "npm:^3.0.1" - checksum: 7616e6a1ca054afe3ad8defda17ebe4c73b0800d2e0efd635c44ee1b286f8ac7900517314b5330862ce99b28cd2782348ee78bae573ff0f55832ad81d9657f3f + checksum: 9bb57d759f9e2a27935dbab0e4a790137adebace832b393e350a8bf5db461ee9206bb642d4fe47568ee0b44080479c8b4a9ad0ebe3712422d77edf9992a672fd languageName: node linkType: hard @@ -13214,7 +14283,7 @@ __metadata: resolution: "snapdragon-util@npm:3.0.1" dependencies: kind-of: "npm:^3.2.0" - checksum: 4441856d343399ba7f37f79681949d51b922e290fcc07e7bc94655a50f584befa4fb08f40c3471cd160e004660161964d8ff140cba49baa59aa6caba774240e3 + checksum: 684997dbe37ec995c03fd3f412fba2b711fc34cb4010452b7eb668be72e8811a86a12938b511e8b19baf853b325178c56d8b78d655305e5cfb0bb8b21677e7b7 languageName: node linkType: hard @@ -13230,7 +14299,7 @@ __metadata: source-map: "npm:^0.5.6" source-map-resolve: "npm:^0.5.0" use: "npm:^3.1.0" - checksum: dfdac1f73d47152d72fc07f4322da09bbddfa31c1c9c3ae7346f252f778c45afa5b03e90813332f02f04f6de8003b34a168c456f8bb719024d092f932520ffca + checksum: a197f242a8f48b11036563065b2487e9b7068f50a20dd81d9161eca6af422174fc158b8beeadbe59ce5ef172aa5718143312b3aebaae551c124b7824387c8312 languageName: node linkType: hard @@ -13241,7 +14310,7 @@ __metadata: agent-base: "npm:^6.0.2" debug: "npm:^4.3.3" socks: "npm:^2.6.2" - checksum: b859f7eb8e96ec2c4186beea233ae59c02404094f3eb009946836af27d6e5c1627d1975a69b4d2e20611729ed543b6db3ae8481eb38603433c50d0345c987600 + checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 languageName: node linkType: hard @@ -13251,14 +14320,14 @@ __metadata: dependencies: ip: "npm:^2.0.0" smart-buffer: "npm:^4.2.0" - checksum: 43f69dbc9f34fc8220bc51c6eea1c39715ab3cfdb115d6e3285f6c7d1a603c5c75655668a5bbc11e3c7e2c99d60321fb8d7ab6f38cda6a215fadd0d6d0b52130 + checksum: 259d9e3e8e1c9809a7f5c32238c3d4d2a36b39b83851d0f573bfde5f21c4b1288417ce1af06af1452569cd1eb0841169afd4998f0e04ba04656f6b7f0e46d748 languageName: node linkType: hard "source-map-js@npm:>=0.6.2 <2.0.0, source-map-js@npm:^1.0.2": version: 1.0.2 resolution: "source-map-js@npm:1.0.2" - checksum: 32f2dfd1e9b7168f9a9715eb1b4e21905850f3b50cf02cf476e47e4eebe8e6b762b63a64357896aa29b37e24922b4282df0f492e0d2ace572b43d15525976ff8 + checksum: c049a7fc4deb9a7e9b481ae3d424cc793cb4845daa690bc5a05d428bf41bf231ced49b4cf0c9e77f9d42fdb3d20d6187619fc586605f5eabe995a316da8d377c languageName: node linkType: hard @@ -13271,7 +14340,7 @@ __metadata: resolve-url: "npm:^0.2.1" source-map-url: "npm:^0.4.0" urix: "npm:^0.1.0" - checksum: 410acbe93882e058858d4c1297be61da3e1533f95f25b95903edddc1fb719654e705663644677542d1fb78a66390238fad1a57115fc958a0724cf9bb509caf57 + checksum: c73fa44ac00783f025f6ad9e038ab1a2e007cd6a6b86f47fe717c3d0765b4a08d264f6966f3bd7cd9dbcd69e4832783d5472e43247775b2a550d6f2155d24bae languageName: node linkType: hard @@ -13281,7 +14350,7 @@ __metadata: dependencies: buffer-from: "npm:^1.0.0" source-map: "npm:^0.6.0" - checksum: 137539f8c453fa0f496ea42049ab5da4569f96781f6ac8e5bfda26937be9494f4e8891f523c5f98f0e85f71b35d74127a00c46f83f6a4f54672b58d53202565e + checksum: 933550047b6c1a2328599a21d8b7666507427c0f5ef5eaadd56b5da0fd9505e239053c66fe181bf1df469a3b7af9d775778eee283cbb7ae16b902ddc09e93a97 languageName: node linkType: hard @@ -13291,35 +14360,35 @@ __metadata: dependencies: buffer-from: "npm:^1.0.0" source-map: "npm:^0.6.0" - checksum: 9ee09942f415e0f721d6daad3917ec1516af746a8120bba7bb56278707a37f1eb8642bde456e98454b8a885023af81a16e646869975f06afc1a711fb90484e7d + checksum: 43e98d700d79af1d36f859bdb7318e601dfc918c7ba2e98456118ebc4c4872b327773e5a1df09b0524e9e5063bb18f0934538eace60cca2710d1fa687645d137 languageName: node linkType: hard "source-map-url@npm:^0.4.0": version: 0.4.1 resolution: "source-map-url@npm:0.4.1" - checksum: f8af0678500d536c7f643e32094d6718a4070ab4ca2d2326532512cfbe2d5d25a45849b4b385879326f2d7523bb3b686d0360dd347a3cda09fd89a5c28d4bc58 + checksum: 64c5c2c77aff815a6e61a4120c309ae4cac01298d9bcbb3deb1b46a4dd4c46d4a1eaeda79ec9f684766ae80e8dc86367b89326ce9dd2b89947bd9291fc1ac08c languageName: node linkType: hard "source-map@npm:^0.5.6": version: 0.5.7 resolution: "source-map@npm:0.5.7" - checksum: 904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599 + checksum: 5dc2043b93d2f194142c7f38f74a24670cd7a0063acdaf4bf01d2964b402257ae843c2a8fa822ad5b71013b5fcafa55af7421383da919752f22ff488bc553f4d languageName: node linkType: hard "source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" - checksum: ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 + checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 languageName: node linkType: hard "space-separated-tokens@npm:^1.0.0": version: 1.1.5 resolution: "space-separated-tokens@npm:1.1.5" - checksum: 3ee0a6905f89e1ffdfe474124b1ade9fe97276a377a0b01350bc079b6ec566eb5b219e26064cc5b7f3899c05bde51ffbc9154290b96eaf82916a1e2c2c13ead9 + checksum: 8ef68f1cfa8ccad316b7f8d0df0919d0f1f6d32101e8faeee34ea3a923ce8509c1ad562f57388585ee4951e92d27afa211ed0a077d3d5995b5ba9180331be708 languageName: node linkType: hard @@ -13329,14 +14398,14 @@ __metadata: dependencies: spdx-expression-parse: "npm:^3.0.0" spdx-license-ids: "npm:^3.0.0" - checksum: 49208f008618b9119208b0dadc9208a3a55053f4fd6a0ae8116861bd22696fc50f4142a35ebfdb389e05ccf2de8ad142573fefc9e26f670522d899f7b2fe7386 + checksum: e9ae98d22f69c88e7aff5b8778dc01c361ef635580e82d29e5c60a6533cc8f4d820803e67d7432581af0cc4fb49973125076ee3b90df191d153e223c004193b2 languageName: node linkType: hard "spdx-exceptions@npm:^2.1.0": version: 2.3.0 resolution: "spdx-exceptions@npm:2.3.0" - checksum: 83089e77d2a91cb6805a5c910a2bedb9e50799da091f532c2ba4150efdef6e53f121523d3e2dc2573a340dc0189e648b03157097f65465b3a0c06da1f18d7e8a + checksum: cb69a26fa3b46305637123cd37c85f75610e8c477b6476fa7354eb67c08128d159f1d36715f19be6f9daf4b680337deb8c65acdcae7f2608ba51931540687ac0 languageName: node linkType: hard @@ -13346,14 +14415,14 @@ __metadata: dependencies: spdx-exceptions: "npm:^2.1.0" spdx-license-ids: "npm:^3.0.0" - checksum: 6f8a41c87759fa184a58713b86c6a8b028250f158159f1d03ed9d1b6ee4d9eefdc74181c8ddc581a341aa971c3e7b79e30b59c23b05d2436d5de1c30bdef7171 + checksum: a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde languageName: node linkType: hard "spdx-license-ids@npm:^3.0.0": version: 3.0.13 resolution: "spdx-license-ids@npm:3.0.13" - checksum: a5cb77ea7be86d574c8876970920e34d9b37f2fb6e361e6b732b61267afbc63dd37831160b731f85c1478f5ba95ae00369742555920e3c694f047f7068d33318 + checksum: 3469d85c65f3245a279fa11afc250c3dca96e9e847f2f79d57f466940c5bb8495da08a542646086d499b7f24a74b8d0b42f3fc0f95d50ff99af1f599f6360ad7 languageName: node linkType: hard @@ -13362,14 +14431,14 @@ __metadata: resolution: "split-string@npm:3.1.0" dependencies: extend-shallow: "npm:^3.0.0" - checksum: 72d7cd625445c7af215130e1e2bc183013bb9dd48a074eda1d35741e2b0dcb355e6df5b5558a62543a24dcec37dd1d6eb7a6228ff510d3c9de0f3dc1d1da8a70 + checksum: ae5af5c91bdc3633628821bde92fdf9492fa0e8a63cf6a0376ed6afde93c701422a1610916f59be61972717070119e848d10dfbbd5024b7729d6a71972d2a84c languageName: node linkType: hard "sprintf-js@npm:~1.0.2": version: 1.0.3 resolution: "sprintf-js@npm:1.0.3" - checksum: ecadcfe4c771890140da5023d43e190b7566d9cf8b2d238600f31bec0fc653f328da4450eb04bd59a431771a8e9cc0e118f0aa3974b683a4981b4e07abc2a5bb + checksum: 19d79aec211f09b99ec3099b5b2ae2f6e9cdefe50bc91ac4c69144b6d3928a640bb6ae5b3def70c2e85a2c3d9f5ec2719921e3a59d3ca3ef4b2fd1a4656a0df3 languageName: node linkType: hard @@ -13378,14 +14447,14 @@ __metadata: resolution: "ssri@npm:10.0.4" dependencies: minipass: "npm:^5.0.0" - checksum: d085474ea6b439623a9a6a2c67570cb9e68e1bb6060e46e4d387f113304d75a51946d57c524be3a90ebfa3c73026edf76eb1a2d79a7f6cff0b04f21d99f127ab + checksum: fb14da9f8a72b04eab163eb13a9dda11d5962cd2317f85457c4e0b575e9a6e0e3a6a87b5bf122c75cb36565830cd5f263fb457571bf6f1587eb5f95d095d6165 languageName: node linkType: hard "stable@npm:^0.1.8": version: 0.1.8 resolution: "stable@npm:0.1.8" - checksum: df74b5883075076e78f8e365e4068ecd977af6c09da510cfc3148a303d4b87bc9aa8f7c48feb67ed4ef970b6140bd9eabba2129e28024aa88df5ea0114cba39d + checksum: 2ff482bb100285d16dd75cd8f7c60ab652570e8952c0bfa91828a2b5f646a0ff533f14596ea4eabd48bb7f4aeea408dce8f8515812b975d958a4cc4fa6b9dfeb languageName: node linkType: hard @@ -13394,7 +14463,7 @@ __metadata: resolution: "stack-utils@npm:2.0.6" dependencies: escape-string-regexp: "npm:^2.0.0" - checksum: 651c9f87667e077584bbe848acaecc6049bc71979f1e9a46c7b920cad4431c388df0f51b8ad7cfd6eed3db97a2878d0fc8b3122979439ea8bac29c61c95eec8a + checksum: 052bf4d25bbf5f78e06c1d5e67de2e088b06871fa04107ca8d3f0e9d9263326e2942c8bedee3545795fc77d787d443a538345eef74db2f8e35db3558c6f91ff7 languageName: node linkType: hard @@ -13404,14 +14473,14 @@ __metadata: dependencies: define-property: "npm:^0.2.5" object-copy: "npm:^0.1.0" - checksum: 284f5865a9e19d079f1badbcd70d5f9f82e7a08393f818a220839cd5f71729e89105e1c95322bd28e833161d484cee671380ca443869ae89578eef2bf55c0653 + checksum: 8657485b831f79e388a437260baf22784540417a9b29e11572c87735df24c22b84eda42107403a64b30861b2faf13df9f7fc5525d51f9d1d2303aba5cbf4e12c languageName: node linkType: hard "statuses@npm:2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" - checksum: 34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0 + checksum: 18c7623fdb8f646fb213ca4051be4df7efb3484d4ab662937ca6fbef7ced9b9e12842709872eb3020cc3504b93bde88935c9f6417489627a7786f24f8031cbcb languageName: node linkType: hard @@ -13420,40 +14489,40 @@ __metadata: resolution: "stop-iteration-iterator@npm:1.0.0" dependencies: internal-slot: "npm:^1.0.4" - checksum: c4158d6188aac510d9e92925b58709207bd94699e9c31186a040c80932a687f84a51356b5895e6dc72710aad83addb9411c22171832c9ae0e6e11b7d61b0dfb9 + checksum: d04173690b2efa40e24ab70e5e51a3ff31d56d699550cfad084104ab3381390daccb36652b25755e420245f3b0737de66c1879eaa2a8d4fc0a78f9bf892fcb42 languageName: node linkType: hard "store2@npm:^2.14.2": version: 2.14.2 resolution: "store2@npm:2.14.2" - checksum: 2f27c3eaa7207b81410e170e7c41379816d22c1566308a9d97fbf853c4facff531fcb2a85f085c7503c578736570972f747c26018ebeaba7d1341fb82a7b6d52 + checksum: 6f270fc5bab99b63f45fcc7bd8b99c2714b4adf880f557ed7ffb5ed3987131251165bccde425a00928aaf044870aee79ddeef548576d093c68703ed2edec45d7 languageName: node linkType: hard -"storybook@npm:7.0.12": - version: 7.0.12 - resolution: "storybook@npm:7.0.12" +"storybook@npm:7.6.7": + version: 7.6.7 + resolution: "storybook@npm:7.6.7" dependencies: - "@storybook/cli": "npm:7.0.12" + "@storybook/cli": 7.6.7 bin: - sb: index.js - storybook: index.js - checksum: 775cf1925f5b7d8d5e6b81d8329c8ac2d8e5e22069985ed750e6bf961ec783aae17483d3462db80c0e87705fa3c0b14cf52c1a05eb1bf921c50105bbed61aaf8 + sb: ./index.js + storybook: ./index.js + checksum: 8954904e0c513097ac11f80946ceaf7461df8eed6492423c6be67b0d9a73f002c9f61556665dab93852b3e99292c380195b2e5aa2abf569389ae8e813cf95efe languageName: node linkType: hard "stream-shift@npm:^1.0.0": version: 1.0.1 resolution: "stream-shift@npm:1.0.1" - checksum: b63a0d178cde34b920ad93e2c0c9395b840f408d36803b07c61416edac80ef9e480a51910e0ceea0d679cec90921bcd2cccab020d3a9fa6c73a98b0fbec132fd + checksum: 59b82b44b29ec3699b5519a49b3cedcc6db58c72fb40c04e005525dfdcab1c75c4e0c180b923c380f204bed78211b9bad8faecc7b93dece4d004c3f6ec75737b languageName: node linkType: hard "strict-uri-encode@npm:^1.0.0": version: 1.1.0 resolution: "strict-uri-encode@npm:1.1.0" - checksum: eb8a4109ba2588239787389313ba58ec49e043d4c64a1d44716defe5821a68ae49abe0cdefed9946ca9fc2a4af7ecf321da92422b0a67258ec0a3638b053ae62 + checksum: 9466d371f7b36768d43f7803f26137657559e4c8b0161fb9e320efb8edba3ae22f8e99d4b0d91da023b05a13f62ec5412c3f4f764b5788fac11d1fea93720bb3 languageName: node linkType: hard @@ -13463,18 +14532,18 @@ __metadata: dependencies: char-regex: "npm:^1.0.2" strip-ansi: "npm:^6.0.0" - checksum: 1cd77409c3d7db7bc59406f6bcc9ef0783671dcbabb23597a1177c166906ef2ee7c8290f78cae73a8aec858768f189d2cb417797df5e15ec4eb5e16b3346340c + checksum: ce85533ef5113fcb7e522bcf9e62cb33871aa99b3729cec5595f4447f660b0cefd542ca6df4150c97a677d58b0cb727a3fe09ac1de94071d05526c73579bf505 languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: emoji-regex: "npm:^8.0.0" is-fullwidth-code-point: "npm:^3.0.0" strip-ansi: "npm:^6.0.1" - checksum: 1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b + checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb languageName: node linkType: hard @@ -13485,7 +14554,7 @@ __metadata: eastasianwidth: "npm:^0.2.0" emoji-regex: "npm:^9.2.2" strip-ansi: "npm:^7.0.1" - checksum: ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca + checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 languageName: node linkType: hard @@ -13501,7 +14570,7 @@ __metadata: internal-slot: "npm:^1.0.3" regexp.prototype.flags: "npm:^1.4.3" side-channel: "npm:^1.0.4" - checksum: 644523d05c1ee93bab7474e999a5734ee5f6ad2d7ad24ed6ea8706c270dc92b352bde0f2a5420bfbeed54e28cb6a770c3800e1988a5267a70fd5e677c7750abc + checksum: 952da3a818de42ad1c10b576140a5e05b4de7b34b8d9dbf00c3ac8c1293e9c0f533613a39c5cda53e0a8221f2e710bc2150e730b1c2278d60004a8a35726efb6 languageName: node linkType: hard @@ -13512,7 +14581,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 31698f6d718794e422db6fcfa6685dcd9243097273b3b2a8b7948b5d45a183cd336378893ff0d4a7b2531b604c32bb5c45193dd6da3d2f5504df5cd222372c09 + checksum: 05b7b2d6af63648e70e44c4a8d10d8cc457536df78b55b9d6230918bde75c5987f6b8604438c4c8652eb55e4fc9725d2912789eb4ec457d6995f3495af190c09 languageName: node linkType: hard @@ -13523,7 +14592,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 51b663e3195a74b58620a250b3fc4efb58951000f6e7d572a9f671c038f2f37f24a2b8c6994500a882aeab2f1c383fac1e8c023c01eb0c8b4e52d2f13b6c4513 + checksum: 0fdc34645a639bd35179b5a08227a353b88dc089adf438f46be8a7c197fc3f22f8514c1c9be4629b3cd29c281582730a8cbbad6466c60f76b5f99cf2addb132e languageName: node linkType: hard @@ -13534,7 +14603,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 13b9970d4e234002dfc8069c655c1fe19e83e10ced208b54858c41bb0f7544e581ac0ce746e92b279563664ad63910039f7253f36942113fec413b2b4e7c1fcd + checksum: 89080feef416621e6ef1279588994305477a7a91648d9436490d56010a1f7adc39167cddac7ce0b9884b8cdbef086987c4dcb2960209f2af8bac0d23ceff4f41 languageName: node linkType: hard @@ -13543,7 +14612,7 @@ __metadata: resolution: "string_decoder@npm:1.3.0" dependencies: safe-buffer: "npm:~5.2.0" - checksum: 810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d + checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 languageName: node linkType: hard @@ -13552,7 +14621,7 @@ __metadata: resolution: "string_decoder@npm:1.1.1" dependencies: safe-buffer: "npm:~5.1.0" - checksum: b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e + checksum: 9ab7e56f9d60a28f2be697419917c50cac19f3e8e6c28ef26ed5f4852289fe0de5d6997d29becf59028556f2c62983790c1d9ba1e2a3cc401768ca12d5183a5b languageName: node linkType: hard @@ -13561,7 +14630,7 @@ __metadata: resolution: "strip-ansi@npm:6.0.1" dependencies: ansi-regex: "npm:^5.0.1" - checksum: 1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 + checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c languageName: node linkType: hard @@ -13570,7 +14639,7 @@ __metadata: resolution: "strip-ansi@npm:3.0.1" dependencies: ansi-regex: "npm:^2.0.0" - checksum: f6e7fbe8e700105dccf7102eae20e4f03477537c74b286fd22cfc970f139002ed6f0d9c10d0e21aa9ed9245e0fa3c9275930e8795c5b947da136e4ecb644a70f + checksum: 9b974de611ce5075c70629c00fa98c46144043db92ae17748fb780f706f7a789e9989fd10597b7c2053ae8d1513fd707816a91f1879b2f71e6ac0b6a863db465 languageName: node linkType: hard @@ -13579,28 +14648,28 @@ __metadata: resolution: "strip-ansi@npm:7.1.0" dependencies: ansi-regex: "npm:^6.0.1" - checksum: a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4 + checksum: 859c73fcf27869c22a4e4d8c6acfe690064659e84bef9458aa6d13719d09ca88dcfd40cbf31fd0be63518ea1a643fe070b4827d353e09533a5b0b9fd4553d64d languageName: node linkType: hard "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" - checksum: 51201f50e021ef16672593d7434ca239441b7b760e905d9f33df6e4f3954ff54ec0e0a06f100d028af0982d6f25c35cd5cda2ce34eaebccd0250b8befb90d8f1 + checksum: 8d50ff27b7ebe5ecc78f1fe1e00fcdff7af014e73cf724b46fb81ef889eeb1015fc5184b64e81a2efe002180f3ba431bdd77e300da5c6685d702780fbf0c8d5b languageName: node linkType: hard "strip-bom@npm:^4.0.0": version: 4.0.0 resolution: "strip-bom@npm:4.0.0" - checksum: 26abad1172d6bc48985ab9a5f96c21e440f6e7e476686de49be813b5a59b3566dccb5c525b831ec54fe348283b47f3ffb8e080bc3f965fde12e84df23f6bb7ef + checksum: 9dbcfbaf503c57c06af15fe2c8176fb1bf3af5ff65003851a102749f875a6dbe0ab3b30115eccf6e805e9d756830d3e40ec508b62b3f1ddf3761a20ebe29d3f3 languageName: node linkType: hard "strip-final-newline@npm:^2.0.0": version: 2.0.0 resolution: "strip-final-newline@npm:2.0.0" - checksum: bddf8ccd47acd85c0e09ad7375409d81653f645fda13227a9d459642277c253d877b68f2e5e4d819fe75733b0e626bac7e954c04f3236f6d196f79c94fa4a96f + checksum: 69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 languageName: node linkType: hard @@ -13609,14 +14678,23 @@ __metadata: resolution: "strip-indent@npm:3.0.0" dependencies: min-indent: "npm:^1.0.0" - checksum: ae0deaf41c8d1001c5d4fbe16cb553865c1863da4fae036683b474fa926af9fc121e155cb3fc57a68262b2ae7d5b8420aa752c97a6428c315d00efe2a3875679 + checksum: 18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530 + languageName: node + linkType: hard + +"strip-indent@npm:^4.0.0": + version: 4.0.0 + resolution: "strip-indent@npm:4.0.0" + dependencies: + min-indent: ^1.0.1 + checksum: 06cbcd93da721c46bc13caeb1c00af93a9b18146a1c95927672d2decab6a25ad83662772417cea9317a2507fb143253ecc23c4415b64f5828cef9b638a744598 languageName: node linkType: hard "strip-json-comments@npm:^3.0.1, strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" - checksum: 9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd + checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 languageName: node linkType: hard @@ -13625,7 +14703,7 @@ __metadata: resolution: "style-to-js@npm:1.1.3" dependencies: style-to-object: "npm:0.4.1" - checksum: e445bab2494328dda68af10086c0dd1a8caf2679ae72eec7e29b181d9d533a6d9f4642f75d785c0d30ae2232f7fcdb159840db4d39688276b210e7b9337e2504 + checksum: 7aaeacff909d43bbfc28e9a004019224d0eda895ac3d0d9f3160b6ad044dca8d3965f7b2b92ac649f63f62889324b560147d21cf3149f29794692c5d7b207110 languageName: node linkType: hard @@ -13634,14 +14712,14 @@ __metadata: resolution: "style-to-object@npm:0.4.1" dependencies: inline-style-parser: "npm:0.1.1" - checksum: bde789dab148ec01032d75ea3a7d9294aa8dac369e9ef44f9a8f504df565f806b5a2c7226e3355f09a7e5d127684c65a0b7a7ade08780e0f893299e945d1464e + checksum: 2ea213e98eed21764ae1d1dc9359231a9f2d480d6ba55344c4c15eb275f0809f1845786e66d4caf62414a5cc8f112ce9425a58d251c77224060373e0db48f8c2 languageName: node linkType: hard "supports-color@npm:^2.0.0": version: 2.0.0 resolution: "supports-color@npm:2.0.0" - checksum: 570e0b63be36cccdd25186350a6cb2eaad332a95ff162fa06d9499982315f2fe4217e69dd98e862fbcd9c81eaff300a825a1fe7bf5cc752e5b84dfed042b0dda + checksum: 602538c5812b9006404370b5a4b885d3e2a1f6567d314f8b4a41974ffe7d08e525bf92ae0f9c7030e3b4c78e4e34ace55d6a67a74f1571bc205959f5972f88f0 languageName: node linkType: hard @@ -13650,7 +14728,7 @@ __metadata: resolution: "supports-color@npm:3.2.3" dependencies: has-flag: "npm:^1.0.0" - checksum: d39a57dbd75c3b5740654f8ec16aaf7203b8d12b8a51314507bed590c9081120805f105b4ce741db13105e6f842ac09700e4bd665b9ffc46eb0b34ba54720bd3 + checksum: 56afc05fa87d00100d90148c4d0a6e20a0af0d56dca5c54d4d40b2553ee737dab0ca4e8b53c4471afc035227b5b44dfa4824747a7f01ad733173536f7da6fbbb languageName: node linkType: hard @@ -13659,7 +14737,7 @@ __metadata: resolution: "supports-color@npm:5.5.0" dependencies: has-flag: "npm:^3.0.0" - checksum: 6ae5ff319bfbb021f8a86da8ea1f8db52fac8bd4d499492e30ec17095b58af11f0c55f8577390a749b1c4dde691b6a0315dab78f5f54c9b3d83f8fb5905c1c05 + checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac languageName: node linkType: hard @@ -13668,7 +14746,7 @@ __metadata: resolution: "supports-color@npm:7.2.0" dependencies: has-flag: "npm:^4.0.0" - checksum: afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 + checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a languageName: node linkType: hard @@ -13677,14 +14755,14 @@ __metadata: resolution: "supports-color@npm:8.1.1" dependencies: has-flag: "npm:^4.0.0" - checksum: ea1d3c275dd604c974670f63943ed9bd83623edc102430c05adb8efc56ba492746b6e95386e7831b872ec3807fd89dd8eb43f735195f37b5ec343e4234cc7e89 + checksum: c052193a7e43c6cdc741eb7f378df605636e01ad434badf7324f17fb60c69a880d8d8fcdcb562cf94c2350e57b937d7425ab5b8326c67c2adc48f7c87c1db406 languageName: node linkType: hard "supports-preserve-symlinks-flag@npm:^1.0.0": version: 1.0.0 resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 + checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae languageName: node linkType: hard @@ -13705,14 +14783,14 @@ __metadata: posthtml-svg-mode: "npm:^1.0.3" query-string: "npm:^4.3.2" traverse: "npm:^0.6.6" - checksum: 52768030b4c5c47a4301c89dd2e15e960d442eb1b9b40ac8ef14fc1f1c7588ede46cd810a0486510b836cfd8192224a66974b81b4567c2aae2053e9e1bbc80f3 + checksum: 06724dd6cd098016a11a778cfa2771defac6bdcdee1e4c61669aa32ebfa52815d66cea989ea1f1d31b440634ceda54637e2d7d57687925b0d256adf9ba176b50 languageName: node linkType: hard "svg-parser@npm:^2.0.4": version: 2.0.4 resolution: "svg-parser@npm:2.0.4" - checksum: 02f6cb155dd7b63ebc2f44f36365bc294543bebb81b614b7628f1af3c54ab64f7e1cec20f06e252bf95bdde78441ae295a412c68ad1678f16a6907d924512b7a + checksum: b3de6653048212f2ae7afe4a423e04a76ec6d2d06e1bf7eacc618a7c5f7df7faa5105561c57b94579ec831fbbdbf5f190ba56a9205ff39ed13eabdf8ab086ddf languageName: node linkType: hard @@ -13729,28 +14807,28 @@ __metadata: stable: "npm:^0.1.8" bin: svgo: bin/svgo - checksum: 0741f5d5cad63111a90a0ce7a1a5a9013f6d293e871b75efe39addb57f29a263e45294e485a4d2ff9cc260a5d142c8b5937b2234b4ef05efdd2706fb2d360ecc + checksum: b92f71a8541468ffd0b81b8cdb36b1e242eea320bf3c1a9b2c8809945853e9d8c80c19744267eb91cabf06ae9d5fff3592d677df85a31be4ed59ff78534fa420 languageName: node linkType: hard "symbol-tree@npm:^3.2.4": version: 3.2.4 resolution: "symbol-tree@npm:3.2.4" - checksum: dfbe201ae09ac6053d163578778c53aa860a784147ecf95705de0cd23f42c851e1be7889241495e95c37cabb058edb1052f141387bef68f705afc8f9dd358509 + checksum: 6e8fc7e1486b8b54bea91199d9535bb72f10842e40c79e882fc94fb7b14b89866adf2fd79efa5ebb5b658bc07fb459ccce5ac0e99ef3d72f474e74aaf284029d languageName: node linkType: hard "synchronous-promise@npm:^2.0.15": version: 2.0.17 resolution: "synchronous-promise@npm:2.0.17" - checksum: 1babe643d8417789ef6e5a2f3d4b8abcda2de236acd09bbe2c98f6be82c0a2c92ed21a6e4f934845fa8de18b1435a9cba1e8c3d945032e8a532f076224c024b1 + checksum: 7b1342c93741f3f92ebde1edf5d6ce8dde2278de948d84e9bd85e232c16c0d77c90c4940f9975be3effcb20f047cfb0f16fa311c3b4e092c22f3bf2889fb0fb4 languageName: node linkType: hard "tabbable@npm:^6.0.1": version: 6.2.0 resolution: "tabbable@npm:6.2.0" - checksum: ced8b38f05f2de62cd46836d77c2646c42b8c9713f5bd265daf0e78ff5ac73d3ba48a7ca45f348bafeef29b23da7187c72250742d37627883ef89cbd7fa76898 + checksum: f8440277d223949272c74bb627a3371be21735ca9ad34c2570f7e1752bd646ccfc23a9d8b1ee65d6561243f4134f5fbbf1ad6b39ac3c4b586554accaff4a1300 languageName: node linkType: hard @@ -13762,7 +14840,7 @@ __metadata: mkdirp-classic: "npm:^0.5.2" pump: "npm:^3.0.0" tar-stream: "npm:^2.1.4" - checksum: 871d26a934bfb7beeae4c4d8a09689f530b565f79bd0cf489823ff0efa3705da01278160da10bb006d1a793fa0425cf316cec029b32a9159eacbeaff4965fb6d + checksum: f5b9a70059f5b2969e65f037b4e4da2daf0fa762d3d232ffd96e819e3f94665dbbbe62f76f084f1acb4dbdcce16c6e4dac08d12ffc6d24b8d76720f4d9cf032d languageName: node linkType: hard @@ -13775,7 +14853,7 @@ __metadata: fs-constants: "npm:^1.0.0" inherits: "npm:^2.0.3" readable-stream: "npm:^3.1.1" - checksum: 2f4c910b3ee7196502e1ff015a7ba321ec6ea837667220d7bcb8d0852d51cb04b87f7ae471008a6fb8f5b1a1b5078f62f3a82d30c706f20ada1238ac797e7692 + checksum: 699831a8b97666ef50021c767f84924cfee21c142c2eb0e79c63254e140e6408d6d55a065a2992548e72b06de39237ef2b802b99e3ece93ca3904a37622a66f3 languageName: node linkType: hard @@ -13789,23 +14867,23 @@ __metadata: minizlib: "npm:^2.1.1" mkdirp: "npm:^1.0.3" yallist: "npm:^4.0.0" - checksum: bb2babe7b14442f690d83c2b2c571c9dd0bf802314773e05f4a3e4a241fdecd7fb560b8e4e7d6ea34533c8cd692e1b8418a3b8ba3b9687fe78a683dfbad7f82d + checksum: f23832fceeba7578bf31907aac744ae21e74a66f4a17a9e94507acf460e48f6db598c7023882db33bab75b80e027c21f276d405e4a0322d58f51c7088d428268 languageName: node linkType: hard -"telejson@npm:^7.0.3": - version: 7.1.0 - resolution: "telejson@npm:7.1.0" +"telejson@npm:^7.2.0": + version: 7.2.0 + resolution: "telejson@npm:7.2.0" dependencies: - memoizerific: "npm:^1.11.3" - checksum: dc9a185d0e00d947c0eaa229bfb993aab61a3ba79282ae409768fc8ae66d236e89a64ebe291f9ea6ed5e05396e0be52a7542ea32b6c1321b20440f28c7828edc + memoizerific: ^1.11.3 + checksum: 55a3380c9ff3c5ad84581bb6bda28fc33c6b7c4a0c466894637da687639b8db0d21b0ff4c1bc1a7a92ae6b70662549d09e7b9e8b1ec334b2ef93078762ecdfb9 languageName: node linkType: hard "temp-dir@npm:^2.0.0": version: 2.0.0 resolution: "temp-dir@npm:2.0.0" - checksum: b1df969e3f3f7903f3426861887ed76ba3b495f63f6d0c8e1ce22588679d9384d336df6064210fda14e640ed422e2a17d5c40d901f60e161c99482d723f4d309 + checksum: cc4f0404bf8d6ae1a166e0e64f3f409b423f4d1274d8c02814a59a5529f07db6cd070a749664141b992b2c1af337fa9bb451a460a43bb9bcddc49f235d3115aa languageName: node linkType: hard @@ -13814,7 +14892,7 @@ __metadata: resolution: "temp@npm:0.8.4" dependencies: rimraf: "npm:~2.6.2" - checksum: 7f071c963031bfece37e13c5da11e9bb451e4ddfc4653e23e327a2f91594102dc826ef6a693648e09a6e0eb856f507967ec759ae55635e0878091eccf411db37 + checksum: f35bed78565355dfdf95f730b7b489728bd6b7e35071bcc6497af7c827fb6c111fbe9063afc7b8cbc19522a072c278679f9a0ee81e684aa2c8617cc0f2e9c191 languageName: node linkType: hard @@ -13827,7 +14905,7 @@ __metadata: temp-dir: "npm:^2.0.0" type-fest: "npm:^0.16.0" unique-string: "npm:^2.0.0" - checksum: 864a1cf1b5536dc21e84ae45dbbc3ba4dd2c7ec1674d895f99c349cf209df959a53d797ca38d0b2cf69c7684d565fde5cfc67faaa63b7208ffb21d454b957472 + checksum: e77ca4440af18e42dc64d8903b7ed0be673455b76680ff94a7d7c6ee7c16f7604bdcdee3c39436342b1082c23eda010dbe48f6094e836e0bd53c8b1aa63e5b95 languageName: node linkType: hard @@ -13838,14 +14916,14 @@ __metadata: "@istanbuljs/schema": "npm:^0.1.2" glob: "npm:^7.1.4" minimatch: "npm:^3.0.4" - checksum: 019d33d81adff3f9f1bfcff18125fb2d3c65564f437d9be539270ee74b994986abb8260c7c2ce90e8f30162178b09dbbce33c6389273afac4f36069c48521f57 + checksum: 3b34a3d77165a2cb82b34014b3aba93b1c4637a5011807557dc2f3da826c59975a5ccad765721c4648b39817e3472789f9b0fa98fc854c5c1c7a1e632aacdc28 languageName: node linkType: hard "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" - checksum: 02805740c12851ea5982686810702e2f14369a5f4c5c40a836821e3eefc65ffeec3131ba324692a37608294b0fd8c1e55a2dd571ffed4909822787668ddbee5c + checksum: b6937a38c80c7f84d9c11dd75e49d5c44f71d95e810a3250bd1f1797fc7117c57698204adf676b71497acc205d769d65c16ae8fa10afad832ae1322630aef10a languageName: node linkType: hard @@ -13855,28 +14933,35 @@ __metadata: dependencies: readable-stream: "npm:~2.3.6" xtend: "npm:~4.0.1" - checksum: cbfe5b57943fa12b4f8c043658c2a00476216d79c014895cef1ac7a1d9a8b31f6b438d0e53eecbb81054b93128324a82ecd59ec1a4f91f01f7ac113dcb14eade + checksum: beb0f338aa2931e5660ec7bf3ad949e6d2e068c31f4737b9525e5201b824ac40cac6a337224856b56bd1ddd866334bbfb92a9f57cd6f66bc3f18d3d86fc0fe50 + languageName: node + linkType: hard + +"tiny-invariant@npm:^1.3.1": + version: 1.3.1 + resolution: "tiny-invariant@npm:1.3.1" + checksum: 872dbd1ff20a21303a2fd20ce3a15602cfa7fcf9b228bd694a52e2938224313b5385a1078cb667ed7375d1612194feaca81c4ecbe93121ca1baebe344de4f84c languageName: node linkType: hard "tiny-warning@npm:^1.0.3": version: 1.0.3 resolution: "tiny-warning@npm:1.0.3" - checksum: ef8531f581b30342f29670cb41ca248001c6fd7975ce22122bd59b8d62b4fc84ad4207ee7faa95cde982fa3357cd8f4be650142abc22805538c3b1392d7084fa + checksum: da62c4acac565902f0624b123eed6dd3509bc9a8d30c06e017104bedcf5d35810da8ff72864400ad19c5c7806fc0a8323c68baf3e326af7cb7d969f846100d71 languageName: node linkType: hard "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5" - checksum: f935537799c2d1922cb5d6d3805f594388f75338fe7a4a9dac41504dd539704ca4db45b883b52e7b0aa5b2fd5ddadb1452bf95cd23a69da2f793a843f9451cc9 + checksum: cd922d9b853c00fe414c5a774817be65b058d54a2d01ebb415840960406c669a0fc632f66df885e24cb022ec812739199ccbdb8d1164c3e513f85bfca5ab2873 languageName: node linkType: hard "to-fast-properties@npm:^2.0.0": version: 2.0.0 resolution: "to-fast-properties@npm:2.0.0" - checksum: b214d21dbfb4bce3452b6244b336806ffea9c05297148d32ebb428d5c43ce7545bdfc65a1ceb58c9ef4376a65c0cb2854d645f33961658b3e3b4f84910ddcdd7 + checksum: be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168 languageName: node linkType: hard @@ -13885,7 +14970,7 @@ __metadata: resolution: "to-object-path@npm:0.3.0" dependencies: kind-of: "npm:^3.0.2" - checksum: 731832a977614c03a770363ad2bd9e9c82f233261861724a8e612bb90c705b94b1a290a19f52958e8e179180bb9b71121ed65e245691a421467726f06d1d7fc3 + checksum: 9425effee5b43e61d720940fa2b889623f77473d459c2ce3d4a580a4405df4403eec7be6b857455908070566352f9e2417304641ed158dda6f6a365fe3e66d70 languageName: node linkType: hard @@ -13895,7 +14980,7 @@ __metadata: dependencies: is-number: "npm:^3.0.0" repeat-string: "npm:^1.6.1" - checksum: 440d82dbfe0b2e24f36dd8a9467240406ad1499fc8b2b0f547372c22ed1d092ace2a3eb522bb09bfd9c2f39bf1ca42eb78035cf6d2b8c9f5c78da3abc96cd949 + checksum: 46093cc14be2da905cc931e442d280b2e544e2bfdb9a24b3cf821be8d342f804785e5736c108d5be026021a05d7b38144980a61917eee3c88de0a5e710e10320 languageName: node linkType: hard @@ -13904,7 +14989,7 @@ __metadata: resolution: "to-regex-range@npm:5.0.1" dependencies: is-number: "npm:^7.0.0" - checksum: 487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 + checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed languageName: node linkType: hard @@ -13916,21 +15001,28 @@ __metadata: extend-shallow: "npm:^3.0.2" regex-not: "npm:^1.0.2" safe-regex: "npm:^1.1.0" - checksum: 99d0b8ef397b3f7abed4bac757b0f0bb9f52bfd39167eb7105b144becfaa9a03756892352d01ac6a911f0c1ceef9f81db68c46899521a3eed054082042796120 + checksum: 4ed4a619059b64e204aad84e4e5f3ea82d97410988bcece7cf6cbfdbf193d11bff48cf53842d88b8bb00b1bfc0d048f61f20f0709e6f393fd8fe0122662d9db4 + languageName: node + linkType: hard + +"tocbot@npm:^4.20.1": + version: 4.25.0 + resolution: "tocbot@npm:4.25.0" + checksum: ac382063526ae8cde93390e42761da7aac136a452f5109ddcbcaf0d1890de478a13d2cf01ef52ec2a50934e4fa10f1d4237109cccfa651ba8c5021638528b982 languageName: node linkType: hard "toggle-selection@npm:^1.0.6": version: 1.0.6 resolution: "toggle-selection@npm:1.0.6" - checksum: f2cf1f2c70f374fd87b0cdc8007453ba9e981c4305a8bf4eac10a30e62ecdfd28bca7d18f8f15b15a506bf8a7bfb20dbe3539f0fcf2a2c8396c1a78d53e1f179 + checksum: a90dc80ed1e7b18db8f4e16e86a5574f87632dc729cfc07d9ea3ced50021ad42bb4e08f22c0913e0b98e3837b0b717e0a51613c65f30418e21eb99da6556a74c languageName: node linkType: hard "toidentifier@npm:1.0.1": version: 1.0.1 resolution: "toidentifier@npm:1.0.1" - checksum: 93937279934bd66cc3270016dd8d0afec14fb7c94a05c72dc57321f8bd1fa97e5bea6d1f7c89e728d077ca31ea125b78320a616a6c6cd0e6b9cb94cb864381c1 + checksum: 952c29e2a85d7123239b5cfdd889a0dde47ab0497f0913d70588f19c53f7e0b5327c95f4651e413c74b785147f9637b17410ac8c846d5d4a20a5a33eb6dc3a45 languageName: node linkType: hard @@ -13942,7 +15034,7 @@ __metadata: punycode: "npm:^2.1.1" universalify: "npm:^0.2.0" url-parse: "npm:^1.5.3" - checksum: 4fc0433a0cba370d57c4b240f30440c848906dee3180bb6e85033143c2726d322e7e4614abb51d42d111ebec119c4876ed8d7247d4113563033eebbc1739c831 + checksum: c9226afff36492a52118432611af083d1d8493a53ff41ec4ea48e5b583aec744b989e4280bcf476c910ec1525a89a4a0f1cae81c08b18fb2ec3a9b3a72b91dcc languageName: node linkType: hard @@ -13951,35 +15043,28 @@ __metadata: resolution: "tr46@npm:3.0.0" dependencies: punycode: "npm:^2.1.1" - checksum: cdc47cad3a9d0b6cb293e39ccb1066695ae6fdd39b9e4f351b010835a1f8b4f3a6dc3a55e896b421371187f22b48d7dac1b693de4f6551bdef7b6ab6735dfe3b + checksum: 44c3cc6767fb800490e6e9fd64fd49041aa4e49e1f6a012b34a75de739cc9ed3a6405296072c1df8b6389ae139c5e7c6496f659cfe13a04a4bff3a1422981270 languageName: node linkType: hard "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" - checksum: 047cb209a6b60c742f05c9d3ace8fa510bff609995c129a37ace03476a9b12db4dbf975e74600830ef0796e18882b2381fb5fb1f6b4f96b832c374de3ab91a11 + checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 languageName: node linkType: hard "traverse@npm:^0.6.6": version: 0.6.7 resolution: "traverse@npm:0.6.7" - checksum: 97312cbcce0fdc640cf871a33c3f8efa85fbc2e21020bcbbf48b50883db4c41cfef580f3deaab67217291b761be4558fff34aab1baff7eb2b65323412458a489 + checksum: 21018085ab72f717991597e12e2b52446962ed59df591502e4d7e1a709bc0a989f7c3d451aa7d882666ad0634f1546d696c5edecda1f2fc228777df7bb529a1e languageName: node linkType: hard "ts-dedent@npm:^2.0.0, ts-dedent@npm:^2.2.0": version: 2.2.0 resolution: "ts-dedent@npm:2.2.0" - checksum: 175adea838468cc2ff7d5e97f970dcb798bbcb623f29c6088cb21aa2880d207c5784be81ab1741f56b9ac37840cbaba0c0d79f7f8b67ffe61c02634cafa5c303 - languageName: node - linkType: hard - -"ts-toolbelt@npm:^9.6.0": - version: 9.6.0 - resolution: "ts-toolbelt@npm:9.6.0" - checksum: 838f9a2f0fe881d5065257a23b402c41315b33ff987b73db3e2b39fcb70640c4c7220e1ef118ed5676763543724fdbf4eda7b0e2c17acb667ed1401336af9f8c + checksum: 93ed8f7878b6d5ed3c08d99b740010eede6bccfe64bce61c5a4da06a2c17d6ddbb80a8c49c2d15251de7594a4f93ffa21dd10e7be75ef66a4dc9951b4a94e2af languageName: node linkType: hard @@ -13993,7 +15078,7 @@ __metadata: optional: true bin: tsconfck: bin/tsconfck.js - checksum: 1ae5381b57049d536620e0d2061c5621662109a0783ea93b650326dd2ec83c1b6f1fb984388000f51fbefa57eadc329e75361a65a2e0daeeda0485dea0aaadf1 + checksum: c531525f39763cbbd7e6dbf5e29f12a7ae67eb8712816c14d06a9db6cbdc9dda9ac3cd6db07ef645f8a4cdea906447ab44e2c8679e320871cf9dd598756e8c83 languageName: node linkType: hard @@ -14005,21 +15090,28 @@ __metadata: json5: "npm:^1.0.2" minimist: "npm:^1.2.6" strip-bom: "npm:^3.0.0" - checksum: fdc92bb7b18b31c0e76f8ec4f98d07236b09590fd6578e587ad024792c8b2235d65125a8fd007fa47a84400f84ceccbf33f24e5198d953249e7204f4cef3517c + checksum: a6162eaa1aed680537f93621b82399c7856afd10ec299867b13a0675e981acac4e0ec00896860480efc59fc10fd0b16fdc928c0b885865b52be62cadac692447 languageName: node linkType: hard -"tslib@npm:^1.8.1": +"tslib@npm:^1.13.0, tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" - checksum: 69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 + checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd languageName: node linkType: hard "tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.4.0": version: 2.6.0 resolution: "tslib@npm:2.6.0" - checksum: 8d18020a8b9e70ecc529a744c883c095f177805efdbc9786bd50bd82a46c17547923133c5444fbcaf1f7f1c44e0e29c89f73ecf6d8fd1039668024a073a81dc6 + checksum: c01066038f950016a18106ddeca4649b4d76caa76ec5a31e2a26e10586a59fceb4ee45e96719bf6c715648e7c14085a81fee5c62f7e9ebee68e77a5396e5538f + languageName: node + linkType: hard + +"tslib@npm:^2.1.0": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad languageName: node linkType: hard @@ -14030,7 +15122,7 @@ __metadata: tslib: "npm:^1.8.1" peerDependencies: typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 02f19e458ec78ead8fffbf711f834ad8ecd2cc6ade4ec0320790713dccc0a412b99e7fd907c4cda2a1dc602c75db6f12e0108e87a5afad4b2f9e90a24cabd5a2 + checksum: 1843f4c1b2e0f975e08c4c21caa4af4f7f65a12ac1b81b3b8489366826259323feb3fc7a243123453d2d1a02314205a7634e048d4a8009921da19f99755cdc48 languageName: node linkType: hard @@ -14039,56 +15131,56 @@ __metadata: resolution: "type-check@npm:0.4.0" dependencies: prelude-ls: "npm:^1.2.1" - checksum: 7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 + checksum: ec688ebfc9c45d0c30412e41ca9c0cdbd704580eb3a9ccf07b9b576094d7b86a012baebc95681999dd38f4f444afd28504cb3a89f2ef16b31d4ab61a0739025a languageName: node linkType: hard "type-detect@npm:4.0.8": version: 4.0.8 resolution: "type-detect@npm:4.0.8" - checksum: 8fb9a51d3f365a7de84ab7f73b653534b61b622aa6800aecdb0f1095a4a646d3f5eb295322127b6573db7982afcd40ab492d038cf825a42093a58b1e1353e0bd + checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15 languageName: node linkType: hard "type-fest@npm:^0.16.0": version: 0.16.0 resolution: "type-fest@npm:0.16.0" - checksum: 6b4d846534e7bcb49a6160b068ffaed2b62570d989d909ac3f29df5ef1e993859f890a4242eebe023c9e923f96adbcb3b3e88a198c35a1ee9a731e147a6839c3 + checksum: 1a4102c06dc109db00418c753062e206cab65befd469d000ece4452ee649bf2a9cf57686d96fb42326bc9d918d9a194d4452897b486dcc41989e5c99e4e87094 languageName: node linkType: hard "type-fest@npm:^0.20.2": version: 0.20.2 resolution: "type-fest@npm:0.20.2" - checksum: dea9df45ea1f0aaa4e2d3bed3f9a0bfe9e5b2592bddb92eb1bf06e50bcf98dbb78189668cd8bc31a0511d3fc25539b4cd5c704497e53e93e2d40ca764b10bfc3 + checksum: 4fb3272df21ad1c552486f8a2f8e115c09a521ad7a8db3d56d53718d0c907b62c6e9141ba5f584af3f6830d0872c521357e512381f24f7c44acae583ad517d73 languageName: node linkType: hard "type-fest@npm:^0.21.3": version: 0.21.3 resolution: "type-fest@npm:0.21.3" - checksum: 902bd57bfa30d51d4779b641c2bc403cdf1371fb9c91d3c058b0133694fcfdb817aef07a47f40faf79039eecbaa39ee9d3c532deff244f3a19ce68cea71a61e8 + checksum: e6b32a3b3877f04339bae01c193b273c62ba7bfc9e325b8703c4ee1b32dc8fe4ef5dfa54bf78265e069f7667d058e360ae0f37be5af9f153b22382cd55a9afe0 languageName: node linkType: hard "type-fest@npm:^0.6.0": version: 0.6.0 resolution: "type-fest@npm:0.6.0" - checksum: 0c585c26416fce9ecb5691873a1301b5aff54673c7999b6f925691ed01f5b9232db408cdbb0bd003d19f5ae284322523f44092d1f81ca0a48f11f7cf0be8cd38 + checksum: b2188e6e4b21557f6e92960ec496d28a51d68658018cba8b597bd3ef757721d1db309f120ae987abeeda874511d14b776157ff809f23c6d1ce8f83b9b2b7d60f languageName: node linkType: hard "type-fest@npm:^0.8.1": version: 0.8.1 resolution: "type-fest@npm:0.8.1" - checksum: dffbb99329da2aa840f506d376c863bd55f5636f4741ad6e65e82f5ce47e6914108f44f340a0b74009b0cb5d09d6752ae83203e53e98b1192cf80ecee5651636 + checksum: d61c4b2eba24009033ae4500d7d818a94fd6d1b481a8111612ee141400d5f1db46f199c014766b9fa9b31a6a7374d96fc748c6d688a78a3ce5a33123839becb7 languageName: node linkType: hard -"type-fest@npm:^2.19.0": +"type-fest@npm:^2.19.0, type-fest@npm:~2.19": version: 2.19.0 resolution: "type-fest@npm:2.19.0" - checksum: a5a7ecf2e654251613218c215c7493574594951c08e52ab9881c9df6a6da0aeca7528c213c622bc374b4e0cb5c443aa3ab758da4e3c959783ce884c3194e12cb + checksum: a4ef07ece297c9fba78fc1bd6d85dff4472fe043ede98bd4710d2615d15776902b595abf62bd78339ed6278f021235fb28a96361f8be86ed754f778973a0d278 languageName: node linkType: hard @@ -14098,7 +15190,7 @@ __metadata: dependencies: media-typer: "npm:0.3.0" mime-types: "npm:~2.1.24" - checksum: a23daeb538591b7efbd61ecf06b6feb2501b683ffdc9a19c74ef5baba362b4347e42f1b4ed81f5882a8c96a3bfff7f93ce3ffaf0cbbc879b532b04c97a55db9d + checksum: 2c8e47675d55f8b4e404bcf529abdf5036c537a04c2b20177bcf78c9e3c1da69da3942b1346e6edb09e823228c0ee656ef0e033765ec39a70d496ef601a0c657 languageName: node linkType: hard @@ -14111,7 +15203,7 @@ __metadata: for-each: "npm:^0.3.3" has-proto: "npm:^1.0.1" is-typed-array: "npm:^1.1.10" - checksum: 4036ce007ae9752931bed3dd61e0d6de2a3e5f6a5a85a05f3adb35388d2c0728f9b1a1e638d75579f168e49c289bfb5417f00e96d4ab081f38b647fc854ff7a5 + checksum: 04f6f02d0e9a948a95fbfe0d5a70b002191fae0b8fe0fe3130a9b2336f043daf7a3dda56a31333c35a067a97e13f539949ab261ca0f3692c41603a46a94e960b languageName: node linkType: hard @@ -14122,23 +15214,14 @@ __metadata: call-bind: "npm:^1.0.2" for-each: "npm:^0.3.3" is-typed-array: "npm:^1.1.9" - checksum: c5163c0103d07fefc8a2ad0fc151f9ca9a1f6422098c00f695d55f9896e4d63614cd62cf8d8a031c6cee5f418e8980a533796597174da4edff075b3d275a7e23 + checksum: 2228febc93c7feff142b8c96a58d4a0d7623ecde6c7a24b2b98eb3170e99f7c7eff8c114f9b283085cd59dcd2bd43aadf20e25bba4b034a53c5bb292f71f8956 languageName: node linkType: hard "typedarray@npm:^0.0.6": version: 0.0.6 resolution: "typedarray@npm:0.0.6" - checksum: 6005cb31df50eef8b1f3c780eb71a17925f3038a100d82f9406ac2ad1de5eb59f8e6decbdc145b3a1f8e5836e17b0c0002fb698b9fe2516b8f9f9ff602d36412 - languageName: node - linkType: hard - -"types-ramda@npm:^0.29.4": - version: 0.29.4 - resolution: "types-ramda@npm:0.29.4" - dependencies: - ts-toolbelt: "npm:^9.6.0" - checksum: 7f73719de87ad49ffa48bdece4feb41d9707f945cad649c5bd1c0b1c2f80703d9eb90cc9003411a5af4d4eee3c0c582f8baa86af069be29e9c46f802db203825 + checksum: 33b39f3d0e8463985eeaeeacc3cb2e28bc3dfaf2a5ed219628c0b629d5d7b810b0eb2165f9f607c34871d5daa92ba1dc69f49051cf7d578b4cbd26c340b9d1b1 languageName: node linkType: hard @@ -14148,17 +15231,17 @@ __metadata: bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: aa0e2a766412a0c9f609133681753cc88098aa44e079820d203dc0628a8fc3997d4e6b93c2c813c483f770698561c3225c5ab3e5c8896639cfc5d94528e3005f + checksum: bef1dcd166acfc6934b2ec4d72f93edb8961a5fab36b8dd2aaf6f4f4cd5c0210f2e0850aef4724f3b4913d5aef203a94a28ded731b370880c8bcff7e4ff91fc1 languageName: node linkType: hard -"typescript@patch:typescript@npm%3A5.0.2#optional!builtin": +"typescript@patch:typescript@5.0.2#~builtin": version: 5.0.2 - resolution: "typescript@patch:typescript@npm%3A5.0.2#optional!builtin::version=5.0.2&hash=b5f058" + resolution: "typescript@patch:typescript@npm%3A5.0.2#~builtin::version=5.0.2&hash=b5f058" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 7889472e5f13d6c6df993f8cc26ac5bd9d27ed5e5e865afc150ceffb5c02d944e27e5e92dfd730232a9180549c6b7d3f622deacd1d96c0457cba72e17ed6901f + checksum: 0411be9e19bf6a547d574b3261fa8598f55a5243123f2a50a79b0dc15a017abbf541f15b8b43331294e409cc978e548ac5ae4e0c5b98ba5ae98029304de047be languageName: node linkType: hard @@ -14167,7 +15250,7 @@ __metadata: resolution: "uglify-js@npm:3.17.4" bin: uglifyjs: bin/uglifyjs - checksum: 8b7fcdca69deb284fed7d2025b73eb747ce37f9aca6af53422844f46427152d5440601b6e2a033e77856a2f0591e4167153d5a21b68674ad11f662034ec13ced + checksum: 7b3897df38b6fc7d7d9f4dcd658599d81aa2b1fb0d074829dd4e5290f7318dbca1f4af2f45acb833b95b1fe0ed4698662ab61b87e94328eb4c0a0d3435baf924 languageName: node linkType: hard @@ -14179,21 +15262,21 @@ __metadata: has-bigints: "npm:^1.0.2" has-symbols: "npm:^1.0.3" which-boxed-primitive: "npm:^1.0.2" - checksum: 81ca2e81134167cc8f75fa79fbcc8a94379d6c61de67090986a2273850989dd3bae8440c163121b77434b68263e34787a675cbdcb34bb2f764c6b9c843a11b66 + checksum: b7a1cf5862b5e4b5deb091672ffa579aa274f648410009c81cca63fed3b62b610c4f3b773f912ce545bb4e31edc3138975b5bc777fc6e4817dca51affb6380e9 languageName: node linkType: hard -"unfetch@npm:^4.2.0": - version: 4.2.0 - resolution: "unfetch@npm:4.2.0" - checksum: a5c0a896a6f09f278b868075aea65652ad185db30e827cb7df45826fe5ab850124bf9c44c4dafca4bf0c55a0844b17031e8243467fcc38dd7a7d435007151f1b +"undici-types@npm:~5.26.4": + version: 5.26.5 + resolution: "undici-types@npm:5.26.5" + checksum: 3192ef6f3fd5df652f2dc1cd782b49d6ff14dc98e5dced492aa8a8c65425227da5da6aafe22523c67f035a272c599bb89cfe803c1db6311e44bed3042fc25487 languageName: node linkType: hard "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" - checksum: 0fe812641bcfa3ae433025178a64afb5d9afebc21a922dafa7cba971deebb5e4a37350423890750132a85c936c290fb988146d0b1bd86838ad4897f4fc5bd0de + checksum: 39be078afd014c14dcd957a7a46a60061bc37c4508ba146517f85f60361acf4c7539552645ece25de840e17e293baa5556268d091ca6762747fdd0c705001a45 languageName: node linkType: hard @@ -14203,21 +15286,21 @@ __metadata: dependencies: unicode-canonical-property-names-ecmascript: "npm:^2.0.0" unicode-property-aliases-ecmascript: "npm:^2.0.0" - checksum: 4d05252cecaf5c8e36d78dc5332e03b334c6242faf7cf16b3658525441386c0a03b5f603d42cbec0f09bb63b9fd25c9b3b09667aee75463cac3efadae2cd17ec + checksum: 1f34a7434a23df4885b5890ac36c5b2161a809887000be560f56ad4b11126d433c0c1c39baf1016bdabed4ec54829a6190ee37aa24919aa116dc1a5a8a62965a languageName: node linkType: hard "unicode-match-property-value-ecmascript@npm:^2.1.0": version: 2.1.0 resolution: "unicode-match-property-value-ecmascript@npm:2.1.0" - checksum: f5b9499b9e0ffdc6027b744d528f17ec27dd7c15da03254ed06851feec47e0531f20d410910c8a49af4a6a190f4978413794c8d75ce112950b56d583b5d5c7f2 + checksum: 8d6f5f586b9ce1ed0e84a37df6b42fdba1317a05b5df0c249962bd5da89528771e2d149837cad11aa26bcb84c35355cb9f58a10c3d41fa3b899181ece6c85220 languageName: node linkType: hard "unicode-property-aliases-ecmascript@npm:^2.0.0": version: 2.1.0 resolution: "unicode-property-aliases-ecmascript@npm:2.1.0" - checksum: 50ded3f8c963c7785e48c510a3b7c6bc4e08a579551489aa0349680a35b1ceceec122e33b2b6c1b579d0be2250f34bb163ac35f5f8695fe10bbc67fb757f0af8 + checksum: 243524431893649b62cc674d877bd64ef292d6071dd2fd01ab4d5ad26efbc104ffcd064f93f8a06b7e4ec54c172bf03f6417921a0d8c3a9994161fe1f88f815b languageName: node linkType: hard @@ -14229,7 +15312,7 @@ __metadata: get-value: "npm:^2.0.6" is-extendable: "npm:^0.1.1" set-value: "npm:^2.0.1" - checksum: 8758d880cb9545f62ce9cfb9b791b2b7a206e0ff5cc4b9d7cd6581da2c6839837fbb45e639cf1fd8eef3cae08c0201b614b7c06dd9f5f70d9dbe7c5fe2fbf592 + checksum: a3464097d3f27f6aa90cf103ed9387541bccfc006517559381a10e0dffa62f465a9d9a09c9b9c3d26d0f4cbe61d4d010e2fbd710fd4bf1267a768ba8a774b0ba languageName: node linkType: hard @@ -14238,7 +15321,7 @@ __metadata: resolution: "unique-filename@npm:3.0.0" dependencies: unique-slug: "npm:^4.0.0" - checksum: 6363e40b2fa758eb5ec5e21b3c7fb83e5da8dcfbd866cc0c199d5534c42f03b9ea9ab069769cc388e1d7ab93b4eeef28ef506ab5f18d910ef29617715101884f + checksum: 8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df languageName: node linkType: hard @@ -14247,7 +15330,7 @@ __metadata: resolution: "unique-slug@npm:4.0.0" dependencies: imurmurhash: "npm:^0.1.4" - checksum: cb811d9d54eb5821b81b18205750be84cb015c20a4a44280794e915f5a0a70223ce39066781a354e872df3572e8155c228f43ff0cce94c7cbf4da2cc7cbdd635 + checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 languageName: node linkType: hard @@ -14256,14 +15339,14 @@ __metadata: resolution: "unique-string@npm:2.0.0" dependencies: crypto-random-string: "npm:^2.0.0" - checksum: 11820db0a4ba069d174bedfa96c588fc2c96b083066fafa186851e563951d0de78181ac79c744c1ed28b51f9d82ac5b8196ff3e4560d0178046ef455d8c2244b + checksum: ef68f639136bcfe040cf7e3cd7a8dff076a665288122855148a6f7134092e6ed33bf83a7f3a9185e46c98dddc445a0da6ac25612afa1a7c38b8b654d6c02498e languageName: node linkType: hard "unist-util-is@npm:^4.0.0": version: 4.1.0 resolution: "unist-util-is@npm:4.1.0" - checksum: 21ca3d7bacc88853b880b19cb1b133a056c501617d7f9b8cce969cd8b430ed7e1bc416a3a11b02540d5de6fb86807e169d00596108a459d034cf5faec97c055e + checksum: 726484cd2adc9be75a939aeedd48720f88294899c2e4a3143da413ae593f2b28037570730d5cf5fd910ff41f3bc1501e3d636b6814c478d71126581ef695f7ea languageName: node linkType: hard @@ -14273,7 +15356,7 @@ __metadata: dependencies: "@types/unist": "npm:^2.0.0" unist-util-is: "npm:^4.0.0" - checksum: 231c80c5ba8e79263956fcaa25ed2a11ad7fe77ac5ba0d322e9d51bbc4238501e3bb52f405e518bcdc5471e27b33eff520db0aa4a3b1feb9fb6e2de6ae385d49 + checksum: 1170e397dff88fab01e76d5154981666eb0291019d2462cff7a2961a3e76d3533b42eaa16b5b7e2d41ad42a5ea7d112301458283d255993e660511387bf67bc3 languageName: node linkType: hard @@ -14284,40 +15367,40 @@ __metadata: "@types/unist": "npm:^2.0.0" unist-util-is: "npm:^4.0.0" unist-util-visit-parents: "npm:^3.0.0" - checksum: 7b11303d82271ca53a2ced2d56c87a689dd518596c99ff4a11cdff750f5cc5c0e4b64b146bd2363557cb29443c98713bfd1e8dc6d1c3f9d474b9eb1f23a60888 + checksum: 1fe19d500e212128f96d8c3cfa3312846e586b797748a1fd195fe6479f06bc90a6f6904deb08eefc00dd58e83a1c8a32fb8677252d2273ad7a5e624525b69b8f languageName: node linkType: hard "universalify@npm:^0.2.0": version: 0.2.0 resolution: "universalify@npm:0.2.0" - checksum: cedbe4d4ca3967edf24c0800cfc161c5a15e240dac28e3ce575c689abc11f2c81ccc6532c8752af3b40f9120fb5e454abecd359e164f4f6aa44c29cd37e194fe + checksum: e86134cb12919d177c2353196a4cc09981524ee87abf621f7bc8d249dbbbebaec5e7d1314b96061497981350df786e4c5128dbf442eba104d6e765bc260678b5 languageName: node linkType: hard "universalify@npm:^2.0.0": version: 2.0.0 resolution: "universalify@npm:2.0.0" - checksum: 07092b9f46df61b823d8ab5e57f0ee5120c178b39609a95e4a15a98c42f6b0b8e834e66fbb47ff92831786193be42f1fd36347169b88ce8639d0f9670af24a71 + checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 languageName: node linkType: hard "unpipe@npm:1.0.0, unpipe@npm:~1.0.0": version: 1.0.0 resolution: "unpipe@npm:1.0.0" - checksum: 193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c + checksum: 4fa18d8d8d977c55cb09715385c203197105e10a6d220087ec819f50cb68870f02942244f1017565484237f1f8c5d3cd413631b1ae104d3096f24fdfde1b4aa2 languageName: node linkType: hard -"unplugin@npm:^0.10.2": - version: 0.10.2 - resolution: "unplugin@npm:0.10.2" +"unplugin@npm:^1.3.1": + version: 1.6.0 + resolution: "unplugin@npm:1.6.0" dependencies: - acorn: "npm:^8.8.0" - chokidar: "npm:^3.5.3" - webpack-sources: "npm:^3.2.3" - webpack-virtual-modules: "npm:^0.4.5" - checksum: 3e326b470df042af62c1ea1febe43b0681554663ad50257ad2ae14cf261740d0137570d97d2067ee3cdd6b819a4249f1aa3dff05a8c7476ad12715263b0b1ae8 + acorn: ^8.11.2 + chokidar: ^3.5.3 + webpack-sources: ^3.2.3 + webpack-virtual-modules: ^0.6.1 + checksum: 1c2817f791f4fe59543f5b0cbedba6c37f66005c43c48260dc5934d13bb90ea347aa0040a9701bfeca072b99dd464e67133f5d5237191874499db73d62ab01fa languageName: node linkType: hard @@ -14327,14 +15410,14 @@ __metadata: dependencies: has-value: "npm:^0.3.1" isobject: "npm:^3.0.0" - checksum: 68a796dde4a373afdbf017de64f08490a3573ebee549136da0b3a2245299e7f65f647ef70dc13c4ac7f47b12fba4de1646fa0967a365638578fedce02b9c0b1f + checksum: 5990ecf660672be2781fc9fb322543c4aa592b68ed9a3312fa4df0e9ba709d42e823af090fc8f95775b4cd2c9a5169f7388f0cec39238b6d0d55a69fc2ab6b29 languageName: node linkType: hard "untildify@npm:^4.0.0": version: 4.0.0 resolution: "untildify@npm:4.0.0" - checksum: d758e624c707d49f76f7511d75d09a8eda7f2020d231ec52b67ff4896bcf7013be3f9522d8375f57e586e9a2e827f5641c7e06ee46ab9c435fc2b2b2e9de517a + checksum: 39ced9c418a74f73f0a56e1ba4634b4d959422dff61f4c72a8e39f60b99380c1b45ed776fbaa0a4101b157e4310d873ad7d114e8534ca02609b4916bb4187fb9 languageName: node linkType: hard @@ -14348,7 +15431,21 @@ __metadata: browserslist: ">= 4.21.0" bin: update-browserslist-db: cli.js - checksum: 280d5cf92e302d8de0c12ef840a6af26ec024a5158aa2020975cd01bf0ded09c709793a6f421e6d0f1a47557d6a1a10dc43af80f9c30b8fd0df9691eb98c1c69 + checksum: b98327518f9a345c7cad5437afae4d2ae7d865f9779554baf2a200fdf4bac4969076b679b1115434bd6557376bdd37ca7583d0f9b8f8e302d7d4cc1e91b5f231 + languageName: node + linkType: hard + +"update-browserslist-db@npm:^1.0.13": + version: 1.0.13 + resolution: "update-browserslist-db@npm:1.0.13" + dependencies: + escalade: ^3.1.1 + picocolors: ^1.0.0 + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 1e47d80182ab6e4ad35396ad8b61008ae2a1330221175d0abd37689658bdb61af9b705bfc41057fd16682474d79944fb2d86767c5ed5ae34b6276b9bed353322 languageName: node linkType: hard @@ -14357,14 +15454,14 @@ __metadata: resolution: "uri-js@npm:4.4.1" dependencies: punycode: "npm:^2.1.0" - checksum: 4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c + checksum: 7167432de6817fe8e9e0c9684f1d2de2bb688c94388f7569f7dbdb1587c9f4ca2a77962f134ec90be0cc4d004c939ff0d05acc9f34a0db39a3c797dada262633 languageName: node linkType: hard "urix@npm:^0.1.0": version: 0.1.0 resolution: "urix@npm:0.1.0" - checksum: 264f1b29360c33c0aec5fb9819d7e28f15d1a3b83175d2bcc9131efe8583f459f07364957ae3527f1478659ec5b2d0f1ad401dfb625f73e4d424b3ae35fc5fc0 + checksum: 4c076ecfbf3411e888547fe844e52378ab5ada2d2f27625139011eada79925e77f7fbf0e4016d45e6a9e9adb6b7e64981bd49b22700c7c401c5fc15f423303b3 languageName: node linkType: hard @@ -14374,7 +15471,22 @@ __metadata: dependencies: querystringify: "npm:^2.1.1" requires-port: "npm:^1.0.0" - checksum: bd5aa9389f896974beb851c112f63b466505a04b4807cea2e5a3b7092f6fbb75316f0491ea84e44f66fed55f1b440df5195d7e3a8203f64fcefa19d182f5be87 + checksum: fbdba6b1d83336aca2216bbdc38ba658d9cfb8fc7f665eb8b17852de638ff7d1a162c198a8e4ed66001ddbf6c9888d41e4798912c62b4fd777a31657989f7bdf + languageName: node + linkType: hard + +"use-callback-ref@npm:^1.3.0": + version: 1.3.1 + resolution: "use-callback-ref@npm:1.3.1" + dependencies: + tslib: ^2.0.0 + peerDependencies: + "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 6a6a3a8bfe88f466eab982b8a92e5da560a7127b3b38815e89bc4d195d4b33aa9a53dba50d93e8138e7502bcc7e39efe9f2735a07a673212630990c73483e8e9 languageName: node linkType: hard @@ -14386,7 +15498,23 @@ __metadata: peerDependencies: react: 16.8.0 - 18 react-dom: 16.8.0 - 18 - checksum: 6ccdeb09fe20566ec182b1635a22f189e13d46226b74610432590e69b31ef5d05d069badc3306ebd0d2bb608743b17981fb535763a1d7dc2c8ae462ee8e5999c + checksum: 92be0ac34a3b3cf884cd55847c90792b5b44833dc258e96d650152815ad246afe45825aa223332203004d836535a927ab74f18dc0313229e2c7c69510eddf382 + languageName: node + linkType: hard + +"use-sidecar@npm:^1.1.2": + version: 1.1.2 + resolution: "use-sidecar@npm:1.1.2" + dependencies: + detect-node-es: ^1.1.0 + tslib: ^2.0.0 + peerDependencies: + "@types/react": ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 925d1922f9853e516eaad526b6fed1be38008073067274f0ecc3f56b17bb8ab63480140dd7c271f94150027c996cea4efe83d3e3525e8f3eda22055f6a39220b languageName: node linkType: hard @@ -14395,25 +15523,25 @@ __metadata: resolution: "use-sync-external-store@npm:1.2.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: ac4814e5592524f242921157e791b022efe36e451fe0d4fd4d204322d5433a4fc300d63b0ade5185f8e0735ded044c70bcf6d2352db0f74d097a238cebd2da02 + checksum: 5c639e0f8da3521d605f59ce5be9e094ca772bd44a4ce7322b055a6f58eeed8dda3c94cabd90c7a41fb6fa852210092008afe48f7038792fd47501f33299116a languageName: node linkType: hard "use@npm:^3.1.0": version: 3.1.1 resolution: "use@npm:3.1.1" - checksum: 75b48673ab80d5139c76922630d5a8a44e72ed58dbaf54dee1b88352d10e1c1c1fc332066c782d8ae9a56503b85d3dc67ff6d2ffbd9821120466d1280ebb6d6e + checksum: 08a130289f5238fcbf8f59a18951286a6e660d17acccc9d58d9b69dfa0ee19aa038e8f95721b00b432c36d1629a9e32a464bf2e7e0ae6a244c42ddb30bdd8b33 languageName: node linkType: hard "util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" - checksum: 41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 + checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 languageName: node linkType: hard -"util@npm:^0.12.0, util@npm:^0.12.4": +"util@npm:^0.12.0, util@npm:^0.12.4, util@npm:^0.12.5": version: 0.12.5 resolution: "util@npm:0.12.5" dependencies: @@ -14422,14 +15550,14 @@ __metadata: is-generator-function: "npm:^1.0.7" is-typed-array: "npm:^1.1.3" which-typed-array: "npm:^1.1.2" - checksum: c27054de2cea2229a66c09522d0fa1415fb12d861d08523a8846bf2e4cbf0079d4c3f725f09dcb87493549bcbf05f5798dce1688b53c6c17201a45759e7253f3 + checksum: 705e51f0de5b446f4edec10739752ac25856541e0254ea1e7e45e5b9f9b0cb105bc4bd415736a6210edc68245a7f903bf085ffb08dd7deb8a0e847f60538a38a languageName: node linkType: hard "utils-merge@npm:1.0.1": version: 1.0.1 resolution: "utils-merge@npm:1.0.1" - checksum: 02ba649de1b7ca8854bfe20a82f1dfbdda3fb57a22ab4a8972a63a34553cf7aa51bc9081cf7e001b035b88186d23689d69e71b510e610a09a4c66f68aa95b672 + checksum: c81095493225ecfc28add49c106ca4f09cdf56bc66731aa8dabc2edbbccb1e1bfe2de6a115e5c6a380d3ea166d1636410b62ef216bb07b3feb1cfde1d95d5080 languageName: node linkType: hard @@ -14438,18 +15566,18 @@ __metadata: resolution: "uuid@npm:9.0.0" bin: uuid: dist/bin/uuid - checksum: 8867e438990d1d33ac61093e2e4e3477a2148b844e4fa9e3c2360fa4399292429c4b6ec64537eb1659c97b2d10db349c673ad58b50e2824a11e0d3630de3c056 + checksum: 8dd2c83c43ddc7e1c71e36b60aea40030a6505139af6bee0f382ebcd1a56f6cd3028f7f06ffb07f8cf6ced320b76aea275284b224b002b289f89fe89c389b028 languageName: node linkType: hard -"v8-to-istanbul@npm:^9.0.0, v8-to-istanbul@npm:^9.0.1": +"v8-to-istanbul@npm:^9.0.1": version: 9.1.0 resolution: "v8-to-istanbul@npm:9.1.0" dependencies: "@jridgewell/trace-mapping": "npm:^0.3.12" "@types/istanbul-lib-coverage": "npm:^2.0.1" convert-source-map: "npm:^1.6.0" - checksum: 657ef7c52a514c1a0769663f96dd6f2cd11d2d3f6c8272d1035f4a543dca0b52c84b005beb7f0ca215eb98425c8bc4aa92a62826b1fc76abc1f7228d33ccbc60 + checksum: 2069d59ee46cf8d83b4adfd8a5c1a90834caffa9f675e4360f1157ffc8578ef0f763c8f32d128334424159bb6b01f3876acd39cd13297b2769405a9da241f8d1 languageName: node linkType: hard @@ -14459,14 +15587,14 @@ __metadata: dependencies: spdx-correct: "npm:^3.0.0" spdx-expression-parse: "npm:^3.0.0" - checksum: 7b91e455a8de9a0beaa9fe961e536b677da7f48c9a493edf4d4d4a87fd80a7a10267d438723364e432c2fcd00b5650b5378275cded362383ef570276e6312f4f + checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad languageName: node linkType: hard "vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" - checksum: f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f + checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b languageName: node linkType: hard @@ -14480,7 +15608,7 @@ __metadata: peerDependencies: eslint: ">=7" vite: ">=2" - checksum: 123c3dcf8229fe2104f139877e866c1a7fc21903dc09f80bebb319a29929667074b9db6d89b3c48eea4740567a07c875d13c4c863ccf7a30a6c9621c74a5c37a + checksum: 65598893e2063a287a690ae296ba1fc212ee50dbc810d396a6cda44ee60c6f400adb52fc4c4a5ff54a89c11100bbaaf43eada23c9a78654ab1717f097d78176f languageName: node linkType: hard @@ -14489,7 +15617,7 @@ __metadata: resolution: "vite-plugin-react-remove-attributes@npm:1.0.3" peerDependencies: vite: ^2.4.4 - checksum: aed62844d7aff39dae90e85a4a9f76dfe398acf14b0bc545e909cd10d30edc08a006f77eab3397ffbbeb25db89e46224aeae8ab3789c30dedffad12e92d1a834 + checksum: 9ae11525a6b4d111a6d655b7495c319cb99dc2aadaf2f5e1a6c311b3db32a93118f0d4b314f2c039a27e21a15a644bbfafbb7fb87963afcc06912b95c505505b languageName: node linkType: hard @@ -14502,7 +15630,7 @@ __metadata: svgo: "npm:^2.8.0" peerDependencies: vite: ^2 || ^3 || ^4 - checksum: cc958374186664babb3689dae6e98f54a95d669f6fbe1b1b15c267f04d6b1580e5b70c8d87c61e8897845cafd9d4cc56704ae762d5db6c50ceb41e1d8ec2b511 + checksum: 2f1ae63fae87b286548912f3da3e3b9ea4c77ee5aafd45144e29d594632e0684e9ebadb070cb088f90c275493a2a2e2df8958f288c3ac1c8e5429ff6ca79a317 languageName: node linkType: hard @@ -14515,7 +15643,7 @@ __metadata: "@svgr/plugin-jsx": "npm:^7.0.0" peerDependencies: vite: ^2.6.0 || 3 || 4 - checksum: f801759810be82e997acb26b6b0f8c6dc012d7bcb4d430e1e75ef210f6f05580c589b7f65c9729fe4993fa919433903b71a74ddfc490e41af69720cf857de9d9 + checksum: 19887e1db910ecdd6c12645e430d9e1d9ad40fe6945d3f7de68fc235fba0277586deffa47db1a6be2fa511207b01893a3c5bad9d1bd558ca28971feca13ecd9a languageName: node linkType: hard @@ -14531,7 +15659,7 @@ __metadata: peerDependenciesMeta: vite: optional: true - checksum: 04bd792bb4f6b4fb57ec8368cff076abffba8d6923af032affb14be43b6e2dfd8b25085947a3204d702a8c8e9d79d3c361373cf98566df682420728857906289 + checksum: 73a8467de72d7ac502328454fd00c19571cd4bad2dd5982643b24718bb95e449a3f4153cfc2d58a358bfc8f37e592fb442fc10884b59ae82138c1329160cd952 languageName: node linkType: hard @@ -14571,7 +15699,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 28e616abc86038aa73d856b77525193bd77d6ac7fe49f699a3b2a93586613d5f109f07c9917c294faa23b939d07e181c55f9a33392109d278550cc0c87a2d5a3 + checksum: c91d5228cd0b2410e95ea4b17279640a414f1a2d5290a01baec77351af2dda7d5901c240ed6a62de2b465567e328168d386da2aaa262d3a138fde827b289592d languageName: node linkType: hard @@ -14580,7 +15708,7 @@ __metadata: resolution: "w3c-xmlserializer@npm:4.0.0" dependencies: xml-name-validator: "npm:^4.0.0" - checksum: 02cc66d6efc590bd630086cd88252444120f5feec5c4043932b0d0f74f8b060512f79dc77eb093a7ad04b4f02f39da79ce4af47ceb600f2bf9eacdc83204b1a8 + checksum: eba070e78deb408ae8defa4d36b429f084b2b47a4741c4a9be3f27a0a3d1845e277e3072b04391a138f7e43776842627d1334e448ff13ff90ad9fb1214ee7091 languageName: node linkType: hard @@ -14589,7 +15717,7 @@ __metadata: resolution: "walker@npm:1.0.8" dependencies: makeerror: "npm:1.0.12" - checksum: a17e037bccd3ca8a25a80cb850903facdfed0de4864bd8728f1782370715d679fa72e0a0f5da7c1c1379365159901e5935f35be531229da53bbfc0efdabdb48e + checksum: ad7a257ea1e662e57ef2e018f97b3c02a7240ad5093c392186ce0bcf1f1a60bbadd520d073b9beb921ed99f64f065efb63dfc8eec689a80e569f93c1c5d5e16c languageName: node linkType: hard @@ -14599,35 +15727,44 @@ __metadata: dependencies: glob-to-regexp: "npm:^0.4.1" graceful-fs: "npm:^4.1.2" - checksum: c5e35f9fb9338d31d2141d9835643c0f49b5f9c521440bb648181059e5940d93dd8ed856aa8a33fbcdd4e121dad63c7e8c15c063cf485429cd9d427be197fe62 + checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131 + languageName: node + linkType: hard + +"wcwidth@npm:^1.0.1": + version: 1.0.1 + resolution: "wcwidth@npm:1.0.1" + dependencies: + defaults: ^1.0.3 + checksum: 814e9d1ddcc9798f7377ffa448a5a3892232b9275ebb30a41b529607691c0491de47cba426e917a4d08ded3ee7e9ba2f3fe32e62ee3cd9c7d3bafb7754bd553c languageName: node linkType: hard "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" - checksum: 5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db + checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c languageName: node linkType: hard "webidl-conversions@npm:^7.0.0": version: 7.0.0 resolution: "webidl-conversions@npm:7.0.0" - checksum: 228d8cb6d270c23b0720cb2d95c579202db3aaf8f633b4e9dd94ec2000a04e7e6e43b76a94509cdb30479bd00ae253ab2371a2da9f81446cc313f89a4213a2c4 + checksum: f05588567a2a76428515333eff87200fae6c83c3948a7482ebb109562971e77ef6dc49749afa58abb993391227c5697b3ecca52018793e0cb4620a48f10bd21b languageName: node linkType: hard "webpack-sources@npm:^3.2.3": version: 3.2.3 resolution: "webpack-sources@npm:3.2.3" - checksum: 2ef63d77c4fad39de4a6db17323d75eb92897b32674e97d76f0a1e87c003882fc038571266ad0ef581ac734cbe20952912aaa26155f1905e96ce251adbb1eb4e + checksum: 989e401b9fe3536529e2a99dac8c1bdc50e3a0a2c8669cbafad31271eadd994bc9405f88a3039cd2e29db5e6d9d0926ceb7a1a4e7409ece021fe79c37d9c4607 languageName: node linkType: hard -"webpack-virtual-modules@npm:^0.4.5": - version: 0.4.6 - resolution: "webpack-virtual-modules@npm:0.4.6" - checksum: d3ecd680289e04f6fac70f09a682385b176303cfdc69ad08f11fce6fa031f9c054b3e728cb54967da48f051cd2ebe3f0d0d02bf78d3dfc8a3a9be91ea7544bbb +"webpack-virtual-modules@npm:^0.6.1": + version: 0.6.1 + resolution: "webpack-virtual-modules@npm:0.6.1" + checksum: 0cd993d7b00af0ed89eee96ed6dcb2307fa8dc38e37f34e78690088314976aa79a31cf146553c5e414cdc87222878c5e4979abeb0b00bf6dc9c6f018604a1310 languageName: node linkType: hard @@ -14636,14 +15773,14 @@ __metadata: resolution: "whatwg-encoding@npm:2.0.0" dependencies: iconv-lite: "npm:0.6.3" - checksum: 91b90a49f312dc751496fd23a7e68981e62f33afe938b97281ad766235c4872fc4e66319f925c5e9001502b3040dd25a33b02a9c693b73a4cbbfdc4ad10c3e3e + checksum: 7087810c410aa9b689cbd6af8773341a53cdc1f3aae2a882c163bd5522ec8ca4cdfc269aef417a5792f411807d5d77d50df4c24e3abb00bb60192858a40cc675 languageName: node linkType: hard "whatwg-mimetype@npm:^3.0.0": version: 3.0.0 resolution: "whatwg-mimetype@npm:3.0.0" - checksum: 323895a1cda29a5fb0b9ca82831d2c316309fede0365047c4c323073e3239067a304a09a1f4b123b9532641ab604203f33a1403b5ca6a62ef405bcd7a204080f + checksum: ce08bbb36b6aaf64f3a84da89707e3e6a31e5ab1c1a2379fd68df79ba712a4ab090904f0b50e6693b0dafc8e6343a6157e40bf18fdffd26e513cf95ee2a59824 languageName: node linkType: hard @@ -14653,7 +15790,7 @@ __metadata: dependencies: tr46: "npm:^3.0.0" webidl-conversions: "npm:^7.0.0" - checksum: f7ec264976d7c725e0696fcaf9ebe056e14422eacbf92fdbb4462034609cba7d0c85ffa1aab05e9309d42969bcf04632ba5ed3f3882c516d7b093053315bf4c1 + checksum: ed4826aaa57e66bb3488a4b25c9cd476c46ba96052747388b5801f137dd740b73fde91ad207d96baf9f17fbcc80fc1a477ad65181b5eb5fa718d27c69501d7af languageName: node linkType: hard @@ -14663,7 +15800,7 @@ __metadata: dependencies: tr46: "npm:~0.0.3" webidl-conversions: "npm:^3.0.0" - checksum: 1588bed84d10b72d5eec1d0faa0722ba1962f1821e7539c535558fb5398d223b0c50d8acab950b8c488b4ba69043fd833cc2697056b167d8ad46fac3995a55d5 + checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c languageName: node linkType: hard @@ -14676,7 +15813,7 @@ __metadata: is-number-object: "npm:^1.0.4" is-string: "npm:^1.0.5" is-symbol: "npm:^1.0.3" - checksum: 0a62a03c00c91dd4fb1035b2f0733c341d805753b027eebd3a304b9cb70e8ce33e25317add2fe9b5fea6f53a175c0633ae701ff812e604410ddd049777cd435e + checksum: 53ce774c7379071729533922adcca47220228405e1895f26673bbd71bdf7fb09bee38c1d6399395927c6289476b5ae0629863427fd151491b71c4b6cb04f3a5e languageName: node linkType: hard @@ -14688,7 +15825,7 @@ __metadata: is-set: "npm:^2.0.1" is-weakmap: "npm:^2.0.1" is-weakset: "npm:^2.0.1" - checksum: 249f913e1758ed2f06f00706007d87dc22090a80591a56917376e70ecf8fc9ab6c41d98e1c87208bb9648676f65d4b09c0e4d23c56c7afb0f0a73a27d701df5d + checksum: c815bbd163107ef9cb84f135e6f34453eaf4cca994e7ba85ddb0d27cea724c623fae2a473ceccfd5549c53cc65a5d82692de418166df3f858e1e5dc60818581c languageName: node linkType: hard @@ -14702,7 +15839,7 @@ __metadata: gopd: "npm:^1.0.1" has-tostringtag: "npm:^1.0.0" is-typed-array: "npm:^1.1.10" - checksum: e85918fa7ee060b37e264996f560bbdfe0b1c7029772d0986f3a72ff62b6bd42ba624c4b80218b498aa42472b54f4514e46dbe869691730e0c6c025bcb25fe2b + checksum: 149f54f5d11773ce938c60a2c36306720a1824eccb62bda0620170932c2783fa50ad0226254c5741a962e35c7ccba5f4e4c402b8618cb3b4f2cf47bf5e6ade31 languageName: node linkType: hard @@ -14713,32 +15850,23 @@ __metadata: isexe: "npm:^2.0.0" bin: node-which: ./bin/node-which - checksum: 66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f + checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 languageName: node linkType: hard -"wide-align@npm:^1.1.2, wide-align@npm:^1.1.5": +"wide-align@npm:^1.1.5": version: 1.1.5 resolution: "wide-align@npm:1.1.5" dependencies: string-width: "npm:^1.0.2 || 2 || 3 || 4" - checksum: 1d9c2a3e36dfb09832f38e2e699c367ef190f96b82c71f809bc0822c306f5379df87bab47bed27ea99106d86447e50eb972d3c516c2f95782807a9d082fbea95 - languageName: node - linkType: hard - -"widest-line@npm:^3.1.0": - version: 3.1.0 - resolution: "widest-line@npm:3.1.0" - dependencies: - string-width: "npm:^4.0.0" - checksum: b1e623adcfb9df35350dd7fc61295d6d4a1eaa65a406ba39c4b8360045b614af95ad10e05abf704936ed022569be438c4bfa02d6d031863c4166a238c301119f + checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 languageName: node linkType: hard "wordwrap@npm:^1.0.0": version: 1.0.0 resolution: "wordwrap@npm:1.0.0" - checksum: 7ed2e44f3c33c5c3e3771134d2b0aee4314c9e49c749e37f464bf69f2bcdf0cbf9419ca638098e2717cff4875c47f56a007532f6111c3319f557a2ca91278e92 + checksum: 2a44b2788165d0a3de71fd517d4880a8e20ea3a82c080ce46e294f0b68b69a2e49cff5f99c600e275c698a90d12c5ea32aff06c311f0db2eb3f1201f3e7b2a04 languageName: node linkType: hard @@ -14749,7 +15877,7 @@ __metadata: ansi-styles: "npm:^4.0.0" string-width: "npm:^4.1.0" strip-ansi: "npm:^6.0.0" - checksum: d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da + checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b languageName: node linkType: hard @@ -14760,14 +15888,14 @@ __metadata: ansi-styles: "npm:^6.1.0" string-width: "npm:^5.0.1" strip-ansi: "npm:^7.0.1" - checksum: 138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 + checksum: 371733296dc2d616900ce15a0049dca0ef67597d6394c57347ba334393599e800bab03c41d4d45221b6bc967b8c453ec3ae4749eff3894202d16800fdfe0e238 languageName: node linkType: hard "wrappy@npm:1": version: 1.0.2 resolution: "wrappy@npm:1.0.2" - checksum: 56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0 + checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 languageName: node linkType: hard @@ -14778,7 +15906,7 @@ __metadata: graceful-fs: "npm:^4.1.11" imurmurhash: "npm:^0.1.4" signal-exit: "npm:^3.0.2" - checksum: 8cb4bba0c1ab814a9b127844da0db4fb8c5e06ddbe6317b8b319377c73b283673036c8b9360120062898508b9428d81611cf7fa97584504a00bc179b2a580b92 + checksum: 2db81f92ae974fd87ab4a5e7932feacaca626679a7c98fcc73ad8fcea5a1950eab32fa831f79e9391ac99b562ca091ad49be37a79045bd65f595efbb8f4596ae languageName: node linkType: hard @@ -14788,7 +15916,7 @@ __metadata: dependencies: imurmurhash: "npm:^0.1.4" signal-exit: "npm:^3.0.7" - checksum: a2c282c95ef5d8e1c27b335ae897b5eca00e85590d92a3fd69a437919b7b93ff36a69ea04145da55829d2164e724bc62202cdb5f4b208b425aba0807889375c7 + checksum: 5da60bd4eeeb935eec97ead3df6e28e5917a6bd317478e4a85a5285e8480b8ed96032bbcc6ecd07b236142a24f3ca871c924ec4a6575e623ec1b11bf8c1c253c languageName: node linkType: hard @@ -14797,7 +15925,7 @@ __metadata: resolution: "ws@npm:6.2.2" dependencies: async-limiter: "npm:~1.0.0" - checksum: d628a1e95668a296644b4f51ce5debb43d9f1d89ebb2e32fef205a685b9439378eb824d60ce3a40bbc3bad0e887d84a56b343f2076f48d74f17c4c0800c42967 + checksum: aec3154ec51477c094ac2cb5946a156e17561a581fa27005cbf22c53ac57f8d4e5f791dd4bbba6a488602cb28778c8ab7df06251d590507c3c550fd8ebeee949 languageName: node linkType: hard @@ -14812,78 +15940,56 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 579817dbbab3ee46669129c220cfd81ba6cdb9ab5c3e9a105702dd045743c4ab72e33bb384573827c0c481213417cc880e41bc097e0fc541a0b79fa3eb38207d + checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c languageName: node linkType: hard "xml-name-validator@npm:^4.0.0": version: 4.0.0 resolution: "xml-name-validator@npm:4.0.0" - checksum: c1bfa219d64e56fee265b2bd31b2fcecefc063ee802da1e73bad1f21d7afd89b943c9e2c97af2942f60b1ad46f915a4c81e00039c7d398b53cf410e29d3c30bd + checksum: af100b79c29804f05fa35aa3683e29a321db9b9685d5e5febda3fa1e40f13f85abc40f45a6b2bf7bee33f68a1dc5e8eaef4cec100a304a9db565e6061d4cb5ad languageName: node linkType: hard "xmlchars@npm:^2.2.0": version: 2.2.0 resolution: "xmlchars@npm:2.2.0" - checksum: b64b535861a6f310c5d9bfa10834cf49127c71922c297da9d4d1b45eeaae40bf9b4363275876088fbe2667e5db028d2cd4f8ee72eed9bede840a67d57dab7593 + checksum: 8c70ac94070ccca03f47a81fcce3b271bd1f37a591bf5424e787ae313fcb9c212f5f6786e1fa82076a2c632c0141552babcd85698c437506dfa6ae2d58723062 languageName: node linkType: hard "xtend@npm:^4.0.0, xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" - checksum: 366ae4783eec6100f8a02dff02ac907bf29f9a00b82ac0264b4d8b832ead18306797e283cf19de776538babfdcb2101375ec5646b59f08c52128ac4ab812ed0e + checksum: ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a languageName: node linkType: hard "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" - checksum: 4df2842c36e468590c3691c894bc9cdbac41f520566e76e24f59401ba7d8b4811eb1e34524d57e54bc6d864bcb66baab7ffd9ca42bf1eda596618f9162b91249 + checksum: 54f0fb95621ee60898a38c572c515659e51cc9d9f787fb109cef6fde4befbe1c4602dc999d30110feee37456ad0f1660fa2edcfde6a9a740f86a290999550d30 languageName: node linkType: hard "yallist@npm:^3.0.2": version: 3.1.1 resolution: "yallist@npm:3.1.1" - checksum: c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 + checksum: 48f7bb00dc19fc635a13a39fe547f527b10c9290e7b3e836b9a8f1ca04d4d342e85714416b3c2ab74949c9c66f9cebb0473e6bc353b79035356103b47641285d languageName: node linkType: hard "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" - checksum: 2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a - languageName: node - linkType: hard - -"yargs-parser@npm:^20.2.2, yargs-parser@npm:^20.2.9": - version: 20.2.9 - resolution: "yargs-parser@npm:20.2.9" - checksum: 0685a8e58bbfb57fab6aefe03c6da904a59769bd803a722bb098bd5b0f29d274a1357762c7258fb487512811b8063fb5d2824a3415a0a4540598335b3b086c72 + checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 languageName: node linkType: hard "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" - checksum: f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2 - languageName: node - linkType: hard - -"yargs@npm:^16.2.0": - version: 16.2.0 - resolution: "yargs@npm:16.2.0" - dependencies: - cliui: "npm:^7.0.2" - escalade: "npm:^3.1.1" - get-caller-file: "npm:^2.0.5" - require-directory: "npm:^2.1.1" - string-width: "npm:^4.2.0" - y18n: "npm:^5.0.5" - yargs-parser: "npm:^20.2.2" - checksum: b1dbfefa679848442454b60053a6c95d62f2d2e21dd28def92b647587f415969173c6e99a0f3bab4f1b67ee8283bf735ebe3544013f09491186ba9e8a9a2b651 + checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c languageName: node linkType: hard @@ -14898,7 +16004,7 @@ __metadata: string-width: "npm:^4.2.3" y18n: "npm:^5.0.5" yargs-parser: "npm:^21.1.1" - checksum: ccd7e723e61ad5965fffbb791366db689572b80cca80e0f96aad968dfff4156cd7cd1ad18607afe1046d8241e6fb2d6c08bf7fa7bfb5eaec818735d8feac8f05 + checksum: 73b572e863aa4a8cbef323dd911d79d193b772defd5a51aab0aca2d446655216f5002c42c5306033968193bdbf892a7a4c110b0d77954a7fdf563e653967b56a languageName: node linkType: hard @@ -14908,13 +16014,13 @@ __metadata: dependencies: buffer-crc32: "npm:~0.2.3" fd-slicer: "npm:~1.1.0" - checksum: f265002af7541b9ec3589a27f5fb8f11cf348b53cc15e2751272e3c062cd73f3e715bc72d43257de71bbaecae446c3f1b14af7559e8ab0261625375541816422 + checksum: 7f21fe0bbad6e2cb130044a5d1d0d5a0e5bf3d8d4f8c4e6ee12163ce798fee3de7388d22a7a0907f563ac5f9d40f8699a223d3d5c1718da90b0156da6904022b languageName: node linkType: hard "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" - checksum: dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f + checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard From 709f87cab17a58db9c5f858284259a406ac7f31e Mon Sep 17 00:00:00 2001 From: Aleksandr Alferov Date: Wed, 17 Jan 2024 11:55:34 +0000 Subject: [PATCH 040/151] ADCM-5204 Add tests for host-action for inventory --- python/cm/tests/bundles/cluster_1/config.yaml | 10 ++ .../files/response_templates/cluster.json.j2 | 4 +- .../files/response_templates/one_host.json.j2 | 4 +- .../files/response_templates/provider.json.j2 | 4 +- .../service_one_component.json.j2 | 8 +- .../service_two_components.json.j2 | 12 +- .../response_templates/two_hosts.json.j2 | 8 +- .../two_services_two_components_each.json.j2 | 24 +--- python/cm/tests/test_inventory/base.py | 18 +-- .../test_inventory/test_cluster_hosts.py | 8 +- .../tests/test_inventory/test_components.py | 76 +--------- .../tests/test_inventory/test_host_action.py | 134 ++++++++++++++++++ 12 files changed, 169 insertions(+), 141 deletions(-) create mode 100644 python/cm/tests/test_inventory/test_host_action.py diff --git a/python/cm/tests/bundles/cluster_1/config.yaml b/python/cm/tests/bundles/cluster_1/config.yaml index 4b7105c1d2..93aa33c71f 100644 --- a/python/cm/tests/bundles/cluster_1/config.yaml +++ b/python/cm/tests/bundles/cluster_1/config.yaml @@ -32,6 +32,14 @@ script_type: ansible states: available: any + host_action_on_cluster: &host_action + type: job + script: ./playbook.yaml + script_type: ansible + host_action: true + states: + available: any + - name: service_one_component type: service @@ -39,6 +47,7 @@ config: *config actions: action_on_service: *action + host_action_on_service: *host_action components: component_1: @@ -46,6 +55,7 @@ config: *config actions: action_on_component: *action + host_action_on_component: *host_action - name: service_two_components type: service diff --git a/python/cm/tests/files/response_templates/cluster.json.j2 b/python/cm/tests/files/response_templates/cluster.json.j2 index 738e834bf8..7bebb3020d 100644 --- a/python/cm/tests/files/response_templates/cluster.json.j2 +++ b/python/cm/tests/files/response_templates/cluster.json.j2 @@ -1,9 +1,7 @@ { "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ password }}" - }, + "password": "password", "string": "string", "list": [ "value1", diff --git a/python/cm/tests/files/response_templates/one_host.json.j2 b/python/cm/tests/files/response_templates/one_host.json.j2 index c8d616ffc8..4de9dd861f 100644 --- a/python/cm/tests/files/response_templates/one_host.json.j2 +++ b/python/cm/tests/files/response_templates/one_host.json.j2 @@ -1,9 +1,7 @@ { "{{ host_fqdn }}": { "integer": 10, - "password": { - "__ansible_vault": "{{ password }}" - }, + "password": "password", "string": "string", "list": [ "value1", diff --git a/python/cm/tests/files/response_templates/provider.json.j2 b/python/cm/tests/files/response_templates/provider.json.j2 index 0752743aa1..317b9b1457 100644 --- a/python/cm/tests/files/response_templates/provider.json.j2 +++ b/python/cm/tests/files/response_templates/provider.json.j2 @@ -1,9 +1,7 @@ { "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ password }}" - }, + "password": "password", "string": "string", "list": [ "value1", diff --git a/python/cm/tests/files/response_templates/service_one_component.json.j2 b/python/cm/tests/files/response_templates/service_one_component.json.j2 index fb312a6525..926ae3a4af 100644 --- a/python/cm/tests/files/response_templates/service_one_component.json.j2 +++ b/python/cm/tests/files/response_templates/service_one_component.json.j2 @@ -6,9 +6,7 @@ "multi_state": [], "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ service_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", @@ -25,9 +23,7 @@ "component_id": {{ component_id }}, "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ component_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", diff --git a/python/cm/tests/files/response_templates/service_two_components.json.j2 b/python/cm/tests/files/response_templates/service_two_components.json.j2 index bc677c351b..9ba97fec92 100644 --- a/python/cm/tests/files/response_templates/service_two_components.json.j2 +++ b/python/cm/tests/files/response_templates/service_two_components.json.j2 @@ -6,9 +6,7 @@ "multi_state": [], "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ service_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", @@ -25,9 +23,7 @@ "component_id": {{ component_1_id }}, "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ component_1_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", @@ -47,9 +43,7 @@ "component_id": {{ component_2_id }}, "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ component_2_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", diff --git a/python/cm/tests/files/response_templates/two_hosts.json.j2 b/python/cm/tests/files/response_templates/two_hosts.json.j2 index 59e3f34683..20d5ba4704 100644 --- a/python/cm/tests/files/response_templates/two_hosts.json.j2 +++ b/python/cm/tests/files/response_templates/two_hosts.json.j2 @@ -1,9 +1,7 @@ { "host_1": { "integer": 10, - "password": { - "__ansible_vault": "{{ host_1_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", @@ -16,9 +14,7 @@ }, "host_2": { "integer": 10, - "password": { - "__ansible_vault": "{{ host_2_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", diff --git a/python/cm/tests/files/response_templates/two_services_two_components_each.json.j2 b/python/cm/tests/files/response_templates/two_services_two_components_each.json.j2 index 89b203ff02..13452a9440 100644 --- a/python/cm/tests/files/response_templates/two_services_two_components_each.json.j2 +++ b/python/cm/tests/files/response_templates/two_services_two_components_each.json.j2 @@ -6,9 +6,7 @@ "multi_state": [], "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ service_1_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", @@ -25,9 +23,7 @@ "component_id": {{ component_1_s1_id }}, "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ component_1_s1_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", @@ -47,9 +43,7 @@ "component_id": {{ component_2_s1_id }}, "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ component_2_s1_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", @@ -73,9 +67,7 @@ "multi_state": [], "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ service_2_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", @@ -92,9 +84,7 @@ "component_id": {{ component_1_s2_id }}, "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ component_1_s2_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", @@ -114,9 +104,7 @@ "component_id": {{ component_2_s2_id }}, "config": { "integer": 10, - "password": { - "__ansible_vault": "{{ component_2_s2_password }}" - }, + "password": "password", "string": "string", "list": [ "value1", diff --git a/python/cm/tests/test_inventory/base.py b/python/cm/tests/test_inventory/base.py index 29c23ed3de..87c703395f 100644 --- a/python/cm/tests/test_inventory/base.py +++ b/python/cm/tests/test_inventory/base.py @@ -18,15 +18,7 @@ from cm.adcm_config.ansible import ansible_decrypt from cm.api import add_hc from cm.inventory import get_inventory_data -from cm.models import ( - Action, - ADCMEntity, - Cluster, - ConfigLog, - Host, - HostComponent, - ServiceComponent, -) +from cm.models import Action, ADCMEntity, Cluster, Host, HostComponent, ServiceComponent from django.conf import settings from jinja2 import Template @@ -65,7 +57,9 @@ def check_hosts_topology(self, data: Mapping[str, dict], expected: Mapping[str, for group_name, host_names in expected.items(): errors = set(data[group_name]["hosts"].keys()).symmetric_difference(set(host_names)) - self.assertSetEqual(errors, set()) + self.assertSetEqual( + errors, set(), msg=f"Host(s): '{', '.join(errors)}' should not be in the '{group_name}' group" + ) @staticmethod def set_hostcomponent(cluster: Cluster, entries: Iterable[tuple[Host, ServiceComponent]]) -> list[HostComponent]: @@ -95,21 +89,19 @@ def get_action_on_host_expected_template_data_part(self, host: Host) -> Template { "host_fqdn": host.fqdn, "adcm_hostid": host.pk, - "password": ConfigLog.objects.get(pk=host.config.current).config["password"], }, ), ("HOST", "vars", "provider"): ( self.templates_dir / "provider.json.j2", { "id": host.provider.pk, - "password": ConfigLog.objects.get(pk=host.provider.config.current).config["password"], "host_prototype_id": host.prototype.pk, }, ), } def assert_inventory(self, obj: ADCMEntity, action: Action, expected_topology: dict, expected_data: dict): - actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] + actual_inventory = decrypt_secrets(source=get_inventory_data(obj=obj, action=action)["all"]["children"]) self.check_hosts_topology(data=actual_inventory, expected=expected_topology) self.check_data_by_template(data=actual_inventory, templates_data=expected_data) diff --git a/python/cm/tests/test_inventory/test_cluster_hosts.py b/python/cm/tests/test_inventory/test_cluster_hosts.py index fd91fdab8f..39ed0b5c2d 100644 --- a/python/cm/tests/test_inventory/test_cluster_hosts.py +++ b/python/cm/tests/test_inventory/test_cluster_hosts.py @@ -13,7 +13,7 @@ from pathlib import Path -from cm.models import Action, ConfigLog +from cm.models import Action from cm.tests.test_inventory.base import BaseInventoryTestCase @@ -42,7 +42,6 @@ def test_cluster_action_on_cluster(self): self.templates_dir / "cluster.json.j2", { "id": self.cluster_1.pk, - "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], }, ), } @@ -71,14 +70,12 @@ def test_add_1_host_on_cluster_actions(self): { "host_fqdn": host_1.fqdn, "adcm_hostid": host_1.pk, - "password": ConfigLog.objects.get(pk=host_1.config.current).config["password"], }, ), ("CLUSTER", "vars", "cluster"): ( self.templates_dir / "cluster.json.j2", { "id": self.cluster_1.pk, - "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], }, ), } @@ -117,16 +114,13 @@ def test_add_2_hosts_on_cluster_actions(self): self.templates_dir / "two_hosts.json.j2", { "host_1_id": host_1.pk, - "host_1_password": ConfigLog.objects.get(pk=host_1.config.current).config["password"], "host_2_id": host_2.pk, - "host_2_password": ConfigLog.objects.get(pk=host_2.config.current).config["password"], }, ), ("CLUSTER", "vars", "cluster"): ( self.templates_dir / "cluster.json.j2", { "id": self.cluster_1.pk, - "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], }, ), } diff --git a/python/cm/tests/test_inventory/test_components.py b/python/cm/tests/test_inventory/test_components.py index c32322083c..8bb777456a 100644 --- a/python/cm/tests/test_inventory/test_components.py +++ b/python/cm/tests/test_inventory/test_components.py @@ -15,15 +15,8 @@ from api_v2.service.utils import bulk_add_services_to_cluster from cm.inventory import get_inventory_data -from cm.models import ( - Action, - ClusterObject, - ConfigLog, - ObjectType, - Prototype, - ServiceComponent, -) -from cm.tests.test_inventory.base import BaseInventoryTestCase +from cm.models import Action, ClusterObject, ObjectType, Prototype, ServiceComponent +from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets class TestInventoryComponents(BaseInventoryTestCase): @@ -107,25 +100,19 @@ def test_1_component_1_host(self): { "host_fqdn": self.host_1.fqdn, "adcm_hostid": self.host_1.pk, - "password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], }, ), ("CLUSTER", "vars", "cluster"): ( self.templates_dir / "cluster.json.j2", { "id": self.cluster_1.pk, - "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], }, ), ("CLUSTER", "vars", "services"): ( self.templates_dir / "service_one_component.json.j2", { "service_id": service_one_component.pk, - "service_password": ConfigLog.objects.get(pk=service_one_component.config.current).config[ - "password" - ], "component_id": component_1.pk, - "component_password": ConfigLog.objects.get(pk=component_1.config.current).config["password"], }, ), } @@ -188,29 +175,21 @@ def test_2_components_2_hosts_mapped_all_to_all(self): self.templates_dir / "two_hosts.json.j2", { "host_1_id": self.host_1.pk, - "host_1_password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], "host_2_id": self.host_2.pk, - "host_2_password": ConfigLog.objects.get(pk=self.host_2.config.current).config["password"], }, ), ("CLUSTER", "vars", "cluster"): ( self.templates_dir / "cluster.json.j2", { "id": self.cluster_1.pk, - "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], }, ), ("CLUSTER", "vars", "services"): ( self.templates_dir / "service_two_components.json.j2", { "service_id": service_two_components.pk, - "service_password": ConfigLog.objects.get(pk=service_two_components.config.current).config[ - "password" - ], "component_1_id": component_1.pk, - "component_1_password": ConfigLog.objects.get(pk=component_1.config.current).config["password"], "component_2_id": component_2.pk, - "component_2_password": ConfigLog.objects.get(pk=component_2.config.current).config["password"], }, ), } @@ -234,7 +213,7 @@ def test_2_components_2_hosts_mapped_all_to_all(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - actual_inventory = get_inventory_data(obj=obj, action=action)["all"]["children"] + actual_inventory = decrypt_secrets(source=get_inventory_data(obj=obj, action=action)["all"]["children"]) self.check_hosts_topology(data=actual_inventory, expected=expected_topology) self.check_data_by_template(data=actual_inventory, templates_data=expected_data) @@ -281,29 +260,21 @@ def test_2_components_2_hosts_mapped_in_pairs(self): self.templates_dir / "two_hosts.json.j2", { "host_1_id": self.host_1.pk, - "host_1_password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], "host_2_id": self.host_2.pk, - "host_2_password": ConfigLog.objects.get(pk=self.host_2.config.current).config["password"], }, ), ("CLUSTER", "vars", "cluster"): ( self.templates_dir / "cluster.json.j2", { "id": self.cluster_1.pk, - "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], }, ), ("CLUSTER", "vars", "services"): ( self.templates_dir / "service_two_components.json.j2", { "service_id": service_two_components.pk, - "service_password": ConfigLog.objects.get(pk=service_two_components.config.current).config[ - "password" - ], "component_1_id": component_1.pk, - "component_1_password": ConfigLog.objects.get(pk=component_1.config.current).config["password"], "component_2_id": component_2.pk, - "component_2_password": ConfigLog.objects.get(pk=component_2.config.current).config["password"], }, ), } @@ -384,43 +355,23 @@ def test_2_services_2_components_each_on_1_host(self): { "host_fqdn": self.host_1.fqdn, "adcm_hostid": self.host_1.pk, - "password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], }, ), ("CLUSTER", "vars", "cluster"): ( self.templates_dir / "cluster.json.j2", { "id": self.cluster_1.pk, - "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], }, ), ("CLUSTER", "vars", "services"): ( self.templates_dir / "two_services_two_components_each.json.j2", { "service_1_id": service_two_components.pk, - "service_1_password": ConfigLog.objects.get(pk=service_two_components.config.current).config[ - "password" - ], "component_1_s1_id": component_1_s1.pk, - "component_1_s1_password": ConfigLog.objects.get(pk=component_1_s1.config.current).config[ - "password" - ], "component_2_s1_id": component_2_s1.pk, - "component_2_s1_password": ConfigLog.objects.get(pk=component_2_s1.config.current).config[ - "password" - ], "service_2_id": another_service_two_components.pk, - "service_2_password": ConfigLog.objects.get( - pk=another_service_two_components.config.current - ).config["password"], "component_1_s2_id": component_1_s2.pk, - "component_1_s2_password": ConfigLog.objects.get(pk=component_1_s2.config.current).config[ - "password" - ], "component_2_s2_id": component_2_s2.pk, - "component_2_s2_password": ConfigLog.objects.get(pk=component_2_s2.config.current).config[ - "password" - ], }, ), } @@ -500,45 +451,24 @@ def test_2_services_2_components_each_2_hosts_cross_mapping(self): self.templates_dir / "two_hosts.json.j2", { "host_1_id": self.host_1.pk, - "host_1_password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], "host_2_id": self.host_2.pk, - "host_2_password": ConfigLog.objects.get(pk=self.host_2.config.current).config["password"], }, ), ("CLUSTER", "vars", "cluster"): ( self.templates_dir / "cluster.json.j2", { "id": self.cluster_1.pk, - "password": ConfigLog.objects.get(pk=self.cluster_1.config.current).config["password"], }, ), ("CLUSTER", "vars", "services"): ( self.templates_dir / "two_services_two_components_each.json.j2", { "service_1_id": service_two_components.pk, - "service_1_password": ConfigLog.objects.get(pk=service_two_components.config.current).config[ - "password" - ], "component_1_s1_id": component_1_s1.pk, - "component_1_s1_password": ConfigLog.objects.get(pk=component_1_s1.config.current).config[ - "password" - ], "component_2_s1_id": component_2_s1.pk, - "component_2_s1_password": ConfigLog.objects.get(pk=component_2_s1.config.current).config[ - "password" - ], "service_2_id": another_service_two_components.pk, - "service_2_password": ConfigLog.objects.get( - pk=another_service_two_components.config.current - ).config["password"], "component_1_s2_id": component_1_s2.pk, - "component_1_s2_password": ConfigLog.objects.get(pk=component_1_s2.config.current).config[ - "password" - ], "component_2_s2_id": component_2_s2.pk, - "component_2_s2_password": ConfigLog.objects.get(pk=component_2_s2.config.current).config[ - "password" - ], }, ), } diff --git a/python/cm/tests/test_inventory/test_host_action.py b/python/cm/tests/test_inventory/test_host_action.py new file mode 100644 index 0000000000..d622fdff0f --- /dev/null +++ b/python/cm/tests/test_inventory/test_host_action.py @@ -0,0 +1,134 @@ +# Licensed 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. + +from pathlib import Path + +from api_v2.service.utils import bulk_add_services_to_cluster +from cm.inventory import get_inventory_data +from cm.models import Action, ClusterObject, ObjectType, Prototype, ServiceComponent +from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets + + +class TestHostAction(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes + def setUp(self) -> None: + bundles_dir = Path(__file__).parent.parent / "bundles" + self.templates_dir = Path(__file__).parent.parent / "files/response_templates" + + self.provider_bundle = self.add_bundle(source_dir=bundles_dir / "provider") + cluster_bundle = self.add_bundle(source_dir=bundles_dir / "cluster_1") + + self.cluster = self.add_cluster(bundle=cluster_bundle, name="cluster_1") + self.provider = self.add_provider(bundle=self.provider_bundle, name="provider") + self.host_1 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_1", cluster=self.cluster + ) + self.host_2 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster + ) + + self.service: ClusterObject = bulk_add_services_to_cluster( + cluster=self.cluster, + prototypes=Prototype.objects.filter( + type=ObjectType.SERVICE, name="service_one_component", bundle=self.cluster.prototype.bundle + ), + ).get() + + self.component = ServiceComponent.objects.get(service=self.service, prototype__name="component_1") + self.add_hostcomponent_map( + cluster=self.cluster, + hc_map=[ + {"service_id": self.service.pk, "component_id": self.component.pk, "host_id": self.host_1.pk}, + {"service_id": self.service.pk, "component_id": self.component.pk, "host_id": self.host_2.pk}, + ], + ) + + def test_host_action(self): + host_names = [self.host_1.fqdn, self.host_2.fqdn] + expected_topology = { + "CLUSTER": host_names, + self.service.name: host_names, + f"{self.service.name}.{self.component.name}": host_names, + "HOST": [self.host_1.fqdn], + "target": [self.host_1.fqdn], + } + + expected_data = { + ("CLUSTER", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_2_id": self.host_2.pk, + }, + ), + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster.pk, + }, + ), + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "service_one_component.json.j2", + { + "service_id": self.service.pk, + "component_id": self.component.pk, + }, + ), + ("HOST", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + }, + ), + ("HOST", "vars", "provider"): ( + self.templates_dir / "provider.json.j2", + { + "id": self.provider.pk, + "host_prototype_id": self.host_1.prototype.pk, + }, + ), + ("target", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + }, + ), + ("target", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster.pk, + }, + ), + ("target", "vars", "services"): ( + self.templates_dir / "service_one_component.json.j2", + { + "service_id": self.service.pk, + "component_id": self.component.pk, + }, + ), + } + actions = [ + Action.objects.get(name="host_action_on_cluster", prototype=self.cluster.prototype), + Action.objects.get(name="host_action_on_service", prototype=self.service.prototype), + Action.objects.get(name="host_action_on_component", prototype=self.component.prototype), + ] + for action in actions: + with self.subTest( + msg=f"Object: {self.host_1.prototype.type} #{self.host_1.pk} {self.host_1.name}, action: {action.name}" + ): + actual_inventory = decrypt_secrets( + source=get_inventory_data(obj=self.host_1, action=action)["all"]["children"] + ) + + self.check_hosts_topology(data=actual_inventory, expected=expected_topology) + self.check_data_by_template(data=actual_inventory, templates_data=expected_data) From 2b32cc8efc7bacc280dae8780d1e3ef62125b5c9 Mon Sep 17 00:00:00 2001 From: Egor Araslanov Date: Thu, 18 Jan 2024 10:44:16 +0500 Subject: [PATCH 041/151] ADCM-5217 Fix bug with cluster creation with non-existing prototype id --- python/api_v2/cluster/views.py | 12 +++++++----- python/api_v2/tests/test_cluster.py | 11 +++++++++++ python/cm/errors.py | 4 ++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/python/api_v2/cluster/views.py b/python/api_v2/cluster/views.py index 75c3e4f6b8..8450b1f5d1 100644 --- a/python/api_v2/cluster/views.py +++ b/python/api_v2/cluster/views.py @@ -58,6 +58,7 @@ HTTP_201_CREATED, HTTP_204_NO_CONTENT, HTTP_403_FORBIDDEN, + HTTP_409_CONFLICT, ) from adcm.permissions import ( @@ -106,11 +107,12 @@ def create(self, request, *args, **kwargs): serializer.is_valid(raise_exception=True) valid = serializer.validated_data - cluster = add_cluster( - prototype=Prototype.objects.get(pk=valid["prototype_id"], type=ObjectType.CLUSTER), - name=valid["name"], - description=valid["description"], - ) + prototype = Prototype.objects.filter(pk=valid["prototype_id"], type=ObjectType.CLUSTER).first() + + if not prototype: + raise AdcmEx(code="PROTOTYPE_NOT_FOUND", http_code=HTTP_409_CONFLICT) + + cluster = add_cluster(prototype=prototype, name=valid["name"], description=valid["description"]) return Response(data=ClusterSerializer(cluster).data, status=HTTP_201_CREATED) diff --git a/python/api_v2/tests/test_cluster.py b/python/api_v2/tests/test_cluster.py index 59e2e9fc25..ed06a271b9 100644 --- a/python/api_v2/tests/test_cluster.py +++ b/python/api_v2/tests/test_cluster.py @@ -196,6 +196,17 @@ def test_create_same_name_fail(self): ) self.assertEqual(response.status_code, HTTP_409_CONFLICT) + def test_create_non_existent_prototype_fail(self): + response = self.client.post( + path=reverse(viewname="v2:cluster-list"), + data={ + "prototypeId": self.get_non_existent_pk(Prototype), + "name": "cool name", + "description": "Test cluster description", + }, + ) + self.assertEqual(response.status_code, HTTP_409_CONFLICT) + def test_update_failed(self): wrong_cluster_name = "__new_test_cluster_name" correct_cluster_name = "new_test_cluster_name" diff --git a/python/cm/errors.py b/python/cm/errors.py index 5d931c1598..d539f1b70f 100644 --- a/python/cm/errors.py +++ b/python/cm/errors.py @@ -254,12 +254,12 @@ def get_error(code): class AdcmEx(APIException): - def __init__(self, code, msg="", http_code="", args=""): + def __init__(self, code, msg="", http_code: int | None = None, args=""): err_code, err_msg, err_http_code, level = get_error(code) if msg != "": err_msg = msg - if http_code != "": + if http_code is not None: err_http_code = http_code self.msg = err_msg From e2e4946359d0488c51398a214ff9af8eb962c35f Mon Sep 17 00:00:00 2001 From: Daniil Skrynnik Date: Thu, 18 Jan 2024 09:58:53 +0000 Subject: [PATCH 042/151] ADCM-5203: Add tests for actions with hc_acl --- python/cm/tests/bundles/cluster_1/config.yaml | 17 +- python/cm/tests/test_inventory/base.py | 12 +- .../tests/test_inventory/test_components.py | 64 ++-- .../test_inventory/test_hc_acl_actions.py | 330 ++++++++++++++++++ 4 files changed, 382 insertions(+), 41 deletions(-) create mode 100644 python/cm/tests/test_inventory/test_hc_acl_actions.py diff --git a/python/cm/tests/bundles/cluster_1/config.yaml b/python/cm/tests/bundles/cluster_1/config.yaml index 93aa33c71f..2c069a0571 100644 --- a/python/cm/tests/bundles/cluster_1/config.yaml +++ b/python/cm/tests/bundles/cluster_1/config.yaml @@ -39,7 +39,21 @@ host_action: true states: available: any - + hc_acl_action_on_cluster: &hc_acl_action + <<: *action + hc_acl: + - service: service_two_components + component: component_1 + action: add + - service: service_two_components + component: component_1 + action: remove + - service: service_two_components + component: component_2 + action: add + - service: service_two_components + component: component_2 + action: remove - name: service_one_component type: service @@ -63,6 +77,7 @@ config: *config actions: action_on_service: *action + hc_acl_action_on_service: *hc_acl_action components: component_1: diff --git a/python/cm/tests/test_inventory/base.py b/python/cm/tests/test_inventory/base.py index 87c703395f..90854ea89e 100644 --- a/python/cm/tests/test_inventory/base.py +++ b/python/cm/tests/test_inventory/base.py @@ -13,7 +13,7 @@ from functools import reduce from json import loads from pathlib import Path -from typing import Any, Iterable, Mapping, TypeAlias +from typing import Any, Iterable, Literal, Mapping, TypeAlias from cm.adcm_config.ansible import ansible_decrypt from cm.api import add_hc @@ -25,6 +25,8 @@ from adcm.tests.base import BaseTestCase, BusinessLogicMixin TemplatesData: TypeAlias = Mapping[tuple[str, ...], tuple[Path, Mapping[str, Any]]] +MappingEntry: TypeAlias = dict[Literal["host_id", "component_id", "service_id"], int] +Delta: TypeAlias = dict[Literal["add", "remove"], dict[str, dict[str, Host]]] def decrypt_secrets(source: dict) -> dict: @@ -100,8 +102,12 @@ def get_action_on_host_expected_template_data_part(self, host: Host) -> Template ), } - def assert_inventory(self, obj: ADCMEntity, action: Action, expected_topology: dict, expected_data: dict): - actual_inventory = decrypt_secrets(source=get_inventory_data(obj=obj, action=action)["all"]["children"]) + def assert_inventory( + self, obj: ADCMEntity, action: Action, expected_topology: dict, expected_data: dict, delta: Delta | None = None + ) -> None: + actual_inventory = decrypt_secrets( + source=get_inventory_data(obj=obj, action=action, delta=delta)["all"]["children"] + ) self.check_hosts_topology(data=actual_inventory, expected=expected_topology) self.check_data_by_template(data=actual_inventory, templates_data=expected_data) diff --git a/python/cm/tests/test_inventory/test_components.py b/python/cm/tests/test_inventory/test_components.py index 8bb777456a..6ee301f0de 100644 --- a/python/cm/tests/test_inventory/test_components.py +++ b/python/cm/tests/test_inventory/test_components.py @@ -13,10 +13,8 @@ # pylint: disable=attribute-defined-outside-init,too-many-locals -from api_v2.service.utils import bulk_add_services_to_cluster -from cm.inventory import get_inventory_data -from cm.models import Action, ClusterObject, ObjectType, Prototype, ServiceComponent -from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets +from cm.models import Action, ClusterObject, ServiceComponent +from cm.tests.test_inventory.base import BaseInventoryTestCase class TestInventoryComponents(BaseInventoryTestCase): @@ -35,20 +33,14 @@ def setUp(self) -> None: def _prepare_two_services( self, ) -> tuple[ClusterObject, ServiceComponent, ServiceComponent, ClusterObject, ServiceComponent, ServiceComponent]: - service_two_components: ClusterObject = bulk_add_services_to_cluster( - cluster=self.cluster_1, - prototypes=Prototype.objects.filter( - type=ObjectType.SERVICE, name="service_two_components", bundle=self.cluster_1.prototype.bundle - ), + service_two_components: ClusterObject = self.add_services_to_cluster( + service_names=["service_two_components"], cluster=self.cluster_1 ).get() component_1_s1 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_1") component_2_s1 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_2") - another_service_two_components: ClusterObject = bulk_add_services_to_cluster( - cluster=self.cluster_1, - prototypes=Prototype.objects.filter( - type=ObjectType.SERVICE, name="another_service_two_components", bundle=self.cluster_1.prototype.bundle - ), + another_service_two_components: ClusterObject = self.add_services_to_cluster( + service_names=["another_service_two_components"], cluster=self.cluster_1 ).get() component_1_s2 = ServiceComponent.objects.get( service=another_service_two_components, prototype__name="component_1" @@ -67,11 +59,8 @@ def _prepare_two_services( ) def test_1_component_1_host(self): - service_one_component: ClusterObject = bulk_add_services_to_cluster( - cluster=self.cluster_1, - prototypes=Prototype.objects.filter( - type=ObjectType.SERVICE, name="service_one_component", bundle=self.cluster_1.prototype.bundle - ), + service_one_component: ClusterObject = self.add_services_to_cluster( + service_names=["service_one_component"], cluster=self.cluster_1 ).get() component_1 = ServiceComponent.objects.get(service=service_one_component, prototype__name="component_1") @@ -129,18 +118,17 @@ def test_1_component_1_host(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory(obj, action, expected_topology, expected_data) + self.assert_inventory( + obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data + ) def test_2_components_2_hosts_mapped_all_to_all(self): self.host_2 = self.add_host( bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster_1 ) - service_two_components: ClusterObject = bulk_add_services_to_cluster( - cluster=self.cluster_1, - prototypes=Prototype.objects.filter( - type=ObjectType.SERVICE, name="service_two_components", bundle=self.cluster_1.prototype.bundle - ), + service_two_components: ClusterObject = self.add_services_to_cluster( + service_names=["service_two_components"], cluster=self.cluster_1 ).get() component_1 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_1") component_2 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_2") @@ -213,21 +201,17 @@ def test_2_components_2_hosts_mapped_all_to_all(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - actual_inventory = decrypt_secrets(source=get_inventory_data(obj=obj, action=action)["all"]["children"]) - - self.check_hosts_topology(data=actual_inventory, expected=expected_topology) - self.check_data_by_template(data=actual_inventory, templates_data=expected_data) + self.assert_inventory( + obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data + ) def test_2_components_2_hosts_mapped_in_pairs(self): self.host_2 = self.add_host( bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster_1 ) - service_two_components: ClusterObject = bulk_add_services_to_cluster( - cluster=self.cluster_1, - prototypes=Prototype.objects.filter( - type=ObjectType.SERVICE, name="service_two_components", bundle=self.cluster_1.prototype.bundle - ), + service_two_components: ClusterObject = self.add_services_to_cluster( + service_names=["service_two_components"], cluster=self.cluster_1 ).get() component_1 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_1") component_2 = ServiceComponent.objects.get(service=service_two_components, prototype__name="component_2") @@ -298,7 +282,9 @@ def test_2_components_2_hosts_mapped_in_pairs(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory(obj, action, expected_topology, expected_data) + self.assert_inventory( + obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data + ) def test_2_services_2_components_each_on_1_host(self): ( @@ -392,7 +378,9 @@ def test_2_services_2_components_each_on_1_host(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory(obj, action, expected_topology, expected_data) + self.assert_inventory( + obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data + ) def test_2_services_2_components_each_2_hosts_cross_mapping(self): self.host_2 = self.add_host( @@ -495,4 +483,6 @@ def test_2_services_2_components_each_2_hosts_cross_mapping(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory(obj, action, expected_topology, expected_data) + self.assert_inventory( + obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data + ) diff --git a/python/cm/tests/test_inventory/test_hc_acl_actions.py b/python/cm/tests/test_inventory/test_hc_acl_actions.py new file mode 100644 index 0000000000..1ef9c6bf6a --- /dev/null +++ b/python/cm/tests/test_inventory/test_hc_acl_actions.py @@ -0,0 +1,330 @@ +# Licensed 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. + +# pylint: disable=too-many-instance-attributes + + +from cm.inventory import HcAclAction +from cm.models import Action, ClusterObject, Host, HostComponent, ServiceComponent +from cm.tests.test_inventory.base import BaseInventoryTestCase, Delta, MappingEntry + + +class TestInventoryHcAclActions(BaseInventoryTestCase): + def setUp(self) -> None: + super().setUp() + + self.provider_bundle = self.add_bundle(source_dir=self.bundles_dir / "provider") + cluster_bundle = self.add_bundle(source_dir=self.bundles_dir / "cluster_1") + + self.cluster_1 = self.add_cluster(bundle=cluster_bundle, name="cluster_1") + self.provider = self.add_provider(bundle=self.provider_bundle, name="provider") + self.host_1 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_1", cluster=self.cluster_1 + ) + self.host_2 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster_1 + ) + self.service: ClusterObject = self.add_services_to_cluster( + service_names=["service_two_components"], cluster=self.cluster_1 + ).get() + self.component_1 = ServiceComponent.objects.get(prototype__name="component_1", service=self.service) + self.component_2 = ServiceComponent.objects.get(prototype__name="component_2", service=self.service) + + self.hc_acl_action_cluster = Action.objects.get( + name="hc_acl_action_on_cluster", prototype=self.cluster_1.prototype + ) + self.hc_acl_action_service = Action.objects.get( + name="hc_acl_action_on_service", prototype=self.service.prototype + ) + + self.initial_hc_h1_c1 = [ + { + "service_id": self.service.pk, + "component_id": self.component_1.pk, + "host_id": self.host_1.pk, + } + ] + self.expected_data = { + ("CLUSTER", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_2_id": self.host_2.pk, + }, + ), + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "cluster.json.j2", + { + "id": self.cluster_1.pk, + }, + ), + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "service_two_components.json.j2", + { + "service_id": self.service.pk, + "component_1_id": self.component_1.pk, + "component_2_id": self.component_2.pk, + }, + ), + } + + @staticmethod + def _get_mapping_delta(cluster, new_mapping: list[MappingEntry]) -> Delta: + existing_mapping_ids = set( + (hc.host.pk, hc.component.pk, hc.service.pk) for hc in HostComponent.objects.filter(cluster=cluster) + ) + new_mapping_ids = set((hc["host_id"], hc["component_id"], hc["service_id"]) for hc in new_mapping) + + added = {} + for host_id, component_id, service_id in new_mapping_ids.difference(existing_mapping_ids): + host = Host.objects.get(pk=host_id, cluster=cluster) + service = ClusterObject.objects.get(pk=service_id, cluster=cluster) + component = ServiceComponent.objects.get(pk=component_id, cluster=cluster, service=service) + + added.setdefault(f"{service.name}.{component.name}", {}).setdefault(host.fqdn, host) + + removed = {} + for host_id, component_id, service_id in existing_mapping_ids.difference(new_mapping_ids): + host = Host.objects.get(pk=host_id, cluster=cluster) + service = ClusterObject.objects.get(pk=service_id, cluster=cluster) + component = ServiceComponent.objects.get(pk=component_id, cluster=cluster, service=service) + + removed.setdefault(f"{service.name}.{component.name}", {}).setdefault(host.fqdn, host) + + return { + HcAclAction.ADD: added, + HcAclAction.REMOVE: removed, + } + + def test_expand(self): + base_expected_topology = { + "CLUSTER": [self.host_1.fqdn, self.host_2.fqdn], + self.service.name: [self.host_1.fqdn], + f"{self.service.name}.{self.component_1.name}": [self.host_1.fqdn], + } + + action_hc_map_add_h2_c2 = [ + *self.initial_hc_h1_c1, + {"host_id": self.host_2.pk, "component_id": self.component_2.pk, "service_id": self.service.pk}, + ] + expected_topology_add_h2_c2 = { + **base_expected_topology, + **{f"{self.service.name}.{self.component_2.name}.{HcAclAction.ADD}": [self.host_2.fqdn]}, + } + action_hc_map_add_h2_c1 = [ + *self.initial_hc_h1_c1, + {"host_id": self.host_2.pk, "component_id": self.component_1.pk, "service_id": self.service.pk}, + ] + expected_topology_add_h2_c1 = { + **base_expected_topology, + **{f"{self.service.name}.{self.component_1.name}.{HcAclAction.ADD}": [self.host_2.fqdn]}, + } + + for obj, action, action_hc_map, expected_topology in ( + ( + self.cluster_1, + self.hc_acl_action_cluster, + action_hc_map_add_h2_c2, + expected_topology_add_h2_c2, + ), + ( + self.service, + self.hc_acl_action_service, + action_hc_map_add_h2_c2, + expected_topology_add_h2_c2, + ), + ( + self.cluster_1, + self.hc_acl_action_cluster, + action_hc_map_add_h2_c1, + expected_topology_add_h2_c1, + ), + ( + self.service, + self.hc_acl_action_service, + action_hc_map_add_h2_c1, + expected_topology_add_h2_c1, + ), + ): + with self.subTest( + msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, " + f"action: {action.name}, action_hc_map: {action_hc_map}" + ): + self.add_hostcomponent_map(cluster=self.cluster_1, hc_map=self.initial_hc_h1_c1) + delta = self._get_mapping_delta(cluster=self.cluster_1, new_mapping=action_hc_map) + + self.assert_inventory( + obj=obj, + action=action, + expected_topology=expected_topology, + expected_data=self.expected_data, + delta=delta, + ) + + def test_shrink(self): + base_expected_topology = { + "CLUSTER": [self.host_1.fqdn, self.host_2.fqdn], + f"{self.service.name}.{self.component_1.name}": [self.host_1.fqdn], + } + + initial_hc_h1_c1_h2_c2 = [ + *self.initial_hc_h1_c1, + {"service_id": self.service.pk, "component_id": self.component_2.pk, "host_id": self.host_2.pk}, + ] + expected_topology_remove_h2_c2 = { + **base_expected_topology, + **{ + self.service.name: [self.host_1.fqdn, self.host_2.fqdn], + f"{self.service.name}.{self.component_2.name}": [self.host_2.fqdn], + f"{self.service.name}.{self.component_2.name}.{HcAclAction.REMOVE}": [self.host_2.fqdn], + }, + } + + initial_hc_h1_c1_h1_c2 = [ + *self.initial_hc_h1_c1, + {"service_id": self.service.pk, "component_id": self.component_2.pk, "host_id": self.host_1.pk}, + ] + expected_topology_remove_h1_c2 = { + **base_expected_topology, + **{ + self.service.name: [self.host_1.fqdn], + f"{self.service.name}.{self.component_2.name}": [self.host_1.fqdn], + f"{self.service.name}.{self.component_2.name}.{HcAclAction.REMOVE}": [self.host_1.fqdn], + }, + } + + for obj, action, initial_hc_map, expected_topology in ( + (self.cluster_1, self.hc_acl_action_cluster, initial_hc_h1_c1_h2_c2, expected_topology_remove_h2_c2), + (self.service, self.hc_acl_action_service, initial_hc_h1_c1_h2_c2, expected_topology_remove_h2_c2), + (self.cluster_1, self.hc_acl_action_cluster, initial_hc_h1_c1_h1_c2, expected_topology_remove_h1_c2), + (self.service, self.hc_acl_action_service, initial_hc_h1_c1_h1_c2, expected_topology_remove_h1_c2), + ): + action_hc_map = initial_hc_map[:-1] + with self.subTest( + msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, " + f"action: {action.name}, action_hc_map: {action_hc_map}" + ): + self.add_hostcomponent_map(cluster=self.cluster_1, hc_map=initial_hc_map) + delta = self._get_mapping_delta(cluster=self.cluster_1, new_mapping=action_hc_map) + + self.assert_inventory( + obj=obj, + action=action, + expected_topology=expected_topology, + expected_data=self.expected_data, + delta=delta, + ) + + def test_expand_shrink_move(self): + base_expected_topology = { + "CLUSTER": [self.host_1.fqdn, self.host_2.fqdn], + self.service.name: [self.host_1.fqdn], + f"{self.service.name}.{self.component_1.name}": [self.host_1.fqdn], + } + + action_hc_map_remove_h1_c1_add_h2_c2 = [ + { + "service_id": self.service.pk, + "component_id": self.component_2.pk, + "host_id": self.host_2.pk, + } + ] + expected_topology_remove_h1_c1_add_h2_c2 = { + **base_expected_topology, + **{ + f"{self.service.name}.{self.component_1.name}.{HcAclAction.REMOVE}": [self.host_1.fqdn], + f"{self.service.name}.{self.component_2.name}.{HcAclAction.ADD}": [self.host_2.fqdn], + }, + } + + action_hc_map_remove_h1_c1_add_h1_c2 = [ + { + "service_id": self.service.pk, + "component_id": self.component_2.pk, + "host_id": self.host_1.pk, + } + ] + expected_topology_remove_h1_c1_add_h1_c2 = { + **base_expected_topology, + **{ + f"{self.service.name}.{self.component_1.name}.{HcAclAction.REMOVE}": [self.host_1.fqdn], + f"{self.service.name}.{self.component_2.name}.{HcAclAction.ADD}": [self.host_1.fqdn], + }, + } + + action_hc_map_remove_h1_c1_add_h2_c1 = [ + { + "service_id": self.service.pk, + "component_id": self.component_1.pk, + "host_id": self.host_2.pk, + } + ] + expected_topology_remove_h1_c1_add_h2_c1 = { + **base_expected_topology, + **{ + f"{self.service.name}.{self.component_1.name}.{HcAclAction.REMOVE}": [self.host_1.fqdn], + f"{self.service.name}.{self.component_1.name}.{HcAclAction.ADD}": [self.host_2.fqdn], + }, + } + + for obj, action, action_hc_map, expected_topology in ( + ( + self.cluster_1, + self.hc_acl_action_cluster, + action_hc_map_remove_h1_c1_add_h2_c2, + expected_topology_remove_h1_c1_add_h2_c2, + ), + ( + self.service, + self.hc_acl_action_service, + action_hc_map_remove_h1_c1_add_h2_c2, + expected_topology_remove_h1_c1_add_h2_c2, + ), + ( + self.cluster_1, + self.hc_acl_action_cluster, + action_hc_map_remove_h1_c1_add_h1_c2, + expected_topology_remove_h1_c1_add_h1_c2, + ), + ( + self.service, + self.hc_acl_action_service, + action_hc_map_remove_h1_c1_add_h1_c2, + expected_topology_remove_h1_c1_add_h1_c2, + ), + ( + self.cluster_1, + self.hc_acl_action_cluster, + action_hc_map_remove_h1_c1_add_h2_c1, + expected_topology_remove_h1_c1_add_h2_c1, + ), + ( + self.service, + self.hc_acl_action_service, + action_hc_map_remove_h1_c1_add_h2_c1, + expected_topology_remove_h1_c1_add_h2_c1, + ), + ): + with self.subTest( + msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, " + f"action: {action.name}, action_hc_map: {action_hc_map}" + ): + self.add_hostcomponent_map(cluster=self.cluster_1, hc_map=self.initial_hc_h1_c1) + delta = self._get_mapping_delta(cluster=self.cluster_1, new_mapping=action_hc_map) + + self.assert_inventory( + obj=obj, + action=action, + expected_topology=expected_topology, + expected_data=self.expected_data, + delta=delta, + ) From 2cfb260c5b8dc352a57d6a69581dd6220cbdc9d4 Mon Sep 17 00:00:00 2001 From: Daniil Skrynnik Date: Thu, 18 Jan 2024 10:30:28 +0000 Subject: [PATCH 043/151] ADCM-5042: Saving mapping improvements --- python/api_v2/cluster/data_containers.py | 167 +++++++++++ python/api_v2/cluster/utils.py | 337 ++++++++++++++++++++++- python/api_v2/cluster/views.py | 14 +- python/api_v2/tests/test_mapping.py | 80 ++++-- python/cm/api.py | 77 +----- python/cm/data_containers.py | 82 ++++++ python/cm/issue.py | 63 +++-- 7 files changed, 693 insertions(+), 127 deletions(-) create mode 100644 python/api_v2/cluster/data_containers.py create mode 100644 python/cm/data_containers.py diff --git a/python/api_v2/cluster/data_containers.py b/python/api_v2/cluster/data_containers.py new file mode 100644 index 0000000000..2c686e2e28 --- /dev/null +++ b/python/api_v2/cluster/data_containers.py @@ -0,0 +1,167 @@ +# Licensed 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. + +from dataclasses import dataclass +from functools import cached_property +from typing import Any, Literal + +from cm.data_containers import ( + ClusterData, + ComponentData, + HostComponentData, + HostData, + PrototypeData, + ServiceData, +) +from cm.models import Host + + +@dataclass +class MappingEntryData: + host: HostData + component: ComponentData + service: ServiceData + + +@dataclass +class MappingData: # pylint: disable=too-many-instance-attributes + cluster: ClusterData + services: dict[int, ServiceData] + components: dict[int, ComponentData] + hosts: dict[int, HostData] + prototypes: dict[int, PrototypeData] + mapping: list[MappingEntryData] + existing_mapping: list[HostComponentData] + orm_objects: dict[Literal["hosts", "cluster", "providers"], dict[int, Any] | Any] + not_found_object_ids: dict[Literal["hosts", "components"], set] + + @cached_property + def mapping_difference(self) -> dict[Literal["add", "remove", "remain"], list[MappingEntryData]]: + input_mapping_ids = set((map_.host.id, map_.component.id, map_.service.id) for map_ in self.mapping) + existing_mapping_ids = set((map_.host_id, map_.component_id, map_.service_id) for map_ in self.existing_mapping) + + return { + "add": [ + MappingEntryData( + host=self.hosts[ids[0]], component=self.components[ids[1]], service=self.services[ids[2]] + ) + for ids in input_mapping_ids.difference(existing_mapping_ids) + ], + "remove": [ + MappingEntryData( + host=self.hosts[ids[0]], component=self.components[ids[1]], service=self.services[ids[2]] + ) + for ids in existing_mapping_ids.difference(input_mapping_ids) + ], + "remain": [ + MappingEntryData( + host=self.hosts[ids[0]], component=self.components[ids[1]], service=self.services[ids[2]] + ) + for ids in input_mapping_ids.intersection(existing_mapping_ids) + ], + } + + @cached_property + def mapping_names(self) -> dict[Literal["services", "components"], set[str]]: + return { + "services": set( + self.prototypes[map_.service.prototype_id].name + for map_ in self.mapping + if self.prototypes[map_.service.prototype_id].type == "service" + ), + "components": set( + self.prototypes[map_.service.prototype_id].name + for map_ in self.mapping + if self.prototypes[map_.service.prototype_id].type == "component" + ), + } + + @cached_property + def mapping_prototypes(self) -> list[dict[Literal["service", "component"], PrototypeData]]: + return [ + { + "service": self.prototypes[map_.service.prototype_id], + "component": self.prototypes[map_.component.prototype_id], + } + for map_ in self.mapping + ] + + @cached_property + def objects_by_prototype_name( + self, + ) -> dict[ + Literal["services", "components"], + dict[str, dict[Literal["object", "prototype"], ServiceData | ComponentData | PrototypeData]], + ]: + return { + "components": { + self.prototypes[obj.prototype_id].name: {"object": obj, "prototype": self.prototypes[obj.prototype_id]} + for obj in self.components.values() + }, + "services": { + self.prototypes[obj.prototype_id].name: {"object": obj, "prototype": self.prototypes[obj.prototype_id]} + for obj in self.services.values() + }, + } + + @cached_property + def added_hosts(self) -> list[Host]: + existing_host_ids = {map_.host_id for map_ in self.existing_mapping} + + return [ + self.orm_objects["hosts"][map_.host.id] for map_ in self.mapping if map_.host.id not in existing_host_ids + ] + + @cached_property + def removed_hosts(self) -> list[Host]: + mapping_host_ids = {map_.host.id for map_ in self.mapping} + + return [ + self.orm_objects["hosts"][map_.host_id] + for map_ in self.existing_mapping + if map_.host_id not in mapping_host_ids + ] + + def entry_prototypes(self, entry: MappingEntryData) -> tuple[PrototypeData, PrototypeData]: + service_prototype = self.prototypes[entry.service.prototype_id] + component_prototype = self.prototypes[entry.component.prototype_id] + + return service_prototype, component_prototype + + def entry_bound_targets(self, entry: MappingEntryData) -> list[MappingEntryData]: + _, component_prototype = self.entry_prototypes(entry=entry) + bound_to = component_prototype.bound_to + + bound_targets: list[MappingEntryData] = [] + for mapping_entry in self.mapping: + service_prototype, component_prototype = self.entry_prototypes(entry=mapping_entry) + if all( + ( + service_prototype.name == bound_to.service, + component_prototype.name == bound_to.component, + entry.host.id == mapping_entry.host.id, + ) + ): + bound_targets.append(mapping_entry) + + return bound_targets + + def service_components(self, service: ServiceData) -> list[tuple[ComponentData, PrototypeData]]: + service_prototype = self.prototypes[service.prototype_id] + + target_components = [] + for component in self.components.values(): + component_prototype = self.prototypes[component.prototype_id] + if component_prototype.parent_id == service_prototype.id: + target_components.append((component, component_prototype)) + + return target_components diff --git a/python/api_v2/cluster/utils.py b/python/api_v2/cluster/utils.py index 5013f5ebcf..fd4ae66105 100644 --- a/python/api_v2/cluster/utils.py +++ b/python/api_v2/cluster/utils.py @@ -11,9 +11,48 @@ # limitations under the License. from collections import defaultdict +from itertools import chain +from typing import Literal +from api_v2.cluster.data_containers import MappingData, MappingEntryData from api_v2.prototype.utils import get_license_text -from cm.models import ObjectType, Prototype +from cm.api import load_service_map +from cm.api_context import CTX +from cm.data_containers import ( + ClusterData, + ComponentData, + Empty, + HostComponentData, + HostData, + PrototypeData, + RequiresData, + ServiceData, +) +from cm.errors import AdcmEx +from cm.issue import ( + add_concern_to_object, + check_components_mapping_contraints, + remove_concern_from_object, + update_hierarchy_issues, + update_issue_after_deleting, +) +from cm.models import ( + Cluster, + ClusterObject, + GroupConfig, + Host, + HostComponent, + MaintenanceMode, + ObjectType, + Prototype, + ServiceComponent, +) +from cm.status_api import send_host_component_map_update_event +from django.contrib.contenttypes.models import ContentType +from django.db.models import QuerySet +from django.db.transaction import atomic, on_commit +from rbac.models import Policy +from rest_framework.status import HTTP_409_CONFLICT def get_requires(requires: list[dict]) -> dict: @@ -81,3 +120,299 @@ def get_depend_on( get_depend_on(prototype=required_service, depend_on=depend_on, checked_objects=checked_objects) return depend_on + + +def retrieve_mapping_data( + cluster: Cluster, plain_hc: list[dict[Literal["host_id", "component_id"], int]] +) -> MappingData: + mapping_data = { + "cluster": ClusterData.from_orm(obj=cluster), + "services": {}, + "components": {}, + "hosts": {}, + "prototypes": {}, + "mapping": [], + "existing_mapping": [], + "orm_objects": {"cluster": cluster, "hosts": {}, "providers": {}}, + "not_found_object_ids": {}, + } + + for service in ( + ClusterObject.objects.filter(cluster=cluster) + .select_related("prototype") + .prefetch_related("servicecomponent_set", "servicecomponent_set__prototype") + ): + service: ClusterObject + mapping_data["services"][service.pk] = ServiceData.from_orm(obj=service) + mapping_data["prototypes"][service.prototype.pk] = PrototypeData.from_orm(obj=service.prototype) + for component in service.servicecomponent_set.all(): + component: ServiceComponent + mapping_data["components"][component.pk] = ComponentData.from_orm(obj=component) + mapping_data["prototypes"][component.prototype.pk] = PrototypeData.from_orm(obj=component.prototype) + + for host in Host.objects.filter(cluster=cluster).select_related("provider"): + host: Host + mapping_data["hosts"][host.pk] = HostData.from_orm(obj=host) + mapping_data["orm_objects"]["hosts"][host.pk] = host + mapping_data["orm_objects"]["providers"][host.provider.pk] = host.provider + + for map_ in HostComponent.objects.filter(cluster=cluster): + mapping_data["existing_mapping"].append(HostComponentData.from_orm(obj=map_)) + + mapping_data = MappingData(**mapping_data) + + mapping_data.mapping = [ + MappingEntryData( + host=mapping_data.hosts[record["host_id"]], + component=mapping_data.components[record["component_id"]], + service=mapping_data.services[mapping_data.components[record["component_id"]].service_id], + ) + for record in plain_hc + if record["host_id"] in mapping_data.hosts and record["component_id"] in mapping_data.components + ] + mapping_data.not_found_object_ids = { + "hosts": {record["host_id"] for record in plain_hc if record["host_id"] not in mapping_data.hosts}, + "components": { + record["component_id"] for record in plain_hc if record["component_id"] not in mapping_data.components + }, + } + + return mapping_data + + +def save_mapping(mapping_data: MappingData) -> QuerySet[HostComponent]: + """ + Save given hosts-components mapping if all sanity checks pass + """ + + _check_mapping_data(mapping_data=mapping_data) + return _save_mapping(mapping_data=mapping_data) + + +def _check_mapping_data(mapping_data: MappingData) -> None: + if mapping_data.not_found_object_ids["hosts"]: + ids_repr = ", ".join([f'"{host_id}"' for host_id in mapping_data.not_found_object_ids["hosts"]]) + raise AdcmEx( + code="HOST_NOT_FOUND", + http_code=HTTP_409_CONFLICT, + msg=f'Host(s) {ids_repr} do not belong to cluster "{mapping_data.cluster.name}"', + ) + if mapping_data.not_found_object_ids["components"]: + ids_repr = ", ".join([f'"{component_id}"' for component_id in mapping_data.not_found_object_ids["components"]]) + raise AdcmEx( + code="COMPONENT_NOT_FOUND", + http_code=HTTP_409_CONFLICT, + msg=f'Component(s) {ids_repr} do not belong to cluster "{mapping_data.cluster.name}"', + ) + + seen = set() + duplicates = set() + for map_ in mapping_data.mapping: + ids = (map_.host.id, map_.component.id, map_.service.id) + if ids in seen: + duplicates.add(ids) + seen.add(ids) + + if duplicates: + error_mapping_repr = ", ".join( + (f"component {map_ids[1]} - host {map_ids[0]}" for map_ids in sorted(duplicates)) + ) + raise AdcmEx(code="INVALID_INPUT", msg=f"Mapping entries duplicates found: {error_mapping_repr}.") + + hosts_mm_states_in_add_remove_groups = set( + diff.host.maintenance_mode for diff in mapping_data.mapping_difference["add"] + ).union(set(diff.host.maintenance_mode for diff in mapping_data.mapping_difference["remove"])) + if MaintenanceMode.ON.value in hosts_mm_states_in_add_remove_groups: + raise AdcmEx("INVALID_HC_HOST_IN_MM") + + for mapping_entry in mapping_data.mapping: + service_prototype, component_prototype = mapping_data.entry_prototypes(entry=mapping_entry) + + if service_prototype.requires or component_prototype.requires: + _check_single_mapping_requires(mapping_entry=mapping_entry, mapping_data=mapping_data) + + if not isinstance(component_prototype.bound_to, Empty): + _check_single_mapping_bound_to(mapping_entry=mapping_entry, mapping_data=mapping_data) + + for service in mapping_data.services.values(): + service_prototype = mapping_data.prototypes[service.prototype_id] + if service_prototype.requires: + _check_single_service_requires( + service_prototype=service_prototype, cluster_objects=mapping_data.objects_by_prototype_name + ) + for component, component_prototype in mapping_data.service_components(service=service): + check_components_mapping_contraints( + hosts_count=len(mapping_data.hosts), + target_mapping_count=len( + [ + map_ + for map_ in mapping_data.mapping + if map_.service.id == service.id and map_.component.id == component.id + ] + ), + service_prototype=service_prototype, + component_prototype=component_prototype, + ) + + +@atomic +def _save_mapping(mapping_data: MappingData) -> QuerySet[HostComponent]: + on_commit(func=load_service_map) + + for removed_host in mapping_data.removed_hosts: + remove_concern_from_object(object_=removed_host, concern=CTX.lock) + + for added_host in mapping_data.added_hosts: + add_concern_to_object(object_=added_host, concern=CTX.lock) + + _handle_mapping_config_groups(mapping_data=mapping_data) + + mapping_objects: list[HostComponent] = [] + for map_ in mapping_data.mapping: + mapping_objects.append( + HostComponent( + cluster_id=mapping_data.cluster.id, + host_id=map_.host.id, + service_id=map_.service.id, + component_id=map_.component.id, + ) + ) + + HostComponent.objects.filter(cluster_id=mapping_data.cluster.id).delete() + HostComponent.objects.bulk_create(objs=mapping_objects) + + update_hierarchy_issues(obj=mapping_data.orm_objects["cluster"]) + for provider_id in set(host.provider_id for host in mapping_data.hosts.values()): + update_hierarchy_issues(obj=mapping_data.orm_objects["providers"][provider_id]) + update_issue_after_deleting() + + _handle_mapping_policies(mapping_data=mapping_data) + send_host_component_map_update_event(cluster=mapping_data.orm_objects["cluster"]) + + return HostComponent.objects.filter(cluster_id=mapping_data.cluster.id) + + +def _handle_mapping_config_groups(mapping_data: MappingData) -> None: + remaining_host_service = set((diff.host.id, diff.service.id) for diff in mapping_data.mapping_difference["remain"]) + removed_hosts_not_in_mapping = { + mapping_data.orm_objects["hosts"][removed_mapping.host.id] + for removed_mapping in mapping_data.mapping_difference["remove"] + if (removed_mapping.host.id, removed_mapping.service.id) not in remaining_host_service + } + removed_mapping_host_ids = {hc.host.id for hc in mapping_data.mapping_difference["remove"]} + + for group_config in GroupConfig.objects.filter( + object_type__model__in=["clusterobject", "servicecomponent"], + hosts__in=removed_mapping_host_ids, + ).distinct(): + group_config.hosts.remove(*removed_hosts_not_in_mapping) + + +def _handle_mapping_policies(mapping_data: MappingData) -> None: + service_ids_in_mappings: set[int] = set( + chain( + (map_.service.id for map_ in mapping_data.mapping), + (map_.service_id for map_ in mapping_data.existing_mapping), + ) + ) + for policy in Policy.objects.filter( + object__object_id__in=service_ids_in_mappings, + object__content_type=ContentType.objects.get_for_model(model=ClusterObject), + ): + policy.apply() + + for policy in Policy.objects.filter( + object__object_id=mapping_data.cluster.id, + object__content_type=ContentType.objects.get_for_model(model=Cluster), + ): + policy.apply() + + +def _check_single_mapping_requires(mapping_entry: MappingEntryData, mapping_data: MappingData) -> None: + service_prototype, component_prototype = mapping_data.entry_prototypes(entry=mapping_entry) + + for require, source_type in [ + *zip(component_prototype.requires, [component_prototype.type] * len(component_prototype.requires)), + *zip(service_prototype.requires, [service_prototype.type] * len(service_prototype.requires)), + ]: + require: RequiresData + + if require.service not in mapping_data.mapping_names["services"]: + if source_type == ObjectType.COMPONENT.value: + reference = f'component "{component_prototype.name}" of service "{service_prototype.name}"' + else: + reference = f'service "{service_prototype.name}"' + + raise AdcmEx( + code="COMPONENT_CONSTRAINT_ERROR", msg=f'No required service "{require.service}" for {reference}' + ) + + if require.component is None: + continue + + if not [ + mapping_entry + for mapping_entry in mapping_data.mapping_prototypes + if mapping_entry[ObjectType.SERVICE.value].name == require.service + and mapping_entry[ObjectType.COMPONENT.value].name == require.component + ]: + if source_type == ObjectType.COMPONENT.value: + reference = f'component "{component_prototype.name}" of service "{service_prototype.name}"' + else: + reference = f'service "{service_prototype.name}"' + + raise AdcmEx( + code="COMPONENT_CONSTRAINT_ERROR", + msg=f'No required component "{require.component}" of service "{require.service}" for {reference}', + ) + + +def _check_single_mapping_bound_to(mapping_entry: MappingEntryData, mapping_data: MappingData) -> None: + if not mapping_data.entry_bound_targets(entry=mapping_entry): + service_prototype, component_prototype = mapping_data.entry_prototypes(entry=mapping_entry) + + bound_service_name = component_prototype.bound_to.service + bound_component_name = component_prototype.bound_to.component + + bound_target_ref = f'component "{bound_component_name}" of service "{bound_service_name}"' + bound_requester_ref = ( + f'component "{component_prototype.display_name}" of service "{service_prototype.display_name}"' + ) + + msg = f'No {bound_target_ref} on host "{mapping_entry.host.fqdn}" for {bound_requester_ref}' + raise AdcmEx(code="COMPONENT_CONSTRAINT_ERROR", msg=msg) + + +def _check_single_service_requires( + service_prototype: PrototypeData, + cluster_objects: dict[ + Literal["services", "components"], + dict[str, dict[Literal["object", "prototype"], ServiceData | ComponentData | PrototypeData]], + ], +) -> None: + for require in service_prototype.requires: + required_service: ServiceData | None = cluster_objects["services"].get(require.service, {}).get("object") + required_service_prototype: PrototypeData | None = ( + cluster_objects["services"].get(require.service, {}).get("prototype") + ) + + target_reference = f'service "{require.service}"' + is_requirements_satisfied: bool = required_service is not None and required_service_prototype is not None + + if require.component is not None: + required_component: ComponentData | None = ( + cluster_objects["components"].get(require.component, {}).get("object") + ) + required_component_prototype: PrototypeData | None = ( + cluster_objects["components"].get(require.component, {}).get("prototype") + ) + + if required_component is None or required_component_prototype is None: + target_reference = f'component "{require.component}" of service "{require.service}"' + is_requirements_satisfied = False + + if not is_requirements_satisfied: + raise AdcmEx( + code="SERVICE_CONFLICT", + msg=f"No required {target_reference} for {service_prototype.reference}", + ) diff --git a/python/api_v2/cluster/views.py b/python/api_v2/cluster/views.py index 75c3e4f6b8..07a13a50d0 100644 --- a/python/api_v2/cluster/views.py +++ b/python/api_v2/cluster/views.py @@ -26,17 +26,13 @@ RelatedServicesStatusesSerializer, ServicePrototypeSerializer, ) +from api_v2.cluster.utils import retrieve_mapping_data, save_mapping from api_v2.component.serializers import ComponentMappingSerializer from api_v2.config.utils import ConfigSchemaMixin from api_v2.host.serializers import HostMappingSerializer from api_v2.views import CamelCaseModelViewSet from audit.utils import audit -from cm.api import ( - add_cluster, - delete_cluster, - retrieve_host_component_objects, - set_host_component, -) +from cm.api import add_cluster, delete_cluster from cm.errors import AdcmEx from cm.issue import update_hierarchy_issues from cm.models import ( @@ -218,10 +214,10 @@ def mapping(self, request: Request, *args, **kwargs) -> Response: # pylint: dis serializer = self.get_serializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) - host_component_objects = retrieve_host_component_objects(cluster=cluster, plain_hc=serializer.validated_data) - new_host_component = set_host_component(cluster=cluster, host_component_objects=host_component_objects) + mapping_data = retrieve_mapping_data(cluster=cluster, plain_hc=serializer.validated_data) + new_mapping = save_mapping(mapping_data=mapping_data) - return Response(data=self.get_serializer(instance=new_host_component, many=True).data, status=HTTP_201_CREATED) + return Response(data=self.get_serializer(instance=new_mapping, many=True).data, status=HTTP_201_CREATED) @action(methods=["get"], detail=True, url_path="mapping/hosts", url_name="mapping-hosts") def mapping_hosts(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument diff --git a/python/api_v2/tests/test_mapping.py b/python/api_v2/tests/test_mapping.py index 824b8455cd..50d458efb9 100644 --- a/python/api_v2/tests/test_mapping.py +++ b/python/api_v2/tests/test_mapping.py @@ -25,7 +25,12 @@ ) from django.urls import reverse from rest_framework.response import Response -from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_409_CONFLICT +from rest_framework.status import ( + HTTP_200_OK, + HTTP_201_CREATED, + HTTP_400_BAD_REQUEST, + HTTP_409_CONFLICT, +) class TestMapping(BaseAPITestCase): @@ -63,11 +68,8 @@ def test_list_mapping_success(self): def test_create_mapping_success(self): host_3 = self.add_host(bundle=self.provider_bundle, provider=self.provider, fqdn="test_host_3") self.add_host_to_cluster(cluster=self.cluster_1, host=host_3) - component_2 = ServiceComponent.objects.get( - cluster=self.cluster_1, service=self.service_1, prototype__name="component_2" - ) data = [ - {"hostId": host_3.pk, "componentId": component_2.pk}, + {"hostId": host_3.pk, "componentId": self.component_2.pk}, {"hostId": self.host_1.pk, "componentId": self.component_1.pk}, ] @@ -77,6 +79,40 @@ def test_create_mapping_success(self): self.assertEqual(response.status_code, HTTP_201_CREATED) self.assertEqual(HostComponent.objects.count(), 2) + def test_create_mapping_duplicates_fail(self): + host_3 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="test_host_3", cluster=self.cluster_1 + ) + + data = [ + {"hostId": self.host_1.pk, "componentId": self.component_1.pk}, + {"hostId": self.host_1.pk, "componentId": self.component_1.pk}, # duplicate h1 c1 + {"hostId": self.host_1.pk, "componentId": self.component_1.pk}, # another duplicate h1 c1 + {"hostId": self.host_2.pk, "componentId": self.component_2.pk}, + {"hostId": self.host_2.pk, "componentId": self.component_2.pk}, # duplicate h2 c2 + {"hostId": self.host_2.pk, "componentId": self.component_2.pk}, # another duplicate h2 c2 + {"hostId": host_3.pk, "componentId": self.component_1.pk}, + ] + + duplicate_ids = ( + (self.host_1.pk, self.component_1.pk, self.component_1.service.pk), + (self.host_2.pk, self.component_2.pk, self.component_2.service.pk), + ) + error_msg_part = ", ".join(f"component {map_ids[1]} - host {map_ids[0]}" for map_ids in sorted(duplicate_ids)) + + response = self.client.post( + path=reverse(viewname="v2:cluster-mapping", kwargs={"pk": self.cluster_1.pk}), data=data + ) + self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) + self.assertDictEqual( + response.json(), + { + "code": "INVALID_INPUT", + "level": "error", + "desc": f"Mapping entries duplicates found: {error_msg_part}.", + }, + ) + def test_create_empty_mapping_success(self): response = self.client.post( path=reverse(viewname="v2:cluster-mapping", kwargs={"pk": self.cluster_1.pk}), @@ -194,9 +230,10 @@ def test_host_not_in_cluster_fail(self): self.assertDictEqual( response.json(), { - "code": "FOREIGN_HOST", + "code": "HOST_NOT_FOUND", "level": "error", - "desc": f'Host "{self.host_not_in_cluster.display_name}" does not belong to any cluster', + "desc": f'Host(s) "{self.host_not_in_cluster.pk}" ' + f'do not belong to cluster "{self.cluster.display_name}"', }, ) self.assertEqual(HostComponent.objects.count(), 0) @@ -221,12 +258,9 @@ def test_foreign_host_fail(self): self.assertDictEqual( response.json(), { - "code": "FOREIGN_HOST", + "code": "HOST_NOT_FOUND", "level": "error", - "desc": ( - f'Host "{self.foreign_host.display_name}" (cluster "{self.foreign_host.cluster.display_name}") ' - f'does not belong to cluster "{self.cluster.display_name}"' - ), + "desc": (f'Host(s) "{self.foreign_host.pk}" do not belong to cluster "{self.cluster.display_name}"'), }, ) self.assertEqual(HostComponent.objects.count(), 0) @@ -255,7 +289,8 @@ def test_non_existent_host_fail(self): { "code": "HOST_NOT_FOUND", "level": "error", - "desc": f"Hosts not found: {non_existent_host_pk}, {non_existent_host_pk + 1}", + "desc": f'Host(s) "{non_existent_host_pk}", "{non_existent_host_pk + 1}" ' + f'do not belong to cluster "{self.cluster.display_name}"', }, ) self.assertEqual(HostComponent.objects.count(), 0) @@ -284,7 +319,8 @@ def test_non_existent_component_fail(self): { "code": "COMPONENT_NOT_FOUND", "level": "error", - "desc": f"Components not found: {non_existent_component_pk}, {non_existent_component_pk + 1}", + "desc": f'Component(s) "{non_existent_component_pk}", "{non_existent_component_pk + 1}" ' + f'do not belong to cluster "{self.cluster.display_name}"', }, ) self.assertEqual(HostComponent.objects.count(), 0) @@ -348,11 +384,20 @@ def test_no_required_component_fail(self): service=service_requires_component, cluster=self.cluster, ) + service_with_component_required = self.add_services_to_cluster( + service_names=["service_with_component_required"], cluster=self.cluster + ).get() + not_required_component = ServiceComponent.objects.get( + prototype__name="not_required_component", + service=service_with_component_required, + cluster=self.cluster, + ) response: Response = self.client.post( path=reverse(viewname="v2:cluster-mapping", kwargs={"pk": self.cluster.pk}), data=[ {"hostId": self.host_1.pk, "componentId": component_1.pk}, + {"hostId": self.host_1.pk, "componentId": not_required_component.pk}, ], ) @@ -465,8 +510,9 @@ def test_no_bound_fail(self): "code": "COMPONENT_CONSTRAINT_ERROR", "level": "error", "desc": ( - f'Component "bound_target_component" of service "bound_target_service" not in hc for ' - f'component "{bound_component.display_name}" of service "{bound_component.service.display_name}"' + f'No component "bound_target_component" of service "bound_target_service" ' + f'on host "{self.host_1.fqdn}" for component "{bound_component.display_name}" ' + f'of service "{bound_component.service.display_name}"' ), }, ) @@ -1075,7 +1121,7 @@ def test_no_required_service_not_in_hc_fail(self): "code": "SERVICE_CONFLICT", "level": "error", "desc": ( - f'No required service "service_required" 1.0 for service ' + f'No required service "service_required" for service ' f'"{service_requires_service.display_name}" {service_requires_service.prototype.version}' ), }, diff --git a/python/cm/api.py b/python/cm/api.py index f3adfabcb1..5ac6687f7a 100644 --- a/python/cm/api.py +++ b/python/cm/api.py @@ -14,7 +14,6 @@ import json from collections import defaultdict from functools import partial, wraps -from typing import Literal from adcm_version import compare_prototype_versions from cm.adcm_config.config import ( @@ -64,13 +63,12 @@ send_delete_service_event, send_host_component_map_update_event, ) -from cm.utils import build_id_object_mapping, obj_ref +from cm.utils import obj_ref from django.contrib.contenttypes.models import ContentType from django.core.exceptions import MultipleObjectsReturned from django.db.transaction import atomic, on_commit from rbac.models import Policy, re_apply_object_policy from rbac.roles import apply_policy_for_new_config -from rest_framework.status import HTTP_409_CONFLICT def check_license(prototype: Prototype) -> None: @@ -596,52 +594,6 @@ def check_sub(_sub_key, _sub_type, _item): raise_adcm_ex("INVALID_INPUT", f"duplicate ({item}) in host service list") -def retrieve_host_component_objects( - cluster: Cluster, plain_hc: list[dict[Literal["host_id", "component_id"], int]] -) -> list[tuple[ClusterObject, Host, ServiceComponent]]: - host_ids: set[int] = set() - component_ids: set[int] = set() - for record in plain_hc: - host_ids.add(record["host_id"]) - component_ids.add(record["component_id"]) - - hosts_in_hc: dict[int, Host] = build_id_object_mapping( - objects=Host.objects.select_related("cluster").filter(pk__in=host_ids) - ) - if not_found_host_ids := host_ids.difference(hosts_in_hc.keys()): - message = f"Hosts not found: {', '.join([str(host_id) for host_id in not_found_host_ids])}" - raise AdcmEx(code="HOST_NOT_FOUND", http_code=HTTP_409_CONFLICT, msg=message) - - components_in_hc: dict[int, ServiceComponent] = build_id_object_mapping( - objects=ServiceComponent.objects.select_related("service").filter(pk__in=component_ids, cluster=cluster) - ) - if not_found_component_ids := component_ids.difference(components_in_hc.keys()): - message = f"Components not found: {', '.join([str(component_id) for component_id in not_found_component_ids])}" - raise AdcmEx(code="COMPONENT_NOT_FOUND", http_code=HTTP_409_CONFLICT, msg=message) - - host_component_objects = [] - - for record in plain_hc: - host: Host = hosts_in_hc[record["host_id"]] - - if not host.cluster: - message = f'Host "{host.fqdn}" does not belong to any cluster' - raise AdcmEx(code="FOREIGN_HOST", msg=message) - - if host.cluster.pk != cluster.pk: - message = ( - f'Host "{host.fqdn}" (cluster "{host.cluster.display_name}") ' - f'does not belong to cluster "{cluster.display_name}"' - ) - raise AdcmEx(code="FOREIGN_HOST", msg=message) - - component: ServiceComponent = components_in_hc[record["component_id"]] - - host_component_objects.append((component.service, host, component)) - - return host_component_objects - - def make_host_comp_list(cluster: Cluster, hc_in: list[dict]) -> list[tuple[ClusterObject, Host, ServiceComponent]]: host_comp_list = [] for item in hc_in: @@ -776,33 +728,6 @@ def save_hc( return host_component_list -def set_host_component( - cluster: Cluster, host_component_objects: list[tuple[ClusterObject, Host, ServiceComponent]] -) -> list[HostComponent]: - """ - Save given hosts-components mapping if all sanity checks pass - """ - - check_hc_requires(shc_list=host_component_objects) - - check_bound_components(shc_list=host_component_objects) - - for service in ClusterObject.objects.select_related("prototype").filter(cluster=cluster): - check_component_constraint( - cluster=cluster, - service_prototype=service.prototype, - hc_in=[i for i in host_component_objects if i[0] == service], - ) - check_service_requires(cluster=cluster, proto=service.prototype) - - check_maintenance_mode(cluster=cluster, host_comp_list=host_component_objects) - - with atomic(): - new_host_component = save_hc(cluster=cluster, host_comp_list=host_component_objects) - - return new_host_component - - def add_hc(cluster: Cluster, hc_in: list[dict]) -> list[HostComponent]: host_comp_list = check_hc(cluster=cluster, hc_in=hc_in) diff --git a/python/cm/data_containers.py b/python/cm/data_containers.py new file mode 100644 index 0000000000..97a5641d80 --- /dev/null +++ b/python/cm/data_containers.py @@ -0,0 +1,82 @@ +# Licensed 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. + +from typing import Any, Optional + +from pydantic import BaseModel # pylint: disable=no-name-in-module + + +class DBModel(BaseModel): + id: int + + class Config: + orm_mode = True + + +class Empty(BaseModel): + class Config: + extra = "forbid" + + +class RequiresData(BaseModel): + service: str + component: Optional[str] + + +class BoundToData(BaseModel): + service: str + component: str + + +class PrototypeData(DBModel): + name: str + display_name: str + type: str + version: str + parent_id: int | None + requires: list[RequiresData] + bound_to: BoundToData | Empty + constraint: list[Any] + + @property + def reference(self) -> str: + return f'{self.type} "{self.name}" {self.version}' + + +class ClusterData(DBModel): + name: str + prototype_id: int + + +class ServiceData(DBModel): + cluster_id: int + prototype_id: int + + +class ComponentData(DBModel): + service_id: int + cluster_id: int + prototype_id: int + + +class HostData(DBModel): + fqdn: str + cluster_id: int + prototype_id: int + provider_id: int + maintenance_mode: str + + +class HostComponentData(DBModel): + host_id: int + component_id: int + service_id: int diff --git a/python/cm/issue.py b/python/cm/issue.py index dfa495aeee..f2abf50250 100755 --- a/python/cm/issue.py +++ b/python/cm/issue.py @@ -15,6 +15,7 @@ from api_v2.concern.serializers import ConcernSerializer from cm.adcm_config.config import get_prototype_config from cm.adcm_config.utils import proto_ref +from cm.data_containers import PrototypeData from cm.errors import AdcmEx from cm.hierarchy import Tree from cm.logger import logger @@ -258,56 +259,69 @@ def get_obj_config(obj: ADCMEntity) -> tuple[dict, dict]: return config_log.config, attr -def check_min_required_components(count: int, constraint: int, comp: ServiceComponent, ref: str) -> None: +def check_min_required_components(count: int, constraint: int, component_prototype: Prototype, ref: str) -> None: if count < constraint: raise AdcmEx( code="COMPONENT_CONSTRAINT_ERROR", - msg=f'Less then {constraint} required component "{comp.name}" ({count}) {ref}', + msg=f'Less then {constraint} required component "{component_prototype.name}" ({count}) {ref}', ) -def check_max_required_components(count: int, constraint: int, comp: ServiceComponent, ref: str) -> None: +def check_max_required_components(count: int, constraint: int, component_prototype: Prototype, ref: str) -> None: if count > constraint: raise AdcmEx( code="COMPONENT_CONSTRAINT_ERROR", - msg=f'Amount ({count}) of component "{comp.name}" more then maximum ({constraint}) {ref}', + msg=f'Amount ({count}) of component "{component_prototype.name}" more then maximum ({constraint}) {ref}', ) -def check_components_number_is_odd(count: int, constraint: str, comp: ServiceComponent, ref: str) -> None: +def check_components_number_is_odd(count: int, constraint: str, component_prototype: Prototype, ref: str) -> None: if count % 2 == 0: raise AdcmEx( code="COMPONENT_CONSTRAINT_ERROR", - msg=f'Amount ({count}) of component "{comp.name}" should be odd ({constraint}) {ref}', + msg=f'Amount ({count}) of component "{component_prototype.name}" should be odd ({constraint}) {ref}', ) def check_components_mapping_contraints( - cluster: Cluster, service_prototype: Prototype, comp: ServiceComponent, hc_in: list, constraint: list + hosts_count: int, + target_mapping_count: int, + service_prototype: Prototype | PrototypeData, + component_prototype: Prototype | PrototypeData, ) -> None: - all_hosts_number = Host.objects.filter(cluster=cluster).count() + constraint = component_prototype.constraint ref = f'in host component list for {service_prototype.type} "{service_prototype.name}"' - count = 0 - for _, _, component in hc_in: - if comp.name == component.prototype.name: - count += 1 if isinstance(constraint[0], int): - check_min_required_components(count=count, constraint=constraint[0], comp=comp, ref=ref) + check_min_required_components( + count=target_mapping_count, constraint=constraint[0], component_prototype=component_prototype, ref=ref + ) if len(constraint) < 2: - check_max_required_components(count=count, constraint=constraint[0], comp=comp, ref=ref) + check_max_required_components( + count=target_mapping_count, constraint=constraint[0], component_prototype=component_prototype, ref=ref + ) if len(constraint) > 1: if isinstance(constraint[1], int): - check_max_required_components(count=count, constraint=constraint[1], comp=comp, ref=ref) - elif constraint[1] == "odd" and count: - check_components_number_is_odd(count=count, constraint=constraint[1], comp=comp, ref=ref) + check_max_required_components( + count=target_mapping_count, constraint=constraint[1], component_prototype=component_prototype, ref=ref + ) + elif constraint[1] == "odd" and target_mapping_count: + check_components_number_is_odd( + count=target_mapping_count, constraint=constraint[1], component_prototype=component_prototype, ref=ref + ) if constraint[0] == "+": - check_min_required_components(count=count, constraint=all_hosts_number, comp=comp, ref=ref) + check_min_required_components( + count=target_mapping_count, constraint=hosts_count, component_prototype=component_prototype, ref=ref + ) elif constraint[0] == "odd": # synonym to [1,odd] - check_min_required_components(count=count, constraint=1, comp=comp, ref=ref) - check_components_number_is_odd(count=count, constraint=constraint[0], comp=comp, ref=ref) + check_min_required_components( + count=target_mapping_count, constraint=1, component_prototype=component_prototype, ref=ref + ) + check_components_number_is_odd( + count=target_mapping_count, constraint=constraint[0], component_prototype=component_prototype, ref=ref + ) def check_component_constraint( @@ -331,11 +345,12 @@ def check_component_constraint( continue check_components_mapping_contraints( - cluster=cluster, + hosts_count=Host.objects.filter(cluster=cluster).count(), + target_mapping_count=len( + [i for i in hc_in if i[0].prototype == service_prototype and i[2].prototype == component_prototype] + ), service_prototype=service_prototype, - comp=component_prototype, - hc_in=hc_in, - constraint=component_prototype.constraint, + component_prototype=component_prototype, ) From d1d11ea78d620771194cfe60f3758268433b81fe Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Thu, 18 Jan 2024 11:03:18 +0000 Subject: [PATCH 044/151] ADCM-5208 Add inventory tests on configs and imports --- python/api_v2/imports/utils.py | 17 +- python/cm/api.py | 9 +- .../bundles/cluster_full_config/config.yaml | 126 ++++++++ .../bundles/cluster_group_config/config.yaml | 45 +++ .../bundles/provider_full_config/config.yaml | 109 +++++++ .../configs_and_imports/host_1_full.json.j2 | 93 ++++++ .../configs_and_imports/host_2_full.json.j2 | 105 +++++++ .../hostprovider_full.json.j2 | 96 ++++++ .../vars_multiple_imports.json.j2 | 218 ++++++++++++++ .../vars_no_imports.json.j2 | 149 ++++++++++ .../vars_single_imports.json.j2 | 184 ++++++++++++ python/cm/tests/test_inventory/base.py | 46 ++- .../tests/test_inventory/test_group_config.py | 29 +- .../cm/tests/test_inventory/test_imports.py | 280 ++++++++++++++++++ python/cm/variant.py | 22 +- 15 files changed, 1476 insertions(+), 52 deletions(-) create mode 100644 python/cm/tests/bundles/cluster_full_config/config.yaml create mode 100644 python/cm/tests/bundles/provider_full_config/config.yaml create mode 100644 python/cm/tests/files/response_templates/configs_and_imports/host_1_full.json.j2 create mode 100644 python/cm/tests/files/response_templates/configs_and_imports/host_2_full.json.j2 create mode 100644 python/cm/tests/files/response_templates/configs_and_imports/hostprovider_full.json.j2 create mode 100644 python/cm/tests/files/response_templates/configs_and_imports/vars_multiple_imports.json.j2 create mode 100644 python/cm/tests/files/response_templates/configs_and_imports/vars_no_imports.json.j2 create mode 100644 python/cm/tests/files/response_templates/configs_and_imports/vars_single_imports.json.j2 create mode 100644 python/cm/tests/test_inventory/test_imports.py diff --git a/python/api_v2/imports/utils.py b/python/api_v2/imports/utils.py index c02312d89e..45195b1405 100644 --- a/python/api_v2/imports/utils.py +++ b/python/api_v2/imports/utils.py @@ -22,8 +22,8 @@ UIObjectImport, UIPrototype, ) -from cm.api import is_version_suitable -from cm.errors import raise_adcm_ex +from cm.api import DataForMultiBind, is_version_suitable +from cm.errors import AdcmEx, raise_adcm_ex from cm.models import ( Cluster, ClusterBind, @@ -208,19 +208,22 @@ def get_imports(obj: Cluster | ClusterObject) -> list[UIObjectImport]: return out_data -def cook_data_for_multibind(validated_data: list, obj: Cluster | ClusterObject) -> list: +def cook_data_for_multibind(validated_data: list, obj: Cluster | ClusterObject) -> list[DataForMultiBind]: bind_data = [] for item in validated_data: if item["source"]["type"] == ObjectType.CLUSTER: export_obj = Cluster.objects.get(pk=item["source"]["id"]) - cluster_id = export_obj.pk - service_id = None + cluster_id: int = export_obj.pk + service_id: None = None elif item["source"]["type"] == ObjectType.SERVICE: export_obj = ClusterObject.objects.get(pk=item["source"]["id"]) - cluster_id = export_obj.cluster.pk - service_id = export_obj.pk + cluster_id: int = export_obj.cluster.pk + service_id: int = export_obj.pk + + else: + raise AdcmEx("INVALID_INPUT", "Incorrect type of `source`") proto_import = PrototypeImport.objects.filter(name=export_obj.prototype.name, prototype=obj.prototype).first() diff --git a/python/cm/api.py b/python/cm/api.py index 2b9f43a1df..60d7bc6a85 100644 --- a/python/cm/api.py +++ b/python/cm/api.py @@ -13,7 +13,7 @@ import json from functools import partial, wraps -from typing import Literal +from typing import Literal, TypedDict from adcm_version import compare_prototype_versions from cm.adcm_config.config import ( @@ -981,7 +981,12 @@ def get_prototype_import(import_pk: int, import_obj: Cluster | ClusterObject) -> return proto_import -def multi_bind(cluster: Cluster, service: ClusterObject | None, bind_list: list[dict]): +class DataForMultiBind(TypedDict): + import_id: int + export_id: dict[Literal["cluster_id", "service_id"], int] + + +def multi_bind(cluster: Cluster, service: ClusterObject | None, bind_list: list[DataForMultiBind]): check_bind_post(bind_list=bind_list) import_obj = get_bind_obj(cluster=cluster, service=service) old_bind = {} diff --git a/python/cm/tests/bundles/cluster_full_config/config.yaml b/python/cm/tests/bundles/cluster_full_config/config.yaml new file mode 100644 index 0000000000..2616eb1d1b --- /dev/null +++ b/python/cm/tests/bundles/cluster_full_config/config.yaml @@ -0,0 +1,126 @@ +- type: cluster + name: with_all_config_params + version: 1.0 + + import: + very_complex: + multibind: true + for_export: + multibind: true + + actions: &actions + dummy: + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any + + config: &config + - type: boolean + name: boolean + required: false + - type: integer + name: integer + required: false + - type: float + name: float + required: false + - type: string + name: string + required: false + - type: text + name: text + required: false + - type: secrettext + name: secrettext + required: false + - type: password + name: password + required: false + - type: map + name: map + required: false + - type: secretmap + name: secretmap + required: false + - type: json + name: json + required: false + - type: list + name: list + required: false + - type: file + name: file + required: false + - type: secretfile + name: secretfile + required: false + - name: source_list + type: list + default: ["ok", "fail"] + - name: variant_config + required: false + type: variant + source: + type: config + name: source_list + - name: variant_inline + type: variant + required: false + source: + type: inline + value: + - f + - c + - name: variant_builtin + type: variant + required: false + source: + type: builtin + name: host_in_cluster + - name: plain_group + type: group + subs: + - name: simple + type: string + required: false + - name: map + type: map + required: false + - name: file + type: file + required: false + - name: listofstuff + type: list + required: false + # activatable group + - name: activatable_group + type: group + activatable: true + active: false + subs: + - name: simple + type: string + required: false + - name: list + type: list + required: false + +- type: service + name: all_params + version: 1.1 + + import: + very_complex: + multibind: false + for_export: + multibind: false + + actions: *actions + config: *config + + components: + all_params_component: + actions: *actions + config: *config diff --git a/python/cm/tests/bundles/cluster_group_config/config.yaml b/python/cm/tests/bundles/cluster_group_config/config.yaml index 04b8877297..f3243d7785 100644 --- a/python/cm/tests/bundles/cluster_group_config/config.yaml +++ b/python/cm/tests/bundles/cluster_group_config/config.yaml @@ -3,6 +3,11 @@ version: 2.3 config_group_customization: true + export: + - just_integer + - variant_inline + - plain_group + config: &config - name: just_bool type: boolean @@ -139,6 +144,46 @@ states: available: any +- type: service + name: for_export + version: 4.3 + config_group_customization: true + + export: + - just_integer + - plain_group + - activatable_group + + config: + - name: just_integer + type: integer + default: 12 + # plain group + - name: plain_group + type: group + subs: + - name: list_of_dicts + display_name: List of Dicts + type: structure + yspec: ./lod.yaml + required: false + - name: listofstuff + type: list + default: [ "x", "y" ] + # activatable group + - name: activatable_group + type: group + activatable: true + active: false + subs: + - name: simple + type: string + default: "inactgroup" + - name: secretmap + type: secretmap + default: + agk1: agv1 + agk2: agv2 - type: service name: not_simple diff --git a/python/cm/tests/bundles/provider_full_config/config.yaml b/python/cm/tests/bundles/provider_full_config/config.yaml new file mode 100644 index 0000000000..8c6acbde6c --- /dev/null +++ b/python/cm/tests/bundles/provider_full_config/config.yaml @@ -0,0 +1,109 @@ +- type: provider + name: with_all_config_params_provider + version: 1.0 + + actions: &actions + dummy: + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any + + config: &config + - type: boolean + name: boolean + required: false + - type: integer + name: integer + required: false + - type: float + name: float + required: false + - type: string + name: string + required: false + - type: text + name: text + required: false + - type: secrettext + name: secrettext + required: false + - type: password + name: password + required: false + - type: map + name: map + required: false + - type: secretmap + name: secretmap + required: false + - type: json + name: json + required: false + - type: list + name: list + required: false + - type: file + name: file + required: false + - type: secretfile + name: secretfile + required: false + - name: source_list + type: list + default: ["ok", "fail"] + - name: variant_config + required: false + type: variant + source: + type: config + name: source_list + - name: variant_inline + type: variant + required: false + source: + type: inline + value: + - f + - c + - name: variant_builtin + type: variant + required: false + source: + type: builtin + name: host_not_in_clusters + - name: plain_group + type: group + subs: + - name: simple + type: string + required: false + - name: map + type: map + required: false + - name: file + type: file + required: false + - name: listofstuff + type: list + required: false + # activatable group + - name: activatable_group + type: group + activatable: true + active: false + subs: + - name: simple + type: string + required: false + - name: list + type: list + required: false + +- type: host + name: all_params_host + version: 1.1 + + actions: *actions + config: *config diff --git a/python/cm/tests/files/response_templates/configs_and_imports/host_1_full.json.j2 b/python/cm/tests/files/response_templates/configs_and_imports/host_1_full.json.j2 new file mode 100644 index 0000000000..b48378bbc7 --- /dev/null +++ b/python/cm/tests/files/response_templates/configs_and_imports/host_1_full.json.j2 @@ -0,0 +1,93 @@ +{ + "HOST": { + "hosts": { + "host-1": { + "plain_group": { + "simple": null, + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/host.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": null, + "boolean": true, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": null, + "map": {}, + "secretmap": {}, + "json": null, + "list": [ + "1", + "5", + "baset" + ], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": null, + "adcm_hostid": {{ host_1.id }}, + "state": "created", + "multi_state": [] + } + }, + "vars": { + "provider": { + "config": { + "plain_group": { + "simple": null, + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/provider.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": null, + "boolean": true, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": null, + "map": {}, + "secretmap": {}, + "json": null, + "list": [ + "1", + "5", + "baset" + ], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": null + }, + "name": "Host Provider", + "id": {{ hostprovider.id }}, + "host_prototype_id": {{ host_1.prototype.id }}, + "state": "created", + "multi_state": [], + "before_upgrade": { + "state": null + } + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/configs_and_imports/host_2_full.json.j2 b/python/cm/tests/files/response_templates/configs_and_imports/host_2_full.json.j2 new file mode 100644 index 0000000000..1bd4f89dfa --- /dev/null +++ b/python/cm/tests/files/response_templates/configs_and_imports/host_2_full.json.j2 @@ -0,0 +1,105 @@ +{ + "HOST": { + "hosts": { + "host-2": { + "plain_group": { + "simple": "ingroup", + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/host.2.plain_group.file", + "listofstuff": [] + }, + "activatable_group": { + "simple": "inactive", + "list": [ + "one", + "two" + ] + }, + "boolean": true, + "integer": 4102, + "float": 23.43, + "string": "outside", + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": "unbreakable", + "map": { + "see": "yes", + "no": "no" + }, + "secretmap": { + "see": "dont", + "me": "you" + }, + "json": "{\"hey\": [\"yooo\", 1]}", + "list": [ + "1", + "5", + "baset" + ], + "file": "{{ filedir }}/host.2.file.", + "secretfile": "{{ filedir }}/host.2.secretfile.", + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": "host-1", + "adcm_hostid": {{ host_2.id }}, + "state": "created", + "multi_state": [] + } + }, + "vars": { + "provider": { + "config": { + "plain_group": { + "simple": null, + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/provider.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": null, + "boolean": true, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": null, + "map": {}, + "secretmap": {}, + "json": null, + "list": [ + "1", + "5", + "baset" + ], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": null + }, + "name": "Host Provider", + "id": {{ hostprovider.id }}, + "host_prototype_id": {{ host_2.prototype.id }}, + "state": "created", + "multi_state": [], + "before_upgrade": { + "state": null + } + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/configs_and_imports/hostprovider_full.json.j2 b/python/cm/tests/files/response_templates/configs_and_imports/hostprovider_full.json.j2 new file mode 100644 index 0000000000..c3d21c8d87 --- /dev/null +++ b/python/cm/tests/files/response_templates/configs_and_imports/hostprovider_full.json.j2 @@ -0,0 +1,96 @@ +{ + "PROVIDER": { + "hosts": { + "host-1": { + "plain_group": { + "simple": null, + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/host.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": null, + "boolean": true, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": null, + "map": {}, + "secretmap": {}, + "json": null, + "list": [ + "1", + "5", + "baset" + ], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": null, + "adcm_hostid": {{ host_1.id }}, + "state": "created", + "multi_state": [] + }, + "host-2": { + "plain_group": { + "simple": "ingroup", + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/host.2.plain_group.file", + "listofstuff": [] + }, + "activatable_group": { + "simple": "inactive", + "list": [ + "one", + "two" + ] + }, + "boolean": true, + "integer": 4102, + "float": 23.43, + "string": "outside", + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": "unbreakable", + "map": { + "see": "yes", + "no": "no" + }, + "secretmap": { + "see": "dont", + "me": "you" + }, + "json": "{\"hey\": [\"yooo\", 1]}", + "list": [ + "1", + "5", + "baset" + ], + "file": "{{ filedir }}/host.2.file.", + "secretfile": "{{ filedir }}/host.2.secretfile.", + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": "host-1", + "adcm_hostid": {{ host_2.id }}, + "state": "created", + "multi_state": [] + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/configs_and_imports/vars_multiple_imports.json.j2 b/python/cm/tests/files/response_templates/configs_and_imports/vars_multiple_imports.json.j2 new file mode 100644 index 0000000000..81403fde4b --- /dev/null +++ b/python/cm/tests/files/response_templates/configs_and_imports/vars_multiple_imports.json.j2 @@ -0,0 +1,218 @@ +{ + "cluster": { + "config": { + "plain_group": { + "simple": null, + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/cluster.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": null, + "boolean": true, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": null, + "map": {}, + "secretmap": {}, + "json": null, + "list": [ + "1", + "5", + "baset" + ], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": null + }, + "name": "Main Cluster", + "id": {{ cluster.id }}, + "version": "1.0", + "edition": "community", + "state": "created", + "multi_state": [], + "before_upgrade": { + "state": null + }, + "imports": { + "for_export": [ + { + "activatable_group": null + }, + { + "just_integer": 12 + }, + { + "plain_group": { + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + } + }, + { + "activatable_group": { + "simple": "inactgroup", + "secretmap": { + "agk1": "agv1", + "agk2": "agv2", + "one": "two" + } + } + }, + { + "just_integer": 100 + }, + { + "plain_group": { + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + } + ], + "listofstuff": [ + "x", + "y" + ] + } + } + ], + "very_complex": [ + { + "just_integer": 4 + }, + { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/cluster.3.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + } + }, + { + "variant_inline": null + } + ] + } + }, + "services": { + "all_params": { + "id": {{ service.id }}, + "version": "1.1", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": "ingroup", + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/service.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": { + "simple": "inactive", + "list": [ + "one", + "two" + ] + }, + "boolean": true, + "integer": 4102, + "float": 23.43, + "string": "outside", + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": "unbreakable", + "map": { + "see": "yes", + "no": "no" + }, + "secretmap": { + "see": "dont", + "me": "you" + }, + "json": "{\"hey\": [\"yooo\", 1]}", + "list": [ + "1", + "5", + "baset" + ], + "file": "{{ filedir }}/service.1.file.", + "secretfile": "{{ filedir }}/service.1.secretfile.", + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": "host-1" + }, + "maintenance_mode": false, + "display_name": "all_params", + "before_upgrade": { + "state": null + }, + "all_params_component": { + "component_id": {{ component.id }}, + "config": { + "plain_group": { + "simple": null, + "map": {}, + "file": null, + "listofstuff": [] + }, + "activatable_group": null, + "boolean": null, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": null, + "password": null, + "map": {}, + "secretmap": null, + "json": null, + "list": [], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": null, + "variant_builtin": null + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "all_params_component", + "before_upgrade": { + "state": null + } + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/configs_and_imports/vars_no_imports.json.j2 b/python/cm/tests/files/response_templates/configs_and_imports/vars_no_imports.json.j2 new file mode 100644 index 0000000000..824e2e7b8a --- /dev/null +++ b/python/cm/tests/files/response_templates/configs_and_imports/vars_no_imports.json.j2 @@ -0,0 +1,149 @@ +{ + "cluster": { + "config": { + "plain_group": { + "simple": "ingroup", + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/cluster.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": { + "simple": "inactive", + "list": [ + "one", + "two" + ] + }, + "boolean": true, + "integer": 4102, + "float": 23.43, + "string": "outside", + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": "unbreakable", + "map": { + "see": "yes", + "no": "no" + }, + "secretmap": { + "see": "dont", + "me": "you" + }, + "json": "{\"hey\": [\"yooo\", 1]}", + "list": [ + "1", + "5", + "baset" + ], + "file": "{{ filedir }}/cluster.1.file.", + "secretfile": "{{ filedir }}/cluster.1.secretfile.", + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": "host-1" + }, + "name": "Main Cluster", + "id": {{ cluster.id }}, + "version": "1.0", + "edition": "community", + "state": "created", + "multi_state": [], + "before_upgrade": { + "state": null + } + }, + "services": { + "all_params": { + "id": {{ service.id }}, + "version": "1.1", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": null, + "map": {}, + "file": null, + "listofstuff": [] + }, + "activatable_group": null, + "boolean": null, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": null, + "password": null, + "map": {}, + "secretmap": null, + "json": null, + "list": [], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": null, + "variant_builtin": null + }, + "maintenance_mode": false, + "display_name": "all_params", + "before_upgrade": { + "state": null + }, + "all_params_component": { + "component_id": {{ component.id }}, + "config": { + "plain_group": { + "simple": null, + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/component.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": null, + "boolean": true, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": null, + "map": {}, + "secretmap": {}, + "json": null, + "list": [ + "1", + "5", + "baset" + ], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": null + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "all_params_component", + "before_upgrade": { + "state": null + } + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/configs_and_imports/vars_single_imports.json.j2 b/python/cm/tests/files/response_templates/configs_and_imports/vars_single_imports.json.j2 new file mode 100644 index 0000000000..11f68b7964 --- /dev/null +++ b/python/cm/tests/files/response_templates/configs_and_imports/vars_single_imports.json.j2 @@ -0,0 +1,184 @@ +{ + "cluster": { + "config": { + "plain_group": { + "simple": null, + "map": {}, + "file": null, + "listofstuff": [] + }, + "activatable_group": null, + "boolean": null, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": null, + "password": null, + "map": {}, + "secretmap": null, + "json": null, + "list": [], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": null, + "variant_builtin": null + }, + "name": "Main Cluster", + "id": {{ cluster.id }}, + "version": "1.0", + "edition": "community", + "state": "created", + "multi_state": [], + "before_upgrade": { + "state": null + }, + "imports": { + "very_complex": { + "just_integer": 100, + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/cluster.2.plain_group.secretfile", + "list_of_dicts": [ + { + "integer": 2, + "string": "two" + } + ], + "listofstuff": [ + "x", + "y" + ] + }, + "variant_inline": "f" + }, + "for_export": { + "activatable_group": null, + "just_integer": 12, + "plain_group": { + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + } + } + } + }, + "services": { + "all_params": { + "id": {{ service.id }}, + "version": "1.1", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": null, + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/service.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": null, + "boolean": true, + "integer": null, + "float": null, + "string": null, + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": null, + "map": {}, + "secretmap": {}, + "json": null, + "list": [ + "1", + "5", + "baset" + ], + "file": null, + "secretfile": null, + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": null + }, + "maintenance_mode": false, + "display_name": "all_params", + "before_upgrade": { + "state": null + }, + "all_params_component": { + "component_id": {{ component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "map": { + "k": "v", + "key": "val" + }, + "file": "{{ filedir }}/component.1.plain_group.file", + "listofstuff": [] + }, + "activatable_group": { + "simple": "inactive", + "list": [ + "one", + "two" + ] + }, + "boolean": true, + "integer": 4102, + "float": 23.43, + "string": "outside", + "text": null, + "secrettext": "awe\nsopme\n\ttext\n", + "password": "unbreakable", + "map": { + "see": "yes", + "no": "no" + }, + "secretmap": { + "see": "dont", + "me": "you" + }, + "json": "{\"hey\": [\"yooo\", 1]}", + "list": [ + "1", + "5", + "baset" + ], + "file": "{{ filedir }}/component.1.file.", + "secretfile": "{{ filedir }}/component.1.secretfile.", + "source_list": [ + "ok", + "fail" + ], + "variant_config": null, + "variant_inline": "f", + "variant_builtin": "host-1" + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "all_params_component", + "before_upgrade": { + "state": null + } + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/test_inventory/base.py b/python/cm/tests/test_inventory/base.py index 90854ea89e..bd3dda80c8 100644 --- a/python/cm/tests/test_inventory/base.py +++ b/python/cm/tests/test_inventory/base.py @@ -13,12 +13,24 @@ from functools import reduce from json import loads from pathlib import Path -from typing import Any, Iterable, Literal, Mapping, TypeAlias +from typing import Any, Callable, Iterable, Literal, Mapping, TypeAlias +from api_v2.config.utils import convert_adcm_meta_to_attr, convert_attr_to_adcm_meta from cm.adcm_config.ansible import ansible_decrypt -from cm.api import add_hc +from cm.api import add_hc, update_obj_config from cm.inventory import get_inventory_data -from cm.models import Action, ADCMEntity, Cluster, Host, HostComponent, ServiceComponent +from cm.models import ( + Action, + ADCMEntity, + ADCMModel, + Cluster, + ConfigLog, + GroupConfig, + Host, + HostComponent, + ServiceComponent, +) +from cm.utils import deep_merge from django.conf import settings from jinja2 import Template @@ -33,7 +45,10 @@ def decrypt_secrets(source: dict) -> dict: result = {} for key, value in source.items(): if not isinstance(value, dict): - result[key] = value + if isinstance(value, list): + result[key] = [entry if not isinstance(entry, dict) else decrypt_secrets(entry) for entry in value] + else: + result[key] = value continue if "__ansible_vault" in value: @@ -73,6 +88,29 @@ def set_hostcomponent(cluster: Cluster, entries: Iterable[tuple[Host, ServiceCom ], ) + @staticmethod + def change_configuration( + target: ADCMModel | GroupConfig, + config_diff: dict, + meta_diff: dict | None = None, + preprocess_config: Callable[[dict], dict] = lambda x: x, + ) -> ConfigLog: + meta = meta_diff or {} + + target.refresh_from_db() + current_config = ConfigLog.objects.get(id=target.config.current) + + new_config = update_obj_config( + obj_conf=target.config, + config=deep_merge(origin=preprocess_config(current_config.config), renovator=config_diff), + attr=convert_adcm_meta_to_attr( + deep_merge(origin=convert_attr_to_adcm_meta(current_config.attr), renovator=meta) + ), + description="", + ) + + return new_config + def check_data_by_template(self, data: Mapping[str, dict], templates_data: TemplatesData) -> None: for key_chain, template_data in templates_data.items(): template_path, kwargs = template_data diff --git a/python/cm/tests/test_inventory/test_group_config.py b/python/cm/tests/test_inventory/test_group_config.py index 474796f6b9..814d97a71a 100644 --- a/python/cm/tests/test_inventory/test_group_config.py +++ b/python/cm/tests/test_inventory/test_group_config.py @@ -10,16 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. import json -from typing import Callable, Iterable +from typing import Iterable -from api_v2.config.utils import convert_adcm_meta_to_attr, convert_attr_to_adcm_meta from api_v2.service.utils import bulk_add_services_to_cluster -from cm.api import update_obj_config from cm.inventory import get_inventory_data from cm.models import ( Action, ADCMModel, - ConfigLog, GroupConfig, Host, ObjectType, @@ -27,7 +24,6 @@ ServiceComponent, ) from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets -from cm.utils import deep_merge from django.contrib.contenttypes.models import ContentType from jinja2 import Template @@ -80,29 +76,6 @@ def add_group_config(parent: ADCMModel, hosts: Iterable[Host]) -> GroupConfig: group_config.hosts.set(hosts) return group_config - @staticmethod - def change_configuration( - target: ADCMModel | GroupConfig, - config_diff: dict, - meta_diff: dict | None = None, - preprocess_config: Callable[[dict], dict] = lambda x: x, - ) -> ConfigLog: - meta = meta_diff or {} - - target.refresh_from_db() - current_config = ConfigLog.objects.get(id=target.config.current) - - new_config = update_obj_config( - obj_conf=target.config, - config=deep_merge(origin=preprocess_config(current_config.config), renovator=config_diff), - attr=convert_adcm_meta_to_attr( - deep_merge(origin=convert_attr_to_adcm_meta(current_config.attr), renovator=meta) - ), - description="", - ) - - return new_config - def test_group_config_in_inventory(self) -> None: self.set_hostcomponent( cluster=self.cluster, diff --git a/python/cm/tests/test_inventory/test_imports.py b/python/cm/tests/test_inventory/test_imports.py new file mode 100644 index 0000000000..0cef72dec6 --- /dev/null +++ b/python/cm/tests/test_inventory/test_imports.py @@ -0,0 +1,280 @@ +# Licensed 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 json +from typing import Iterable + +from cm.api import DataForMultiBind, multi_bind +from cm.inventory import get_inventory_data +from cm.models import ( + Action, + ADCMModel, + Cluster, + ClusterObject, + PrototypeImport, + ServiceComponent, +) +from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets +from jinja2 import Template + + +class TestConfigAndImportsInInventory(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes + PARTIAL_CONFIG = { + "boolean": True, + "secrettext": "awe\nsopme\n\ttext\n", + "list": ["1", "5", "baset"], + "variant_inline": "f", + "plain_group": {"file": "contente\t\n\n\n\tbest\n\t ", "map": {"k": "v", "key": "val"}}, + } + + FULL_CONFIG = { + **PARTIAL_CONFIG, + "integer": 4102, + "float": 23.43, + "string": "outside", + "password": "unbreakable", + "map": {"see": "yes", "no": "no"}, + "secretmap": {"see": "dont", "me": "you"}, + "json": '{"hey": ["yooo", 1]}', + "file": "filecontent", + "secretfile": "somesecrethere", + "variant_builtin": "host-1", + "plain_group": {**PARTIAL_CONFIG["plain_group"], "simple": "ingroup"}, + "activatable_group": {"simple": "inactive", "list": ["one", "two"]}, + } + + def setUp(self) -> None: + super().setUp() + + self.hostprovider = self.add_provider( + bundle=self.add_bundle(self.bundles_dir / "provider_full_config"), name="Host Provider" + ) + self.host_1 = self.add_host( + bundle=self.hostprovider.prototype.bundle, provider=self.hostprovider, fqdn="host-1" + ) + self.host_2 = self.add_host( + bundle=self.hostprovider.prototype.bundle, provider=self.hostprovider, fqdn="host-2" + ) + + self.cluster = self.add_cluster( + bundle=self.add_bundle(self.bundles_dir / "cluster_full_config"), name="Main Cluster" + ) + self.service = self.add_services_to_cluster(service_names=["all_params"], cluster=self.cluster).first() + self.component = ServiceComponent.objects.get(service=self.service) + + self.export_cluster_1 = self.add_cluster( + bundle=self.add_bundle(self.bundles_dir / "cluster_group_config"), name="Cluster With Export 1" + ) + self.export_cluster_2 = self.add_cluster( + bundle=self.export_cluster_1.prototype.bundle, name="Cluster With Export 2" + ) + self.export_service_1 = self.add_services_to_cluster( + service_names=["for_export"], cluster=self.export_cluster_1 + ).first() + self.export_service_2 = self.add_services_to_cluster( + service_names=["for_export"], cluster=self.export_cluster_2 + ).first() + + self.context = { + "cluster": self.cluster, + "service": self.service, + "component": self.component, + "host_1": self.host_1, + "host_2": self.host_2, + "hostprovider": self.hostprovider, + "filedir": self.directories["FILE_DIR"], + } + + def prepare_cluster_hostcomponent(self) -> None: + self.add_host_to_cluster(cluster=self.cluster, host=self.host_1) + self.add_host_to_cluster(cluster=self.cluster, host=self.host_2) + self.set_hostcomponent( + cluster=self.cluster, entries=((self.host_1, self.component), (self.host_2, self.component)) + ) + + @staticmethod + def bind_objects(*entries: tuple[Cluster | ClusterObject, Iterable[Cluster | ClusterObject]]) -> None: + for import_object, export_objects in entries: + multibind_data: list[DataForMultiBind] = [] + + for export_object in export_objects: + if isinstance(export_object, Cluster): + export_entry = {"cluster_id": export_object.pk} + else: + export_entry = {"cluster_id": export_object.cluster.pk, "service_id": export_object.pk} + + proto_import = PrototypeImport.objects.filter( + name=export_object.prototype.name, prototype=import_object.prototype + ).first() + + multibind_data.append({"import_id": int(proto_import.pk), "export_id": export_entry}) + + if isinstance(import_object, Cluster): + multi_bind(cluster=import_object, service=None, bind_list=multibind_data) + else: + multi_bind(cluster=import_object.cluster, service=import_object, bind_list=multibind_data) + + def change_config_partial(self, target: ADCMModel) -> None: + self.change_configuration( + target=target, + config_diff=self.PARTIAL_CONFIG, + preprocess_config=lambda d: { + **d, + "map": {}, + "secretmap": {}, + "plain_group": {**d["plain_group"], "map": {}}, + }, + ) + + def change_config_full(self, target: ADCMModel) -> None: + self.change_configuration( + target=target, + config_diff=self.FULL_CONFIG, + meta_diff={"/activatable_group": {"isActive": True}}, + preprocess_config=lambda d: { + **d, + "map": {}, + "secretmap": {}, + "activatable_group": d["activatable_group"], + "plain_group": {**d["plain_group"], "map": {}}, + }, + ) + + def test_hostprovider_objects_success(self) -> None: + self.change_config_partial(target=self.host_1) + self.change_config_full(target=self.host_2) + self.change_config_partial(target=self.hostprovider) + + for object_, template in ( + (self.hostprovider, "hostprovider_full.json.j2"), + (self.host_1, "host_1_full.json.j2"), + (self.host_2, "host_2_full.json.j2"), + ): + actual_inventory = decrypt_secrets( + get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ + "all" + ]["children"] + ) + expected_inventory = json.loads( + Template( + source=(self.templates_dir / "configs_and_imports" / template).read_text(encoding="utf-8") + ).render(**self.context) + ) + self.assertDictEqual(actual_inventory, expected_inventory) + + def test_cluster_objects_no_import_success(self) -> None: + self.prepare_cluster_hostcomponent() + + self.change_config_full(target=self.cluster) + self.change_config_partial(target=self.component) + + expected_vars = json.loads( + Template( + source=(self.templates_dir / "configs_and_imports" / "vars_no_imports.json.j2").read_text( + encoding="utf-8" + ) + ).render(**self.context) + ) + + for object_ in (self.cluster, self.service, self.component): + actual_inventory = decrypt_secrets( + get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ + "all" + ]["children"] + ) + + self.assertDictEqual(actual_inventory["CLUSTER"]["vars"], expected_vars) + + def test_cluster_objects_single_import_success(self) -> None: + self.prepare_cluster_hostcomponent() + + self.change_config_partial(target=self.service) + self.change_config_full(target=self.component) + + self.change_configuration( + target=self.export_cluster_1, + config_diff={ + "list_of_dicts": [{"integer": 1, "string": "one"}], + "just_integer": 100, + "variant_inline": "f", + "plain_group": {"list_of_dicts": [{"integer": 2, "string": "two"}]}, + }, + ) + + self.bind_objects( + # undefined behavior + # (self.cluster, [self.export_cluster_1]), + (self.service, [self.export_cluster_1, self.export_service_1]), + ) + + expected_vars = json.loads( + Template( + source=(self.templates_dir / "configs_and_imports" / "vars_single_imports.json.j2").read_text( + encoding="utf-8" + ) + ).render(**self.context) + ) + + for object_ in (self.cluster, self.service, self.component): + actual_inventory = decrypt_secrets( + get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ + "all" + ]["children"] + ) + self.assertDictEqual(actual_inventory["CLUSTER"]["vars"], expected_vars) + + def test_cluster_objects_multi_import_success(self) -> None: + self.prepare_cluster_hostcomponent() + + self.change_config_partial(target=self.cluster) + self.change_config_full(target=self.service) + + self.bind_objects( + (self.cluster, [self.export_cluster_2, self.export_service_1, self.export_service_2]), + # undefined behavior + # (self.service, [self.export_cluster_1, self.export_service_2]), + ) + + self.change_configuration( + target=self.export_cluster_1, + config_diff={ + "list_of_dicts": [{"integer": 1, "string": "one"}], + "just_integer": 100, + "variant_inline": "f", + "plain_group": {"list_of_dicts": [{"integer": 2, "string": "two"}]}, + }, + ) + self.change_configuration( + target=self.export_service_2, + config_diff={ + "just_integer": 100, + "plain_group": {"list_of_dicts": [{"integer": 3, "string": "three"}]}, + "activatable_group": {"secretmap": {"one": "two"}}, + }, + meta_diff={"/activatable_group": {"isActive": True}}, + preprocess_config=lambda d: {**d, "activatable_group": d["activatable_group"]}, + ) + + expected_vars = json.loads( + Template( + source=(self.templates_dir / "configs_and_imports" / "vars_multiple_imports.json.j2").read_text( + encoding="utf-8" + ) + ).render(**self.context) + ) + + for object_ in (self.cluster, self.service, self.component): + actual_inventory = decrypt_secrets( + get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ + "all" + ]["children"] + ) + self.assertDictEqual(actual_inventory["CLUSTER"]["vars"], expected_vars) diff --git a/python/cm/variant.py b/python/cm/variant.py index 0c81e6dcf5..bab3bd27b0 100644 --- a/python/cm/variant.py +++ b/python/cm/variant.py @@ -16,6 +16,7 @@ from cm.errors import raise_adcm_ex as err from cm.logger import logger from cm.models import ( + Cluster, ClusterObject, GroupConfig, Host, @@ -47,20 +48,19 @@ def with_not_found_handle(*args, **kwargs): return with_not_found_handle -def get_cluster(obj): +def get_cluster(obj) -> Cluster | None: if isinstance(obj, GroupConfig): obj = obj.object - if obj.prototype.type == "service": - cluster = obj.cluster - elif obj.prototype.type == "host": - cluster = obj.cluster - elif obj.prototype.type == "cluster": - cluster = obj - else: - return None - - return cluster + match obj.prototype.type: + case "cluster": + return obj + case "service" | "component": + return obj.cluster + case "host": + return obj.cluster + case _: + return None def variant_service_in_cluster(**kwargs): From 72eb43a449c7a14c9ca533cbd7acc4f9272bc144 Mon Sep 17 00:00:00 2001 From: Daniil Skrynnik Date: Thu, 18 Jan 2024 11:07:40 +0000 Subject: [PATCH 045/151] ADCM-5206: Add tests for action on provider/host --- .../test_inventory/test_hostprovider_host.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 python/cm/tests/test_inventory/test_hostprovider_host.py diff --git a/python/cm/tests/test_inventory/test_hostprovider_host.py b/python/cm/tests/test_inventory/test_hostprovider_host.py new file mode 100644 index 0000000000..02a26f331d --- /dev/null +++ b/python/cm/tests/test_inventory/test_hostprovider_host.py @@ -0,0 +1,75 @@ +# Licensed 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. + +from cm.models import Action +from cm.tests.test_inventory.base import BaseInventoryTestCase + + +class TestInventoryHostproviderHost(BaseInventoryTestCase): + def setUp(self) -> None: + super().setUp() + + self.provider_bundle = self.add_bundle(source_dir=self.bundles_dir / "provider") + + self.hostprovider = self.add_provider(bundle=self.provider_bundle, name="provider") + self.host_1 = self.add_host(bundle=self.provider_bundle, provider=self.hostprovider, fqdn="host_1") + self.host_2 = self.add_host(bundle=self.provider_bundle, provider=self.hostprovider, fqdn="host_2") + + self.action_on_hostprovider = Action.objects.get( + name="action_on_provider", prototype=self.hostprovider.prototype + ) + self.action_on_host_1 = Action.objects.get(name="action_on_host", prototype=self.host_1.prototype) + + def test_action_on_hostprovider(self): + expected_topology = {"PROVIDER": [self.host_1.fqdn, self.host_2.fqdn]} + expected_data = { + ("PROVIDER", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_2_id": self.host_2.pk, + }, + ) + } + + self.assert_inventory( + obj=self.hostprovider, + action=self.action_on_hostprovider, + expected_topology=expected_topology, + expected_data=expected_data, + ) + + def test_action_on_host(self): + expected_topology = {"HOST": [self.host_1.fqdn]} + expected_data = { + ("HOST", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + }, + ), + ("HOST", "vars", "provider"): ( + self.templates_dir / "provider.json.j2", + { + "id": self.host_1.provider.pk, + "host_prototype_id": self.host_1.prototype.pk, + }, + ), + } + + self.assert_inventory( + obj=self.host_1, + action=self.action_on_host_1, + expected_topology=expected_topology, + expected_data=expected_data, + ) From 6ba7a1493b8c32cde3742eb33f12b2fadcea1a33 Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Thu, 18 Jan 2024 12:03:18 +0000 Subject: [PATCH 046/151] ADCM-5209 Add test on action configs generation (config.json) Changed: 1. Added `vars` check to group config in inventory test 2. Template rendering extracted to common test functions 3. Couple of sub-tests added to existing tests Added: 1. Test on action config generation --- python/cm/job.py | 25 +- .../bundles/cluster_full_config/config.yaml | 25 +- .../bundles/provider_full_config/config.yaml | 20 +- .../action_configs/cluster.json.j2 | 61 +++ .../action_configs/cluster_on_host.json.j2 | 103 ++++ .../action_configs/component.json.j2 | 95 ++++ .../action_configs/component_on_host.json.j2 | 67 +++ .../action_configs/host.json.j2 | 95 ++++ .../action_configs/hostprovider.json.j2 | 102 ++++ .../action_configs/service.json.j2 | 105 ++++ .../action_configs/service_on_host.json.j2 | 94 ++++ .../group_config/vars.json.j2 | 487 ++++++++++++++++++ python/cm/tests/test_inventory/base.py | 15 +- .../test_inventory/test_action_config.py | 126 +++++ .../tests/test_inventory/test_group_config.py | 29 +- .../cm/tests/test_inventory/test_imports.py | 70 +-- python/cm/tests/test_job.py | 17 +- 17 files changed, 1431 insertions(+), 105 deletions(-) create mode 100644 python/cm/tests/files/response_templates/action_configs/cluster.json.j2 create mode 100644 python/cm/tests/files/response_templates/action_configs/cluster_on_host.json.j2 create mode 100644 python/cm/tests/files/response_templates/action_configs/component.json.j2 create mode 100644 python/cm/tests/files/response_templates/action_configs/component_on_host.json.j2 create mode 100644 python/cm/tests/files/response_templates/action_configs/host.json.j2 create mode 100644 python/cm/tests/files/response_templates/action_configs/hostprovider.json.j2 create mode 100644 python/cm/tests/files/response_templates/action_configs/service.json.j2 create mode 100644 python/cm/tests/files/response_templates/action_configs/service_on_host.json.j2 create mode 100644 python/cm/tests/files/response_templates/group_config/vars.json.j2 create mode 100644 python/cm/tests/test_inventory/test_action_config.py diff --git a/python/cm/job.py b/python/cm/job.py index 9c015738ef..7d75c3d2bf 100644 --- a/python/cm/job.py +++ b/python/cm/job.py @@ -447,7 +447,7 @@ def get_bundle_root(action: Action) -> str: return str(settings.BUNDLE_DIR) -def cook_script(action: Action, sub_action: SubAction): +def cook_script(action: Action, sub_action: SubAction | None): prefix = action.prototype.bundle.hash script = action.script @@ -521,7 +521,7 @@ def prepare_job( hosts: JSONField | None, verbose: bool, ): - prepare_job_config(action, sub_action, job_id, obj, conf, verbose) + write_job_config(job_id=job_id, config=prepare_job_config(action, sub_action, job_id, obj, conf, verbose)) prepare_job_inventory(obj, job_id, action, delta, hosts) prepare_ansible_config(job_id, action, sub_action) @@ -576,12 +576,12 @@ def prepare_context( def prepare_job_config( action: Action, - sub_action: SubAction, + sub_action: SubAction | None, job_id: int, obj: ADCM | Cluster | ClusterObject | ServiceComponent | HostProvider | Host, - conf: JSONField | None, + conf: dict | JSONField | None, verbose: bool, -): +) -> dict: # pylint: disable=too-many-branches,too-many-statements job_conf = { @@ -590,7 +590,7 @@ def prepare_job_config( "env": { "run_dir": str(settings.RUN_DIR), "log_dir": str(settings.LOG_DIR), - "tmp_dir": str(Path(settings.RUN_DIR, f"{job_id}", "tmp")), + "tmp_dir": str(settings.RUN_DIR / f"{job_id}" / "tmp"), "stack_dir": str(Path(get_bundle_root(action), action.prototype.bundle.hash)), "status_api_token": str(settings.STATUS_SECRET_KEY), }, @@ -656,17 +656,20 @@ def prepare_job_config( elif action.prototype.type == "adcm": job_conf["job"]["hostgroup"] = "127.0.0.1" else: - raise_adcm_ex("NOT_IMPLEMENTED", f'unknown prototype type "{action.prototype.type}"') + raise AdcmEx("NOT_IMPLEMENTED", f'unknown prototype type "{action.prototype.type}"') if conf: job_conf["job"]["config"] = conf - with open( - Path(settings.RUN_DIR, f"{job_id}", "config.json"), - "w", + return job_conf + + +def write_job_config(job_id: int, config: dict) -> None: + with (settings.RUN_DIR / f"{job_id}" / "config.json").open( + mode="w", encoding=settings.ENCODING_UTF_8, ) as file_descriptor: - json.dump(job_conf, file_descriptor, sort_keys=True, separators=(",", ":")) + json.dump(config, file_descriptor, sort_keys=True, separators=(",", ":")) def create_task( diff --git a/python/cm/tests/bundles/cluster_full_config/config.yaml b/python/cm/tests/bundles/cluster_full_config/config.yaml index 2616eb1d1b..ad1efbdf33 100644 --- a/python/cm/tests/bundles/cluster_full_config/config.yaml +++ b/python/cm/tests/bundles/cluster_full_config/config.yaml @@ -8,14 +8,6 @@ for_export: multibind: true - actions: &actions - dummy: - type: job - script: ./playbook.yaml - script_type: ansible - states: - available: any - config: &config - type: boolean name: boolean @@ -107,6 +99,23 @@ type: list required: false + actions: &actions + dummy: &job + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any + + with_config: + <<: *job + config: *config + + with_config_on_host: + <<: *job + config: *config + host_action: true + - type: service name: all_params version: 1.1 diff --git a/python/cm/tests/bundles/provider_full_config/config.yaml b/python/cm/tests/bundles/provider_full_config/config.yaml index 8c6acbde6c..a69e62607a 100644 --- a/python/cm/tests/bundles/provider_full_config/config.yaml +++ b/python/cm/tests/bundles/provider_full_config/config.yaml @@ -2,14 +2,6 @@ name: with_all_config_params_provider version: 1.0 - actions: &actions - dummy: - type: job - script: ./playbook.yaml - script_type: ansible - states: - available: any - config: &config - type: boolean name: boolean @@ -101,6 +93,18 @@ type: list required: false + actions: &actions + dummy: &job + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any + + with_config: + <<: *job + config: *config + - type: host name: all_params_host version: 1.1 diff --git a/python/cm/tests/files/response_templates/action_configs/cluster.json.j2 b/python/cm/tests/files/response_templates/action_configs/cluster.json.j2 new file mode 100644 index 0000000000..be4110b3ad --- /dev/null +++ b/python/cm/tests/files/response_templates/action_configs/cluster.json.j2 @@ -0,0 +1,61 @@ +{ + "adcm": { + "config": { + "global": { + "adcm_url": null, + "verification_public_key": "{{ stackdir }}/data/file/adcm.1.global.verification_public_key" + }, + "statistics_collection": { + "url": "adcm-usage-ss.arenadata.io" + }, + "google_oauth": { + "client_id": null, + "secret": null + }, + "yandex_oauth": { + "client_id": null, + "secret": null + }, + "ansible_settings": { + "forks": 5 + }, + "logrotate": null, + "audit_data_retention": { + "log_rotation_on_fs": 365, + "log_rotation_in_db": 365, + "config_rotation_in_db": 0, + "retention_period": 1825, + "data_archiving": false + }, + "ldap_integration": null, + "auth_policy": { + "min_password_length": 12, + "max_password_length": 20, + "login_attempt_limit": 5, + "block_time": 5 + } + } + }, + "context": { + "cluster_id": 1, + "type": "cluster" + }, + "env": { + "run_dir": "{{ datadir }}/run", + "log_dir": "{{ datadir }}/log", + "tmp_dir": "{{ datadir }}/run/1/tmp", + "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", + "status_api_token": "{{ token }}" + }, + "job": { + "id": 1, + "action": "with_config", + "job_name": "with_config", + "command": "with_config", + "script": "./playbook.yaml", + "verbose": false, + "playbook": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}/playbook.yaml", + "cluster_id": 1, + "hostgroup": "CLUSTER" + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/action_configs/cluster_on_host.json.j2 b/python/cm/tests/files/response_templates/action_configs/cluster_on_host.json.j2 new file mode 100644 index 0000000000..45643630e4 --- /dev/null +++ b/python/cm/tests/files/response_templates/action_configs/cluster_on_host.json.j2 @@ -0,0 +1,103 @@ +{ + "adcm": { + "config": { + "global": { + "adcm_url": null, + "verification_public_key": "{{ stackdir }}/data/file/adcm.1.global.verification_public_key" + }, + "statistics_collection": { + "url": "adcm-usage-ss.arenadata.io" + }, + "google_oauth": { + "client_id": null, + "secret": null + }, + "yandex_oauth": { + "client_id": null, + "secret": null + }, + "ansible_settings": { + "forks": 5 + }, + "logrotate": null, + "audit_data_retention": { + "log_rotation_on_fs": 365, + "log_rotation_in_db": 365, + "config_rotation_in_db": 0, + "retention_period": 1825, + "data_archiving": false + }, + "ldap_integration": null, + "auth_policy": { + "min_password_length": 12, + "max_password_length": 20, + "login_attempt_limit": 5, + "block_time": 5 + } + } + }, + "context": { + "host_id": 1, + "cluster_id": 1, + "type": "cluster" + }, + "env": { + "run_dir": "{{ datadir }}/run", + "log_dir": "{{ datadir }}/log", + "tmp_dir": "{{ datadir }}/run/100/tmp", + "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", + "status_api_token": "{{ token }}" + }, + "job": { + "id": 100, + "action": "with_config_on_host", + "job_name": "with_config_on_host", + "command": "with_config_on_host", + "script": "./playbook.yaml", + "verbose": true, + "playbook": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}/playbook.yaml", + "cluster_id": 1, + "hostgroup": "CLUSTER", + "config": { + "boolean": true, + "secrettext": "awe\nsopme\n\ttext\n", + "list": [ + "1", + "5", + "baset" + ], + "variant_inline": "f", + "plain_group": { + "file": "contente\t\n\n\n\tbest\n\t ", + "map": { + "k": "v", + "key": "val" + }, + "simple": "ingroup" + }, + "integer": 4102, + "float": 23.43, + "string": "outside", + "password": "unbreakable", + "map": { + "see": "yes", + "no": "no" + }, + "secretmap": { + "see": "dont", + "me": "you" + }, + "json": "{\"hey\": [\"yooo\", 1]}", + "file": "filecontent", + "secretfile": "somesecrethere", + "variant_builtin": "host-1", + "activatable_group": { + "simple": "inactive", + "list": [ + "one", + "two" + ] + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/action_configs/component.json.j2 b/python/cm/tests/files/response_templates/action_configs/component.json.j2 new file mode 100644 index 0000000000..d289c4a087 --- /dev/null +++ b/python/cm/tests/files/response_templates/action_configs/component.json.j2 @@ -0,0 +1,95 @@ +{ + "adcm": { + "config": { + "global": { + "adcm_url": null, + "verification_public_key": "{{ stackdir }}/data/file/adcm.1.global.verification_public_key" + }, + "statistics_collection": { + "url": "adcm-usage-ss.arenadata.io" + }, + "google_oauth": { + "client_id": null, + "secret": null + }, + "yandex_oauth": { + "client_id": null, + "secret": null + }, + "ansible_settings": { + "forks": 5 + }, + "logrotate": null, + "audit_data_retention": { + "log_rotation_on_fs": 365, + "log_rotation_in_db": 365, + "config_rotation_in_db": 0, + "retention_period": 1825, + "data_archiving": false + }, + "ldap_integration": null, + "auth_policy": { + "min_password_length": 12, + "max_password_length": 20, + "login_attempt_limit": 5, + "block_time": 5 + } + } + }, + "context": { + "component_id": 1, + "service_id": 1, + "cluster_id": 1, + "type": "component" + }, + "env": { + "run_dir": "{{ datadir }}/run", + "log_dir": "{{ datadir }}/log", + "tmp_dir": "{{ datadir }}/run/1/tmp", + "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", + "status_api_token": "{{ token }}" + }, + "job": { + "id": 1, + "action": "with_config", + "job_name": "with_config", + "command": "with_config", + "script": "./playbook.yaml", + "verbose": false, + "playbook": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}/playbook.yaml", + "cluster_id": 1, + "hostgroup": "all_params.all_params_component", + "service_id": 1, + "component_id": 1, + "component_type_id": 6, + "config": { + "boolean": true, + "secrettext": "awe\nsopme\n\ttext\n", + "list": [ + "1", + "5", + "baset" + ], + "variant_inline": "f", + "plain_group": { + "file": "contente\t\n\n\n\tbest\n\t ", + "map": { + "k": "v", + "key": "val" + }, + "simple": null + }, + "integer": null, + "float": null, + "string": null, + "password": null, + "map": null, + "secretmap": null, + "json": null, + "file": null, + "secretfile": null, + "variant_builtin": null, + "activatable_group": null + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/action_configs/component_on_host.json.j2 b/python/cm/tests/files/response_templates/action_configs/component_on_host.json.j2 new file mode 100644 index 0000000000..27d577f4a9 --- /dev/null +++ b/python/cm/tests/files/response_templates/action_configs/component_on_host.json.j2 @@ -0,0 +1,67 @@ +{ + "adcm": { + "config": { + "global": { + "adcm_url": null, + "verification_public_key": "{{ stackdir }}/data/file/adcm.1.global.verification_public_key" + }, + "statistics_collection": { + "url": "adcm-usage-ss.arenadata.io" + }, + "google_oauth": { + "client_id": null, + "secret": null + }, + "yandex_oauth": { + "client_id": null, + "secret": null + }, + "ansible_settings": { + "forks": 5 + }, + "logrotate": null, + "audit_data_retention": { + "log_rotation_on_fs": 365, + "log_rotation_in_db": 365, + "config_rotation_in_db": 0, + "retention_period": 1825, + "data_archiving": false + }, + "ldap_integration": null, + "auth_policy": { + "min_password_length": 12, + "max_password_length": 20, + "login_attempt_limit": 5, + "block_time": 5 + } + } + }, + "context": { + "host_id": 1, + "component_id": 1, + "service_id": 1, + "cluster_id": 1, + "type": "component" + }, + "env": { + "run_dir": "{{ datadir }}/run", + "log_dir": "{{ datadir }}/log", + "tmp_dir": "{{ datadir }}/run/100/tmp", + "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", + "status_api_token": "{{ token }}" + }, + "job": { + "id": 100, + "action": "with_config_on_host", + "job_name": "with_config_on_host", + "command": "with_config_on_host", + "script": "./playbook.yaml", + "verbose": true, + "playbook": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}/playbook.yaml", + "cluster_id": 1, + "hostgroup": "all_params.all_params_component", + "service_id": 1, + "component_id": 1, + "component_type_id": 6 + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/action_configs/host.json.j2 b/python/cm/tests/files/response_templates/action_configs/host.json.j2 new file mode 100644 index 0000000000..d1bb37a557 --- /dev/null +++ b/python/cm/tests/files/response_templates/action_configs/host.json.j2 @@ -0,0 +1,95 @@ +{ + "adcm": { + "config": { + "global": { + "adcm_url": null, + "verification_public_key": "{{ stackdir }}/data/file/adcm.1.global.verification_public_key" + }, + "statistics_collection": { + "url": "adcm-usage-ss.arenadata.io" + }, + "google_oauth": { + "client_id": null, + "secret": null + }, + "yandex_oauth": { + "client_id": null, + "secret": null + }, + "ansible_settings": { + "forks": 5 + }, + "logrotate": null, + "audit_data_retention": { + "log_rotation_on_fs": 365, + "log_rotation_in_db": 365, + "config_rotation_in_db": 0, + "retention_period": 1825, + "data_archiving": false + }, + "ldap_integration": null, + "auth_policy": { + "min_password_length": 12, + "max_password_length": 20, + "login_attempt_limit": 5, + "block_time": 5 + } + } + }, + "context": { + "host_id": 1, + "provider_id": 1, + "type": "host" + }, + "env": { + "run_dir": "{{ datadir }}/run", + "log_dir": "{{ datadir }}/log", + "tmp_dir": "{{ datadir }}/run/1/tmp", + "stack_dir": "{{ stackdir }}/data/bundle/{{ hostprovider_bundle.hash }}", + "status_api_token": "{{ token }}" + }, + "job": { + "id": 1, + "action": "with_config", + "job_name": "with_config", + "command": "with_config", + "script": "./playbook.yaml", + "verbose": false, + "playbook": "{{ stackdir }}/data/bundle/{{ hostprovider_bundle.hash }}/playbook.yaml", + "cluster_id": 1, + "hostgroup": "HOST", + "hostname": "host-1", + "host_id": 1, + "host_type_id": 3, + "provider_id": 1, + "config": { + "boolean": true, + "secrettext": "awe\nsopme\n\ttext\n", + "list": [ + "1", + "5", + "baset" + ], + "variant_inline": "f", + "plain_group": { + "file": "contente\t\n\n\n\tbest\n\t ", + "map": { + "k": "v", + "key": "val" + }, + "simple": null + }, + "integer": null, + "float": null, + "string": null, + "password": null, + "map": null, + "secretmap": null, + "json": null, + "file": null, + "secretfile": null, + "variant_builtin": null, + "activatable_group": null + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/action_configs/hostprovider.json.j2 b/python/cm/tests/files/response_templates/action_configs/hostprovider.json.j2 new file mode 100644 index 0000000000..809ab856ae --- /dev/null +++ b/python/cm/tests/files/response_templates/action_configs/hostprovider.json.j2 @@ -0,0 +1,102 @@ +{ + "adcm": { + "config": { + "global": { + "adcm_url": null, + "verification_public_key": "{{ stackdir }}/data/file/adcm.1.global.verification_public_key" + }, + "statistics_collection": { + "url": "adcm-usage-ss.arenadata.io" + }, + "google_oauth": { + "client_id": null, + "secret": null + }, + "yandex_oauth": { + "client_id": null, + "secret": null + }, + "ansible_settings": { + "forks": 5 + }, + "logrotate": null, + "audit_data_retention": { + "log_rotation_on_fs": 365, + "log_rotation_in_db": 365, + "config_rotation_in_db": 0, + "retention_period": 1825, + "data_archiving": false + }, + "ldap_integration": null, + "auth_policy": { + "min_password_length": 12, + "max_password_length": 20, + "login_attempt_limit": 5, + "block_time": 5 + } + } + }, + "context": { + "provider_id": 1, + "type": "provider" + }, + "env": { + "run_dir": "{{ datadir }}/run", + "log_dir": "{{ datadir }}/log", + "tmp_dir": "{{ datadir }}/run/1/tmp", + "stack_dir": "{{ stackdir }}/data/bundle/{{ hostprovider_bundle.hash }}", + "status_api_token": "{{ token }}" + }, + "job": { + "id": 1, + "action": "with_config", + "job_name": "with_config", + "command": "with_config", + "script": "./playbook.yaml", + "verbose": false, + "playbook": "{{ stackdir }}/data/bundle/{{ hostprovider_bundle.hash }}/playbook.yaml", + "hostgroup": "PROVIDER", + "provider_id": 1, + "config": { + "boolean": true, + "secrettext": "awe\nsopme\n\ttext\n", + "list": [ + "1", + "5", + "baset" + ], + "variant_inline": "f", + "plain_group": { + "file": "contente\t\n\n\n\tbest\n\t ", + "map": { + "k": "v", + "key": "val" + }, + "simple": "ingroup" + }, + "integer": 4102, + "float": 23.43, + "string": "outside", + "password": "unbreakable", + "map": { + "see": "yes", + "no": "no" + }, + "secretmap": { + "see": "dont", + "me": "you" + }, + "json": "{\"hey\": [\"yooo\", 1]}", + "file": "filecontent", + "secretfile": "somesecrethere", + "variant_builtin": "host-1", + "activatable_group": { + "simple": "inactive", + "list": [ + "one", + "two" + ] + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/action_configs/service.json.j2 b/python/cm/tests/files/response_templates/action_configs/service.json.j2 new file mode 100644 index 0000000000..612f19ee18 --- /dev/null +++ b/python/cm/tests/files/response_templates/action_configs/service.json.j2 @@ -0,0 +1,105 @@ +{ + "adcm": { + "config": { + "global": { + "adcm_url": null, + "verification_public_key": "{{ stackdir }}/data/file/adcm.1.global.verification_public_key" + }, + "statistics_collection": { + "url": "adcm-usage-ss.arenadata.io" + }, + "google_oauth": { + "client_id": null, + "secret": null + }, + "yandex_oauth": { + "client_id": null, + "secret": null + }, + "ansible_settings": { + "forks": 5 + }, + "logrotate": null, + "audit_data_retention": { + "log_rotation_on_fs": 365, + "log_rotation_in_db": 365, + "config_rotation_in_db": 0, + "retention_period": 1825, + "data_archiving": false + }, + "ldap_integration": null, + "auth_policy": { + "min_password_length": 12, + "max_password_length": 20, + "login_attempt_limit": 5, + "block_time": 5 + } + } + }, + "context": { + "service_id": 1, + "cluster_id": 1, + "type": "service" + }, + "env": { + "run_dir": "{{ datadir }}/run", + "log_dir": "{{ datadir }}/log", + "tmp_dir": "{{ datadir }}/run/1/tmp", + "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", + "status_api_token": "{{ token }}" + }, + "job": { + "id": 1, + "action": "with_config", + "job_name": "with_config", + "command": "with_config", + "script": "./playbook.yaml", + "verbose": false, + "playbook": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}/playbook.yaml", + "cluster_id": 1, + "hostgroup": "all_params", + "service_id": 1, + "service_type_id": 5, + "config": { + "boolean": true, + "secrettext": "awe\nsopme\n\ttext\n", + "list": [ + "1", + "5", + "baset" + ], + "variant_inline": "f", + "plain_group": { + "file": "contente\t\n\n\n\tbest\n\t ", + "map": { + "k": "v", + "key": "val" + }, + "simple": "ingroup" + }, + "integer": 4102, + "float": 23.43, + "string": "outside", + "password": "unbreakable", + "map": { + "see": "yes", + "no": "no" + }, + "secretmap": { + "see": "dont", + "me": "you" + }, + "json": "{\"hey\": [\"yooo\", 1]}", + "file": "filecontent", + "secretfile": "somesecrethere", + "variant_builtin": "host-1", + "activatable_group": { + "simple": "inactive", + "list": [ + "one", + "two" + ] + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/action_configs/service_on_host.json.j2 b/python/cm/tests/files/response_templates/action_configs/service_on_host.json.j2 new file mode 100644 index 0000000000..e3fc7ec5e7 --- /dev/null +++ b/python/cm/tests/files/response_templates/action_configs/service_on_host.json.j2 @@ -0,0 +1,94 @@ +{ + "adcm": { + "config": { + "global": { + "adcm_url": null, + "verification_public_key": "{{ stackdir }}/data/file/adcm.1.global.verification_public_key" + }, + "statistics_collection": { + "url": "adcm-usage-ss.arenadata.io" + }, + "google_oauth": { + "client_id": null, + "secret": null + }, + "yandex_oauth": { + "client_id": null, + "secret": null + }, + "ansible_settings": { + "forks": 5 + }, + "logrotate": null, + "audit_data_retention": { + "log_rotation_on_fs": 365, + "log_rotation_in_db": 365, + "config_rotation_in_db": 0, + "retention_period": 1825, + "data_archiving": false + }, + "ldap_integration": null, + "auth_policy": { + "min_password_length": 12, + "max_password_length": 20, + "login_attempt_limit": 5, + "block_time": 5 + } + } + }, + "context": { + "host_id": 1, + "service_id": 1, + "cluster_id": 1, + "type": "service" + }, + "env": { + "run_dir": "{{ datadir }}/run", + "log_dir": "{{ datadir }}/log", + "tmp_dir": "{{ datadir }}/run/100/tmp", + "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", + "status_api_token": "{{ token }}" + }, + "job": { + "id": 100, + "action": "with_config_on_host", + "job_name": "with_config_on_host", + "command": "with_config_on_host", + "script": "./playbook.yaml", + "verbose": true, + "playbook": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}/playbook.yaml", + "cluster_id": 1, + "hostgroup": "all_params", + "service_id": 1, + "service_type_id": 5, + "config": { + "boolean": true, + "secrettext": "awe\nsopme\n\ttext\n", + "list": [ + "1", + "5", + "baset" + ], + "variant_inline": "f", + "plain_group": { + "file": "contente\t\n\n\n\tbest\n\t ", + "map": { + "k": "v", + "key": "val" + }, + "simple": null + }, + "integer": null, + "float": null, + "string": null, + "password": null, + "map": null, + "secretmap": null, + "json": null, + "file": null, + "secretfile": null, + "variant_builtin": null, + "activatable_group": null + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/group_config/vars.json.j2 b/python/cm/tests/files/response_templates/group_config/vars.json.j2 new file mode 100644 index 0000000000..04fe8148f7 --- /dev/null +++ b/python/cm/tests/files/response_templates/group_config/vars.json.j2 @@ -0,0 +1,487 @@ +{ + "cluster": { + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/cluster.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/cluster.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "name": "Target Cluster", + "id": 1, + "version": "2.3", + "edition": "community", + "state": "created", + "multi_state": [], + "before_upgrade": { + "state": null + } + }, + "services": { + "not_simple": { + "id": {{ not_simple.id }}, + "version": "4.3", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/service.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/service.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "maintenance_mode": false, + "display_name": "not_simple", + "before_upgrade": { + "state": null + }, + "not_simple_component": { + "component_id": {{ not_simple_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.1.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.1.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "not_simple_component", + "before_upgrade": { + "state": null + } + }, + "another_not_simple_component": { + "component_id": {{ another_not_simple_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.2.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.2.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "another_not_simple_component", + "before_upgrade": { + "state": null + } + } + }, + "thesame": { + "id": {{ thesame.id }}, + "version": "2.1", + "state": "created", + "multi_state": [], + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/service.2.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": { + "simple": "bestgroupever", + "secretmap": { + "agk1": "agv1", + "agk2": "agv2" + }, + "secretfile": "{{ filedir }}/service.2.activatable_group.secretfile" + }, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/service.2.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 400, + "string": "woo" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "maintenance_mode": false, + "display_name": "thesame", + "before_upgrade": { + "state": null + }, + "thesame_component": { + "component_id": {{ thesame_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.3.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "x", + "y" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 2.3, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.3.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "thesame_component", + "before_upgrade": { + "state": null + } + }, + "another_thesame_component": { + "component_id": {{ another_thesame_component.id }}, + "config": { + "plain_group": { + "simple": "ingroup", + "secretmap": { + "gk1": "gv1", + "gk2": "gv2" + }, + "secretfile": "{{ filedir }}/component.4.plain_group.secretfile", + "list_of_dicts": null, + "listofstuff": [ + "wind", + "vs", + "oak" + ] + }, + "activatable_group": null, + "just_bool": null, + "just_integer": 4, + "just_float": 1000.304, + "just_string": "outofgroup", + "just_text": "lineone\nsecond line\n", + "just_map": {}, + "just_list": [ + "1" + ], + "just_json": null, + "variant_config": null, + "variant_inline": null, + "variant_builtin": null, + "password": "defaultpass", + "secrettext": "default\npassword\n", + "secretmap": { + "k1": "v1", + "k2": "v2" + }, + "secretfile": "{{ filedir }}/component.4.secretfile.", + "nullist": [], + "list_of_dicts": [ + { + "integer": 3, + "string": "three" + }, + { + "integer": 12, + "string": "twelve" + } + ], + "dict_of_lists": { + "integers": [ + 1, + 103 + ], + "strings": [ + "over", + "and", + "over" + ] + } + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "another_thesame_component", + "before_upgrade": { + "state": null + } + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/test_inventory/base.py b/python/cm/tests/test_inventory/base.py index bd3dda80c8..204c77fbd9 100644 --- a/python/cm/tests/test_inventory/base.py +++ b/python/cm/tests/test_inventory/base.py @@ -9,9 +9,8 @@ # 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 json from functools import reduce -from json import loads from pathlib import Path from typing import Any, Callable, Iterable, Literal, Mapping, TypeAlias @@ -31,7 +30,6 @@ ServiceComponent, ) from cm.utils import deep_merge -from django.conf import settings from jinja2 import Template from adcm.tests.base import BaseTestCase, BusinessLogicMixin @@ -68,6 +66,13 @@ def setUp(self): self.bundles_dir = Path(__file__).parent.parent / "bundles" self.templates_dir = Path(__file__).parent.parent / "files" / "response_templates" + @staticmethod + def render_template(file: Path, context: dict) -> str: + return Template(source=file.read_text(encoding="utf-8")).render(**context) + + def render_json_template(self, file: Path, context: dict) -> list | dict: + return json.loads(self.render_template(file=file, context=context)) + def check_hosts_topology(self, data: Mapping[str, dict], expected: Mapping[str, list[str]]) -> None: errors = set(data.keys()).symmetric_difference(set(expected.keys())) self.assertSetEqual(errors, set()) @@ -115,9 +120,7 @@ def check_data_by_template(self, data: Mapping[str, dict], templates_data: Templ for key_chain, template_data in templates_data.items(): template_path, kwargs = template_data - expected_data = loads( - Template(source=template_path.read_text(encoding=settings.ENCODING_UTF_8)).render(kwargs), strict=False - ) + expected_data = self.render_json_template(file=template_path, context=kwargs) actual_data = reduce(dict.get, key_chain, data) self.assertDictEqual(actual_data, expected_data) diff --git a/python/cm/tests/test_inventory/test_action_config.py b/python/cm/tests/test_inventory/test_action_config.py new file mode 100644 index 0000000000..ff48a6a38d --- /dev/null +++ b/python/cm/tests/test_inventory/test_action_config.py @@ -0,0 +1,126 @@ +# Licensed 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. +from cm.job import prepare_job_config +from cm.models import Action, ServiceComponent +from cm.tests.test_inventory.base import BaseInventoryTestCase +from django.conf import settings + + +class TestConfigAndImportsInInventory(BaseInventoryTestCase): + CONFIG_WITH_NONES = { + "boolean": True, + "secrettext": "awe\nsopme\n\ttext\n", + "list": ["1", "5", "baset"], + "variant_inline": "f", + "plain_group": {"file": "contente\t\n\n\n\tbest\n\t ", "map": {"k": "v", "key": "val"}, "simple": None}, + "integer": None, + "float": None, + "string": None, + "password": None, + "map": None, + "secretmap": None, + "json": None, + "file": None, + "secretfile": None, + "variant_builtin": None, + "activatable_group": None, + } + + FULL_CONFIG = { + **CONFIG_WITH_NONES, + "integer": 4102, + "float": 23.43, + "string": "outside", + "password": "unbreakable", + "map": {"see": "yes", "no": "no"}, + "secretmap": {"see": "dont", "me": "you"}, + "json": '{"hey": ["yooo", 1]}', + "file": "filecontent", + "secretfile": "somesecrethere", + "variant_builtin": "host-1", + "plain_group": {**CONFIG_WITH_NONES["plain_group"], "simple": "ingroup"}, + "activatable_group": {"simple": "inactive", "list": ["one", "two"]}, + } + + def setUp(self) -> None: + super().setUp() + + self.hostprovider = self.add_provider( + bundle=self.add_bundle(self.bundles_dir / "provider_full_config"), name="Host Provider" + ) + self.host_1 = self.add_host( + bundle=self.hostprovider.prototype.bundle, provider=self.hostprovider, fqdn="host-1" + ) + self.host_2 = self.add_host( + bundle=self.hostprovider.prototype.bundle, provider=self.hostprovider, fqdn="host-2" + ) + + self.cluster = self.add_cluster( + bundle=self.add_bundle(self.bundles_dir / "cluster_full_config"), name="Main Cluster" + ) + self.service = self.add_services_to_cluster(service_names=["all_params"], cluster=self.cluster).first() + self.component = ServiceComponent.objects.get(service=self.service) + + self.add_host_to_cluster(cluster=self.cluster, host=self.host_1) + self.add_host_to_cluster(cluster=self.cluster, host=self.host_2) + self.set_hostcomponent( + cluster=self.cluster, entries=((self.host_1, self.component), (self.host_2, self.component)) + ) + + self.context = { + "hostprovider_bundle": self.hostprovider.prototype.bundle, + "cluster_bundle": self.cluster.prototype.bundle, + "datadir": self.directories["DATA_DIR"], + "stackdir": self.directories["STACK_DIR"], + "token": settings.STATUS_SECRET_KEY, + } + + def test_action_config(self) -> None: + # Thou action has a defined config + # `prepare_job_config` itself doesn't check input config sanity, + # but `None` is a valid config, + # so I find it easier to check it in pairs here rather than use a separate action + for object_, config, type_name in ( + (self.cluster, None, "cluster"), + (self.service, self.FULL_CONFIG, "service"), + (self.component, self.CONFIG_WITH_NONES, "component"), + (self.hostprovider, self.FULL_CONFIG, "hostprovider"), + (self.host_1, self.CONFIG_WITH_NONES, "host"), + ): + with self.subTest(f"Own Action for {object_.__class__.__name__}"): + expected_data = self.render_json_template( + file=self.templates_dir / "action_configs" / f"{type_name}.json.j2", context=self.context + ) + + action = Action.objects.filter(prototype=object_.prototype, name="with_config").first() + job_config = prepare_job_config( + action=action, sub_action=None, job_id=1, obj=object_, conf=config, verbose=False + ) + + self.assertDictEqual(job_config, expected_data) + + for object_, config, type_name in ( + (self.cluster, self.FULL_CONFIG, "cluster"), + (self.service, self.CONFIG_WITH_NONES, "service"), + (self.component, None, "component"), + ): + with self.subTest(f"Host Action for {object_.__class__.__name__}"): + expected_data = self.render_json_template( + file=self.templates_dir / "action_configs" / f"{type_name}_on_host.json.j2", context=self.context + ) + + action = Action.objects.filter(prototype=object_.prototype, name="with_config_on_host").first() + job_config = prepare_job_config( + action=action, sub_action=action, job_id=100, obj=self.host_1, conf=config, verbose=True + ) + + self.assertDictEqual(job_config, expected_data) diff --git a/python/cm/tests/test_inventory/test_group_config.py b/python/cm/tests/test_inventory/test_group_config.py index 814d97a71a..c96c8924fd 100644 --- a/python/cm/tests/test_inventory/test_group_config.py +++ b/python/cm/tests/test_inventory/test_group_config.py @@ -9,7 +9,6 @@ # 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 json from typing import Iterable from api_v2.service.utils import bulk_add_services_to_cluster @@ -25,7 +24,6 @@ ) from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets from django.contrib.contenttypes.models import ContentType -from jinja2 import Template class TestGroupConfigsInInventory(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes @@ -117,9 +115,7 @@ def test_group_config_in_inventory(self) -> None: "filedir": self.directories["FILE_DIR"], } expected_parts = { - file.stem.replace(".json", ""): json.loads( - Template(source=file.read_text(encoding="utf-8")).render(**context), strict=False - ) + file.stem.replace(".json", ""): self.render_json_template(file=file, context=context) for file in (self.templates_dir / "group_config").iterdir() } @@ -197,15 +193,14 @@ def test_group_config_in_inventory(self) -> None: self.component_thesame, self.component_another_thesame, ): - actual_inventory = decrypt_secrets( - get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ - "all" - ]["children"] - ) - self.check_hosts_topology(actual_inventory, expected_topology) - for group in actual_inventory.values(): - for host_name, actual_data in group["hosts"].items(): - self.assertDictEqual( - actual_data["cluster"]["config"], expected_parts[f"{host_name}_cluster_config"] - ) - self.assertDictEqual(actual_data["services"], expected_parts[f"{host_name}_services"]) + with self.subTest(object_.__class__.__name__): + action = Action.objects.filter(prototype=object_.prototype).first() + actual_inventory = decrypt_secrets(get_inventory_data(obj=object_, action=action)["all"]["children"]) + self.check_hosts_topology(actual_inventory, expected_topology) + self.assertDictEqual(actual_inventory["CLUSTER"]["vars"], expected_parts["vars"]) + for group in actual_inventory.values(): + for host_name, actual_data in group["hosts"].items(): + self.assertDictEqual( + actual_data["cluster"]["config"], expected_parts[f"{host_name}_cluster_config"] + ) + self.assertDictEqual(actual_data["services"], expected_parts[f"{host_name}_services"]) diff --git a/python/cm/tests/test_inventory/test_imports.py b/python/cm/tests/test_inventory/test_imports.py index 0cef72dec6..32692fee07 100644 --- a/python/cm/tests/test_inventory/test_imports.py +++ b/python/cm/tests/test_inventory/test_imports.py @@ -9,7 +9,6 @@ # 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 json from typing import Iterable from cm.api import DataForMultiBind, multi_bind @@ -23,7 +22,6 @@ ServiceComponent, ) from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets -from jinja2 import Template class TestConfigAndImportsInInventory(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes @@ -158,17 +156,13 @@ def test_hostprovider_objects_success(self) -> None: (self.host_1, "host_1_full.json.j2"), (self.host_2, "host_2_full.json.j2"), ): - actual_inventory = decrypt_secrets( - get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ - "all" - ]["children"] - ) - expected_inventory = json.loads( - Template( - source=(self.templates_dir / "configs_and_imports" / template).read_text(encoding="utf-8") - ).render(**self.context) - ) - self.assertDictEqual(actual_inventory, expected_inventory) + with self.subTest(object_.__class__.__name__): + action = Action.objects.filter(prototype=object_.prototype, name="dummy").first() + actual_inventory = decrypt_secrets(get_inventory_data(obj=object_, action=action)["all"]["children"]) + expected_inventory = self.render_json_template( + file=self.templates_dir / "configs_and_imports" / template, context=self.context + ) + self.assertDictEqual(actual_inventory, expected_inventory) def test_cluster_objects_no_import_success(self) -> None: self.prepare_cluster_hostcomponent() @@ -176,20 +170,14 @@ def test_cluster_objects_no_import_success(self) -> None: self.change_config_full(target=self.cluster) self.change_config_partial(target=self.component) - expected_vars = json.loads( - Template( - source=(self.templates_dir / "configs_and_imports" / "vars_no_imports.json.j2").read_text( - encoding="utf-8" - ) - ).render(**self.context) + expected_vars = self.render_json_template( + file=self.templates_dir / "configs_and_imports" / "vars_no_imports.json.j2", context=self.context ) for object_ in (self.cluster, self.service, self.component): - actual_inventory = decrypt_secrets( - get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ - "all" - ]["children"] - ) + with self.subTest(object_.__class__.__name__): + action = Action.objects.filter(prototype=object_.prototype, name="dummy").first() + actual_inventory = decrypt_secrets(get_inventory_data(obj=object_, action=action)["all"]["children"]) self.assertDictEqual(actual_inventory["CLUSTER"]["vars"], expected_vars) @@ -215,20 +203,14 @@ def test_cluster_objects_single_import_success(self) -> None: (self.service, [self.export_cluster_1, self.export_service_1]), ) - expected_vars = json.loads( - Template( - source=(self.templates_dir / "configs_and_imports" / "vars_single_imports.json.j2").read_text( - encoding="utf-8" - ) - ).render(**self.context) + expected_vars = self.render_json_template( + file=self.templates_dir / "configs_and_imports" / "vars_single_imports.json.j2", context=self.context ) for object_ in (self.cluster, self.service, self.component): - actual_inventory = decrypt_secrets( - get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ - "all" - ]["children"] - ) + with self.subTest(object_.__class__.__name__): + action = Action.objects.filter(prototype=object_.prototype, name="dummy").first() + actual_inventory = decrypt_secrets(get_inventory_data(obj=object_, action=action)["all"]["children"]) self.assertDictEqual(actual_inventory["CLUSTER"]["vars"], expected_vars) def test_cluster_objects_multi_import_success(self) -> None: @@ -263,18 +245,12 @@ def test_cluster_objects_multi_import_success(self) -> None: preprocess_config=lambda d: {**d, "activatable_group": d["activatable_group"]}, ) - expected_vars = json.loads( - Template( - source=(self.templates_dir / "configs_and_imports" / "vars_multiple_imports.json.j2").read_text( - encoding="utf-8" - ) - ).render(**self.context) + expected_vars = self.render_json_template( + file=self.templates_dir / "configs_and_imports" / "vars_multiple_imports.json.j2", context=self.context ) for object_ in (self.cluster, self.service, self.component): - actual_inventory = decrypt_secrets( - get_inventory_data(obj=object_, action=Action.objects.filter(prototype=object_.prototype).first())[ - "all" - ]["children"] - ) - self.assertDictEqual(actual_inventory["CLUSTER"]["vars"], expected_vars) + with self.subTest(object_.__class__.__name__): + action = Action.objects.filter(prototype=object_.prototype, name="dummy").first() + actual_inventory = decrypt_secrets(get_inventory_data(obj=object_, action=action)["all"]["children"]) + self.assertDictEqual(actual_inventory["CLUSTER"]["vars"], expected_vars) diff --git a/python/cm/tests/test_job.py b/python/cm/tests/test_job.py index e446bbea67..56a3282090 100644 --- a/python/cm/tests/test_job.py +++ b/python/cm/tests/test_job.py @@ -32,6 +32,7 @@ restore_hc, set_action_state, set_job_start_status, + write_job_config, ) from cm.models import ( ADCM, @@ -311,7 +312,10 @@ def test_check_cluster(self, mock_err): @patch("cm.job.prepare_ansible_config") @patch("cm.job.prepare_job_config") @patch("cm.job.prepare_job_inventory") - def test_prepare_job(self, mock_prepare_job_inventory, mock_prepare_job_config, mock_prepare_ansible_config): + @patch("cm.job.write_job_config") + def test_prepare_job( + self, mock_write_job_config, mock_prepare_job_inventory, mock_prepare_job_config, mock_prepare_ansible_config + ): bundle = Bundle.objects.create() prototype = Prototype.objects.create(bundle=bundle) cluster = Cluster.objects.create(prototype=prototype) @@ -323,6 +327,7 @@ def test_prepare_job(self, mock_prepare_job_inventory, mock_prepare_job_config, mock_prepare_job_inventory.assert_called_once_with(cluster, job.id, action, {}, None) mock_prepare_job_config.assert_called_once_with(action, None, job.id, cluster, "", False) mock_prepare_ansible_config.assert_called_once_with(job.id, action, None) + mock_write_job_config.assert_called() @patch("cm.job.get_obj_config") def test_get_adcm_config(self, mock_get_obj_config): @@ -408,7 +413,7 @@ def test_cook_script(self, mock_get_bundle_root): @patch("cm.job.prepare_context") @patch("cm.job.get_adcm_config") @patch("json.dump") - @patch("builtins.open") + @patch("pathlib.Path.open") def test_prepare_job_config( self, mock_open, @@ -462,7 +467,8 @@ def test_prepare_job_config( for prototype_type, obj, action in data: with self.subTest(provider_type=prototype_type, obj=obj): - prepare_job_config(action, None, job.pk, obj, conf, False) + config = prepare_job_config(action, None, job.pk, obj, conf, False) + write_job_config(job_id=job.pk, config=config) job_config = { "adcm": {"config": {}}, @@ -513,11 +519,6 @@ def test_prepare_job_config( elif prototype_type == "adcm": job_config["job"]["hostgroup"] = "127.0.0.1" - mock_open.assert_called_with( - settings.RUN_DIR / f"{job.id}" / "config.json", - "w", - encoding=settings.ENCODING_UTF_8, - ) mock_dump.assert_called_with( job_config, file_mock.__enter__.return_value, separators=(",", ":"), sort_keys=True ) From fbb4c1bfa53b92e3d81e3639ab2165da704d463a Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Fri, 19 Jan 2024 08:23:00 +0000 Subject: [PATCH 047/151] [UI] ADCM-5218: Refactor Groups page slices https://tracker.yandex.ru/ADCM-5218 --- .../AccessManagerGroupsTable.tsx | 7 ++- .../AccessManagerGroupsDeleteButton.tsx | 4 +- .../AccessManagerGroupsDeleteDialog.tsx | 6 +- .../store/adcm/groups/groupActionsSlice.ts | 59 ++++++++++++++++++- .../app/src/store/adcm/groups/groupsSlice.ts | 49 +-------------- 5 files changed, 68 insertions(+), 57 deletions(-) diff --git a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTable/AccessManagerGroupsTable.tsx b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTable/AccessManagerGroupsTable.tsx index 4705dbf6c4..1fd9c52f45 100644 --- a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTable/AccessManagerGroupsTable.tsx +++ b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTable/AccessManagerGroupsTable.tsx @@ -2,7 +2,7 @@ import { Dispatch, SetStateAction, useCallback } from 'react'; import { Table, TableRow, TableCell, IconButton, Checkbox } from '@uikit'; import { useDispatch, useStore } from '@hooks'; import { columns } from './AccessManagerGroupsTable.constants'; -import { setDeletableId, setSelectedItemsIds as setSelectedIds } from '@store/adcm/groups/groupsSlice'; +import { openDeleteDialog, setSelectedItemsIds as setSelectedIds } from '@store/adcm/groups/groupActionsSlice'; import { setSortParams } from '@store/adcm/groups/groupsTableSlice'; import { SortParams } from '@uikit/types/list.types'; import { AdcmGroup } from '@models/adcm'; @@ -12,7 +12,8 @@ import { isShowSpinner } from '@uikit/Table/Table.utils'; const AccessManagerGroupsTable = () => { const dispatch = useDispatch(); - const { groups, selectedItemsIds } = useStore((s) => s.adcm.groups); + const groups = useStore((s) => s.adcm.groups.groups); + const selectedItemsIds = useStore((s) => s.adcm.groupsActions.selectedItemsIds); const isLoading = useStore((s) => isShowSpinner(s.adcm.groups.loadState)); const sortParams = useStore((s) => s.adcm.groupsTable.sortParams); @@ -33,7 +34,7 @@ const AccessManagerGroupsTable = () => { ); const getHandleDeleteClick = (id: number) => () => { - dispatch(setDeletableId(id)); + dispatch(openDeleteDialog(id)); }; const handleSorting = (sortParams: SortParams) => { diff --git a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTableToolbar/AccessManagerGroupsDeleteButton/AccessManagerGroupsDeleteButton.tsx b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTableToolbar/AccessManagerGroupsDeleteButton/AccessManagerGroupsDeleteButton.tsx index 1b9f163ab4..78e52e592d 100644 --- a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTableToolbar/AccessManagerGroupsDeleteButton/AccessManagerGroupsDeleteButton.tsx +++ b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/AccessManagerGroupsTableToolbar/AccessManagerGroupsDeleteButton/AccessManagerGroupsDeleteButton.tsx @@ -1,12 +1,12 @@ import React, { useState } from 'react'; import { Button, Dialog } from '@uikit'; import { useDispatch, useStore } from '@hooks'; -import { deleteGroupsWithUpdate } from '@store/adcm/groups/groupsSlice'; +import { deleteGroupsWithUpdate } from '@store/adcm/groups/groupActionsSlice'; const AccessManagerGroupsDeleteButton: React.FC = () => { const dispatch = useDispatch(); - const selectedItemsIds = useStore(({ adcm }) => adcm.groups.selectedItemsIds); + const selectedItemsIds = useStore(({ adcm }) => adcm.groupsActions.selectedItemsIds); const isSelectedSomeRows = selectedItemsIds.length > 0; const [isOpenDeleteConfirm, setIsOpenDeleteConfirm] = useState(false); diff --git a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/Dialogs/AccessManagerGroupsDeleteDialog/AccessManagerGroupsDeleteDialog.tsx b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/Dialogs/AccessManagerGroupsDeleteDialog/AccessManagerGroupsDeleteDialog.tsx index e9d25efe6a..3878ad3eb9 100644 --- a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/Dialogs/AccessManagerGroupsDeleteDialog/AccessManagerGroupsDeleteDialog.tsx +++ b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerGroupsPage/Dialogs/AccessManagerGroupsDeleteDialog/AccessManagerGroupsDeleteDialog.tsx @@ -1,19 +1,19 @@ import { useDispatch, useStore } from '@hooks'; -import { deleteGroupsWithUpdate, setDeletableId } from '@store/adcm/groups/groupsSlice'; +import { deleteGroupsWithUpdate, closeDeleteDialog } from '@store/adcm/groups/groupActionsSlice'; import { Dialog } from '@uikit'; import React from 'react'; const AccessManagerGroupsDeleteDialog: React.FC = () => { const dispatch = useDispatch(); - const deletableId = useStore(({ adcm }) => adcm.groups.itemsForActions.deletableId); + const deletableId = useStore(({ adcm }) => adcm.groupsActions.deleteDialog.id); const groups = useStore(({ adcm }) => adcm.groups.groups); const isOpen = deletableId !== null; const name = groups.find(({ id }) => id === deletableId)?.displayName; const handleCloseConfirm = () => { - dispatch(setDeletableId(null)); + dispatch(closeDeleteDialog()); }; const handleConfirmDialog = () => { diff --git a/adcm-web/app/src/store/adcm/groups/groupActionsSlice.ts b/adcm-web/app/src/store/adcm/groups/groupActionsSlice.ts index 2d55b81507..e5cd7ef87e 100644 --- a/adcm-web/app/src/store/adcm/groups/groupActionsSlice.ts +++ b/adcm-web/app/src/store/adcm/groups/groupActionsSlice.ts @@ -1,10 +1,11 @@ import { AdcmGroupsApi, AdcmUsersApi, RequestError } from '@api'; import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; -import { showError } from '@store/notificationsSlice'; +import { showError, showInfo } from '@store/notificationsSlice'; import { getErrorMessage } from '@utils/httpResponseUtils'; import { getGroups } from './groupsSlice'; import { AdcmGroup, AdcmUpdateGroupPayload, AdcmCreateGroupPayload, AdcmUser } from '@models/adcm'; import { PaginationParams, SortParams } from '@models/table'; +import { rejectedFilter } from '@utils/promiseUtils'; const createGroup = createAsyncThunk( 'adcm/groupActions/createGroup', @@ -60,6 +61,23 @@ const loadUsers = createAsyncThunk('adcm/groupActions/loadUsers', async (arg, th } }); +const deleteGroupsWithUpdate = createAsyncThunk('adcm/groupActions/deleteGroups', async (ids: number[], thunkAPI) => { + try { + const deletePromises = await Promise.allSettled(ids.map((id) => AdcmGroupsApi.deleteGroup(id))); + const responsesList = rejectedFilter(deletePromises); + + if (responsesList.length > 0) { + throw responsesList[0]; + } + + await thunkAPI.dispatch(getGroups()); + thunkAPI.dispatch(showInfo({ message: 'Groups have been deleted' })); + } catch (error) { + thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); + return error; + } +}); + interface AdcmGroupsActionsState { createDialog: { isOpen: boolean; @@ -68,6 +86,10 @@ interface AdcmGroupsActionsState { group: AdcmGroup | null; isUpdating: boolean; }; + deleteDialog: { + id: number | null; + }; + selectedItemsIds: number[]; relatedData: { users: AdcmUser[]; }; @@ -81,6 +103,10 @@ const createInitialState = (): AdcmGroupsActionsState => ({ group: null, isUpdating: false, }, + deleteDialog: { + id: null, + }, + selectedItemsIds: [], relatedData: { users: [], }, @@ -106,6 +132,18 @@ const groupsActionsSlice = createSlice({ state.updateDialog.group = null; state.updateDialog.isUpdating = false; }, + cleanupItemsForActions(state) { + state.selectedItemsIds = createInitialState().selectedItemsIds; + }, + openDeleteDialog(state, action) { + state.deleteDialog.id = action.payload; + }, + closeDeleteDialog(state) { + state.deleteDialog.id = null; + }, + setSelectedItemsIds(state, action) { + state.selectedItemsIds = action.payload; + }, }, extraReducers: (builder) => { builder @@ -126,11 +164,26 @@ const groupsActionsSlice = createSlice({ }) .addCase(loadUsers.rejected, (state) => { state.relatedData.users = []; + }) + .addCase(deleteGroupsWithUpdate.pending, (state) => { + state.deleteDialog.id = null; + }) + .addCase(getGroups.pending, (state) => { + state.selectedItemsIds = []; }); }, }); -export const { openCreateDialog, closeCreateDialog, openUpdateDialog, closeUpdateDialog } = groupsActionsSlice.actions; -export { createGroup, updateGroup, loadUsers }; +export const { + openCreateDialog, + closeCreateDialog, + openUpdateDialog, + cleanupItemsForActions, + closeUpdateDialog, + openDeleteDialog, + closeDeleteDialog, + setSelectedItemsIds, +} = groupsActionsSlice.actions; +export { createGroup, updateGroup, loadUsers, deleteGroupsWithUpdate }; export default groupsActionsSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/groups/groupsSlice.ts b/adcm-web/app/src/store/adcm/groups/groupsSlice.ts index 6be006e84c..503c84d4e9 100644 --- a/adcm-web/app/src/store/adcm/groups/groupsSlice.ts +++ b/adcm-web/app/src/store/adcm/groups/groupsSlice.ts @@ -1,22 +1,15 @@ import { createSlice } from '@reduxjs/toolkit'; -import { AdcmGroupsApi, RequestError } from '@api'; +import { AdcmGroupsApi } from '@api'; import { createAsyncThunk } from '@store/redux'; import { AdcmGroup } from '@models/adcm'; import { executeWithMinDelay } from '@utils/requestUtils'; import { defaultSpinnerDelay } from '@constants'; -import { showError, showInfo } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; -import { rejectedFilter } from '@utils/promiseUtils'; import { LoadState } from '@models/loadState'; interface AdcmGroupsState { groups: AdcmGroup[]; totalCount: number; - itemsForActions: { - deletableId: number | null; - }; loadState: LoadState; - selectedItemsIds: number[]; } const loadFromBackend = createAsyncThunk('adcm/groups/loadFromBackend', async (arg, thunkAPI) => { @@ -53,31 +46,10 @@ const refreshGroups = createAsyncThunk('adcm/groups/refreshGroups', async (arg, thunkAPI.dispatch(loadFromBackend()); }); -const deleteGroupsWithUpdate = createAsyncThunk('adcm/groups/deleteGroups', async (ids: number[], thunkAPI) => { - try { - const deletePromises = await Promise.allSettled(ids.map((id) => AdcmGroupsApi.deleteGroup(id))); - const responsesList = rejectedFilter(deletePromises); - - if (responsesList.length > 0) { - throw responsesList[0]; - } - - await thunkAPI.dispatch(getGroups()); - thunkAPI.dispatch(showInfo({ message: 'Groups have been deleted' })); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return error; - } -}); - const createInitialState = (): AdcmGroupsState => ({ groups: [], totalCount: 0, - itemsForActions: { - deletableId: null, - }, loadState: LoadState.NotLoaded, - selectedItemsIds: [], }); const groupsSlice = createSlice({ @@ -90,15 +62,6 @@ const groupsSlice = createSlice({ cleanupGroups() { return createInitialState(); }, - cleanupItemsForActions(state) { - state.itemsForActions = createInitialState().itemsForActions; - }, - setDeletableId(state, action) { - state.itemsForActions.deletableId = action.payload; - }, - setSelectedItemsIds(state, action) { - state.selectedItemsIds = action.payload; - }, }, extraReducers: (builder) => { builder @@ -108,16 +71,10 @@ const groupsSlice = createSlice({ }) .addCase(loadFromBackend.rejected, (state) => { state.groups = []; - }) - .addCase(deleteGroupsWithUpdate.pending, (state) => { - state.itemsForActions.deletableId = null; - }) - .addCase(getGroups.pending, (state) => { - groupsSlice.caseReducers.cleanupItemsForActions(state); }); }, }); -const { setLoadState, cleanupGroups, setDeletableId, setSelectedItemsIds } = groupsSlice.actions; -export { getGroups, refreshGroups, deleteGroupsWithUpdate, cleanupGroups, setDeletableId, setSelectedItemsIds }; +const { setLoadState, cleanupGroups } = groupsSlice.actions; +export { getGroups, refreshGroups, cleanupGroups }; export default groupsSlice.reducer; From 6d72128e3ac1f3a8e25418deb9001e547996784c Mon Sep 17 00:00:00 2001 From: Daniil Skrynnik Date: Fri, 19 Jan 2024 12:17:00 +0000 Subject: [PATCH 048/151] ADCM-5215: add mtime to tar files --- python/api_v2/log_storage/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/api_v2/log_storage/utils.py b/python/api_v2/log_storage/utils.py index dd3ce804e5..eba6846fab 100644 --- a/python/api_v2/log_storage/utils.py +++ b/python/api_v2/log_storage/utils.py @@ -13,6 +13,7 @@ # pylint: disable=duplicate-code import io import tarfile +from datetime import datetime, timezone from pathlib import Path from cm.models import ( @@ -80,6 +81,7 @@ def get_task_download_archive_file_handler(task: TaskLog) -> io.BytesIO: for log_file in files: tarinfo = tarfile.TarInfo(f'{f"{job.pk}-{dir_name_suffix}".strip("-")}/{log_file.name}') tarinfo.size = log_file.stat().st_size + tarinfo.mtime = log_file.stat().st_mtime tar_file.addfile(tarinfo=tarinfo, fileobj=io.BytesIO(log_file.read_bytes())) else: log_storages = LogStorage.objects.filter(job=job, type__in={"stdout", "stderr"}) @@ -89,6 +91,7 @@ def get_task_download_archive_file_handler(task: TaskLog) -> io.BytesIO: ) body = io.BytesIO(bytes(log_storage.body, settings.ENCODING_UTF_8)) tarinfo.size = body.getbuffer().nbytes + tarinfo.mtime = datetime.now(tz=timezone.utc).timestamp() tar_file.addfile(tarinfo=tarinfo, fileobj=body) return file_handler From f49460065085c8faff410903083a15758561d944 Mon Sep 17 00:00:00 2001 From: Artem Starovoitov Date: Mon, 22 Jan 2024 07:23:38 +0000 Subject: [PATCH 049/151] ADCM-5207: Add tests for maintenance mode --- .../service_one_component.json.j2 | 4 +- .../tests/test_inventory/test_components.py | 2 + .../tests/test_inventory/test_host_action.py | 4 + .../test_inventory/test_maintenance_mode.py | 439 ++++++++++++++++++ 4 files changed, 447 insertions(+), 2 deletions(-) create mode 100644 python/cm/tests/test_inventory/test_maintenance_mode.py diff --git a/python/cm/tests/files/response_templates/service_one_component.json.j2 b/python/cm/tests/files/response_templates/service_one_component.json.j2 index 926ae3a4af..7895435422 100644 --- a/python/cm/tests/files/response_templates/service_one_component.json.j2 +++ b/python/cm/tests/files/response_templates/service_one_component.json.j2 @@ -14,7 +14,7 @@ "value3" ] }, - "maintenance_mode": false, + "maintenance_mode": {{ service_mm }}, "display_name": "service_one_component", "before_upgrade": { "state": null @@ -33,7 +33,7 @@ }, "state": "created", "multi_state": [], - "maintenance_mode": false, + "maintenance_mode": {{ component_mm }}, "display_name": "component_1", "before_upgrade": { "state": null diff --git a/python/cm/tests/test_inventory/test_components.py b/python/cm/tests/test_inventory/test_components.py index 6ee301f0de..d34ad7ac14 100644 --- a/python/cm/tests/test_inventory/test_components.py +++ b/python/cm/tests/test_inventory/test_components.py @@ -102,6 +102,8 @@ def test_1_component_1_host(self): { "service_id": service_one_component.pk, "component_id": component_1.pk, + "service_mm": "false", + "component_mm": "false", }, ), } diff --git a/python/cm/tests/test_inventory/test_host_action.py b/python/cm/tests/test_inventory/test_host_action.py index d622fdff0f..5e54436102 100644 --- a/python/cm/tests/test_inventory/test_host_action.py +++ b/python/cm/tests/test_inventory/test_host_action.py @@ -80,6 +80,8 @@ def test_host_action(self): { "service_id": self.service.pk, "component_id": self.component.pk, + "service_mm": "false", + "component_mm": "false", }, ), ("HOST", "hosts"): ( @@ -114,6 +116,8 @@ def test_host_action(self): { "service_id": self.service.pk, "component_id": self.component.pk, + "service_mm": "false", + "component_mm": "false", }, ), } diff --git a/python/cm/tests/test_inventory/test_maintenance_mode.py b/python/cm/tests/test_inventory/test_maintenance_mode.py new file mode 100644 index 0000000000..c46f419ec1 --- /dev/null +++ b/python/cm/tests/test_inventory/test_maintenance_mode.py @@ -0,0 +1,439 @@ +# Licensed 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. +from pathlib import Path +from typing import Mapping + +from api_v2.service.utils import bulk_add_services_to_cluster +from cm.models import ( + Action, + Cluster, + ClusterObject, + ConfigLog, + Host, + MaintenanceMode, + ObjectType, + Prototype, + ServiceComponent, +) +from cm.tests.test_inventory.base import BaseInventoryTestCase + +from adcm.settings import ADCM_TURN_ON_MM_ACTION_NAME + + +class TestMaintenanceMode(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes + def setUp(self) -> None: + bundles_dir = Path(__file__).parent.parent / "bundles" + self.templates_dir = Path(__file__).parent.parent / "files/response_templates" + + self.provider_bundle = self.add_bundle(source_dir=bundles_dir / "provider") + cluster_bundle = self.add_bundle(source_dir=bundles_dir / "cluster_1") + + self.cluster_1 = self.add_cluster(bundle=cluster_bundle, name="cluster_1") + self.provider = self.add_provider(bundle=self.provider_bundle, name="provider") + + self.host_1 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_1", cluster=self.cluster_1 + ) + self.host_2 = None + self.service_two_components = None + self.component_1 = None + self.component_2 = None + + def get_provider_mm_config(self, obj: Host): + path, ids = self.get_action_on_host_expected_template_data_part(host=obj)[("HOST", "vars", "provider")] + + return self.render_json_template(path, dict(ids)) + + def get_host_mm_config(self, obj: Host): + path, ids = self.templates_dir / "one_host.json.j2", {"host_fqnd": obj.fqdn, "adcm_hostid": obj.id} + + return self.render_json_template(path, ids)[""] + + def get_cluster_mm_config(self, obj: Cluster): + path, ids = self.templates_dir / "cluster.json.j2", {"id": obj.id} + + return self.render_json_template(path, ids) + + def get_service_mm_config(self, obj: ClusterObject, component: ServiceComponent): + mm_state = {MaintenanceMode.ON: "true", MaintenanceMode.OFF: "false"} + path, ids = self.templates_dir / "service_one_component.json.j2", { + "service_id": obj.id, + "service_mm": mm_state[obj.maintenance_mode], + "component_id": component.pk, + "component_mm": mm_state[component.maintenance_mode], + } + + return self.render_json_template(path, ids) + + def check_hosts_topology(self, data: Mapping[str, dict], expected: Mapping[str, list[str]]) -> None: + errors = set(data.keys()).symmetric_difference(set(expected.keys())) + self.assertSetEqual(errors, set()) + + def _get_2_hosts_topology(self, host_mm_on: Host, host_mm_off: Host): + return { + "CLUSTER": {"hosts": {}, "vars": self.get_cluster_mm_config(self.cluster_1)}, + f"{self.service_two_components.name}": { + "hosts": {host_mm_off.fqdn: self.get_host_mm_config(host_mm_off)}, + }, + f"{self.service_two_components.name}.{self.component_1.name}": { + "hosts": {host_mm_off.fqdn: self.get_host_mm_config(host_mm_off)}, + }, + f"{self.service_two_components.name}.{self.component_2.name}": { + "hosts": {host_mm_off.fqdn: self.get_host_mm_config(host_mm_off)}, + }, + f"{self.service_two_components.name}.{self.component_1.name}.maintenance_mode": { + "hosts": {host_mm_on.fqdn: self.get_host_mm_config(host_mm_on)}, + "vars": { + "cluster": self.get_cluster_mm_config(self.cluster_1), + "services": { + "service_one_component": self.get_service_mm_config( + self.service_two_components, self.component_1 + ) + }, + }, + }, + f"{self.service_two_components.name}.{self.component_2.name}.maintenance_mode": { + "hosts": {host_mm_on.fqdn: self.get_host_mm_config(host_mm_on)}, + "vars": { + "cluster": self.get_cluster_mm_config(self.cluster_1), + "services": { + "service_one_component": self.get_service_mm_config( + self.service_two_components, self.component_1 + ) + }, + }, + }, + f"{self.service_two_components.name}.maintenance_mode": { + "hosts": {host_mm_on.fqdn: self.get_host_mm_config(host_mm_on)}, + "vars": { + "cluster": self.get_cluster_mm_config(self.cluster_1), + "services": { + "service_one_component": self.get_service_mm_config( + self.service_two_components, self.component_1 + ) + }, + }, + }, + "HOST": {"hosts": {}, "vars": self.get_provider_mm_config(host_mm_on)}, + } + + def test_1_component_1_host(self): + service_one_component: ClusterObject = bulk_add_services_to_cluster( + cluster=self.cluster_1, + prototypes=Prototype.objects.filter( + type=ObjectType.SERVICE, name="service_one_component", bundle=self.cluster_1.prototype.bundle + ), + ).get() + component_1 = ServiceComponent.objects.get(service=service_one_component, prototype__name="component_1") + + self.add_hostcomponent_map( + cluster=self.cluster_1, + hc_map=[ + {"service_id": service_one_component.pk, "component_id": component_1.pk, "host_id": self.host_1.pk} + ], + ) + + action_on_service_mm_on = Action.objects.create( + name=ADCM_TURN_ON_MM_ACTION_NAME, prototype=service_one_component.prototype + ) + action_on_component_mm_on = Action.objects.create( + name=ADCM_TURN_ON_MM_ACTION_NAME, prototype=component_1.prototype + ) + action_on_host_on = Action.objects.create(name=ADCM_TURN_ON_MM_ACTION_NAME, prototype=self.host_1.prototype) + + host_names = [self.host_1.fqdn] + expected_topology = { + "CLUSTER": host_names, + f"{service_one_component.name}.{component_1.name}": host_names, + service_one_component.name: host_names, + } + + expected_topology_host_mm = { + "CLUSTER": {"hosts": {}, "vars": self.get_cluster_mm_config(self.cluster_1)}, + f"{service_one_component.name}.{component_1.name}.maintenance_mode": { + "hosts": self.get_provider_mm_config(self.host_1), + "vars": { + "cluster": self.get_cluster_mm_config(self.cluster_1), + "services": { + "service_one_component": self.get_service_mm_config(service_one_component, component_1) + }, + }, + }, + f"{service_one_component.name}.maintenance_mode": { + "hosts": self.get_provider_mm_config(self.host_1), + "vars": { + "cluster": self.get_cluster_mm_config(self.cluster_1), + "services": { + "service_one_component": self.get_service_mm_config(service_one_component, component_1) + }, + }, + }, + "HOST": {"hosts": {}, "vars": self.get_provider_mm_config(self.host_1)}, + } + + expected_data = { + ("service_one_component.component_1", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + "password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + }, + ), + ("service_one_component", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + "password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + }, + ), + } + + expected_data_host_mm = { + ("service_one_component.component_1.maintenance_mode", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + "password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + }, + ), + ("service_one_component.maintenance_mode", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + "password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + }, + ), + } + + for obj, action, expected_topology, expected_data in ( + ( + service_one_component, + action_on_service_mm_on, + expected_topology, + { + **expected_data, + **{ + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "service_one_component.json.j2", + { + "service_id": service_one_component.pk, + "service_password": ConfigLog.objects.get( + pk=service_one_component.config.current + ).config["password"], + "service_mm": "true", + "component_id": component_1.pk, + "component_password": ConfigLog.objects.get(pk=component_1.config.current).config[ + "password" + ], + "component_mm": "true", + }, + ) + }, + }, + ), + ( + component_1, + action_on_component_mm_on, + expected_topology, + { + **expected_data, + **{ + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "service_one_component.json.j2", + { + "service_id": service_one_component.pk, + "service_password": ConfigLog.objects.get( + pk=service_one_component.config.current + ).config["password"], + "service_mm": "true", + "component_id": component_1.pk, + "component_password": ConfigLog.objects.get(pk=component_1.config.current).config[ + "password" + ], + "component_mm": "true", + }, + ) + }, + }, + ), + ( + self.host_1, + action_on_host_on, + expected_topology_host_mm, + expected_data_host_mm, + ), + ): + with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): + obj.maintenance_mode = MaintenanceMode.ON + obj.save() + self.assert_inventory(obj, action, expected_topology, expected_data) + obj.maintenance_mode = MaintenanceMode.OFF + obj.save() + + def test_2_components_2_hosts(self): + self.host_2 = self.add_host( + bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=self.cluster_1 + ) + + self.service_two_components: ClusterObject = bulk_add_services_to_cluster( + cluster=self.cluster_1, + prototypes=Prototype.objects.filter( + type=ObjectType.SERVICE, name="service_two_components", bundle=self.cluster_1.prototype.bundle + ), + ).get() + self.component_1 = ServiceComponent.objects.get( + service=self.service_two_components, prototype__name="component_1" + ) + self.component_2 = ServiceComponent.objects.get( + service=self.service_two_components, prototype__name="component_2" + ) + + self.add_hostcomponent_map( + cluster=self.cluster_1, + hc_map=[ + { + "service_id": self.service_two_components.pk, + "component_id": self.component_1.pk, + "host_id": self.host_1.pk, + }, + { + "service_id": self.service_two_components.pk, + "component_id": self.component_1.pk, + "host_id": self.host_2.pk, + }, + { + "service_id": self.service_two_components.pk, + "component_id": self.component_2.pk, + "host_id": self.host_1.pk, + }, + { + "service_id": self.service_two_components.pk, + "component_id": self.component_2.pk, + "host_id": self.host_2.pk, + }, + ], + ) + + action_on_service_mm_on = Action.objects.create( + name=ADCM_TURN_ON_MM_ACTION_NAME, prototype=self.service_two_components.prototype + ) + action_on_component_1_mm_on = Action.objects.create( + name=ADCM_TURN_ON_MM_ACTION_NAME, prototype=self.component_1.prototype + ) + action_on_component_2_mm_on = Action.objects.create( + name=ADCM_TURN_ON_MM_ACTION_NAME, prototype=self.component_2.prototype + ) + action_on_host_on = Action.objects.create(name=ADCM_TURN_ON_MM_ACTION_NAME, prototype=self.host_1.prototype) + + host_names = [self.host_1.fqdn, self.host_2.fqdn] + expected_hosts_topology = { + "CLUSTER": host_names, + f"{self.service_two_components.name}.{self.component_1.name}": host_names, + f"{self.service_two_components.name}.{self.component_2.name}": host_names, + self.service_two_components.name: host_names, + } + + expected_topology_host_1_mm = self._get_2_hosts_topology(self.host_1, self.host_2) + + expected_topology_host_2_mm = self._get_2_hosts_topology(self.host_2, self.host_1) + + expected_data = { + ("service_two_components.component_1", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_1_password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + "host_2_id": self.host_2.pk, + "host_2_password": ConfigLog.objects.get(pk=self.host_2.config.current).config["password"], + }, + ), + ("service_two_components", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_1_password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + "host_2_id": self.host_2.pk, + "host_2_password": ConfigLog.objects.get(pk=self.host_2.config.current).config["password"], + }, + ), + ("service_two_components.component_2", "hosts"): ( + self.templates_dir / "two_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_1_password": ConfigLog.objects.get(pk=self.host_1.config.current).config["password"], + "host_2_id": self.host_2.pk, + "host_2_password": ConfigLog.objects.get(pk=self.host_2.config.current).config["password"], + }, + ), + } + + expected_data_host_1_mm = { + ("service_two_components.component_1.maintenance_mode", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + }, + ), + ("service_two_components.maintenance_mode", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_1.fqdn, + "adcm_hostid": self.host_1.pk, + }, + ), + } + + expected_data_host_2_mm = { + ("service_two_components.component_1.maintenance_mode", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_2.fqdn, + "adcm_hostid": self.host_2.pk, + }, + ), + ("service_two_components.maintenance_mode", "hosts"): ( + self.templates_dir / "one_host.json.j2", + { + "host_fqdn": self.host_2.fqdn, + "adcm_hostid": self.host_2.pk, + }, + ), + } + + for obj, action, expected_topology, expected_data in ( + (self.service_two_components, action_on_service_mm_on, expected_hosts_topology, expected_data), + (self.component_1, action_on_component_1_mm_on, expected_hosts_topology, expected_data), + (self.component_2, action_on_component_2_mm_on, expected_hosts_topology, expected_data), + ( + self.host_1, + action_on_host_on, + expected_topology_host_1_mm, + expected_data_host_1_mm, + ), + ( + self.host_2, + action_on_host_on, + expected_topology_host_2_mm, + expected_data_host_2_mm, + ), + ): + with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): + obj.maintenance_mode = MaintenanceMode.ON + obj.save() + self.assert_inventory(obj, action, expected_topology, expected_data) + obj.maintenance_mode = MaintenanceMode.OFF + obj.save() From 48757d2a0a9fe14adeece672a04d2cb1a05a71f8 Mon Sep 17 00:00:00 2001 From: Dmitriy Bardin Date: Wed, 24 Jan 2024 08:34:40 +0000 Subject: [PATCH 050/151] ADCM-5230 - [UI 2.0] Change logic of "add hosts to cluster" https://tracker.yandex.ru/ADCM-5230 --- adcm-web/app/src/api/adcm/clusters.ts | 7 +++---- .../LinkHostDialog/useLinkHostForm.ts | 2 +- .../src/store/adcm/cluster/hosts/hostsActionsSlice.ts | 10 +--------- adcm-web/app/src/store/adcm/hosts/hostsActionsSlice.ts | 9 +++++++-- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/adcm-web/app/src/api/adcm/clusters.ts b/adcm-web/app/src/api/adcm/clusters.ts index a8a27e9063..aa0340a786 100644 --- a/adcm-web/app/src/api/adcm/clusters.ts +++ b/adcm-web/app/src/api/adcm/clusters.ts @@ -91,10 +91,9 @@ export class AdcmClustersApi { return response.data; } - public static async linkHost(clusterId: number, hostId: number) { - await httpClient.post(`/api/v2/clusters/${clusterId}/hosts/`, { - hostId, - }); + public static async linkHost(clusterId: number, hostIds: number[]) { + const hostIdsPayload = hostIds.map((id) => ({ hostId: id })); + await httpClient.post(`/api/v2/clusters/${clusterId}/hosts/`, hostIdsPayload); } public static async unlinkHost(clusterId: number, hostId: number) { diff --git a/adcm-web/app/src/components/pages/HostsPage/HostsActionsDialogs/LinkHostDialog/useLinkHostForm.ts b/adcm-web/app/src/components/pages/HostsPage/HostsActionsDialogs/LinkHostDialog/useLinkHostForm.ts index 3ac8456316..1fde36d6d2 100644 --- a/adcm-web/app/src/components/pages/HostsPage/HostsActionsDialogs/LinkHostDialog/useLinkHostForm.ts +++ b/adcm-web/app/src/components/pages/HostsPage/HostsActionsDialogs/LinkHostDialog/useLinkHostForm.ts @@ -40,7 +40,7 @@ export const useLinkHostForm = () => { const submit = useCallback(() => { const { clusterId, hostId } = formData; if (clusterId && hostId) { - dispatch(linkHostWithUpdate({ clusterId, hostId })); + dispatch(linkHostWithUpdate({ clusterId, hostId: [hostId] })); } }, [formData, dispatch]); diff --git a/adcm-web/app/src/store/adcm/cluster/hosts/hostsActionsSlice.ts b/adcm-web/app/src/store/adcm/cluster/hosts/hostsActionsSlice.ts index 78c358c9be..996b515d36 100644 --- a/adcm-web/app/src/store/adcm/cluster/hosts/hostsActionsSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/hosts/hostsActionsSlice.ts @@ -5,7 +5,6 @@ import { getErrorMessage } from '@utils/httpResponseUtils'; import { AdcmHost, AdcmMaintenanceMode } from '@models/adcm'; import { AddClusterHostsPayload } from '@models/adcm'; import { getClusterHosts } from './hostsSlice'; -import { rejectedFilter } from '@utils/promiseUtils'; const loadHosts = createAsyncThunk('adcm/clusterHostsActions/loadHosts', async (arg, thunkAPI) => { try { @@ -52,17 +51,10 @@ const addClusterHosts = createAsyncThunk( 'adcm/clusterHostsActions/addClusterHosts', async ({ clusterId, selectedHostIds }: AddClusterHostsPayload, thunkAPI) => { try { - const linkHostsPromises = await Promise.allSettled( - selectedHostIds.map((id) => AdcmClustersApi.linkHost(clusterId, id)), - ); - const responsesList = rejectedFilter(linkHostsPromises); + await AdcmClustersApi.linkHost(clusterId, selectedHostIds); - if (responsesList.length > 0) { - throw responsesList[0]; - } const message = selectedHostIds.length > 1 ? 'All selected hosts have been added' : 'The host has been added'; thunkAPI.dispatch(showInfo({ message })); - return []; } catch (error) { thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); return thunkAPI.rejectWithValue(error); diff --git a/adcm-web/app/src/store/adcm/hosts/hostsActionsSlice.ts b/adcm-web/app/src/store/adcm/hosts/hostsActionsSlice.ts index 2922bcdf3b..65263ba312 100644 --- a/adcm-web/app/src/store/adcm/hosts/hostsActionsSlice.ts +++ b/adcm-web/app/src/store/adcm/hosts/hostsActionsSlice.ts @@ -35,6 +35,11 @@ const loadHostProviders = createAsyncThunk('adcm/hostsActions/hostProviders', as } }); +interface LinkHostTogglePayload { + hostId: number[]; + clusterId: number; +} + interface UnlinkHostTogglePayload { hostId: number; clusterId: number; @@ -63,7 +68,7 @@ const unlinkHostWithUpdate = createAsyncThunk( const linkHost = createAsyncThunk( 'adcm/hostsActions/linkHost', - async ({ hostId, clusterId }: UnlinkHostTogglePayload, thunkAPI) => { + async ({ hostId, clusterId }: LinkHostTogglePayload, thunkAPI) => { try { await AdcmClustersApi.linkHost(clusterId, hostId); thunkAPI.dispatch(showInfo({ message: 'The host has been linked' })); @@ -78,7 +83,7 @@ const linkHost = createAsyncThunk( const linkHostWithUpdate = createAsyncThunk( 'adcm/hostsActions/linkHostWithUpdate', - async (arg: UnlinkHostTogglePayload, thunkAPI) => { + async (arg: LinkHostTogglePayload, thunkAPI) => { await thunkAPI.dispatch(linkHost(arg)).unwrap(); thunkAPI.dispatch(getHosts()); }, From ae5c35bb1f4d055a83f74a2d16f833359986b166 Mon Sep 17 00:00:00 2001 From: Alexey Latunov Date: Wed, 24 Jan 2024 12:49:40 +0000 Subject: [PATCH 051/151] [UI] ADCM-5211: Change spinner https://tracker.yandex.ru/ADCM-5211 --- .../uikit/Spinner/Spinner.module.scss | 91 +++++++++++++++---- .../src/components/uikit/Spinner/Spinner.tsx | 41 +++++++-- 2 files changed, 105 insertions(+), 27 deletions(-) diff --git a/adcm-web/app/src/components/uikit/Spinner/Spinner.module.scss b/adcm-web/app/src/components/uikit/Spinner/Spinner.module.scss index 2715f6da04..99b31676e8 100644 --- a/adcm-web/app/src/components/uikit/Spinner/Spinner.module.scss +++ b/adcm-web/app/src/components/uikit/Spinner/Spinner.module.scss @@ -5,25 +5,14 @@ body.theme-light { --spinner-overlay-background: rgba(227, 234, 238, 0.9); } - -} - -.spinner { - display: inline-block; - width: 1.65em; - height: 1.65em; - border: 1px solid; - border-top: none; - border-bottom: none; - border-radius: 50%; - :global { - animation: spin 1s linear infinite; - } } .spinnerPanel { display: flex; + justify-content: center; + align-items: center; position: absolute; + border-radius: inherit; background: var(--spinner-overlay-background); backdrop-filter: blur(5px); z-index: var(--z-index-spinner); @@ -33,9 +22,75 @@ bottom: 0; .spinner { - margin: auto; - position: sticky; - top: min(100px, calc(50% - 1.65em)); - bottom: min(100px, calc(50% - 1.65em)); + position: absolute; + } +} + +.spinner { + display: inline-flex; + transform: rotate(300deg); + color: var(--text-green-color); +} + +.polygon_2 { + stroke-dasharray: 65 40%; + animation: dash_2 20s infinite linear; +} + +.polygon_1 { + animation-name: dash_1; + animation-iteration-count: infinite; + animation-duration: 2.2s; + animation-timing-function: linear; +} + +@keyframes dash_2 { + from { + stroke-dashoffset: 1200; + } +} + +@keyframes dash_1 { + 0% { + stroke-dasharray: 0 57; + stroke-dashoffset: 0; + animation-timing-function: ease-out; + } + 12.5% { + stroke-dasharray: 15 42; + stroke-dashoffset: 0; + animation-timing-function: ease-out; + } + 25% { + stroke-dasharray: 45 12; + stroke-dashoffset: 0; + animation-timing-function: ease-out; + } + 37.5% { + stroke-dasharray: 45 12; + stroke-dashoffset: -95%; + animation-timing-function: ease-in-out; + } + 50% { + stroke-dasharray: 45 12; + stroke-dashoffset: -190%; + animation-timing-function: ease-in-out; + } + 62.5% { + stroke-dasharray: 45 12; + stroke-dashoffset: -285%; + } + 75% { + stroke-dasharray: 30 27; + animation-timing-function: ease-in; + } + 87.5% { + stroke-dasharray: 15 42; + animation-timing-function: ease-in; + } + 100% { + stroke-dasharray: 0 57; + stroke-dashoffset: -580%; + animation-timing-function: ease-in; } } diff --git a/adcm-web/app/src/components/uikit/Spinner/Spinner.tsx b/adcm-web/app/src/components/uikit/Spinner/Spinner.tsx index 284ebaa2df..243097fbb8 100644 --- a/adcm-web/app/src/components/uikit/Spinner/Spinner.tsx +++ b/adcm-web/app/src/components/uikit/Spinner/Spinner.tsx @@ -1,17 +1,40 @@ -import React, { HTMLAttributes } from 'react'; -import cn from 'classnames'; +import React from 'react'; import s from './Spinner.module.scss'; +import cn from 'classnames'; -const Spinner: React.FC = () => { - return
; -}; +interface SpinnerProps { + size?: number; + className?: string; +} -export default Spinner; +export const SpinnerPanel: React.FC = ({ className, ...props }) => { + return ( +
+ +
+ ); +}; -export const SpinnerPanel: React.FC, 'children'>> = ({ className, ...props }) => { +export const Spinner: React.FC = ({ className, size = 40 }) => { + const style = { width: size, height: size }; return ( -
- +
+ + + + + +
); }; + +export default Spinner; From fd4b69905f221a47db5ab8d1827ec2418bb4d58d Mon Sep 17 00:00:00 2001 From: Artem Starovoitov Date: Thu, 25 Jan 2024 06:55:28 +0000 Subject: [PATCH 052/151] ADCM-5220: Add tests for before_upgrade --- .../bundles/cluster_1_upgrade/config.yaml | 171 ++++++++++++++ .../bundles/cluster_1_upgrade/playbook.yaml | 10 + .../bundles/provider_upgrade/config.yaml | 81 +++++++ .../bundles/provider_upgrade/playbook.yaml | 10 + .../before_upgrade_2_hosts.json.j2 | 12 + .../before_upgrade_cluster.json.j2 | 31 +++ .../before_upgrade_provider.json.j2 | 17 ++ ...ore_upgrade_service_two_components.json.j2 | 81 +++++++ .../test_inventory/test_before_upgrade.py | 215 ++++++++++++++++++ 9 files changed, 628 insertions(+) create mode 100644 python/cm/tests/bundles/cluster_1_upgrade/config.yaml create mode 100644 python/cm/tests/bundles/cluster_1_upgrade/playbook.yaml create mode 100644 python/cm/tests/bundles/provider_upgrade/config.yaml create mode 100644 python/cm/tests/bundles/provider_upgrade/playbook.yaml create mode 100644 python/cm/tests/files/response_templates/before_upgrade_2_hosts.json.j2 create mode 100644 python/cm/tests/files/response_templates/before_upgrade_cluster.json.j2 create mode 100644 python/cm/tests/files/response_templates/before_upgrade_provider.json.j2 create mode 100644 python/cm/tests/files/response_templates/before_upgrade_service_two_components.json.j2 create mode 100644 python/cm/tests/test_inventory/test_before_upgrade.py diff --git a/python/cm/tests/bundles/cluster_1_upgrade/config.yaml b/python/cm/tests/bundles/cluster_1_upgrade/config.yaml new file mode 100644 index 0000000000..36c6d11d02 --- /dev/null +++ b/python/cm/tests/bundles/cluster_1_upgrade/config.yaml @@ -0,0 +1,171 @@ +--- +- type: cluster + name: cluster_1 + version: &version '2.0' + edition: community + config_group_customization: true + allow_maintenance_mode: true + upgrade: + - name: upgrade + versions: &correct_versions + min: '1.0' + max: '2.0' + states: &always_available + available: any + + - name: upgrade_via_action_simple + versions: *correct_versions + states: *always_available + scripts: &upgrade_scripts + - name: pre + script: ./playbook.yaml + script_type: ansible + - name: switch + script: bundle_switch + script_type: internal + - name: post + script: ./playbook.yaml + script_type: ansible + + - name: upgrade_via_action_complex + versions: *correct_versions + states: *always_available + scripts: *upgrade_scripts + config: + - name: simple + type: string + required: false + - name: grouped + type: group + subs: + - name: simple + type: integer + default: 4 + - name: second + type: float + default: 4.3 + - name: after + type: list + default: + - "1" + - "woohoo" + + ui_options: + disclaimer: "Cool upgrade" + + - name: unfit_version + versions: + min_strict: '0' + max: '0.3' + states: *always_available + + - name: unfit_state + versions: *correct_versions + states: + available: + - doesnotexist + + config: &config + - name: integer + type: integer + required: false + default: 10 + - name: password + type: password + required: false + default: password + - name: string + type: string + required: false + default: string + - name: list + type: list + required: false + default: + - value1 + - value2 + - value3 + actions: + action_on_cluster: &action + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any + host_action_on_cluster: &host_action + type: job + script: ./playbook.yaml + script_type: ansible + host_action: true + states: + available: any + hc_acl_action_on_cluster: &hc_acl_action + <<: *action + hc_acl: + - service: service_two_components + component: component_1 + action: add + - service: service_two_components + component: component_1 + action: remove + - service: service_two_components + component: component_2 + action: add + - service: service_two_components + component: component_2 + action: remove + +- name: service_one_component + type: service + version: *version + config: *config + actions: + action_on_service: *action + host_action_on_service: *host_action + + components: + component_1: + constraint: [ 0, + ] + config: *config + actions: + action_on_component: *action + host_action_on_component: *host_action + +- name: service_two_components + type: service + version: *version + config: *config + actions: + action_on_service: *action + hc_acl_action_on_service: *hc_acl_action + + components: + component_1: + constraint: [ 0, + ] + config: *config + actions: + action_on_component_1: *action + component_2: + constraint: [ 0, + ] + config: *config + actions: + action_on_component_2: *action + +- name: another_service_two_components + type: service + version: *version + config: *config + actions: + action_on_service: *action + + components: + component_1: + constraint: [ 0, + ] + config: *config + actions: + action_on_component_1: *action + component_2: + constraint: [ 0, + ] + config: *config + actions: + action_on_component_2: *action diff --git a/python/cm/tests/bundles/cluster_1_upgrade/playbook.yaml b/python/cm/tests/bundles/cluster_1_upgrade/playbook.yaml new file mode 100644 index 0000000000..be7ea53778 --- /dev/null +++ b/python/cm/tests/bundles/cluster_1_upgrade/playbook.yaml @@ -0,0 +1,10 @@ +--- +- name: sleep + hosts: all + connection: local + gather_facts: no + + tasks: + - name: sleep + pause: + seconds: 1 diff --git a/python/cm/tests/bundles/provider_upgrade/config.yaml b/python/cm/tests/bundles/provider_upgrade/config.yaml new file mode 100644 index 0000000000..b3f14f91f9 --- /dev/null +++ b/python/cm/tests/bundles/provider_upgrade/config.yaml @@ -0,0 +1,81 @@ +--- +- type: provider + name: provider + version: &version '2.0' + upgrade: + - name: upgrade + versions: &correct_versions + min: '1.0' + max: '2.0' + states: &always_available + available: any + + - name: upgrade_via_action_simple + versions: *correct_versions + states: *always_available + scripts: &upgrade_scripts + - name: pre + script: ./playbook.yaml + script_type: ansible + - name: switch + script: bundle_switch + script_type: internal + - name: post + script: ./playbook.yaml + script_type: ansible + + - name: upgrade_via_action_complex + versions: *correct_versions + states: *always_available + scripts: *upgrade_scripts + config: + - name: simple + type: string + required: false + - name: grouped + type: group + subs: + - name: simple + type: integer + default: 4 + - name: second + type: float + default: 4.3 + - name: after + type: list + default: + - "1" + - "woohoo" + ui_options: + disclaimer: "Cool upgrade" + + - name: unfit_version + versions: + min_strict: '0' + max: '0.3' + states: *always_available + + - name: unfit_state + versions: *correct_versions + states: + available: + - doesnotexist + + actions: + provider_action: + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any +- type: host + name: host + version: *version + actions: + host_action: + display_name: "host_action" + type: job + script: ./playbook.yaml + script_type: ansible + states: + available: any diff --git a/python/cm/tests/bundles/provider_upgrade/playbook.yaml b/python/cm/tests/bundles/provider_upgrade/playbook.yaml new file mode 100644 index 0000000000..be7ea53778 --- /dev/null +++ b/python/cm/tests/bundles/provider_upgrade/playbook.yaml @@ -0,0 +1,10 @@ +--- +- name: sleep + hosts: all + connection: local + gather_facts: no + + tasks: + - name: sleep + pause: + seconds: 1 diff --git a/python/cm/tests/files/response_templates/before_upgrade_2_hosts.json.j2 b/python/cm/tests/files/response_templates/before_upgrade_2_hosts.json.j2 new file mode 100644 index 0000000000..c1b2eb9452 --- /dev/null +++ b/python/cm/tests/files/response_templates/before_upgrade_2_hosts.json.j2 @@ -0,0 +1,12 @@ +{ + "host_1":{ + "adcm_hostid": {{ host_1_id }}, + "multi_state":[], + "state":"created" + }, + "host_2":{ + "adcm_hostid": {{ host_2_id }}, + "multi_state":[], + "state":"created" + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/before_upgrade_cluster.json.j2 b/python/cm/tests/files/response_templates/before_upgrade_cluster.json.j2 new file mode 100644 index 0000000000..263f86e49e --- /dev/null +++ b/python/cm/tests/files/response_templates/before_upgrade_cluster.json.j2 @@ -0,0 +1,31 @@ +{ + "config":{ + "integer":10, + "password":"password", + "string":"string", + "list":[ + "value1", + "value2", + "value3" + ] + }, + "name": "{{ object_name }}", + "id": {{ id }}, + "version":"2.0", + "edition":"community", + "state":"success", + "multi_state":[], + "before_upgrade":{ + "state":"created", + "config":{ + "integer":10, + "password":"password", + "string":"string", + "list":[ + "value1", + "value2", + "value3" + ] + } + } +} \ No newline at end of file diff --git a/python/cm/tests/files/response_templates/before_upgrade_provider.json.j2 b/python/cm/tests/files/response_templates/before_upgrade_provider.json.j2 new file mode 100644 index 0000000000..8b8ca5ab17 --- /dev/null +++ b/python/cm/tests/files/response_templates/before_upgrade_provider.json.j2 @@ -0,0 +1,17 @@ +{ + "config": {}, + "name": "provider", + "id": {{ id }}, + "host_prototype_id": {{ host_prototype_id }}, + "state": "success", + "multi_state": [], + "before_upgrade": { + "state": "created", + "config": { + "integer": 10, + "password": "password", + "string": "string", + "list": ["value1", "value2", "value3"] + } + } +} diff --git a/python/cm/tests/files/response_templates/before_upgrade_service_two_components.json.j2 b/python/cm/tests/files/response_templates/before_upgrade_service_two_components.json.j2 new file mode 100644 index 0000000000..a6703610f4 --- /dev/null +++ b/python/cm/tests/files/response_templates/before_upgrade_service_two_components.json.j2 @@ -0,0 +1,81 @@ +{ + "service_two_components": { + "id": {{ service_id }}, + "version": "2.0", + "state": "created", + "multi_state": [], + "config": { + "integer": 10, + "password": "password", + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "maintenance_mode": false, + "display_name": "service_two_components", + "before_upgrade": { + "state": "created", + "config": { + "integer": 10, + "password": "password", + "string": "string", + "list": ["value1", "value2", "value3"] + } + }, + "component_1": { + "component_id": {{ component_1_id }}, + "config": { + "integer": 10, + "password": "password", + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "component_1", + "before_upgrade": { + "state": "created", + "config": { + "integer": 10, + "password": "password", + "string": "string", + "list": ["value1", "value2", "value3"] + } + } + }, + "component_2": { + "component_id": {{ component_2_id }}, + "config": { + "integer": 10, + "password": "password", + "string": "string", + "list": [ + "value1", + "value2", + "value3" + ] + }, + "state": "created", + "multi_state": [], + "maintenance_mode": false, + "display_name": "component_2", + "before_upgrade": { + "state": "created", + "config": { + "integer": 10, + "password": "password", + "string": "string", + "list": ["value1", "value2", "value3"] + } + } + } + } +} \ No newline at end of file diff --git a/python/cm/tests/test_inventory/test_before_upgrade.py b/python/cm/tests/test_inventory/test_before_upgrade.py new file mode 100644 index 0000000000..25986e4ce3 --- /dev/null +++ b/python/cm/tests/test_inventory/test_before_upgrade.py @@ -0,0 +1,215 @@ +# Licensed 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. +from pathlib import Path + +from api_v2.service.utils import bulk_add_services_to_cluster +from cm.inventory import get_inventory_data +from cm.models import ClusterObject, ObjectType, Prototype, ServiceComponent, Upgrade +from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets +from cm.upgrade import bundle_switch, update_before_upgrade + + +class TestBeforeUpgrade(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes + def setUp(self) -> None: + bundles_dir = Path(__file__).parent.parent / "bundles" + self.templates_dir = Path(__file__).parent.parent / "files/response_templates" + + self.provider_bundle = self.add_bundle(source_dir=bundles_dir / "provider") + + self.test_bundles_dir = Path(__file__).parent / "bundles" + + cluster_bundle = self.add_bundle(source_dir=bundles_dir / "cluster_1") + + self.cluster_1 = self.add_cluster(bundle=cluster_bundle, name="cluster_1") + self.provider = self.add_provider(bundle=self.provider_bundle, name="provider") + + self.cluster_upgrade_bundle = self.add_bundle(source_dir=Path(bundles_dir / "cluster_1_upgrade")) + self.provider_upgrade_bundle = self.add_bundle(source_dir=Path(bundles_dir / "provider_upgrade")) + + self.host_1 = self.add_host(bundle=self.provider_bundle, provider=self.provider, fqdn="host_1", cluster=None) + self.host_2 = self.add_host(bundle=self.provider_bundle, provider=self.provider, fqdn="host_2", cluster=None) + self.service_two_components = None + self.component_1 = None + self.component_2 = None + + self.upgrade_for_provider = Upgrade.objects.get( + bundle=self.provider_upgrade_bundle, name="upgrade_via_action_simple" + ) + self.upgrade_for_cluster = Upgrade.objects.get( + bundle=self.cluster_upgrade_bundle, name="upgrade_via_action_simple" + ) + + def test_provider_two_hosts(self): + self.provider.before_upgrade["bundle_id"] = self.provider.prototype.bundle.pk + update_before_upgrade(obj=self.provider) + + bundle_switch(obj=self.provider, upgrade=self.upgrade_for_provider) + + self.provider.state = "success" + self.provider.save(update_fields=["state"]) + + expected_topology_provider = {"PROVIDER": [self.host_1.fqdn, self.host_2.fqdn]} + expected_topology_host_1 = {"HOST": [self.host_1.fqdn]} + expected_topology_host_2 = {"HOST": [self.host_2.fqdn]} + + expected_data_provider = { + ("PROVIDER", "hosts"): ( + self.templates_dir / "before_upgrade_2_hosts.json.j2", + { + "host_1_id": self.host_1.pk, + "host_2_id": self.host_2.pk, + }, + ), + } + + expected_data_host_1 = { + ("HOST", "vars", "provider"): ( + self.templates_dir / "before_upgrade_provider.json.j2", + { + "id": self.host_1.provider.pk, + "host_prototype_id": Prototype.objects.filter(type="host", version="2.0").last().pk, + }, + ) + } + expected_data_host_2 = { + ("HOST", "vars", "provider"): ( + self.templates_dir / "before_upgrade_provider.json.j2", + { + "id": self.host_2.provider.pk, + "host_prototype_id": Prototype.objects.filter(type="host", version="2.0").last().pk, + }, + ), + } + + for obj, topology, expected_data in ( + (self.provider, expected_topology_provider, expected_data_provider), + (self.host_1, expected_topology_host_1, expected_data_host_1), + (self.host_2, expected_topology_host_2, expected_data_host_2), + ): + with self.subTest( + msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {self.upgrade_for_provider.name}" + ): + self.assert_inventory( + obj=obj, + action=self.upgrade_for_provider.action, + expected_topology=topology, + expected_data=expected_data, + ) + + def test_provider_full_two_hosts(self): + self.provider.before_upgrade["bundle_id"] = self.provider.prototype.bundle.pk + update_before_upgrade(obj=self.provider) + + bundle_switch(obj=self.provider, upgrade=self.upgrade_for_provider) + + self.provider.state = "success" + self.provider.save(update_fields=["state"]) + + expected_topology_provider = {"PROVIDER": [self.host_1.fqdn, self.host_2.fqdn]} + + expected_data_provider = { + ("all", "vars", "provider"): ( + self.templates_dir / "before_upgrade_provider.json.j2", + { + "id": self.host_2.provider.pk, + "host_prototype_id": Prototype.objects.filter(type="host", version="2.0").last().pk, + }, + ), + } + + actual_inventory = decrypt_secrets( + source=get_inventory_data(obj=self.provider, action=self.upgrade_for_provider.action) + ) + + self.check_hosts_topology(data=actual_inventory["all"]["children"], expected=expected_topology_provider) + self.check_data_by_template(data=actual_inventory, templates_data=expected_data_provider) + + def test_2_components_2_hosts(self): + self.add_host_to_cluster(cluster=self.cluster_1, host=self.host_1) + self.add_host_to_cluster(cluster=self.cluster_1, host=self.host_2) + + self.service_two_components: ClusterObject = bulk_add_services_to_cluster( + cluster=self.cluster_1, + prototypes=Prototype.objects.filter( + type=ObjectType.SERVICE, name="service_two_components", bundle=self.cluster_1.prototype.bundle + ), + ).get() + self.component_1 = ServiceComponent.objects.get( + service=self.service_two_components, prototype__name="component_1" + ) + self.component_2 = ServiceComponent.objects.get( + service=self.service_two_components, prototype__name="component_2" + ) + + self.add_hostcomponent_map( + cluster=self.cluster_1, + hc_map=[ + { + "service_id": self.service_two_components.pk, + "component_id": self.component_1.pk, + "host_id": self.host_1.pk, + }, + { + "service_id": self.service_two_components.pk, + "component_id": self.component_1.pk, + "host_id": self.host_2.pk, + }, + { + "service_id": self.service_two_components.pk, + "component_id": self.component_2.pk, + "host_id": self.host_1.pk, + }, + { + "service_id": self.service_two_components.pk, + "component_id": self.component_2.pk, + "host_id": self.host_2.pk, + }, + ], + ) + + self.cluster_1.before_upgrade["bundle_id"] = self.cluster_1.prototype.bundle.pk + update_before_upgrade(obj=self.cluster_1) + + bundle_switch(obj=self.cluster_1, upgrade=self.upgrade_for_cluster) + + self.cluster_1.state = "success" + self.cluster_1.save(update_fields=["state"]) + + host_names = [self.host_1.fqdn, self.host_2.fqdn] + expected_topology = { + "CLUSTER": host_names, + f"{self.service_two_components.name}.{self.component_1.name}": host_names, + f"{self.service_two_components.name}.{self.component_2.name}": host_names, + self.service_two_components.name: host_names, + } + + expected_data = { + ("CLUSTER", "vars", "cluster"): ( + self.templates_dir / "before_upgrade_cluster.json.j2", + {"object_name": self.cluster_1.name, "id": self.cluster_1.id}, + ), + ("CLUSTER", "vars", "services"): ( + self.templates_dir / "before_upgrade_service_two_components.json.j2", + { + "service_id": self.service_two_components.pk, + "component_1_id": self.component_1.pk, + "component_2_id": self.component_2.pk, + }, + ), + } + + self.assert_inventory( + obj=self.cluster_1, + action=self.upgrade_for_cluster.action, + expected_topology=expected_topology, + expected_data=expected_data, + ) From 2be19bb398f342ddfa47abcc6b1efe0e87edf705 Mon Sep 17 00:00:00 2001 From: Ella Kurginyan Date: Thu, 25 Jan 2024 09:04:13 +0000 Subject: [PATCH 053/151] ADCM-4169 Remove redundant default.conf (nginx settings) ADCM-4169 Remove redundant default.conf (nginx settings) --- os/etc/nginx/http.d/{adcm.conf => default.conf} | 0 os/etc/sv/wsgi/run | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename os/etc/nginx/http.d/{adcm.conf => default.conf} (100%) diff --git a/os/etc/nginx/http.d/adcm.conf b/os/etc/nginx/http.d/default.conf similarity index 100% rename from os/etc/nginx/http.d/adcm.conf rename to os/etc/nginx/http.d/default.conf diff --git a/os/etc/sv/wsgi/run b/os/etc/sv/wsgi/run index 1833168216..52c0b6e2c7 100755 --- a/os/etc/sv/wsgi/run +++ b/os/etc/sv/wsgi/run @@ -23,4 +23,4 @@ cd "${adcmroot}/python" touch /run/uwsgi.pid uwsgi --socket "${wsgisocketfile}" --pidfile "/run/uwsgi.pid" --module adcm.wsgi --chmod-socket=777 \ --logger file:logfile="${adcmlog}/wsgi.log",maxsize=2000000 \ - --master --processes=4 --harakiri=60 + --master --processes=4 --harakiri=6000 From 7f018e3f156868b938917e1ec1d19e01fd25be0a Mon Sep 17 00:00:00 2001 From: astarovo Date: Fri, 12 Jan 2024 16:23:41 +0300 Subject: [PATCH 054/151] ADCM-5163: Replace pylint, black and isort with ruff --- Makefile | 16 +- conf/adcm/python_scripts/run_ldap_sync.py | 9 +- .../python_scripts/testing_ldap_connection.py | 3 +- license_checker.py | 4 +- poetry.lock | 282 +++--------------- pyproject.toml | 71 +++-- python/adcm/settings.py | 13 +- python/adcm/tests/base.py | 8 +- python/adcm/urls.py | 1 - python/adcm/utils.py | 32 +- python/adcm/views.py | 4 +- .../ansible/plugins/action/adcm_add_host.py | 7 +- .../action/adcm_add_host_to_cluster.py | 12 +- .../plugins/action/adcm_change_flag.py | 16 +- .../action/adcm_change_maintenance_mode.py | 13 +- python/ansible/plugins/action/adcm_check.py | 15 +- python/ansible/plugins/action/adcm_config.py | 30 +- .../ansible/plugins/action/adcm_custom_log.py | 13 +- .../plugins/action/adcm_delete_host.py | 11 +- .../plugins/action/adcm_delete_service.py | 11 +- python/ansible/plugins/action/adcm_hc.py | 9 +- .../plugins/action/adcm_multi_state_set.py | 30 +- .../plugins/action/adcm_multi_state_unset.py | 30 +- .../action/adcm_remove_host_from_cluster.py | 11 +- python/ansible/plugins/action/adcm_state.py | 27 +- python/ansible/plugins/lookup/adcm_config.py | 6 +- python/ansible/plugins/lookup/adcm_state.py | 12 +- python/ansible_secret.py | 3 +- python/api/action/serializers.py | 6 +- python/api/action/urls.py | 3 +- python/api/action/views.py | 31 +- python/api/adcm/serializers.py | 5 +- python/api/adcm/urls.py | 3 +- python/api/adcm/views.py | 5 +- python/api/base_view.py | 36 +-- python/api/cluster/serializers.py | 22 +- python/api/cluster/urls.py | 3 +- python/api/cluster/views.py | 90 +++--- python/api/component/serializers.py | 14 +- python/api/component/urls.py | 3 +- python/api/component/views.py | 25 +- python/api/concern/serializers.py | 4 +- python/api/concern/urls.py | 3 +- python/api/concern/views.py | 31 +- python/api/config/serializers.py | 6 +- python/api/config/urls.py | 3 +- python/api/config/views.py | 30 +- python/api/config_log/serializers.py | 7 +- python/api/config_log/urls.py | 3 +- python/api/config_log/views.py | 10 +- python/api/docs.py | 6 +- python/api/group_config/serializers.py | 36 +-- python/api/group_config/urls.py | 3 +- python/api/group_config/views.py | 47 ++- python/api/host/cluster_urls.py | 3 +- python/api/host/host_urls.py | 3 +- python/api/host/provider_urls.py | 3 +- python/api/host/serializers.py | 12 +- python/api/host/urls.py | 3 +- python/api/host/views.py | 52 ++-- python/api/job/serializers.py | 33 +- python/api/job/task_urls.py | 3 +- python/api/job/urls.py | 3 +- python/api/job/views.py | 42 +-- python/api/object_config/views.py | 5 +- python/api/provider/serializers.py | 17 +- python/api/provider/urls.py | 25 +- python/api/provider/views.py | 32 +- python/api/serializers.py | 8 +- python/api/service/serializers.py | 18 +- python/api/service/urls.py | 3 +- python/api/service/views.py | 42 +-- python/api/stack/serializers.py | 14 +- python/api/stack/urls.py | 5 +- python/api/stack/views.py | 97 +++--- python/api/stats/serializers.py | 3 +- python/api/stats/urls.py | 3 +- python/api/stats/views.py | 9 +- python/api/tests/test_action.py | 3 +- python/api/tests/test_adcm.py | 3 +- .../api/tests/test_adcm_cluster_prototype.py | 3 +- python/api/tests/test_api.py | 78 +++-- python/api/tests/test_bundle.py | 5 +- python/api/tests/test_cluster.py | 3 +- python/api/tests/test_cluster_prototype.py | 3 +- python/api/tests/test_component.py | 3 +- python/api/tests/test_component_prototype.py | 3 +- python/api/tests/test_config.py | 3 +- python/api/tests/test_host.py | 3 +- python/api/tests/test_host_prototype.py | 3 +- python/api/tests/test_hostcomponent.py | 3 +- python/api/tests/test_job.py | 3 +- python/api/tests/test_log_storage.py | 3 +- python/api/tests/test_provider_prototype.py | 3 +- python/api/tests/test_service.py | 3 +- python/api/tests/test_service_prototype.py | 3 +- python/api/tests/test_stack.py | 3 +- python/api/tests/test_task.py | 3 +- python/api/urls.py | 3 +- python/api/utils.py | 22 +- python/api/views.py | 5 +- python/api_ui/stack/serializers.py | 3 +- python/api_ui/stack/urls.py | 5 +- python/api_ui/stack/views.py | 3 +- python/api_ui/tests/test_stack.py | 3 +- python/api_ui/urls.py | 3 +- python/api_v2/action/serializers.py | 3 +- python/api_v2/action/utils.py | 8 +- python/api_v2/action/views.py | 50 ++-- python/api_v2/adcm/serializers.py | 5 +- python/api_v2/adcm/urls.py | 3 +- python/api_v2/adcm/views.py | 17 +- python/api_v2/audit/urls.py | 3 +- python/api_v2/audit/views.py | 8 +- python/api_v2/bundle/serializers.py | 4 +- python/api_v2/bundle/urls.py | 3 +- python/api_v2/bundle/views.py | 16 +- python/api_v2/cluster/data_containers.py | 14 +- python/api_v2/cluster/serializers.py | 10 +- python/api_v2/cluster/urls.py | 3 +- python/api_v2/cluster/utils.py | 17 +- python/api_v2/cluster/views.py | 74 ++--- python/api_v2/component/serializers.py | 13 +- python/api_v2/component/views.py | 50 ++-- python/api_v2/config/utils.py | 8 +- python/api_v2/config/views.py | 26 +- python/api_v2/group_config/serializers.py | 3 +- python/api_v2/group_config/views.py | 22 +- python/api_v2/host/serializers.py | 10 +- python/api_v2/host/urls.py | 3 +- python/api_v2/host/utils.py | 6 +- python/api_v2/host/views.py | 78 +++-- python/api_v2/hostprovider/serializers.py | 6 +- python/api_v2/hostprovider/urls.py | 5 +- python/api_v2/hostprovider/views.py | 26 +- python/api_v2/imports/serializers.py | 3 +- python/api_v2/imports/utils.py | 27 +- python/api_v2/imports/views.py | 30 +- python/api_v2/job/permissions.py | 2 +- python/api_v2/job/serializers.py | 3 +- python/api_v2/job/urls.py | 5 +- python/api_v2/job/views.py | 19 +- python/api_v2/log_storage/serializers.py | 18 +- python/api_v2/log_storage/utils.py | 10 +- python/api_v2/log_storage/views.py | 20 +- python/api_v2/login/serializers.py | 3 +- python/api_v2/login/views.py | 5 +- python/api_v2/logout/views.py | 5 +- python/api_v2/profile/serializers.py | 5 +- python/api_v2/profile/views.py | 5 +- python/api_v2/prototype/serializers.py | 6 +- python/api_v2/prototype/urls.py | 3 +- python/api_v2/prototype/views.py | 24 +- python/api_v2/rbac/group/serializers.py | 3 +- python/api_v2/rbac/group/urls.py | 3 +- python/api_v2/rbac/group/views.py | 24 +- python/api_v2/rbac/policy/serializers.py | 5 +- python/api_v2/rbac/policy/urls.py | 3 +- python/api_v2/rbac/policy/views.py | 14 +- python/api_v2/rbac/role/filters.py | 2 +- python/api_v2/rbac/role/views.py | 18 +- python/api_v2/rbac/urls.py | 5 +- python/api_v2/rbac/user/filters.py | 7 +- python/api_v2/rbac/user/serializers.py | 3 +- python/api_v2/rbac/user/urls.py | 3 +- python/api_v2/rbac/user/views.py | 28 +- python/api_v2/service/filters.py | 4 +- python/api_v2/service/serializers.py | 8 +- python/api_v2/service/utils.py | 8 +- python/api_v2/service/views.py | 54 ++-- python/api_v2/task/filters.py | 4 +- python/api_v2/task/permissions.py | 2 +- python/api_v2/task/serializers.py | 8 +- python/api_v2/task/urls.py | 3 +- python/api_v2/task/views.py | 27 +- python/api_v2/tests/base.py | 3 +- python/api_v2/tests/test_actions.py | 7 +- python/api_v2/tests/test_adcm.py | 3 +- python/api_v2/tests/test_audit/test_adcm.py | 3 +- .../tests/test_audit/test_authorization.py | 3 +- python/api_v2/tests/test_audit/test_bundle.py | 3 +- .../api_v2/tests/test_audit/test_cluster.py | 7 +- .../api_v2/tests/test_audit/test_component.py | 3 +- python/api_v2/tests/test_audit/test_group.py | 3 +- .../tests/test_audit/test_group_config.py | 7 +- python/api_v2/tests/test_audit/test_host.py | 5 +- .../tests/test_audit/test_host_provider.py | 5 +- python/api_v2/tests/test_audit/test_login.py | 3 +- .../tests/test_audit/test_object_renaming.py | 3 +- python/api_v2/tests/test_audit/test_policy.py | 5 +- python/api_v2/tests/test_audit/test_role.py | 3 +- .../api_v2/tests/test_audit/test_service.py | 5 +- python/api_v2/tests/test_audit/test_task.py | 3 +- python/api_v2/tests/test_audit/test_user.py | 3 +- python/api_v2/tests/test_bulk_operations.py | 3 +- python/api_v2/tests/test_bundle.py | 3 +- python/api_v2/tests/test_cluster.py | 7 +- python/api_v2/tests/test_component.py | 3 +- python/api_v2/tests/test_concerns.py | 3 +- python/api_v2/tests/test_config.py | 9 +- python/api_v2/tests/test_group.py | 3 +- python/api_v2/tests/test_group_config.py | 11 +- python/api_v2/tests/test_host.py | 3 +- python/api_v2/tests/test_host_provider.py | 3 +- python/api_v2/tests/test_import.py | 3 +- python/api_v2/tests/test_jobs.py | 7 +- python/api_v2/tests/test_known_bugs.py | 3 +- python/api_v2/tests/test_mapping.py | 9 +- python/api_v2/tests/test_policy.py | 3 +- python/api_v2/tests/test_profile.py | 3 +- python/api_v2/tests/test_prototype.py | 3 +- python/api_v2/tests/test_role.py | 3 +- python/api_v2/tests/test_service.py | 3 +- python/api_v2/tests/test_tasks.py | 9 +- python/api_v2/tests/test_upgrade.py | 5 +- python/api_v2/tests/test_user.py | 5 +- python/api_v2/token/views.py | 5 +- python/api_v2/upgrade/serializers.py | 3 +- python/api_v2/upgrade/views.py | 39 ++- python/api_v2/urls.py | 13 +- python/api_v2/views.py | 6 +- python/audit/apps.py | 2 +- python/audit/cases/adcm.py | 9 +- python/audit/cases/bundle.py | 9 +- python/audit/cases/cases.py | 13 +- python/audit/cases/cluster.py | 38 ++- python/audit/cases/common.py | 35 +-- python/audit/cases/config.py | 18 +- python/audit/cases/host.py | 7 +- python/audit/cases/license.py | 11 +- python/audit/cases/provider.py | 5 +- python/audit/cases/rbac.py | 26 +- python/audit/cases/service.py | 11 +- python/audit/cases/stack.py | 7 +- python/audit/cef_logger.py | 5 +- python/audit/filters.py | 3 +- .../audit/management/commands/clearaudit.py | 16 +- python/audit/middleware.py | 11 +- python/audit/serializers.py | 3 +- python/audit/signals.py | 9 +- python/audit/tests/test_action.py | 14 +- python/audit/tests/test_adcm.py | 14 +- python/audit/tests/test_api.py | 4 +- .../audit/tests/test_audit_object_rename.py | 4 +- python/audit/tests/test_audit_objects.py | 4 +- python/audit/tests/test_authentication.py | 4 +- python/audit/tests/test_bundle.py | 16 +- python/audit/tests/test_cluster.py | 19 +- python/audit/tests/test_component.py | 14 +- python/audit/tests/test_config_log.py | 14 +- python/audit/tests/test_group.py | 12 +- python/audit/tests/test_group_config.py | 16 +- python/audit/tests/test_host.py | 16 +- python/audit/tests/test_logrotate.py | 4 +- python/audit/tests/test_policy.py | 22 +- python/audit/tests/test_provider.py | 14 +- python/audit/tests/test_role.py | 12 +- python/audit/tests/test_service.py | 16 +- python/audit/tests/test_task.py | 14 +- python/audit/tests/test_user.py | 14 +- python/audit/tests/test_views.py | 16 +- python/audit/urls.py | 3 +- python/audit/utils.py | 65 ++-- python/audit/views.py | 10 +- python/backupdb.py | 10 +- python/check_adcm_bundle.py | 8 +- python/check_adcm_config.py | 17 +- python/cm/adcm_config/checks.py | 47 ++- python/cm/adcm_config/config.py | 113 +++---- python/cm/adcm_config/utils.py | 15 +- python/cm/ansible_plugin.py | 18 +- python/cm/api.py | 91 +++--- python/cm/api_context.py | 2 +- python/cm/apps.py | 2 +- python/cm/bundle.py | 38 ++- python/cm/checker.py | 14 +- python/cm/daemon.py | 18 +- python/cm/data_containers.py | 2 +- python/cm/errors.py | 3 +- python/cm/flag.py | 3 +- python/cm/hierarchy.py | 20 +- python/cm/inventory.py | 42 +-- python/cm/issue.py | 26 +- python/cm/job.py | 54 ++-- .../management/commands/collect_statistics.py | 25 +- python/cm/management/commands/dumpcluster.py | 33 +- python/cm/management/commands/loadcluster.py | 49 ++- python/cm/management/commands/logrotate.py | 35 +-- .../cm/management/commands/run_ldap_sync.py | 9 +- .../cm/migrations/0067_tasklog_object_type.py | 12 +- ...106_set_nginx_rotate_config_to_defaults.py | 2 +- python/cm/models.py | 93 +++--- python/cm/schemas.py | 2 +- python/cm/services/cluster.py | 5 +- python/cm/signals.py | 7 +- python/cm/stack.py | 99 +++--- python/cm/status_api.py | 14 +- python/cm/tests/test_action.py | 11 +- python/cm/tests/test_adcm_config.py | 6 +- python/cm/tests/test_adcm_entity.py | 4 +- python/cm/tests/test_bundle.py | 26 +- python/cm/tests/test_cluster.py | 4 +- python/cm/tests/test_component.py | 6 +- python/cm/tests/test_config_group.py | 4 +- python/cm/tests/test_flag.py | 4 +- python/cm/tests/test_hc.py | 12 +- python/cm/tests/test_hierarchy.py | 9 +- python/cm/tests/test_host.py | 8 +- python/cm/tests/test_inventory/base.py | 12 +- .../test_inventory/test_action_config.py | 3 +- .../test_inventory/test_before_upgrade.py | 1 + .../test_inventory/test_cluster_hosts.py | 8 +- .../tests/test_inventory/test_components.py | 30 +- .../tests/test_inventory/test_group_config.py | 3 +- .../test_inventory/test_hc_acl_actions.py | 6 +- .../tests/test_inventory/test_host_action.py | 1 + .../cm/tests/test_inventory/test_inventory.py | 28 +- .../test_inventory/test_maintenance_mode.py | 27 +- python/cm/tests/test_issue.py | 4 +- python/cm/tests/test_job.py | 25 +- python/cm/tests/test_management_commands.py | 7 +- python/cm/tests/test_message_template.py | 4 +- python/cm/tests/test_requires.py | 4 +- python/cm/tests/test_service.py | 10 +- python/cm/tests/test_task_log.py | 16 +- python/cm/tests/test_upgrade.py | 9 +- python/cm/tests/test_variant.py | 5 +- python/cm/tests/test_yaml_checker.py | 3 +- python/cm/tests/utils.py | 5 +- python/cm/upgrade.py | 11 +- python/cm/utils.py | 6 +- python/cm/validators.py | 3 +- python/cm/variant.py | 31 +- python/core/cluster/rules.py | 2 +- python/core/types.py | 4 - python/drf_docs.py | 8 +- python/init_db.py | 7 +- python/jinja_config.py | 14 +- python/job_runner.py | 36 +-- python/manage.py | 4 +- python/rbac/apps.py | 2 +- python/rbac/endpoints/group/serializers.py | 6 +- python/rbac/endpoints/group/urls.py | 3 +- python/rbac/endpoints/group/views.py | 8 +- python/rbac/endpoints/logout.py | 7 +- python/rbac/endpoints/me/serializers.py | 3 +- python/rbac/endpoints/me/urls.py | 1 + python/rbac/endpoints/me/views.py | 5 +- python/rbac/endpoints/policy/serializers.py | 8 +- python/rbac/endpoints/policy/urls.py | 3 +- python/rbac/endpoints/policy/views.py | 17 +- python/rbac/endpoints/role/serializers.py | 5 +- python/rbac/endpoints/role/urls.py | 3 +- python/rbac/endpoints/role/views.py | 24 +- python/rbac/endpoints/serializers.py | 3 +- python/rbac/endpoints/token.py | 6 +- python/rbac/endpoints/user/serializers.py | 6 +- python/rbac/endpoints/user/urls.py | 3 +- python/rbac/endpoints/user/views.py | 8 +- python/rbac/endpoints_ui/role/urls.py | 3 +- python/rbac/endpoints_ui/role/views.py | 10 +- python/rbac/ldap.py | 32 +- .../management/commands/createsuperuser.py | 1 + python/rbac/management/commands/role_map.py | 8 +- .../rbac/management/commands/upgraderole.py | 3 +- python/rbac/models.py | 24 +- python/rbac/roles.py | 5 +- python/rbac/services/group.py | 1 + python/rbac/services/policy.py | 3 +- python/rbac/services/role.py | 5 +- python/rbac/services/user.py | 10 +- python/rbac/settings.py | 8 +- python/rbac/signals.py | 3 +- python/rbac/tests/test_api.py | 6 +- python/rbac/tests/test_base.py | 6 +- python/rbac/tests/test_group.py | 4 +- python/rbac/tests/test_policy/base.py | 6 +- .../test_policy/test_cluster_admin_role.py | 6 +- ...uster_admin_service_admin_hostcomponent.py | 6 +- .../tests/test_policy/test_group_policy.py | 4 +- .../test_no_right_user_have_no_access.py | 6 +- .../tests/test_policy/test_permissions.py | 1 + .../test_policy_cluster_admin_role_upgrade.py | 4 +- .../tests/test_policy/test_policy_delete.py | 3 +- .../test_policy/test_provider_admin_role.py | 4 +- python/rbac/tests/test_policy/test_rbac.py | 3 +- .../test_remove_user_from_policy.py | 6 +- .../test_policy/test_service_admin_role.py | 4 +- python/rbac/tests/test_role.py | 17 +- python/rbac/tests/test_spec.py | 17 +- python/rbac/tests/test_user.py | 4 +- python/rbac/upgrade/role.py | 14 +- python/rbac/urls.py | 1 + python/rbac/urls_ui.py | 1 + python/rbac/validators.py | 2 +- python/rbac/viewsets.py | 2 +- python/task_runner.py | 117 ++++---- spec/conf.py | 23 +- 398 files changed, 2444 insertions(+), 2924 deletions(-) diff --git a/Makefile b/Makefile index 4ff0592c62..ee6c3a1652 100644 --- a/Makefile +++ b/Makefile @@ -52,18 +52,16 @@ ng_tests: pretty: poetry install --no-root --with lint - black license_checker.py python - autoflake -r -i --remove-all-unused-imports --exclude apps.py,python/ansible/plugins,python/init_db.py,python/task_runner.py,python/backupdb.py,python/job_runner.py,python/drf_docs.py license_checker.py python - isort license_checker.py python - python license_checker.py --fix --folders python go + poetry run ruff format license_checker.py python + poetry run ruff check --fix license_checker.py python + poetry run ruff format license_checker.py python + poetry run python license_checker.py --fix --folders python go lint: poetry install --no-root --with lint - poetry run black --check license_checker.py python - poetry run autoflake --check --quiet -r --remove-all-unused-imports --exclude apps.py,python/ansible/plugins,python/init_db.py,python/task_runner.py,python/backupdb.py,python/job_runner.py,python/drf_docs.py license_checker.py python - poetry run isort --check license_checker.py python - python license_checker.py --folders python go - poetry run pylint -j 0 --rcfile pyproject.toml --recursive y python + poetry run python license_checker.py --folders python go + poetry run ruff check license_checker.py python + poetry run ruff format --check version: @echo $(ADCM_VERSION) diff --git a/conf/adcm/python_scripts/run_ldap_sync.py b/conf/adcm/python_scripts/run_ldap_sync.py index e68c701f9f..5aa74bcd91 100644 --- a/conf/adcm/python_scripts/run_ldap_sync.py +++ b/conf/adcm/python_scripts/run_ldap_sync.py @@ -19,7 +19,8 @@ os.environ["PYTHONPATH"] = "/adcm/python/" sys.path.append("/adcm/python/") -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401 # isort:skip + from cm.errors import AdcmEx from cm.logger import logger from django.db import DataError, IntegrityError @@ -68,9 +69,7 @@ def _bind(self) -> ldap.ldapobject.LDAPObject: @staticmethod def _deactivate_extra_users(ldap_usernames: set): - django_usernames = set( - User.objects.filter(type=OriginType.LDAP).values_list("username", flat=True) - ) + django_usernames = set(User.objects.filter(type=OriginType.LDAP).values_list("username", flat=True)) for username in django_usernames - ldap_usernames: user = User.objects.get(username__iexact=username) sys.stdout.write(f"Delete user: {user}\n") @@ -219,7 +218,7 @@ def _sync_ldap_users(self, ldap_users: list, ldap_groups: list) -> None: else: for group in ldap_attributes.get("memberof", []): name = group.split(",")[0][3:] - if not name.lower() in ldap_group_names: + if name.lower() not in ldap_group_names: continue try: group = Group.objects.get(name=f"{name} [ldap]", built_in=False, type=OriginType.LDAP) diff --git a/conf/adcm/python_scripts/testing_ldap_connection.py b/conf/adcm/python_scripts/testing_ldap_connection.py index 36084dfabf..b296284cc9 100644 --- a/conf/adcm/python_scripts/testing_ldap_connection.py +++ b/conf/adcm/python_scripts/testing_ldap_connection.py @@ -19,7 +19,8 @@ os.environ["PYTHONPATH"] = "/adcm/python/" sys.path.append("/adcm/python/") -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401 # isort:skip + from cm.errors import AdcmEx from rbac.ldap import configure_tls, get_ldap_default_settings, is_tls diff --git a/license_checker.py b/license_checker.py index e941e9e908..d7aab1d2d2 100644 --- a/license_checker.py +++ b/license_checker.py @@ -10,10 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -import argparse -import sys from pathlib import Path from typing import TextIO +import sys +import argparse APACHE_LICENCE_PY = [ '# Licensed under the Apache License, Version 2.0 (the "License");\n', diff --git a/poetry.lock b/poetry.lock index dff096101b..07474b7e6d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "adcm-version" @@ -68,20 +68,6 @@ typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] -[[package]] -name = "astroid" -version = "3.0.0" -description = "An abstract syntax tree for Python with inference support." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "astroid-3.0.0-py3-none-any.whl", hash = "sha256:f2510e7fdcd6cfda4ec50014726d4857abf79acfc010084ce8c26091913f1b25"}, - {file = "astroid-3.0.0.tar.gz", hash = "sha256:1defdbca052635dd29657ea674edfc45e4b5be9cd53630c5b084fcfed94344a8"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} - [[package]] name = "attr" version = "0.3.2" @@ -111,21 +97,6 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib- tests = ["attrs[tests-no-zope]", "zope-interface"] tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -[[package]] -name = "autoflake" -version = "2.2.1" -description = "Removes unused imports and unused variables" -optional = false -python-versions = ">=3.8" -files = [ - {file = "autoflake-2.2.1-py3-none-any.whl", hash = "sha256:265cde0a43c1f44ecfb4f30d95b0437796759d07be7706a2f70e4719234c0f79"}, - {file = "autoflake-2.2.1.tar.gz", hash = "sha256:62b7b6449a692c3c9b0c916919bbc21648da7281e8506bcf8d3f8280e431ebc1"}, -] - -[package.dependencies] -pyflakes = ">=3.0.0" -tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} - [[package]] name = "autopep8" version = "2.0.4" @@ -141,52 +112,6 @@ files = [ pycodestyle = ">=2.10.0" tomli = {version = "*", markers = "python_version < \"3.11\""} -[[package]] -name = "black" -version = "23.9.1" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.9.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:d6bc09188020c9ac2555a498949401ab35bb6bf76d4e0f8ee251694664df6301"}, - {file = "black-23.9.1-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:13ef033794029b85dfea8032c9d3b92b42b526f1ff4bf13b2182ce4e917f5100"}, - {file = "black-23.9.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:75a2dc41b183d4872d3a500d2b9c9016e67ed95738a3624f4751a0cb4818fe71"}, - {file = "black-23.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13a2e4a93bb8ca74a749b6974925c27219bb3df4d42fc45e948a5d9feb5122b7"}, - {file = "black-23.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:adc3e4442eef57f99b5590b245a328aad19c99552e0bdc7f0b04db6656debd80"}, - {file = "black-23.9.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:8431445bf62d2a914b541da7ab3e2b4f3bc052d2ccbf157ebad18ea126efb91f"}, - {file = "black-23.9.1-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:8fc1ddcf83f996247505db6b715294eba56ea9372e107fd54963c7553f2b6dfe"}, - {file = "black-23.9.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:7d30ec46de88091e4316b17ae58bbbfc12b2de05e069030f6b747dfc649ad186"}, - {file = "black-23.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031e8c69f3d3b09e1aa471a926a1eeb0b9071f80b17689a655f7885ac9325a6f"}, - {file = "black-23.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:538efb451cd50f43aba394e9ec7ad55a37598faae3348d723b59ea8e91616300"}, - {file = "black-23.9.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:638619a559280de0c2aa4d76f504891c9860bb8fa214267358f0a20f27c12948"}, - {file = "black-23.9.1-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:a732b82747235e0542c03bf352c126052c0fbc458d8a239a94701175b17d4855"}, - {file = "black-23.9.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:cf3a4d00e4cdb6734b64bf23cd4341421e8953615cba6b3670453737a72ec204"}, - {file = "black-23.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf99f3de8b3273a8317681d8194ea222f10e0133a24a7548c73ce44ea1679377"}, - {file = "black-23.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:14f04c990259576acd093871e7e9b14918eb28f1866f91968ff5524293f9c573"}, - {file = "black-23.9.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:c619f063c2d68f19b2d7270f4cf3192cb81c9ec5bc5ba02df91471d0b88c4c5c"}, - {file = "black-23.9.1-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:6a3b50e4b93f43b34a9d3ef00d9b6728b4a722c997c99ab09102fd5efdb88325"}, - {file = "black-23.9.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c46767e8df1b7beefb0899c4a95fb43058fa8500b6db144f4ff3ca38eb2f6393"}, - {file = "black-23.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50254ebfa56aa46a9fdd5d651f9637485068a1adf42270148cd101cdf56e0ad9"}, - {file = "black-23.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:403397c033adbc45c2bd41747da1f7fc7eaa44efbee256b53842470d4ac5a70f"}, - {file = "black-23.9.1-py3-none-any.whl", hash = "sha256:6ccd59584cc834b6d127628713e4b6b968e5f79572da66284532525a042549f9"}, - {file = "black-23.9.1.tar.gz", hash = "sha256:24b6b3ff5c6d9ea08a8888f6977eae858e1f340d7260cf56d70a49823236b62d"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "casestyle" version = "0.0.4" @@ -379,31 +304,6 @@ files = [ {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, ] -[[package]] -name = "click" -version = "8.1.3" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - [[package]] name = "coreapi" version = "2.3.3" @@ -487,20 +387,6 @@ files = [ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, ] -[[package]] -name = "dill" -version = "0.3.7" -description = "serialize all of Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"}, - {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"}, -] - -[package.extras] -graph = ["objgraph (>=1.7.2)"] - [[package]] name = "distlib" version = "0.3.8" @@ -753,22 +639,6 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1 testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] -[[package]] -name = "flake8" -version = "6.1.0" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, - {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.1.0,<3.2.0" - [[package]] name = "googleapis-common-protos" version = "1.59.1" @@ -890,23 +760,6 @@ files = [ {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, ] -[[package]] -name = "isort" -version = "5.12.0" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, -] - -[package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - [[package]] name = "itypes" version = "1.2.0" @@ -1118,17 +971,6 @@ files = [ {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, ] -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - [[package]] name = "multipledispatch" version = "1.0.0" @@ -1140,17 +982,6 @@ files = [ {file = "multipledispatch-1.0.0.tar.gz", hash = "sha256:5c839915465c68206c3e9c473357908216c28383b425361e5d144594bf85a7e0"}, ] -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - [[package]] name = "nodeenv" version = "1.8.0" @@ -1181,28 +1012,6 @@ rsa = ["cryptography (>=3.0.0)"] signals = ["blinker (>=1.4.0)"] signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] -[[package]] -name = "packaging" -version = "23.1" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, -] - -[[package]] -name = "pathspec" -version = "0.11.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, - {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, -] - [[package]] name = "platformdirs" version = "3.8.0" @@ -1469,17 +1278,6 @@ typing-extensions = ">=4.2.0" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] -[[package]] -name = "pyflakes" -version = "3.1.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, - {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, -] - [[package]] name = "pyjwt" version = "2.7.0" @@ -1497,35 +1295,6 @@ dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pyte docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] -[[package]] -name = "pylint" -version = "3.0.1" -description = "python code static checker" -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "pylint-3.0.1-py3-none-any.whl", hash = "sha256:9c90b89e2af7809a1697f6f5f93f1d0e518ac566e2ac4d2af881a69c13ad01ea"}, - {file = "pylint-3.0.1.tar.gz", hash = "sha256:81c6125637be216b4652ae50cc42b9f8208dfb725cdc7e04c48f6902f4dbdf40"}, -] - -[package.dependencies] -astroid = ">=3.0.0,<=3.1.0-dev0" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = [ - {version = ">=0.2", markers = "python_version < \"3.11\""}, - {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, -] -isort = ">=4.2.5,<6" -mccabe = ">=0.6,<0.8" -platformdirs = ">=2.2.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -tomlkit = ">=0.10.1" - -[package.extras] -spelling = ["pyenchant (>=3.2,<4.0)"] -testutils = ["gitpython (>3)"] - [[package]] name = "pyrsistent" version = "0.19.3" @@ -1628,6 +1397,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1635,8 +1405,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1653,6 +1430,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1660,6 +1438,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1729,6 +1508,32 @@ files = [ {file = "rstr-3.2.1.tar.gz", hash = "sha256:c51924c626540eb626ed3eb8e5e6c1d2f2c73959d039c8ff61ee562baeb4e0ff"}, ] +[[package]] +name = "ruff" +version = "0.1.13" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.13-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e3fd36e0d48aeac672aa850045e784673449ce619afc12823ea7868fcc41d8ba"}, + {file = "ruff-0.1.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9fb6b3b86450d4ec6a6732f9f60c4406061b6851c4b29f944f8c9d91c3611c7a"}, + {file = "ruff-0.1.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b13ba5d7156daaf3fd08b6b993360a96060500aca7e307d95ecbc5bb47a69296"}, + {file = "ruff-0.1.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9ebb40442f7b531e136d334ef0851412410061e65d61ca8ce90d894a094feb22"}, + {file = "ruff-0.1.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226b517f42d59a543d6383cfe03cccf0091e3e0ed1b856c6824be03d2a75d3b6"}, + {file = "ruff-0.1.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5f0312ba1061e9b8c724e9a702d3c8621e3c6e6c2c9bd862550ab2951ac75c16"}, + {file = "ruff-0.1.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2f59bcf5217c661254bd6bc42d65a6fd1a8b80c48763cb5c2293295babd945dd"}, + {file = "ruff-0.1.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6894b00495e00c27b6ba61af1fc666f17de6140345e5ef27dd6e08fb987259d"}, + {file = "ruff-0.1.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1600942485c6e66119da294c6294856b5c86fd6df591ce293e4a4cc8e72989"}, + {file = "ruff-0.1.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ee3febce7863e231a467f90e681d3d89210b900d49ce88723ce052c8761be8c7"}, + {file = "ruff-0.1.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dcaab50e278ff497ee4d1fe69b29ca0a9a47cd954bb17963628fa417933c6eb1"}, + {file = "ruff-0.1.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f57de973de4edef3ad3044d6a50c02ad9fc2dff0d88587f25f1a48e3f72edf5e"}, + {file = "ruff-0.1.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7a36fa90eb12208272a858475ec43ac811ac37e91ef868759770b71bdabe27b6"}, + {file = "ruff-0.1.13-py3-none-win32.whl", hash = "sha256:a623349a505ff768dad6bd57087e2461be8db58305ebd5577bd0e98631f9ae69"}, + {file = "ruff-0.1.13-py3-none-win_amd64.whl", hash = "sha256:f988746e3c3982bea7f824c8fa318ce7f538c4dfefec99cd09c8770bd33e6539"}, + {file = "ruff-0.1.13-py3-none-win_arm64.whl", hash = "sha256:6bbbc3042075871ec17f28864808540a26f0f79a4478c357d3e3d2284e832998"}, + {file = "ruff-0.1.13.tar.gz", hash = "sha256:e261f1baed6291f434ffb1d5c6bd8051d1c2a26958072d38dfbec39b3dda7352"}, +] + [[package]] name = "ruyaml" version = "0.91.0" @@ -1854,17 +1659,6 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -[[package]] -name = "tomlkit" -version = "0.12.1" -description = "Style preserving TOML library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, - {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, -] - [[package]] name = "typing-extensions" version = "4.7.0" @@ -1948,4 +1742,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "ff59bf3390898baf789d7d11a7362d801036ceea4be58d036c46384f732fc9b2" +content-hash = "f5e7cd4adf97e9545e5412f5485bbf6ca9c90bbe18aadf349171ea73205f684d" diff --git a/pyproject.toml b/pyproject.toml index 51b899873e..c699bd1b8e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,11 +50,7 @@ drf-spectacular = {version = "^0.27.0", extras = ["sidecar"]} optional = true [tool.poetry.group.lint.dependencies] -autoflake = "^2.2.0" -black = "^23.3.0" -flake8 = "^6.0.0" -isort = "^5.12.0" -pylint = "^3.0.0" +ruff = "^0.1.13" [tool.poetry.group.unittests] optional = true @@ -78,27 +74,46 @@ django-silk = "^5.0.4" requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" -[tool.black] +[tool.ruff] line-length = 120 - -[tool.isort] -profile = "black" -skip_glob = ["python/ansible/plugins"] -skip = ["python/init_db.py", "python/task_runner.py", "python/backupdb.py", "python/job_runner.py", - "python/drf_docs.py"] - -[tool.pylint.master] -ignore = ["migrations"] -enable = ["useless-suppression"] -fail-on = ["useless-suppression"] - -[tool.pylint."messages control"] -disable = ["missing-docstring", "missing-timeout", "no-else-return", "no-member", "too-few-public-methods", - "too-many-arguments", "too-many-ancestors"] -good-names = ["db", "e", "f", "i", "pk"] - -[tool.pylint.format] -max-line-length = 120 - -[tool.pylint.similarities] -min-similarity-lines = 30 +exclude = ["python/cm/migrations/*", "python/audit/migrations/*", "python/rbac/migrations/*"] + +[tool.ruff.format] +exclude = ["python/cm/migrations/*", "python/audit/migrations/*", "python/rbac/migrations/*"] + +[tool.ruff.lint.isort] +force-sort-within-sections = true +length-sort-straight = true +order-by-type = true + +[tool.ruff.lint] +ignore = [ + "E402", + "SIM117", + "A003", + "ANN001", "ANN201","ANN101", "ANN102", "ANN401", "ANN002", "ANN003", "ANN202", "ANN204", "ANN205", "ANN206", + "COM812", + "ARG005", + "S105", + "TRY003", "TRY201", "TRY301", "TRY300", + "S106", + "RET503", "RET505", + "FBT001", "FBT002", "FBT003", + "PIE800", + "PTH103", "PTH107", "PTH110", "PTH112", "PTH118", "PTH119", "PTH120","PTH123", + "S107" +] +select = [ + # Pyflakes + "F", + # Pycodestyle + "E", "W", + # isort + "I", + # "COM" - The following rules may cause conflicts when used with the formatter: `COM812`. + # To avoid unexpected behavior, we recommend disabling these rules + "N", "UP", "YTT", "ANN", + "S", "BLE", "FBT", "B", "COM", "A", "C4", + "DTZ", "ICN", "PIE", "Q", "RET", + "SIM", "ARG", "PTH", "PLE", "TRY" +] diff --git a/python/adcm/settings.py b/python/adcm/settings.py index b023af25c3..6fb15e3888 100644 --- a/python/adcm/settings.py +++ b/python/adcm/settings.py @@ -10,12 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json -import logging +from pathlib import Path import os -import string import sys -from pathlib import Path +import json +import string +import logging from cm.utils import dict_json_get_or_create, get_adcm_token from django.core.management.utils import get_random_secret_key @@ -24,10 +24,7 @@ API_URL = "http://localhost:8020/api/v1/" BASE_DIR = os.getenv("ADCM_BASE_DIR") -if BASE_DIR: - BASE_DIR = Path(BASE_DIR) -else: - BASE_DIR = Path(__file__).absolute().parent.parent.parent +BASE_DIR = Path(BASE_DIR) if BASE_DIR else Path(__file__).absolute().parent.parent.parent STACK_DIR = os.getenv("ADCM_STACK_DIR", BASE_DIR) BUNDLE_DIR = STACK_DIR / "data" / "bundle" diff --git a/python/adcm/tests/base.py b/python/adcm/tests/base.py index 13bb901976..cbc8a30194 100644 --- a/python/adcm/tests/base.py +++ b/python/adcm/tests/base.py @@ -10,14 +10,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -import random -import string -import tarfile from contextlib import contextmanager from pathlib import Path from shutil import rmtree from tempfile import mkdtemp from typing import TypedDict +import random +import string +import tarfile from api_v2.prototype.utils import accept_license from api_v2.service.utils import bulk_add_services_to_cluster @@ -91,8 +91,6 @@ def _prepare_temporal_directories_for_adcm() -> dict: class BaseTestCase(TestCase, ParallelReadyTestCase): - # pylint: disable=too-many-instance-attributes,too-many-public-methods - def setUp(self) -> None: self.test_user_username = "test_user" self.test_user_password = "test_user_password" diff --git a/python/adcm/urls.py b/python/adcm/urls.py index fdd9d27446..8f6ccf7a23 100644 --- a/python/adcm/urls.py +++ b/python/adcm/urls.py @@ -21,6 +21,5 @@ path("api/ui/", include("api_ui.urls")), ] -# pylint: disable=invalid-name handler500 = "adcm.views.server_error" handler404 = "adcm.views.page_not_found" diff --git a/python/adcm/utils.py b/python/adcm/utils.py index 415080d3d9..bad20a3566 100644 --- a/python/adcm/utils.py +++ b/python/adcm/utils.py @@ -45,6 +45,18 @@ HTTP_409_CONFLICT, ) +OBJECT_TYPES_DICT = { + "adcm": "adcm", + "cluster": "cluster", + "service": "clusterobject", + "cluster object": "service", + "component": "servicecomponent", + "service component": "servicecomponent", + "provider": "hostprovider", + "host provider": "hostprovider", + "host": "host", +} + def _change_mm_via_action( prototype: Prototype, @@ -113,14 +125,14 @@ def process_requires( def get_obj_type(obj_type: str) -> str: - if obj_type == "cluster object": - return "service" - elif obj_type == "service component": - return "component" - elif obj_type == "host provider": - return "provider" - - return obj_type + object_names_to_object_types = { + "adcm": "adcm", + "cluster": "cluster", + "cluster object": "service", + "service component": "component", + "host provider": "provider", + } + return object_names_to_object_types[obj_type] def str_remove_non_alnum(value: str) -> str: @@ -212,8 +224,6 @@ def get_maintenance_mode_response( obj: Host | ClusterObject | ServiceComponent, serializer: Serializer, ) -> Response: - # pylint: disable=too-many-branches, too-many-return-statements - turn_on_action_name = settings.ADCM_TURN_ON_MM_ACTION_NAME turn_off_action_name = settings.ADCM_TURN_OFF_MM_ACTION_NAME prototype = obj.prototype @@ -320,7 +330,7 @@ def get_maintenance_mode_response( ) -def delete_service_from_api(service: ClusterObject) -> Response: # pylint: disable=too-many-branches +def delete_service_from_api(service: ClusterObject) -> Response: delete_action = Action.objects.filter( prototype=service.prototype, name=settings.ADCM_DELETE_SERVICE_ACTION_NAME, diff --git a/python/adcm/views.py b/python/adcm/views.py index e41b78665d..3b63e41f90 100644 --- a/python/adcm/views.py +++ b/python/adcm/views.py @@ -15,7 +15,7 @@ from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_500_INTERNAL_SERVER_ERROR -def server_error(request: HttpRequest, *args, **kwargs) -> JsonResponse: # pylint: disable=unused-argument +def server_error(request: HttpRequest, *args, **kwargs) -> JsonResponse: # noqa: ARG001 data = { "code": HTTP_500_INTERNAL_SERVER_ERROR, "level": "error", @@ -24,7 +24,7 @@ def server_error(request: HttpRequest, *args, **kwargs) -> JsonResponse: # pyli return JsonResponse(data=data, status=HTTP_500_INTERNAL_SERVER_ERROR) -def page_not_found(request: HttpRequest, *args, **kwargs) -> JsonResponse: # pylint: disable=unused-argument +def page_not_found(request: HttpRequest, *args, **kwargs) -> JsonResponse: # noqa: ARG001 data = { "code": HTTP_404_NOT_FOUND, "level": "error", diff --git a/python/ansible/plugins/action/adcm_add_host.py b/python/ansible/plugins/action/adcm_add_host.py index ffc5308eea..853abcf694 100644 --- a/python/ansible/plugins/action/adcm_add_host.py +++ b/python/ansible/plugins/action/adcm_add_host.py @@ -10,11 +10,7 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Arenadata"} @@ -51,11 +47,10 @@ import sys from ansible.errors import AnsibleError - from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401, isort:skip from cm.ansible_plugin import get_object_id_from_context from cm.api import add_host from cm.errors import AdcmEx diff --git a/python/ansible/plugins/action/adcm_add_host_to_cluster.py b/python/ansible/plugins/action/adcm_add_host_to_cluster.py index ff9b679dfb..68e623245f 100644 --- a/python/ansible/plugins/action/adcm_add_host_to_cluster.py +++ b/python/ansible/plugins/action/adcm_add_host_to_cluster.py @@ -10,11 +10,6 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position - -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Arenadata"} @@ -49,15 +44,16 @@ import sys from ansible.errors import AnsibleError - from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import -import cm.api + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import get_object_id_from_context from cm.errors import AdcmEx from cm.logger import logger +import cm.api class ActionModule(ActionBase): diff --git a/python/ansible/plugins/action/adcm_change_flag.py b/python/ansible/plugins/action/adcm_change_flag.py index 3ef64085d9..b3d92448ab 100644 --- a/python/ansible/plugins/action/adcm_change_flag.py +++ b/python/ansible/plugins/action/adcm_change_flag.py @@ -9,7 +9,6 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position DOCUMENTATION = """ --- module: adcm_change_flag @@ -24,11 +23,15 @@ - up - down msg: - description: Additional flag message, to use in pattern " has an outdated configuration: ". It might be used if you want several different flags in the same objects. In case of down operation, if message specified then down only flag with specified message. + description: Additional flag message, to use in pattern " has an outdated configuration: ". + It might be used if you want several different flags in the same objects. In case of down operation, + if message specified then down only flag with specified message. required: False type: string objects: - description: List of Services or Components on which you need to raise/lower the flag. If this parameter not specified raise or lower flag on action context object. If you want to raise or lower flag on cluster you needed action in cluster context. + description: List of Services or Components on which you need to raise/lower the flag. + If this parameter not specified raise or lower flag on action context object. + If you want to raise or lower flag on cluster you needed action in cluster context. required: False type: list elements: dict @@ -38,7 +41,7 @@ - type: component service_name: service component_name: component - - type: cluster + - type: cluster """ EXAMPLES = r""" @@ -50,7 +53,7 @@ - type: component service_name: service component_name: component - - type: cluster + - type: cluster - adcm_change_flag: operation: down @@ -65,7 +68,8 @@ from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import + +import adcm.init_django # noqa: F401, isort:skip from cm.ansible_plugin import check_context_type, get_context_object from cm.flag import remove_flag, update_object_flag diff --git a/python/ansible/plugins/action/adcm_change_maintenance_mode.py b/python/ansible/plugins/action/adcm_change_maintenance_mode.py index 38dad262e7..2ba904c161 100644 --- a/python/ansible/plugins/action/adcm_change_maintenance_mode.py +++ b/python/ansible/plugins/action/adcm_change_maintenance_mode.py @@ -9,13 +9,12 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position DOCUMENTATION = """ --- module: adcm_change_maintenance_mode short_description: Change Host, Service or Component maintenance mode to ON or OFF description: - - The C(adcm_change_maintenance_mode) module is intended to + - The C(adcm_change_maintenance_mode) module is intended to change Host, Service or Component maintenance mode to ON or OFF. options: type: @@ -28,7 +27,7 @@ value: description: Maintenance mode value True or False. required: True - type: bool + type: bool """ EXAMPLES = r""" @@ -36,7 +35,7 @@ adcm_change_maintenance_mode: type: host value: True - + - name: Change service maintenance mode to False adcm_change_maintenance_mode: type: service @@ -46,17 +45,17 @@ import sys from ansible.errors import AnsibleActionFail - from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import get_object_id_from_context from cm.api import load_mm_objects -from cm.status_api import send_object_update_event from cm.issue import update_hierarchy_issues from cm.models import ClusterObject, Host, ServiceComponent +from cm.status_api import send_object_update_event class ActionModule(ActionBase): diff --git a/python/ansible/plugins/action/adcm_check.py b/python/ansible/plugins/action/adcm_check.py index a5067f476b..aed05ac31d 100644 --- a/python/ansible/plugins/action/adcm_check.py +++ b/python/ansible/plugins/action/adcm_check.py @@ -10,11 +10,7 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Arenadata"} @@ -100,7 +96,9 @@ from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import create_checklog_object from cm.errors import AdcmEx from cm.logger import logger @@ -121,7 +119,7 @@ class ActionModule(ActionBase): ) ) - def run(self, tmp=None, task_vars=None): # pylint: disable=too-many-locals + def run(self, tmp=None, task_vars=None): super().run(tmp, task_vars) job_id = None if task_vars is not None and "job" in task_vars or "id" in task_vars["job"]: @@ -148,10 +146,7 @@ def run(self, tmp=None, task_vars=None): # pylint: disable=too-many-locals group_fail_msg = self._task.args.get("group_fail_msg", "") group_success_msg = self._task.args.get("group_success_msg", "") - if result: - msg = success_msg if success_msg else msg - else: - msg = fail_msg if fail_msg else msg + msg = (success_msg if success_msg else msg) if result else fail_msg if fail_msg else msg group = {"title": group_title, "success_msg": group_success_msg, "fail_msg": group_fail_msg} diff --git a/python/ansible/plugins/action/adcm_config.py b/python/ansible/plugins/action/adcm_config.py index 90c28e2fdf..7eca12452e 100644 --- a/python/ansible/plugins/action/adcm_config.py +++ b/python/ansible/plugins/action/adcm_config.py @@ -9,18 +9,16 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name import sys from ansible.errors import AnsibleError sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import ( ContextActionModule, set_cluster_config, @@ -38,7 +36,8 @@ module: adcm_config short_description: Change values in config in runtime description: - - This is special ADCM only module which is useful for setting of specified config key or set of config keys for various ADCM objects. + - This is special ADCM only module which is useful for setting of specified config key + or set of config keys for various ADCM objects. - There is support of cluster, service, host and providers config. - This one is allowed to be used in various execution contexts. options: @@ -68,7 +67,8 @@ - option-name: service_name required: false type: string - description: useful in cluster context only. In that context you are able to set a config value for a service belongs to the cluster. + description: useful in cluster context only. + In that context you are able to set a config value for a service belongs to the cluster. notes: - If type is 'service', there is no needs to specify service_name @@ -181,7 +181,7 @@ def _get_attr(self, is_params: bool) -> dict: return attr - def _do_cluster(self, task_vars, context): + def _do_cluster(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_cluster_config, context["cluster_id"], @@ -192,7 +192,7 @@ def _do_cluster(self, task_vars, context): return res - def _do_service_by_name(self, task_vars, context): + def _do_service_by_name(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_service_config_by_name, context["cluster_id"], @@ -204,7 +204,7 @@ def _do_service_by_name(self, task_vars, context): return res - def _do_service(self, task_vars, context): + def _do_service(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_service_config, context["cluster_id"], @@ -216,7 +216,7 @@ def _do_service(self, task_vars, context): return res - def _do_host(self, task_vars, context): + def _do_host(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_host_config, context["host_id"], @@ -227,7 +227,7 @@ def _do_host(self, task_vars, context): return res - def _do_host_from_provider(self, task_vars, context): + def _do_host_from_provider(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_host_config, self._task.args["host_id"], @@ -238,7 +238,7 @@ def _do_host_from_provider(self, task_vars, context): return res - def _do_provider(self, task_vars, context): + def _do_provider(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_provider_config, context["provider_id"], @@ -249,7 +249,7 @@ def _do_provider(self, task_vars, context): return res - def _do_component_by_name(self, task_vars, context): + def _do_component_by_name(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_component_config_by_name, context["cluster_id"], @@ -263,7 +263,7 @@ def _do_component_by_name(self, task_vars, context): return res - def _do_component(self, task_vars, context): + def _do_component(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_component_config, context["component_id"], diff --git a/python/ansible/plugins/action/adcm_custom_log.py b/python/ansible/plugins/action/adcm_custom_log.py index f873cbdefa..658511bb33 100644 --- a/python/ansible/plugins/action/adcm_custom_log.py +++ b/python/ansible/plugins/action/adcm_custom_log.py @@ -10,11 +10,7 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name ANSIBLE_METADATA = {"metadata_version": "1.0", "supported_by": "Arenadata"} @@ -61,17 +57,18 @@ RETURN = r""" """ -import base64 -import sys from binascii import Error +import sys +import base64 from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import -from cm.errors import AdcmEx +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import create_custom_log +from cm.errors import AdcmEx from cm.logger import logger diff --git a/python/ansible/plugins/action/adcm_delete_host.py b/python/ansible/plugins/action/adcm_delete_host.py index caee3a8b18..e3e16488ab 100644 --- a/python/ansible/plugins/action/adcm_delete_host.py +++ b/python/ansible/plugins/action/adcm_delete_host.py @@ -10,11 +10,7 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Arenadata"} @@ -39,15 +35,16 @@ import sys from ansible.errors import AnsibleError - from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import -import cm.api + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import get_object_id_from_context from cm.errors import AdcmEx from cm.logger import logger +import cm.api class ActionModule(ActionBase): diff --git a/python/ansible/plugins/action/adcm_delete_service.py b/python/ansible/plugins/action/adcm_delete_service.py index a5e1ef78e8..57c1b6a9fb 100644 --- a/python/ansible/plugins/action/adcm_delete_service.py +++ b/python/ansible/plugins/action/adcm_delete_service.py @@ -10,11 +10,7 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Arenadata"} @@ -39,15 +35,16 @@ import sys from ansible.errors import AnsibleError - from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import -import cm.api + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import get_object_id_from_context from cm.errors import AdcmEx from cm.logger import logger +import cm.api class ActionModule(ActionBase): diff --git a/python/ansible/plugins/action/adcm_hc.py b/python/ansible/plugins/action/adcm_hc.py index 8a2ca2671d..9c1dd21242 100644 --- a/python/ansible/plugins/action/adcm_hc.py +++ b/python/ansible/plugins/action/adcm_hc.py @@ -10,11 +10,7 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Arenadata"} @@ -51,11 +47,12 @@ import sys from ansible.errors import AnsibleError - from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import change_hc, get_object_id_from_context from cm.errors import AdcmEx from cm.logger import logger diff --git a/python/ansible/plugins/action/adcm_multi_state_set.py b/python/ansible/plugins/action/adcm_multi_state_set.py index 8ad0d1ba18..21a8a7cc37 100644 --- a/python/ansible/plugins/action/adcm_multi_state_set.py +++ b/python/ansible/plugins/action/adcm_multi_state_set.py @@ -9,16 +9,14 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name import sys sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import ( ContextActionModule, set_cluster_multi_state, @@ -59,12 +57,14 @@ - option-name: service_name required: false type: string - description: useful in cluster and component context only. In that context you are able to set the state value for a service belongs to the cluster. + description: useful in cluster and component context only. + In that context you are able to set the state value for a service belongs to the cluster. - option-name: component_name required: false type: string - description: useful in cluster and component context only. In that context you are able to set the state for a component belongs to the service + description: useful in cluster and component context only. + In that context you are able to set the state for a component belongs to the service """ EXAMPLES = r""" @@ -102,12 +102,12 @@ class ActionModule(ContextActionModule): _VALID_ARGS = frozenset(("type", "service_name", "component_name", "state", "host_id")) _MANDATORY_ARGS = ("type", "state") - def _do_cluster(self, task_vars, context): + def _do_cluster(self, task_vars, context): # noqa: ARG002 res = self._wrap_call(set_cluster_multi_state, context["cluster_id"], self._task.args["state"]) res["state"] = self._task.args["state"] return res - def _do_service_by_name(self, task_vars, context): + def _do_service_by_name(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_service_multi_state_by_name, context["cluster_id"], @@ -117,7 +117,7 @@ def _do_service_by_name(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_service(self, task_vars, context): + def _do_service(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_service_multi_state, context["cluster_id"], @@ -127,7 +127,7 @@ def _do_service(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_host(self, task_vars, context): + def _do_host(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_host_multi_state, context["host_id"], @@ -136,12 +136,12 @@ def _do_host(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_provider(self, task_vars, context): + def _do_provider(self, task_vars, context): # noqa: ARG002 res = self._wrap_call(set_provider_multi_state, context["provider_id"], self._task.args["state"]) res["state"] = self._task.args["state"] return res - def _do_host_from_provider(self, task_vars, context): + def _do_host_from_provider(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_host_multi_state, self._task.args["host_id"], @@ -150,7 +150,7 @@ def _do_host_from_provider(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_component_by_name(self, task_vars, context): + def _do_component_by_name(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_component_multi_state_by_name, context["cluster_id"], @@ -162,7 +162,7 @@ def _do_component_by_name(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_component(self, task_vars, context): + def _do_component(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_component_multi_state, context["component_id"], diff --git a/python/ansible/plugins/action/adcm_multi_state_unset.py b/python/ansible/plugins/action/adcm_multi_state_unset.py index 7d39e001a2..cde0381493 100644 --- a/python/ansible/plugins/action/adcm_multi_state_unset.py +++ b/python/ansible/plugins/action/adcm_multi_state_unset.py @@ -9,16 +9,14 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name import sys sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import ( ContextActionModule, unset_cluster_multi_state, @@ -59,12 +57,14 @@ - option-name: service_name required: false type: string - description: useful in cluster and component context only. In that context you are able to set the state value for a service belongs to the cluster. + description: useful in cluster and component context only. + In that context you are able to set the state value for a service belongs to the cluster. - option-name: component_name required: false type: string - description: useful in cluster and component context only. In that context you are able to set the state for a component belongs to the service + description: useful in cluster and component context only. + In that context you are able to set the state for a component belongs to the service - option-name: missing_ok required: false @@ -109,7 +109,7 @@ class ActionModule(ContextActionModule): _VALID_ARGS = frozenset(("type", "service_name", "component_name", "state", "missing_ok", "host_id")) _MANDATORY_ARGS = ("type", "state") - def _do_cluster(self, task_vars, context): + def _do_cluster(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( unset_cluster_multi_state, context["cluster_id"], @@ -119,7 +119,7 @@ def _do_cluster(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_service_by_name(self, task_vars, context): + def _do_service_by_name(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( unset_service_multi_state_by_name, context["cluster_id"], @@ -130,7 +130,7 @@ def _do_service_by_name(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_service(self, task_vars, context): + def _do_service(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( unset_service_multi_state, context["cluster_id"], @@ -141,7 +141,7 @@ def _do_service(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_host(self, task_vars, context): + def _do_host(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( unset_host_multi_state, context["host_id"], @@ -151,7 +151,7 @@ def _do_host(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_provider(self, task_vars, context): + def _do_provider(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( unset_provider_multi_state, context["provider_id"], @@ -161,7 +161,7 @@ def _do_provider(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_host_from_provider(self, task_vars, context): + def _do_host_from_provider(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( unset_host_multi_state, self._task.args["host_id"], @@ -171,7 +171,7 @@ def _do_host_from_provider(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_component_by_name(self, task_vars, context): + def _do_component_by_name(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( unset_component_multi_state_by_name, context["cluster_id"], @@ -184,7 +184,7 @@ def _do_component_by_name(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_component(self, task_vars, context): + def _do_component(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( unset_component_multi_state, context["component_id"], diff --git a/python/ansible/plugins/action/adcm_remove_host_from_cluster.py b/python/ansible/plugins/action/adcm_remove_host_from_cluster.py index 51691cc148..dbfe661e42 100644 --- a/python/ansible/plugins/action/adcm_remove_host_from_cluster.py +++ b/python/ansible/plugins/action/adcm_remove_host_from_cluster.py @@ -10,11 +10,7 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Arenadata"} @@ -49,15 +45,16 @@ import sys from ansible.errors import AnsibleError - from ansible.plugins.action import ActionBase sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import -import cm.api + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import get_object_id_from_context from cm.errors import AdcmEx from cm.logger import logger +import cm.api class ActionModule(ActionBase): diff --git a/python/ansible/plugins/action/adcm_state.py b/python/ansible/plugins/action/adcm_state.py index e79c4ddb4d..a9708d2e0d 100644 --- a/python/ansible/plugins/action/adcm_state.py +++ b/python/ansible/plugins/action/adcm_state.py @@ -9,16 +9,14 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from __future__ import absolute_import, division, print_function - -__metaclass__ = type # pylint: disable=invalid-name import sys sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import ( ContextActionModule, set_cluster_state, @@ -58,7 +56,8 @@ - option-name: service_name required: false type: string - description: useful in cluster context only. In that context you are able to set the state value for a service belongs to the cluster. + description: useful in cluster context only. + In that context you are able to set the state value for a service belongs to the cluster. notes: - If type is 'service', there is no needs to specify service_name @@ -88,12 +87,12 @@ class ActionModule(ContextActionModule): _VALID_ARGS = frozenset(("type", "service_name", "component_name", "state", "host_id")) _MANDATORY_ARGS = ("type", "state") - def _do_cluster(self, task_vars, context): + def _do_cluster(self, task_vars, context): # noqa: ARG002 res = self._wrap_call(set_cluster_state, context["cluster_id"], self._task.args["state"]) res["state"] = self._task.args["state"] return res - def _do_service_by_name(self, task_vars, context): + def _do_service_by_name(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_service_state_by_name, context["cluster_id"], @@ -103,7 +102,7 @@ def _do_service_by_name(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_service(self, task_vars, context): + def _do_service(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_service_state, context["cluster_id"], @@ -113,7 +112,7 @@ def _do_service(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_host(self, task_vars, context): + def _do_host(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_host_state, context["host_id"], @@ -122,7 +121,7 @@ def _do_host(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_host_from_provider(self, task_vars, context): + def _do_host_from_provider(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_host_state, self._task.args["host_id"], @@ -131,12 +130,12 @@ def _do_host_from_provider(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_provider(self, task_vars, context): + def _do_provider(self, task_vars, context): # noqa: ARG002 res = self._wrap_call(set_provider_state, context["provider_id"], self._task.args["state"]) res["state"] = self._task.args["state"] return res - def _do_component_by_name(self, task_vars, context): + def _do_component_by_name(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_component_state_by_name, context["cluster_id"], @@ -148,7 +147,7 @@ def _do_component_by_name(self, task_vars, context): res["state"] = self._task.args["state"] return res - def _do_component(self, task_vars, context): + def _do_component(self, task_vars, context): # noqa: ARG002 res = self._wrap_call( set_component_state, context["component_id"], diff --git a/python/ansible/plugins/lookup/adcm_config.py b/python/ansible/plugins/lookup/adcm_config.py index 63a3407112..0a9db527f4 100644 --- a/python/ansible/plugins/lookup/adcm_config.py +++ b/python/ansible/plugins/lookup/adcm_config.py @@ -9,7 +9,6 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position import sys @@ -18,7 +17,8 @@ sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import ( set_cluster_config, set_host_config, @@ -62,7 +62,7 @@ class LookupModule(LookupBase): - def run(self, terms, variables=None, **kwargs): # pylint: disable=too-many-branches + def run(self, terms, variables=None, **kwargs): logger.debug("run %s %s", terms, kwargs) ret = [] diff --git a/python/ansible/plugins/lookup/adcm_state.py b/python/ansible/plugins/lookup/adcm_state.py index 0209945220..fada3a2a03 100644 --- a/python/ansible/plugins/lookup/adcm_state.py +++ b/python/ansible/plugins/lookup/adcm_state.py @@ -9,16 +9,16 @@ # 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. -# pylint: disable=wrong-import-order,wrong-import-position -from ansible.errors import AnsibleError +import sys +from ansible.errors import AnsibleError from ansible.plugins.lookup import LookupBase -import sys - sys.path.append("/adcm/python") -import adcm.init_django # pylint: disable=unused-import + +import adcm.init_django # noqa: F401, isort:skip + from cm.ansible_plugin import ( set_cluster_state, set_host_state, @@ -62,7 +62,7 @@ class LookupModule(LookupBase): - def run(self, terms, variables=None, **kwargs): # pylint: disable=too-many-branches + def run(self, terms, variables=None, **kwargs): logger.debug("run %s %s", terms, kwargs) ret = [] if len(terms) < 2: diff --git a/python/ansible_secret.py b/python/ansible_secret.py index b8fab8341b..8ef44521d5 100755 --- a/python/ansible_secret.py +++ b/python/ansible_secret.py @@ -11,9 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import adcm.init_django # noqa: F401, isort:skip from django.conf import settings -import adcm.init_django # pylint: disable=unused-import - if __name__ == "__main__": print(settings.ANSIBLE_SECRET) diff --git a/python/api/action/serializers.py b/python/api/action/serializers.py index 6a4c187fb7..7c707dfc66 100644 --- a/python/api/action/serializers.py +++ b/python/api/action/serializers.py @@ -10,8 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.config.serializers import ConfigSerializerUI -from api.utils import get_api_url_kwargs +from adcm.serializers import EmptySerializer from cm.adcm_config.config import get_action_variant, get_prototype_config from cm.models import Action, PrototypeConfig, SubAction from jinja_config import get_jinja_config @@ -26,7 +25,8 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer +from api.config.serializers import ConfigSerializerUI +from api.utils import get_api_url_kwargs class ActionJobSerializer(HyperlinkedModelSerializer): diff --git a/python/api/action/urls.py b/python/api/action/urls.py index 958b126f16..698d5e1171 100644 --- a/python/api/action/urls.py +++ b/python/api/action/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.action.views import ActionDetail, ActionList, RunTask from django.urls import path +from api.action.views import ActionDetail, ActionList, RunTask + urlpatterns = [ path("", ActionList.as_view(), name="object-action"), path("/", ActionDetail.as_view(), name="object-action-details"), diff --git a/python/api/action/views.py b/python/api/action/views.py index a33759a255..a8fc72abcf 100644 --- a/python/api/action/views.py +++ b/python/api/action/views.py @@ -10,17 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -import hashlib from itertools import compress +import hashlib -from api.action.serializers import ( - ActionDetailSerializer, - ActionSerializer, - ActionUISerializer, -) -from api.base_view import GenericUIView -from api.job.serializers import RunTaskRetrieveSerializer -from api.utils import AdcmFilterBackend, create +from adcm.permissions import VIEW_ACTION_PERM, get_object_for_user from audit.utils import audit from cm.errors import AdcmEx from cm.models import ( @@ -42,7 +35,14 @@ from rest_framework.request import Request from rest_framework.response import Response -from adcm.permissions import VIEW_ACTION_PERM, get_object_for_user +from api.action.serializers import ( + ActionDetailSerializer, + ActionSerializer, + ActionUISerializer, +) +from api.base_view import GenericUIView +from api.job.serializers import RunTaskRetrieveSerializer +from api.utils import AdcmFilterBackend, create def get_object_type_id(**kwargs) -> tuple[str, int, int]: @@ -73,7 +73,7 @@ class ActionList(PermissionListMixin, GenericUIView): filter_backends = (AdcmFilterBackend,) permission_required = [VIEW_ACTION_PERM] - def get(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def get(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 obj, _ = get_obj(**kwargs) if obj.concerns.filter(type=ConcernType.LOCK).exists(): @@ -130,7 +130,7 @@ class ActionDetail(PermissionListMixin, GenericUIView): permission_classes = (DjangoOnlyObjectPermissions,) permission_required = [VIEW_ACTION_PERM] - def get(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def get(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 object_type, object_id, action_id = get_object_type_id(**kwargs) model = get_model_by_type(object_type) content_type = ContentType.objects.get_for_model(model) @@ -146,10 +146,7 @@ def get(self, request: Request, *args, **kwargs) -> Response: # pylint: disable self.get_queryset(), id=action_id, ) - if isinstance(obj, Host) and action.host_action: - objects = {"host": obj} - else: - objects = {action.prototype.type: obj} + objects = {"host": obj} if isinstance(obj, Host) and action.host_action else {action.prototype.type: obj} serializer = self.get_serializer(action, context={"request": request, "objects": objects, "obj": obj}) @@ -177,7 +174,7 @@ def check_action_perm(self, action: Action, obj) -> None: raise PermissionDenied() @audit - def post(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def post(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 object_type, object_id, action_id = get_object_type_id(**kwargs) model = get_model_by_type(object_type) content_type = ContentType.objects.get_for_model(model) diff --git a/python/api/adcm/serializers.py b/python/api/adcm/serializers.py index 8b0fef30b9..6c0a696a3c 100644 --- a/python/api/adcm/serializers.py +++ b/python/api/adcm/serializers.py @@ -10,8 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.concern.serializers import ConcernItemSerializer -from api.serializers import StringListSerializer from cm.adcm_config.config import get_main_info from cm.models import ADCM from rest_framework.serializers import ( @@ -21,6 +19,9 @@ SerializerMethodField, ) +from api.concern.serializers import ConcernItemSerializer +from api.serializers import StringListSerializer + class ADCMSerializer(HyperlinkedModelSerializer): class Meta: diff --git a/python/api/adcm/urls.py b/python/api/adcm/urls.py index a41910b281..fa8684cdc4 100644 --- a/python/api/adcm/urls.py +++ b/python/api/adcm/urls.py @@ -10,10 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.adcm.views import ADCMViewSet from django.urls import include, path from rest_framework.routers import SimpleRouter +from api.adcm.views import ADCMViewSet + router = SimpleRouter() router.register("", ADCMViewSet) diff --git a/python/api/adcm/views.py b/python/api/adcm/views.py index 206f086d49..37d49b3c11 100644 --- a/python/api/adcm/views.py +++ b/python/api/adcm/views.py @@ -10,14 +10,15 @@ # See the License for the specific language governing permissions and # limitations under the License. +from cm.models import ADCM +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin + from api.adcm.serializers import ( ADCMRetrieveSerializer, ADCMSerializer, ADCMUISerializer, ) from api.base_view import GenericUIViewSet -from cm.models import ADCM -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin class ADCMViewSet(ListModelMixin, RetrieveModelMixin, GenericUIViewSet): diff --git a/python/api/base_view.py b/python/api/base_view.py index c1034e9f74..e07ab04f95 100644 --- a/python/api/base_view.py +++ b/python/api/base_view.py @@ -10,8 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import rest_framework.pagination -from api.utils import AdcmFilterBackend, AdcmOrderingFilter, getlist_from_querydict +from adcm.permissions import DjangoObjectPermissionsAudit from audit.utils import audit from cm.errors import AdcmEx from django.conf import settings @@ -23,8 +22,9 @@ from rest_framework.schemas.coreapi import AutoSchema from rest_framework.utils.urls import replace_query_param from rest_framework.viewsets import ViewSetMixin +import rest_framework.pagination -from adcm.permissions import DjangoObjectPermissionsAudit +from api.utils import AdcmFilterBackend, AdcmOrderingFilter, getlist_from_querydict class ModelPermOrReadOnlyForAuth(DjangoModelPermissions): @@ -64,18 +64,14 @@ def _is_for_ui(self) -> bool: def get_serializer_class(self): if self.request is not None: - if self.request.method == "POST": - if self.serializer_class_post: - return self.serializer_class_post - elif self.request.method == "PUT": - if self.serializer_class_put: - return self.serializer_class_put - elif self.request.method == "PATCH": - if self.serializer_class_patch: - return self.serializer_class_patch - elif self._is_for_ui(): - if self.serializer_class_ui: - return self.serializer_class_ui + if self.request.method == "POST" and self.serializer_class_post: + return self.serializer_class_post + elif self.request.method == "PUT" and self.serializer_class_put: + return self.serializer_class_put + elif self.request.method == "PATCH" and self.serializer_class_patch: + return self.serializer_class_patch + elif self._is_for_ui() and self.serializer_class_ui: + return self.serializer_class_ui return super().get_serializer_class() @@ -105,7 +101,7 @@ class PaginatedView(GenericUIView): def get_ordering(request, queryset, view): return AdcmOrderingFilter().get_ordering(request, queryset, view) - def is_paged(self, request): # pylint: disable=unused-argument + def is_paged(self, request): # noqa: ARG001, ARG002 limit = self.request.query_params.get("limit", False) offset = self.request.query_params.get("offset", False) @@ -115,9 +111,7 @@ def get_paged_link(self): page = self.paginator url = self.request.build_absolute_uri() url = replace_query_param(url, page.limit_query_param, page.limit) - url = replace_query_param(url, page.offset_query_param, 0) - - return url + return replace_query_param(url, page.offset_query_param, 0) def get_page(self, obj, request, context=None): if not context: @@ -165,7 +159,7 @@ def get_page(self, obj, request, context=None): raise AdcmEx("TOO_LONG", msg=msg, args=self.get_paged_link()) - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 obj = self.filter_queryset(self.get_queryset()) return self.get_page(obj, request) @@ -193,7 +187,7 @@ def get_object(self): return obj - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 obj = self.get_object() serializer = self.get_serializer(obj) diff --git a/python/api/cluster/serializers.py b/python/api/cluster/serializers.py index 673ec67215..668b1e991f 100644 --- a/python/api/cluster/serializers.py +++ b/python/api/cluster/serializers.py @@ -10,13 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.action.serializers import ActionShort -from api.component.serializers import ComponentShortSerializer -from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer -from api.group_config.serializers import GroupConfigsHyperlinkedIdentityField -from api.host.serializers import HostSerializer -from api.serializers import DoUpgradeSerializer, StringListSerializer -from api.utils import CommonAPIURL, ObjectURL, UrlField, check_obj +from adcm.serializers import EmptySerializer +from adcm.utils import filter_actions, get_requires from cm.adcm_config.config import get_main_info from cm.api import add_cluster, add_hc, bind, multi_bind from cm.errors import AdcmEx @@ -40,8 +35,13 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer -from adcm.utils import filter_actions, get_requires +from api.action.serializers import ActionShort +from api.component.serializers import ComponentShortSerializer +from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer +from api.group_config.serializers import GroupConfigsHyperlinkedIdentityField +from api.host.serializers import HostSerializer +from api.serializers import DoUpgradeSerializer, StringListSerializer +from api.utils import CommonAPIURL, ObjectURL, UrlField, check_obj def get_cluster_id(obj): @@ -289,12 +289,12 @@ class HostComponentUISerializer(EmptySerializer): host = SerializerMethodField() component = SerializerMethodField() - def get_host(self, obj): # pylint: disable=unused-argument + def get_host(self, obj): # noqa: ARG001, ARG002 hosts = Host.objects.filter(cluster=self.context.get("cluster")) return HostSerializer(hosts, many=True, context=self.context).data - def get_component(self, obj): # pylint: disable=unused-argument + def get_component(self, obj): # noqa: ARG001, ARG002 comps = ServiceComponent.objects.filter(cluster=self.context.get("cluster")) return HCComponentSerializer(comps, many=True, context=self.context).data diff --git a/python/api/cluster/urls.py b/python/api/cluster/urls.py index 13d4abd14a..b4cab01004 100644 --- a/python/api/cluster/urls.py +++ b/python/api/cluster/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.cluster import views from django.urls import include, path +from api.cluster import views + # fmt: off urlpatterns = [ path("", views.ClusterList.as_view(), name="cluster"), diff --git a/python/api/cluster/views.py b/python/api/cluster/views.py index 2dfe3de3c0..513d966aee 100644 --- a/python/api/cluster/views.py +++ b/python/api/cluster/views.py @@ -12,30 +12,7 @@ from itertools import chain -from api.base_view import DetailView, GenericUIView, PaginatedView -from api.cluster.serializers import ( - BindSerializer, - ClusterBindSerializer, - ClusterDetailSerializer, - ClusterDetailUISerializer, - ClusterSerializer, - ClusterStatusSerializer, - ClusterUISerializer, - ClusterUpdateSerializer, - DoBindSerializer, - DoClusterUpgradeSerializer, - HostComponentSaveSerializer, - HostComponentSerializer, - HostComponentUISerializer, - PostImportSerializer, -) -from api.serializers import ClusterUpgradeSerializer -from api.stack.serializers import ( - BundleServiceUIPrototypeSerializer, - ImportSerializer, - ServicePrototypeSerializer, -) -from api.utils import AdcmOrderingFilter, check_obj, create, update +from adcm.permissions import VIEW_CLUSTER_PERM, check_custom_perm, get_object_for_user from audit.utils import audit from cm.api import delete_cluster, get_import, unbind from cm.errors import AdcmEx @@ -60,7 +37,30 @@ HTTP_400_BAD_REQUEST, ) -from adcm.permissions import VIEW_CLUSTER_PERM, check_custom_perm, get_object_for_user +from api.base_view import DetailView, GenericUIView, PaginatedView +from api.cluster.serializers import ( + BindSerializer, + ClusterBindSerializer, + ClusterDetailSerializer, + ClusterDetailUISerializer, + ClusterSerializer, + ClusterStatusSerializer, + ClusterUISerializer, + ClusterUpdateSerializer, + DoBindSerializer, + DoClusterUpgradeSerializer, + HostComponentSaveSerializer, + HostComponentSerializer, + HostComponentUISerializer, + PostImportSerializer, +) +from api.serializers import ClusterUpgradeSerializer +from api.stack.serializers import ( + BundleServiceUIPrototypeSerializer, + ImportSerializer, + ServicePrototypeSerializer, +) +from api.utils import AdcmOrderingFilter, check_obj, create, update def get_obj_conf(cluster_id, service_id): @@ -90,7 +90,7 @@ class ClusterList(PermissionListMixin, PaginatedView): ordering = ["id"] @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 serializer = self.get_serializer(data=request.data) return create(serializer) @@ -110,21 +110,21 @@ class ClusterDetail(PermissionListMixin, DetailView): ordering = ["id"] @audit - def patch(self, request, *args, **kwargs): # pylint: disable=unused-argument + def patch(self, request, *args, **kwargs): # noqa: ARG001, ARG002 obj = self.get_object() serializer = self.get_serializer(obj, data=request.data, partial=True) return update(serializer) @audit - def put(self, request, *args, **kwargs): # pylint: disable=unused-argument + def put(self, request, *args, **kwargs): # noqa: ARG001, ARG002 obj = self.get_object() serializer = self.get_serializer(obj, data=request.data, partial=False) return update(serializer) @audit - def delete(self, request, *args, **kwargs): # pylint: disable=unused-argument + def delete(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = self.get_object() delete_cluster(cluster) @@ -138,7 +138,7 @@ class ClusterBundle(GenericUIView): ordering_fields = ("id", "name", "display_name", "version") ordering = ["display_name"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) check_custom_perm(request.user, "add_service_to", "cluster", cluster) bundle = self.get_queryset().filter(bundle=cluster.prototype.bundle) @@ -160,7 +160,7 @@ class ClusterImport(GenericUIView): ordering = ["id"] @staticmethod - def get(request, *args, **kwargs): # pylint: disable=unused-argument + def get(request, *args, **kwargs): # noqa: ARG001, ARG002, ARG004 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) check_custom_perm(request.user, "view_import_of", "cluster", cluster, "view_clusterbind") res = get_import(cluster) @@ -168,7 +168,7 @@ def get(request, *args, **kwargs): # pylint: disable=unused-argument return Response(res) @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) check_custom_perm(request.user, "change_import_of", "cluster", cluster) serializer = self.get_serializer(data=request.data, context={"request": request, "cluster": cluster}) @@ -187,7 +187,7 @@ class ClusterBindList(GenericUIView): permission_classes = (IsAuthenticated,) ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) check_custom_perm(request.user, "view_import_of", "cluster", cluster, "view_clusterbind") obj = self.get_queryset().filter(cluster=cluster, service=None) @@ -196,7 +196,7 @@ def get(self, request, *args, **kwargs): # pylint: disable=unused-argument return Response(serializer.data) @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) check_custom_perm(request.user, "change_import_of", "cluster", cluster) serializer = self.get_serializer(data=request.data) @@ -211,14 +211,14 @@ class ClusterBindDetail(GenericUIView): ordering = ["id"] @staticmethod - def get_obj(kwargs, bind_id): # pylint: disable=unused-argument + def get_obj(kwargs, bind_id): # noqa: ARG001, ARG002, ARG004 bind = ClusterBind.objects.filter(pk=bind_id).first() if bind: return bind.source_service return None - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) bind = check_obj(ClusterBind, {"cluster": cluster, "id": kwargs["bind_id"]}) check_custom_perm(request.user, "view_import_of", "cluster", cluster, "view_clusterbind") @@ -227,7 +227,7 @@ def get(self, request, *args, **kwargs): # pylint: disable=unused-argument return Response(serializer.data) @audit - def delete(self, request, *args, **kwargs): # pylint: disable=unused-argument + def delete(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) bind = check_obj(ClusterBind, {"cluster": cluster, "id": kwargs["bind_id"]}) check_custom_perm(request.user, "change_import_of", "cluster", cluster) @@ -246,7 +246,7 @@ def get_ordering(self) -> list | None: order = AdcmOrderingFilter() return order.get_ordering(request=self.request, queryset=self.get_queryset(), view=self) - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user( user=request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=kwargs["cluster_id"] ) @@ -267,7 +267,7 @@ class ClusterUpgradeDetail(GenericUIView): permission_classes = (IsAuthenticated,) ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) check_custom_perm(request.user, "view_upgrade_of", "cluster", cluster) obj = check_obj(Upgrade, {"id": kwargs["upgrade_id"], "bundle__name": cluster.prototype.bundle.name}) @@ -283,7 +283,7 @@ class DoClusterUpgrade(GenericUIView): ordering = ["id"] @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) check_custom_perm(request.user, "do_upgrade_of", "cluster", cluster) serializer = self.get_serializer(data=request.data) @@ -311,7 +311,7 @@ class StatusList(GenericUIView): serializer_class = ClusterStatusSerializer ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) host_components = self.get_queryset().filter(cluster=cluster) if self._is_for_ui(): @@ -331,7 +331,7 @@ class HostComponentList(GenericUIView): ordering_fields = ("id",) ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) check_custom_perm(request.user, "view_host_components_of", "cluster", cluster, "view_hostcomponent") hostcomponent = self.filter_queryset( @@ -339,7 +339,7 @@ def get(self, request, *args, **kwargs): # pylint: disable=unused-argument ) if self._is_for_ui(): ui_hc = HostComponent() - setattr(ui_hc, "hc", hostcomponent) # because pylint disable invalid-name not working here somehow + ui_hc.hc = hostcomponent # because pylint disable invalid-name not working here somehow serializer = self.get_serializer(ui_hc, context={"request": request, "cluster": cluster}) else: serializer = self.get_serializer(hostcomponent, many=True) @@ -347,7 +347,7 @@ def get(self, request, *args, **kwargs): # pylint: disable=unused-argument return Response(serializer.data) @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) check_custom_perm(request.user, "edit_host_components_of", "cluster", cluster) serializer = self.get_serializer( @@ -378,7 +378,7 @@ def get_obj(self, cluster_id, hs_id): return check_obj(HostComponent, {"id": hs_id, "cluster": cluster}, "HOSTSERVICE_NOT_FOUND") - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 obj = self.get_obj(kwargs["cluster_id"], kwargs["hs_id"]) serializer = self.get_serializer(obj) diff --git a/python/api/component/serializers.py b/python/api/component/serializers.py index fa483a88fe..f04d8eae92 100644 --- a/python/api/component/serializers.py +++ b/python/api/component/serializers.py @@ -10,11 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.action.serializers import ActionShort -from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer -from api.group_config.serializers import GroupConfigsHyperlinkedIdentityField -from api.serializers import StringListSerializer -from api.utils import CommonAPIURL, ObjectURL +from adcm.serializers import EmptySerializer +from adcm.utils import filter_actions from cm.adcm_config.config import get_main_info from cm.models import MAINTENANCE_MODE_BOTH_CASES_CHOICES, Action, ServiceComponent from cm.status_api import get_component_status @@ -29,8 +26,11 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer -from adcm.utils import filter_actions +from api.action.serializers import ActionShort +from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer +from api.group_config.serializers import GroupConfigsHyperlinkedIdentityField +from api.serializers import StringListSerializer +from api.utils import CommonAPIURL, ObjectURL class ComponentSerializer(EmptySerializer): diff --git a/python/api/component/urls.py b/python/api/component/urls.py index 0f0390cf2d..2740f20d8d 100644 --- a/python/api/component/urls.py +++ b/python/api/component/urls.py @@ -11,13 +11,14 @@ # limitations under the License. +from django.urls import include, path + from api.component.views import ( ComponentDetailView, ComponentListView, ComponentMaintenanceModeView, StatusList, ) -from django.urls import include, path urlpatterns = [ path("", ComponentListView.as_view(), name="component"), diff --git a/python/api/component/views.py b/python/api/component/views.py index 212f008ed7..59c83636a1 100644 --- a/python/api/component/views.py +++ b/python/api/component/views.py @@ -10,15 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.base_view import DetailView, GenericUIView, PaginatedView -from api.component.serializers import ( - ComponentChangeMaintenanceModeSerializer, - ComponentDetailSerializer, - ComponentDetailUISerializer, - ComponentSerializer, - ComponentStatusSerializer, - ComponentUISerializer, -) +from adcm.permissions import check_custom_perm, get_object_for_user +from adcm.utils import get_maintenance_mode_response from audit.utils import audit from cm.api import update_mm_objects from cm.models import Cluster, ClusterObject, HostComponent, ServiceComponent @@ -30,8 +23,15 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.permissions import check_custom_perm, get_object_for_user -from adcm.utils import get_maintenance_mode_response +from api.base_view import DetailView, GenericUIView, PaginatedView +from api.component.serializers import ( + ComponentChangeMaintenanceModeSerializer, + ComponentDetailSerializer, + ComponentDetailUISerializer, + ComponentSerializer, + ComponentStatusSerializer, + ComponentUISerializer, +) def get_component_queryset(queryset, user, kwargs): @@ -100,7 +100,6 @@ def post(self, request: Request, **kwargs) -> Response: ServiceComponent, id=kwargs["component_id"], ) - # pylint: disable=protected-access check_custom_perm(request.user, "change_maintenance_mode", component._meta.model_name, component) serializer = self.get_serializer(instance=component, data=request.data) serializer.is_valid(raise_exception=True) @@ -118,7 +117,7 @@ class StatusList(GenericUIView): serializer_class = ComponentStatusSerializer ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 queryset = get_component_queryset(ServiceComponent.objects.order_by("id"), request.user, kwargs) component = get_object_for_user(request.user, "cm.view_servicecomponent", queryset, id=kwargs["component_id"]) if self._is_for_ui(): diff --git a/python/api/concern/serializers.py b/python/api/concern/serializers.py index c691bd8001..8402c97228 100644 --- a/python/api/concern/serializers.py +++ b/python/api/concern/serializers.py @@ -10,7 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.utils import get_api_url_kwargs, hlink +from adcm.serializers import EmptySerializer from rest_framework.reverse import reverse from rest_framework.serializers import ( BooleanField, @@ -20,7 +20,7 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer +from api.utils import get_api_url_kwargs, hlink class ConcernItemSerializer(EmptySerializer): diff --git a/python/api/concern/urls.py b/python/api/concern/urls.py index 56e6cd74f9..cb326de374 100644 --- a/python/api/concern/urls.py +++ b/python/api/concern/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.concern.views import ConcernItemDetail, ConcernItemList from django.urls import path +from api.concern.views import ConcernItemDetail, ConcernItemList + urlpatterns = [ path("", ConcernItemList.as_view(), name="concern"), path("/", ConcernItemDetail.as_view(), name="concern-details"), diff --git a/python/api/concern/views.py b/python/api/concern/views.py index 4c24cf44b9..b1432af895 100644 --- a/python/api/concern/views.py +++ b/python/api/concern/views.py @@ -9,6 +9,12 @@ # 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. +from adcm.utils import OBJECT_TYPES_DICT +from cm import models +from cm.errors import AdcmEx +from django.contrib.contenttypes.models import ContentType +from django_filters import rest_framework as drf_filters +from rest_framework.permissions import IsAuthenticated from api.base_view import DetailView, PaginatedView from api.concern.serializers import ( @@ -16,21 +22,8 @@ ConcernItemSerializer, ConcernItemUISerializer, ) -from cm import models -from cm.errors import AdcmEx -from django.contrib.contenttypes.models import ContentType -from django_filters import rest_framework as drf_filters -from rest_framework.permissions import IsAuthenticated -OBJECT_TYPES = { - "adcm": "adcm", - "cluster": "cluster", - "service": "clusterobject", - "component": "servicecomponent", - "provider": "hostprovider", - "host": "host", -} -CHOICES = list(zip(OBJECT_TYPES, OBJECT_TYPES)) +CHOICES = list(zip(OBJECT_TYPES_DICT, OBJECT_TYPES_DICT)) class ConcernFilter(drf_filters.FilterSet): @@ -52,17 +45,17 @@ class Meta: "owner_id", ] - def _filter_by_owner_type(self, queryset, name, value: str): # pylint: disable=unused-argument - owner_type = ContentType.objects.get(app_label="cm", model=OBJECT_TYPES[value]) + def _filter_by_owner_type(self, queryset, name, value: str): # noqa: ARG001, ARG002 + owner_type = ContentType.objects.get(app_label="cm", model=OBJECT_TYPES_DICT[value]) return queryset.filter(owner_type=owner_type) - def _pass(self, queryset, name, value): # pylint: disable=unused-argument + def _pass(self, queryset, name, value): # noqa: ARG001, ARG002 # do not pass to filter directly return queryset - def _filter_by_object(self, queryset, name, value): # pylint: disable=unused-argument + def _filter_by_object(self, queryset, name, value): # noqa: ARG001, ARG002 object_id = self.request.query_params.get("object_id") - filters = {f"{OBJECT_TYPES[value]}_entities__id": object_id} + filters = {f"{OBJECT_TYPES_DICT[value]}_entities__id": object_id} return queryset.filter(**filters) diff --git a/python/api/config/serializers.py b/python/api/config/serializers.py index c852d1970f..bb3d674a71 100644 --- a/python/api/config/serializers.py +++ b/python/api/config/serializers.py @@ -12,7 +12,7 @@ from typing import Any -from api.utils import CommonAPIURL, get_api_url_kwargs +from adcm.serializers import EmptySerializer from cm.adcm_config.config import get_default, restore_cluster_config, ui_config from cm.adcm_config.utils import group_is_activatable from cm.api import update_obj_config @@ -31,7 +31,7 @@ ) from rest_framework.status import HTTP_400_BAD_REQUEST -from adcm.serializers import EmptySerializer +from api.utils import CommonAPIURL, get_api_url_kwargs class ConfigVersionURL(HyperlinkedIdentityField): @@ -135,7 +135,7 @@ def get_display_name(obj: PrototypeConfig) -> str: def get_default_field(obj: PrototypeConfig) -> Any: return get_default(obj) - def get_value(self, obj: PrototypeConfig) -> Any: # pylint: disable=arguments-renamed + def get_value(self, obj: PrototypeConfig) -> Any: proto = self.context.get("prototype", None) return get_default(obj, proto) diff --git a/python/api/config/urls.py b/python/api/config/urls.py index 9aceb7b23b..731b6ce196 100644 --- a/python/api/config/urls.py +++ b/python/api/config/urls.py @@ -10,13 +10,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +from django.urls import path + from api.config.views import ( ConfigHistoryRestoreView, ConfigHistoryView, ConfigVersionView, ConfigView, ) -from django.urls import path urlpatterns = [ path("", ConfigView.as_view(), name="object-config"), diff --git a/python/api/config/views.py b/python/api/config/views.py index af70bf13e5..24ee469ba3 100644 --- a/python/api/config/views.py +++ b/python/api/config/views.py @@ -10,15 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.base_view import GenericUIView -from api.config.serializers import ( - ConfigHistorySerializer, - ConfigObjectConfigSerializer, - HistoryCurrentPreviousConfigSerializer, - ObjectConfigRestoreSerializer, - ObjectConfigUpdateSerializer, -) -from api.utils import check_obj, create, update +from adcm.permissions import check_config_perm from audit.utils import audit from cm.adcm_config.ansible import ansible_encrypt_and_format from cm.adcm_config.config import ui_config @@ -31,7 +23,15 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from adcm.permissions import check_config_perm +from api.base_view import GenericUIView +from api.config.serializers import ( + ConfigHistorySerializer, + ConfigObjectConfigSerializer, + HistoryCurrentPreviousConfigSerializer, + ObjectConfigRestoreSerializer, + ObjectConfigUpdateSerializer, +) +from api.utils import check_obj, create, update def get_config_version(queryset, objconf, version) -> ConfigLog: @@ -84,7 +84,7 @@ class ConfigView(GenericUIView): permission_classes = (IsAuthenticated,) ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 object_type, object_id, _ = get_object_type_id_version(**kwargs) model = get_model_by_type(object_type) obj = model.obj.get(id=object_id) @@ -103,7 +103,7 @@ class ConfigHistoryView(PermissionListMixin, GenericUIView): def get_queryset(self, *args, **kwargs) -> QuerySet: return super().get_queryset(*args, **kwargs) | ConfigLog.objects.filter(obj_ref__adcm__isnull=False) - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 object_type, object_id, _ = get_object_type_id_version(**kwargs) obj, object_config = get_obj(object_type, object_id) config_log = self.get_queryset().filter(obj_ref=object_config).order_by("-id") @@ -112,7 +112,7 @@ def get(self, request, *args, **kwargs): # pylint: disable=unused-argument return Response(serializer.data) @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 object_type, object_id, _ = get_object_type_id_version(**kwargs) obj, object_config = get_obj(object_type, object_id) check_config_perm(user=request.user, action_type="change", model=type_to_model(object_type), obj=obj) @@ -136,7 +136,7 @@ class ConfigVersionView(PermissionListMixin, GenericUIView): def get_queryset(self, *args, **kwargs) -> QuerySet: return super().get_queryset(*args, **kwargs) | ConfigLog.objects.filter(obj_ref__adcm__isnull=False) - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 object_type, object_id, version = get_object_type_id_version(**kwargs) obj, object_config = get_obj(object_type, object_id) config_log = get_config_version(self.get_queryset(), object_config, version) @@ -175,7 +175,7 @@ class ConfigHistoryRestoreView(PermissionListMixin, GenericUIView): ordering = ["id"] @audit - def patch(self, request, *args, **kwargs): # pylint: disable=unused-argument + def patch(self, request, *args, **kwargs): # noqa: ARG001, ARG002 object_type, object_id, version = get_object_type_id_version(**kwargs) obj, object_config = get_obj(object_type, object_id) check_config_perm(user=request.user, action_type="change", model=type_to_model(object_type), obj=obj) diff --git a/python/api/config_log/serializers.py b/python/api/config_log/serializers.py index 890baa0aae..1bee65b569 100644 --- a/python/api/config_log/serializers.py +++ b/python/api/config_log/serializers.py @@ -10,12 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.serializers import UIConfigField from cm.api import update_obj_config from cm.models import ConfigLog from django.db.transaction import atomic from rest_framework.serializers import HyperlinkedIdentityField, ModelSerializer +from api.serializers import UIConfigField + class ConfigLogSerializer(ModelSerializer): url = HyperlinkedIdentityField(view_name="v1:config-log-detail") @@ -31,9 +32,7 @@ def create(self, validated_data: dict) -> ConfigLog: config = validated_data.get("config") attr = validated_data.get("attr", {}) description = validated_data.get("description", "") - config_log = update_obj_config(object_config, config, attr, description) - - return config_log + return update_obj_config(object_config, config, attr, description) class UIConfigLogSerializer(ConfigLogSerializer): diff --git a/python/api/config_log/urls.py b/python/api/config_log/urls.py index 5f495edc11..6705f34ad0 100644 --- a/python/api/config_log/urls.py +++ b/python/api/config_log/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.config_log.views import ConfigLogViewSet from rest_framework.routers import SimpleRouter +from api.config_log.views import ConfigLogViewSet + router = SimpleRouter() router.register("", ConfigLogViewSet, basename="config-log") diff --git a/python/api/config_log/views.py b/python/api/config_log/views.py index 9841c26c9c..c46c20be23 100644 --- a/python/api/config_log/views.py +++ b/python/api/config_log/views.py @@ -10,8 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.base_view import GenericUIViewSet -from api.config_log.serializers import ConfigLogSerializer, UIConfigLogSerializer +from adcm.permissions import DjangoObjectPermissionsAudit, check_config_perm from audit.utils import audit from cm.models import ConfigLog from django.contrib.contenttypes.models import ContentType @@ -20,10 +19,11 @@ from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.response import Response -from adcm.permissions import DjangoObjectPermissionsAudit, check_config_perm +from api.base_view import GenericUIViewSet +from api.config_log.serializers import ConfigLogSerializer, UIConfigLogSerializer -class ConfigLogViewSet( # pylint: disable=too-many-ancestors +class ConfigLogViewSet( PermissionListMixin, CreateModelMixin, ListModelMixin, @@ -48,7 +48,7 @@ def get_serializer_class(self): return super().get_serializer_class() @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) diff --git a/python/api/docs.py b/python/api/docs.py index 101db60620..33cacfecef 100644 --- a/python/api/docs.py +++ b/python/api/docs.py @@ -33,12 +33,10 @@ def docs_html(request): def get_context(request, patterns=None): generator = SchemaGenerator(title="ArenaData Cluster Manager API", description=intro(), patterns=patterns) - data = generator.get_schema(request, True) - context = { - "document": data, + return { + "document": generator.get_schema(request, True), "request": request, } - return context def intro(): diff --git a/python/api/group_config/serializers.py b/python/api/group_config/serializers.py index 14c1848596..e72ecb8a91 100644 --- a/python/api/group_config/serializers.py +++ b/python/api/group_config/serializers.py @@ -9,12 +9,7 @@ # 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. - -from api.serializers import ( - MultiHyperlinkedIdentityField, - MultiHyperlinkedRelatedField, - UIConfigField, -) +from adcm.utils import OBJECT_TYPES_DICT from cm.api import update_obj_config from cm.errors import AdcmEx from cm.models import ConfigLog, GroupConfig, Host, ObjectConfig @@ -25,6 +20,12 @@ from rest_framework import serializers from rest_framework.reverse import reverse +from api.serializers import ( + MultiHyperlinkedIdentityField, + MultiHyperlinkedRelatedField, + UIConfigField, +) + class HostFlexFieldsSerializer(FlexFieldsSerializerMixin, serializers.ModelSerializer): class Meta: @@ -47,26 +48,13 @@ def check_object_type(type_name): def translate_model_name(model_name): """Translating model name to display model name""" - if model_name == "clusterobject": - return "service" - elif model_name == "servicecomponent": - return "component" - elif model_name == "hostprovider": - return "provider" - else: - return model_name + model_names = {value: key for key, value in OBJECT_TYPES_DICT.items()} + return model_names[model_name] def revert_model_name(name): """Translating display model name to model name""" - if name == "service": - return "clusterobject" - elif name == "component": - return "servicecomponent" - elif name == "provider": - return "hostprovider" - else: - return name + return OBJECT_TYPES_DICT[name] class ObjectTypeField(serializers.Field): @@ -245,9 +233,7 @@ def create(self, validated_data): config = validated_data.get("config") attr = validated_data.get("attr", {}) description = validated_data.get("description", "") - config_log = update_obj_config(object_config, config, attr, description) - - return config_log + return update_obj_config(object_config, config, attr, description) class UIGroupConfigConfigLogSerializer(GroupConfigConfigLogSerializer): diff --git a/python/api/group_config/urls.py b/python/api/group_config/urls.py index 473255bd4f..afa380abce 100644 --- a/python/api/group_config/urls.py +++ b/python/api/group_config/urls.py @@ -11,6 +11,8 @@ # limitations under the License. +from rest_framework_extensions.routers import ExtendedSimpleRouter as SimpleRouter + from api.group_config.views import ( GroupConfigConfigLogViewSet, GroupConfigConfigViewSet, @@ -18,7 +20,6 @@ GroupConfigHostViewSet, GroupConfigViewSet, ) -from rest_framework_extensions.routers import ExtendedSimpleRouter as SimpleRouter router = SimpleRouter() diff --git a/python/api/group_config/views.py b/python/api/group_config/views.py index af12c09dbb..eff35ee875 100644 --- a/python/api/group_config/views.py +++ b/python/api/group_config/views.py @@ -10,16 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.base_view import GenericUIViewSet -from api.group_config.serializers import ( - GroupConfigConfigLogSerializer, - GroupConfigConfigSerializer, - GroupConfigHostCandidateSerializer, - GroupConfigHostSerializer, - GroupConfigSerializer, - UIGroupConfigConfigLogSerializer, - revert_model_name, -) +from adcm.permissions import DjangoObjectPermissionsAudit, check_config_perm from audit.utils import audit from cm.errors import AdcmEx from cm.models import ConfigLog, GroupConfig, Host, ObjectConfig @@ -44,7 +35,16 @@ from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet from rest_framework_extensions.mixins import NestedViewSetMixin -from adcm.permissions import DjangoObjectPermissionsAudit, check_config_perm +from api.base_view import GenericUIViewSet +from api.group_config.serializers import ( + GroupConfigConfigLogSerializer, + GroupConfigConfigSerializer, + GroupConfigHostCandidateSerializer, + GroupConfigHostSerializer, + GroupConfigSerializer, + UIGroupConfigConfigLogSerializer, + revert_model_name, +) class GroupConfigFilterSet(FilterSet): @@ -69,7 +69,7 @@ class GroupConfigHostViewSet( RetrieveModelMixin, DestroyModelMixin, GenericViewSet, -): # pylint: disable=too-many-ancestors +): queryset = Host.objects.all() serializer_class = GroupConfigHostSerializer permission_classes = (DjangoObjectPermissionsAudit,) @@ -79,7 +79,7 @@ class GroupConfigHostViewSet( ordering = ["id"] @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer(data=request.data) if serializer.is_valid(raise_exception=True): @@ -94,7 +94,7 @@ def create(self, request, *args, **kwargs): return Response(data=serializer.errors, status=HTTP_400_BAD_REQUEST) @audit - def destroy(self, request, *args, **kwargs): + def destroy(self, request, *args, **kwargs): # noqa: ARG002 group_config = GroupConfig.obj.get(id=self.kwargs.get("parent_lookup_group_config")) host = self.get_object() group_config.hosts.remove(host) @@ -118,14 +118,14 @@ class GroupConfigHostCandidateViewSet( PermissionListMixin, NestedViewSetMixin, ReadOnlyModelViewSet, -): # pylint: disable=too-many-ancestors +): serializer_class = GroupConfigHostCandidateSerializer permission_classes = (DjangoObjectPermissionsAudit,) lookup_url_kwarg = "host_id" permission_required = ["cm.view_host"] schema = AutoSchema() - def get_queryset(self, *args, **kwargs): + def get_queryset(self, *args, **kwargs): # noqa: ARG002 group_config_id = self.kwargs.get("parent_lookup_group_config") if group_config_id is None: return Host.objects.none() @@ -152,7 +152,7 @@ class GroupConfigConfigViewSet( NestedViewSetMixin, RetrieveModelMixin, GenericViewSet, -): # pylint: disable=too-many-ancestors +): queryset = ObjectConfig.objects.all() serializer_class = GroupConfigConfigSerializer permission_classes = (DjangoObjectPermissionsAudit,) @@ -186,7 +186,7 @@ class GroupConfigConfigLogViewSet( ListModelMixin, CreateModelMixin, GenericUIViewSet, -): # pylint: disable=too-many-ancestors +): serializer_class = GroupConfigConfigLogSerializer permission_classes = (DjangoObjectPermissionsAudit,) permission_required = ["view_configlog"] @@ -198,7 +198,7 @@ def get_serializer_class(self): return UIGroupConfigConfigLogSerializer return super().get_serializer_class() - def get_queryset(self, *args, **kwargs): + def get_queryset(self, *args, **kwargs): # noqa: ARG002 kwargs = { "obj_ref__group_config": self.kwargs.get("parent_lookup_obj_ref__group_config"), "obj_ref": self.kwargs.get("parent_lookup_obj_ref"), @@ -232,7 +232,7 @@ def create(self, request, *args, **kwargs): return super().create(request, *args, **kwargs) -class GroupConfigViewSet(PermissionListMixin, NestedViewSetMixin, ModelViewSet): # pylint: disable=too-many-ancestors +class GroupConfigViewSet(PermissionListMixin, NestedViewSetMixin, ModelViewSet): queryset = GroupConfig.objects.all() serializer_class = GroupConfigSerializer filterset_class = GroupConfigFilterSet @@ -242,7 +242,7 @@ class GroupConfigViewSet(PermissionListMixin, NestedViewSetMixin, ModelViewSet): ordering = ["id"] @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer(data=request.data) try: serializer.is_valid(raise_exception=True) @@ -261,7 +261,7 @@ def create(self, request, *args, **kwargs): return Response(serializer.data, status=HTTP_201_CREATED, headers=headers) @audit - def update(self, request, *args, **kwargs): + def update(self, request, *args, **kwargs): # noqa: ARG002 partial = kwargs.pop("partial", False) instance = self.get_object() model = type(instance.object).__name__.lower() @@ -274,13 +274,12 @@ def update(self, request, *args, **kwargs): if getattr(instance, "_prefetched_objects_cache", None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. - # pylint: disable=protected-access instance._prefetched_objects_cache = {} return Response(serializer.data) @audit - def destroy(self, request, *args, **kwargs): + def destroy(self, request, *args, **kwargs): # noqa: ARG002 instance = self.get_object() model = type(instance.object).__name__.lower() check_config_perm(user=self.request.user, action_type="change", model=model, obj=instance.object) diff --git a/python/api/host/cluster_urls.py b/python/api/host/cluster_urls.py index d91c191e2a..6eb4385bd2 100644 --- a/python/api/host/cluster_urls.py +++ b/python/api/host/cluster_urls.py @@ -11,9 +11,10 @@ # limitations under the License. -from api.host.views import HostListCluster from django.urls import include, path +from api.host.views import HostListCluster + urlpatterns = [ path("", HostListCluster.as_view(), name="host"), path("", include("api.host.host_urls")), diff --git a/python/api/host/host_urls.py b/python/api/host/host_urls.py index f548bb4eb4..00728ca133 100644 --- a/python/api/host/host_urls.py +++ b/python/api/host/host_urls.py @@ -11,9 +11,10 @@ # limitations under the License. -from api.host.views import HostDetail, HostMaintenanceModeView, StatusList from django.urls import include, path +from api.host.views import HostDetail, HostMaintenanceModeView, StatusList + urlpatterns = [ path( "/", diff --git a/python/api/host/provider_urls.py b/python/api/host/provider_urls.py index 728aeb76f8..e7815a1fa9 100644 --- a/python/api/host/provider_urls.py +++ b/python/api/host/provider_urls.py @@ -11,9 +11,10 @@ # limitations under the License. -from api.host.views import HostListProvider from django.urls import include, path +from api.host.views import HostListProvider + urlpatterns = [ path("", HostListProvider.as_view(), name="host"), path("", include("api.host.host_urls")), diff --git a/python/api/host/serializers.py b/python/api/host/serializers.py index c3c3f54a99..4c6ddd7b29 100644 --- a/python/api/host/serializers.py +++ b/python/api/host/serializers.py @@ -10,10 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.action.serializers import ActionShort -from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer -from api.serializers import StringListSerializer -from api.utils import CommonAPIURL, ObjectURL, check_obj +from adcm.serializers import EmptySerializer +from adcm.utils import filter_actions from cm.adcm_config.config import get_main_info from cm.api import add_host from cm.issue import update_hierarchy_issues, update_issue_after_deleting @@ -38,8 +36,10 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer -from adcm.utils import filter_actions +from api.action.serializers import ActionShort +from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer +from api.serializers import StringListSerializer +from api.utils import CommonAPIURL, ObjectURL, check_obj class HostSerializer(EmptySerializer): diff --git a/python/api/host/urls.py b/python/api/host/urls.py index 36e2f2dc3d..ef321a2671 100644 --- a/python/api/host/urls.py +++ b/python/api/host/urls.py @@ -11,9 +11,10 @@ # limitations under the License. -from api.host.views import HostList from django.urls import include, path +from api.host.views import HostList + urlpatterns = [ path("", HostList.as_view(), name="host"), path("", include("api.host.host_urls")), diff --git a/python/api/host/views.py b/python/api/host/views.py index fbb96f42f2..afd2b44ab6 100644 --- a/python/api/host/views.py +++ b/python/api/host/views.py @@ -10,19 +10,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.base_view import DetailView, GenericUIView, PaginatedView -from api.host.serializers import ( - ClusterHostSerializer, - HostChangeMaintenanceModeSerializer, - HostDetailSerializer, - HostDetailUISerializer, - HostSerializer, - HostStatusSerializer, - HostUISerializer, - HostUpdateSerializer, - ProvideHostSerializer, +from adcm.permissions import ( + VIEW_CLUSTER_PERM, + VIEW_HOST_PERM, + VIEW_PROVIDER_PERM, + check_custom_perm, + get_object_for_user, ) -from api.utils import create +from adcm.utils import get_maintenance_mode_response from audit.utils import audit from cm.api import ( add_host_to_cluster, @@ -57,14 +52,19 @@ HTTP_409_CONFLICT, ) -from adcm.permissions import ( - VIEW_CLUSTER_PERM, - VIEW_HOST_PERM, - VIEW_PROVIDER_PERM, - check_custom_perm, - get_object_for_user, +from api.base_view import DetailView, GenericUIView, PaginatedView +from api.host.serializers import ( + ClusterHostSerializer, + HostChangeMaintenanceModeSerializer, + HostDetailSerializer, + HostDetailUISerializer, + HostSerializer, + HostStatusSerializer, + HostUISerializer, + HostUpdateSerializer, + ProvideHostSerializer, ) -from adcm.utils import get_maintenance_mode_response +from api.utils import create class NumberInFilter(drf_filters.BaseInFilter, drf_filters.NumberFilter): @@ -162,7 +162,7 @@ def get_queryset(self, *args, **kwargs): return get_objects_for_user(**self.get_get_objects_for_user_kwargs(queryset)) @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 serializer = self.serializer_class( data=request.data, context={ @@ -193,7 +193,7 @@ class HostListCluster(HostList): serializer_class = ClusterHostSerializer @audit - def post(self, request, *args, **kwargs): + def post(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer(data=request.data) if serializer.is_valid(raise_exception=True): validated_data = serializer.validated_data @@ -231,10 +231,10 @@ class HostDetail(PermissionListMixin, DetailView): error_code = "HOST_NOT_FOUND" ordering = ["id"] - def _update_host_object( # pylint: disable=unused-argument + def _update_host_object( self, request, - *args, + *args, # noqa: ARG002 partial=True, **kwargs, ): @@ -268,7 +268,7 @@ def get_queryset(self, *args, **kwargs): return get_objects_for_user(**self.get_get_objects_for_user_kwargs(queryset)) @audit - def delete(self, request, *args, **kwargs): # pylint: disable=unused-argument + def delete(self, request, *args, **kwargs): # noqa: ARG001, ARG002 host = self.get_object() if "cluster_id" in kwargs: cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_id"]) @@ -287,7 +287,7 @@ def patch(self, request, *args, **kwargs): @audit def put(self, request, *args, **kwargs): - return self._update_host_object(request, partial=False, *args, **kwargs) + return self._update_host_object(request, *args, partial=False, **kwargs) class HostMaintenanceModeView(GenericUIView): @@ -323,7 +323,7 @@ class StatusList(GenericUIView): serializer_class = HostStatusSerializer ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = None host = get_object_for_user(request.user, VIEW_HOST_PERM, Host, id=kwargs["host_id"]) if "cluster_id" in kwargs: diff --git a/python/api/job/serializers.py b/python/api/job/serializers.py index bb7a3c2e70..e681da1296 100644 --- a/python/api/job/serializers.py +++ b/python/api/job/serializers.py @@ -10,11 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json from pathlib import Path +import json -from api.action.serializers import ActionJobSerializer -from api.concern.serializers import ConcernItemSerializer from cm.ansible_plugin import get_checklogs_data_by_job_id from cm.job import ActionRunPayload, run_action from cm.models import JobLog, JobStatus, LogStorage, TaskLog @@ -27,6 +25,9 @@ SerializerMethodField, ) +from api.action.serializers import ActionJobSerializer +from api.concern.serializers import ConcernItemSerializer + class JobShortSerializer(HyperlinkedModelSerializer): display_name = SerializerMethodField() @@ -117,16 +118,11 @@ def get_action_url(self, obj: TaskLog) -> str | None: @staticmethod def get_objects(obj: TaskLog) -> list: - objects = [{"type": k, **v} for k, v in obj.selector.items()] - - return objects + return [{"type": k, **v} for k, v in obj.selector.items()] @staticmethod def get_terminatable(obj: TaskLog): - if obj.action: - allow_to_terminate = obj.action.allow_to_terminate - else: - allow_to_terminate = False + allow_to_terminate = obj.action.allow_to_terminate if obj.action else False if allow_to_terminate and obj.status in {JobStatus.CREATED, JobStatus.RUNNING}: return True @@ -214,9 +210,7 @@ class Meta: @staticmethod def get_objects(obj: JobLog) -> list | None: - objects = [{"type": k, **v} for k, v in obj.task.selector.items()] - - return objects + return [{"type": k, **v} for k, v in obj.task.selector.items()] @staticmethod def get_display_name(obj: JobLog) -> str | None: @@ -298,13 +292,12 @@ def get_content(self, obj: LogStorage) -> str: obj.body = get_checklogs_data_by_job_id(obj.job_id) if isinstance(obj.body, str): obj.body = json.loads(obj.body) - elif obj.type == "custom": - if obj.format == "json" and isinstance(obj.body, str): - try: - custom_content = json.loads(obj.body) - obj.body = json.dumps(custom_content, indent=4) - except json.JSONDecodeError: - pass + elif obj.type == "custom" and obj.format == "json" and isinstance(obj.body, str): + try: + custom_content = json.loads(obj.body) + obj.body = json.dumps(custom_content, indent=4) + except json.JSONDecodeError: + pass return obj.body diff --git a/python/api/job/task_urls.py b/python/api/job/task_urls.py index 9cecfd6ded..05a405c097 100644 --- a/python/api/job/task_urls.py +++ b/python/api/job/task_urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.job.views import TaskViewSet from rest_framework.routers import SimpleRouter +from api.job.views import TaskViewSet + router = SimpleRouter() router.register("", TaskViewSet) urlpatterns = router.urls diff --git a/python/api/job/urls.py b/python/api/job/urls.py index 5c16710d81..f0e82f263d 100644 --- a/python/api/job/urls.py +++ b/python/api/job/urls.py @@ -10,10 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.job.views import JobViewSet, LogStorageViewSet from django.urls import path from rest_framework.routers import SimpleRouter +from api.job.views import JobViewSet, LogStorageViewSet + router = SimpleRouter() router.register("", JobViewSet, basename="joblog") diff --git a/python/api/job/views.py b/python/api/job/views.py index f7bb33e69e..51c2483490 100644 --- a/python/api/job/views.py +++ b/python/api/job/views.py @@ -10,20 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +from pathlib import Path import io import re import tarfile -from pathlib import Path -from api.base_view import GenericUIViewSet -from api.job.serializers import ( - JobRetrieveSerializer, - JobSerializer, - LogStorageRetrieveSerializer, - LogStorageSerializer, - TaskRetrieveSerializer, - TaskSerializer, -) +from adcm.permissions import check_custom_perm, get_object_for_user +from adcm.utils import str_remove_non_alnum from audit.utils import audit from cm.job import restart_task from cm.models import ActionType, JobLog, LogStorage, TaskLog @@ -39,8 +32,15 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.permissions import check_custom_perm, get_object_for_user -from adcm.utils import str_remove_non_alnum +from api.base_view import GenericUIViewSet +from api.job.serializers import ( + JobRetrieveSerializer, + JobSerializer, + LogStorageRetrieveSerializer, + LogStorageSerializer, + TaskRetrieveSerializer, + TaskSerializer, +) VIEW_TASKLOG_PERMISSION = "cm.view_tasklog" VIEW_JOBLOG_PERMISSION = "cm.view_joblog" @@ -78,9 +78,7 @@ def get_task_download_archive_name(task: TaskLog) -> str: obj_name = None if task.object_type.name == "cluster": obj_name = task.task_object.name - elif task.object_type.name == "cluster object": - obj_name = task.task_object.cluster.name - elif task.object_type.name == "service component": + elif task.object_type.name == "cluster object" or task.object_type.name == "service component": obj_name = task.task_object.cluster.name elif task.object_type.name == "host provider": obj_name = task.task_object.name @@ -135,7 +133,6 @@ def get_task_download_archive_file_handler(task: TaskLog) -> io.BytesIO: return file_handler -# pylint:disable-next=too-many-ancestors class JobViewSet(PermissionListMixin, ListModelMixin, RetrieveModelMixin, GenericUIViewSet): queryset = JobLog.objects.select_related("task", "action").all() serializer_class = JobSerializer @@ -153,11 +150,7 @@ def get_queryset(self, *args, **kwargs): return queryset def get_permissions(self): - if self.action == "list": - permission_classes = (DjangoModelPermissions,) - else: - permission_classes = (DjangoOnlyObjectPermissions,) - + permission_classes = (DjangoModelPermissions,) if self.action == "list" else (DjangoOnlyObjectPermissions,) return [permission() for permission in permission_classes] def get_serializer_class(self): @@ -177,7 +170,6 @@ def cancel(self, request: Request, job_pk: int) -> Response: return Response(status=HTTP_200_OK) -# pylint:disable-next=too-many-ancestors class TaskViewSet(PermissionListMixin, ListModelMixin, RetrieveModelMixin, GenericUIViewSet): queryset = TaskLog.objects.select_related("action").all() serializer_class = TaskSerializer @@ -231,7 +223,6 @@ def download(self, request: Request, task_pk: int) -> Response: return response -# pylint:disable-next=too-many-ancestors class LogStorageViewSet(PermissionListMixin, ListModelMixin, RetrieveModelMixin, GenericUIViewSet): queryset = LogStorage.objects.all() serializer_class = LogStorageSerializer @@ -267,10 +258,7 @@ def download(self, request: Request, job_pk: int, log_pk: int): filename = f"{job_pk}-{log_storage.name}.{log_storage.format}" filename = re.sub(r"\s+", "_", filename) - if log_storage.format == "txt": - mime_type = "text/plain" - else: - mime_type = "application/json" + mime_type = "text/plain" if log_storage.format == "txt" else "application/json" if log_storage.body is None: file_path = Path( diff --git a/python/api/object_config/views.py b/python/api/object_config/views.py index 3d604eb25a..6c77a84d79 100644 --- a/python/api/object_config/views.py +++ b/python/api/object_config/views.py @@ -10,15 +10,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.object_config.serializers import ObjectConfigSerializer from cm.models import ObjectConfig from guardian.mixins import PermissionListMixin from rest_framework.permissions import DjangoObjectPermissions from rest_framework.schemas.coreapi import AutoSchema from rest_framework.viewsets import ReadOnlyModelViewSet +from api.object_config.serializers import ObjectConfigSerializer + -class ObjectConfigViewSet(PermissionListMixin, ReadOnlyModelViewSet): # pylint: disable=too-many-ancestors +class ObjectConfigViewSet(PermissionListMixin, ReadOnlyModelViewSet): queryset = ObjectConfig.objects.all() serializer_class = ObjectConfigSerializer permission_classes = (DjangoObjectPermissions,) diff --git a/python/api/provider/serializers.py b/python/api/provider/serializers.py index 80dd4ee01b..d41cbefbe6 100644 --- a/python/api/provider/serializers.py +++ b/python/api/provider/serializers.py @@ -10,11 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.action.serializers import ActionShort -from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer -from api.group_config.serializers import GroupConfigsHyperlinkedIdentityField -from api.serializers import DoUpgradeSerializer, StringListSerializer -from api.utils import CommonAPIURL, ObjectURL, check_obj +from adcm.serializers import EmptySerializer +from adcm.utils import filter_actions from cm.adcm_config.config import get_main_info from cm.api import add_host_provider from cm.errors import AdcmEx @@ -30,8 +27,11 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer -from adcm.utils import filter_actions +from api.action.serializers import ActionShort +from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer +from api.group_config.serializers import GroupConfigsHyperlinkedIdentityField +from api.serializers import DoUpgradeSerializer, StringListSerializer +from api.utils import CommonAPIURL, ObjectURL, check_obj class ProviderSerializer(EmptySerializer): @@ -45,8 +45,7 @@ class ProviderSerializer(EmptySerializer): @staticmethod def validate_prototype_id(prototype_id): - proto = check_obj(Prototype, {"id": prototype_id, "type": "provider"}, "PROTOTYPE_NOT_FOUND") - return proto + return check_obj(Prototype, {"id": prototype_id, "type": "provider"}, "PROTOTYPE_NOT_FOUND") def create(self, validated_data): try: diff --git a/python/api/provider/urls.py b/python/api/provider/urls.py index cc59db8380..9360c5319f 100644 --- a/python/api/provider/urls.py +++ b/python/api/provider/urls.py @@ -10,6 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from django.urls import include, path + from api.provider.views import ( DoProviderUpgrade, ProviderDetail, @@ -17,21 +19,20 @@ ProviderUpgrade, ProviderUpgradeDetail, ) -from django.urls import include, path # fmt: off urlpatterns = [ - path('', ProviderList.as_view(), name='provider'), - path('/', include([ - path('', ProviderDetail.as_view(), name='provider-details'), - path('host/', include('api.host.provider_urls')), - path('action/', include('api.action.urls'), {'object_type': 'provider'}), - path('config/', include('api.config.urls'), {'object_type': 'provider'}), - path('upgrade/', include([ - path('', ProviderUpgrade.as_view(), name='provider-upgrade'), - path('/', include([ - path('', ProviderUpgradeDetail.as_view(), name='provider-upgrade-details'), - path('do/', DoProviderUpgrade.as_view(), name='do-provider-upgrade'), + path("", ProviderList.as_view(), name="provider"), + path("/", include([ + path("", ProviderDetail.as_view(), name="provider-details"), + path("host/", include("api.host.provider_urls")), + path("action/", include("api.action.urls"), {"object_type": "provider"}), + path("config/", include("api.config.urls"), {"object_type": "provider"}), + path("upgrade/", include([ + path("", ProviderUpgrade.as_view(), name="provider-upgrade"), + path("/", include([ + path("", ProviderUpgradeDetail.as_view(), name="provider-upgrade-details"), + path("do/", DoProviderUpgrade.as_view(), name="do-provider-upgrade"), ])), ])), ])), diff --git a/python/api/provider/views.py b/python/api/provider/views.py index 1cf4dd4d67..29937e1879 100644 --- a/python/api/provider/views.py +++ b/python/api/provider/views.py @@ -10,16 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.base_view import DetailView, GenericUIView, PaginatedView -from api.provider.serializers import ( - DoProviderUpgradeSerializer, - ProviderDetailSerializer, - ProviderDetailUISerializer, - ProviderSerializer, - ProviderUISerializer, -) -from api.serializers import ProviderUpgradeSerializer -from api.utils import AdcmFilterBackend, AdcmOrderingFilter, check_obj, create +from adcm.permissions import check_custom_perm, get_object_for_user from audit.utils import audit from cm.api import delete_host_provider from cm.issue import update_hierarchy_issues @@ -30,7 +21,16 @@ from rest_framework import permissions, status from rest_framework.response import Response -from adcm.permissions import check_custom_perm, get_object_for_user +from api.base_view import DetailView, GenericUIView, PaginatedView +from api.provider.serializers import ( + DoProviderUpgradeSerializer, + ProviderDetailSerializer, + ProviderDetailUISerializer, + ProviderSerializer, + ProviderUISerializer, +) +from api.serializers import ProviderUpgradeSerializer +from api.utils import AdcmFilterBackend, AdcmOrderingFilter, check_obj, create class ProviderList(PermissionListMixin, PaginatedView): @@ -52,7 +52,7 @@ class ProviderList(PermissionListMixin, PaginatedView): ordering = ["id"] @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 serializer = self.get_serializer(data=request.data) return create(serializer) @@ -75,7 +75,7 @@ class ProviderDetail(PermissionListMixin, DetailView): ordering = ["id"] @audit - def delete(self, request, *args, **kwargs): # pylint: disable=unused-argument + def delete(self, request, *args, **kwargs): # noqa: ARG001, ARG002 """ Remove host provider """ @@ -98,7 +98,7 @@ def get_ordering(self): return order.get_ordering(self.request, self.get_queryset(), self) - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 """ List all available upgrades for specified host provider """ @@ -118,7 +118,7 @@ class ProviderUpgradeDetail(GenericUIView): permission_classes = (permissions.IsAuthenticated,) ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 """ List all available upgrades for specified host provider """ @@ -138,7 +138,7 @@ class DoProviderUpgrade(GenericUIView): ordering = ["id"] @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 provider = get_object_for_user(request.user, "cm.view_hostprovider", HostProvider, id=kwargs["provider_id"]) check_custom_perm(request.user, "do_upgrade_of", "hostprovider", provider) serializer = self.get_serializer(data=request.data) diff --git a/python/api/serializers.py b/python/api/serializers.py index 580d2a4e64..67bd1bfb99 100644 --- a/python/api/serializers.py +++ b/python/api/serializers.py @@ -10,8 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.config.serializers import ConfigSerializerUI -from api.utils import UrlField, check_obj, hlink +from adcm.serializers import EmptySerializer from cm.adcm_config.config import get_action_variant, get_prototype_config, ui_config from cm.errors import raise_adcm_ex from cm.models import Cluster, GroupConfig, HostProvider, PrototypeConfig, Upgrade @@ -28,7 +27,8 @@ ) from rest_framework_extensions.settings import extensions_api_settings -from adcm.serializers import EmptySerializer +from api.config.serializers import ConfigSerializerUI +from api.utils import UrlField, check_obj, hlink class UpgradeSerializer(EmptySerializer): @@ -77,7 +77,7 @@ def get_config(self, instance): conf = ConfigSerializerUI(action_conf, many=True, context=self.context, read_only=True) return {"attr": attr, "config": conf.data} - def get_upgradable(self, instance: Upgrade) -> bool: # pylint: disable=unused-argument + def get_upgradable(self, instance: Upgrade) -> bool: # noqa: ARG001, ARG002 return self.context.get("upgradable", False) diff --git a/python/api/service/serializers.py b/python/api/service/serializers.py index 9b6791455c..2fbc2b91c3 100644 --- a/python/api/service/serializers.py +++ b/python/api/service/serializers.py @@ -10,13 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.action.serializers import ActionShort -from api.cluster.serializers import BindSerializer -from api.component.serializers import ComponentUISerializer -from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer -from api.group_config.serializers import GroupConfigsHyperlinkedIdentityField -from api.serializers import StringListSerializer -from api.utils import CommonAPIURL, ObjectURL, check_obj +from adcm.serializers import EmptySerializer +from adcm.utils import filter_actions from cm.adcm_config.config import get_main_info from cm.api import add_service_to_cluster, bind, multi_bind from cm.errors import AdcmEx @@ -43,8 +38,13 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer -from adcm.utils import filter_actions +from api.action.serializers import ActionShort +from api.cluster.serializers import BindSerializer +from api.component.serializers import ComponentUISerializer +from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer +from api.group_config.serializers import GroupConfigsHyperlinkedIdentityField +from api.serializers import StringListSerializer +from api.utils import CommonAPIURL, ObjectURL, check_obj class ServiceSerializer(EmptySerializer): diff --git a/python/api/service/urls.py b/python/api/service/urls.py index 4a26a272bd..1439fc8514 100644 --- a/python/api/service/urls.py +++ b/python/api/service/urls.py @@ -10,6 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from django.urls import include, path + from api.service.views import ( ServiceBindDetailView, ServiceBindView, @@ -19,7 +21,6 @@ ServiceMaintenanceModeView, StatusList, ) -from django.urls import include, path urlpatterns = [ path("", ServiceListView.as_view(), name="service"), diff --git a/python/api/service/views.py b/python/api/service/views.py index fd8dbdf58e..b3b9fe0673 100644 --- a/python/api/service/views.py +++ b/python/api/service/views.py @@ -10,6 +10,19 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.permissions import check_custom_perm, get_object_for_user +from adcm.utils import delete_service_from_api, get_maintenance_mode_response +from audit.utils import audit +from cm.api import get_import, unbind, update_mm_objects +from cm.models import Cluster, ClusterBind, ClusterObject, HostComponent, Prototype +from cm.status_api import make_ui_service_status +from guardian.mixins import PermissionListMixin +from rbac.viewsets import DjangoOnlyObjectPermissions +from rest_framework import permissions +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.status import HTTP_200_OK, HTTP_204_NO_CONTENT, HTTP_400_BAD_REQUEST + from api.base_view import DetailView, GenericUIView, PaginatedView from api.cluster.serializers import BindSerializer from api.service.serializers import ( @@ -26,19 +39,6 @@ ) from api.stack.serializers import ImportSerializer from api.utils import check_obj, create -from audit.utils import audit -from cm.api import get_import, unbind, update_mm_objects -from cm.models import Cluster, ClusterBind, ClusterObject, HostComponent, Prototype -from cm.status_api import make_ui_service_status -from guardian.mixins import PermissionListMixin -from rbac.viewsets import DjangoOnlyObjectPermissions -from rest_framework import permissions -from rest_framework.request import Request -from rest_framework.response import Response -from rest_framework.status import HTTP_200_OK, HTTP_204_NO_CONTENT, HTTP_400_BAD_REQUEST - -from adcm.permissions import check_custom_perm, get_object_for_user -from adcm.utils import delete_service_from_api, get_maintenance_mode_response class ServiceListView(PermissionListMixin, PaginatedView): @@ -51,7 +51,7 @@ class ServiceListView(PermissionListMixin, PaginatedView): ordering_fields = ("id", "state", "prototype__display_name", "prototype__version_order") ordering = ["id"] - def get(self, request, *args, **kwargs): + def get(self, request, *args, **kwargs): # noqa: ARG002 queryset = self.get_queryset() if "cluster_id" in kwargs: cluster = get_object_for_user(request.user, "cm.view_cluster", Cluster, id=kwargs["cluster_id"]) @@ -60,7 +60,7 @@ def get(self, request, *args, **kwargs): return self.get_page(self.filter_queryset(queryset), request) @audit - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 serializer_class = self.serializer_class if "cluster_id" in kwargs: serializer_class = self.serializer_class_cluster @@ -96,7 +96,7 @@ def get_queryset(self, *args, **kwargs): return queryset @audit - def delete(self, request, *args, **kwargs): # pylint: disable=unused-argument + def delete(self, request, *args, **kwargs): # noqa: ARG001, ARG002, ARG004 instance: ClusterObject = self.get_object() return delete_service_from_api(service=instance) @@ -132,7 +132,7 @@ class ServiceImportView(GenericUIView): ordering = ["id"] @staticmethod - def get(request, *args, **kwargs): # pylint: disable=unused-argument + def get(request, *args, **kwargs): # noqa: ARG001, ARG002, ARG004 service = get_object_for_user(request.user, "cm.view_clusterobject", ClusterObject, id=kwargs["service_id"]) check_custom_perm(request.user, "view_import_of", "clusterobject", service, "view_clusterbind") cluster = service.cluster @@ -161,7 +161,7 @@ class ServiceBindView(GenericUIView): permission_classes = (permissions.IsAuthenticated,) ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 service = get_object_for_user(request.user, "cm.view_clusterobject", ClusterObject, id=kwargs["service_id"]) check_custom_perm(request.user, "view_import_of", "clusterobject", service, "view_clusterbind") binds = self.get_queryset().filter(service=service) @@ -196,7 +196,7 @@ def get_obj(self, kwargs, bind_id): return service, check_obj(ClusterBind, {"cluster": cluster, "id": bind_id}) - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 service, bind = self.get_obj(kwargs, kwargs["bind_id"]) check_custom_perm(request.user, "view_import_of", "clusterobject", service, "view_clusterbind") serializer = self.get_serializer(bind) @@ -204,7 +204,7 @@ def get(self, request, *args, **kwargs): # pylint: disable=unused-argument return Response(serializer.data) @audit - def delete(self, request, *args, **kwargs): # pylint: disable=unused-argument + def delete(self, request, *args, **kwargs): # noqa: ARG001, ARG002 service, bind = self.get_obj(kwargs, kwargs["bind_id"]) check_custom_perm(request.user, "change_import_of", "clusterobject", service) unbind(bind) @@ -218,7 +218,7 @@ class StatusList(GenericUIView): serializer_class = ServiceStatusSerializer ordering = ["id"] - def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 service = get_object_for_user(request.user, "cm.view_clusterobject", ClusterObject, id=kwargs["service_id"]) if self._is_for_ui(): host_components = self.get_queryset().filter(service=service) diff --git a/python/api/stack/serializers.py b/python/api/stack/serializers.py index a119003dad..8b17733207 100644 --- a/python/api/stack/serializers.py +++ b/python/api/stack/serializers.py @@ -10,9 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.action.serializers import StackActionDetailSerializer -from api.config.serializers import ConfigSerializer -from api.serializers import UpgradeSerializer +from adcm.serializers import EmptySerializer +from adcm.utils import get_requires from cm.models import Bundle, ClusterObject, Prototype from cm.schemas import RequiresUISchema from rest_flex_fields.serializers import FlexFieldsSerializerMixin @@ -28,8 +27,9 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer -from adcm.utils import get_requires +from api.action.serializers import StackActionDetailSerializer +from api.config.serializers import ConfigSerializer +from api.serializers import UpgradeSerializer class UploadBundleSerializer(EmptySerializer): @@ -382,7 +382,7 @@ class Meta: read_only_fields = fields -class ProviderPrototypeDetailSerializer(ProviderPrototypeSerializer): # pylint: disable=too-many-ancestors +class ProviderPrototypeDetailSerializer(ProviderPrototypeSerializer): actions = StackActionDetailSerializer(many=True, read_only=True) config = ConfigSerializer(many=True, read_only=True) upgrade = UpgradeSerializer(many=True, read_only=True) @@ -440,7 +440,7 @@ class Meta: read_only_fields = fields -class ClusterPrototypeDetailSerializer(ClusterPrototypeSerializer): # pylint: disable=too-many-ancestors +class ClusterPrototypeDetailSerializer(ClusterPrototypeSerializer): actions = StackActionDetailSerializer(many=True, read_only=True) config = ConfigSerializer(many=True, read_only=True) upgrade = UpgradeSerializer(many=True, read_only=True) diff --git a/python/api/stack/urls.py b/python/api/stack/urls.py index d103997ba9..2f48f101f2 100644 --- a/python/api/stack/urls.py +++ b/python/api/stack/urls.py @@ -10,6 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from django.urls import path +from rest_framework.routers import SimpleRouter + from api.stack.root import StackRoot from api.stack.views import ( ADCMPrototypeViewSet, @@ -25,8 +28,6 @@ UploadBundleView, load_servicemap_view, ) -from django.urls import path -from rest_framework.routers import SimpleRouter router = SimpleRouter() router.register("bundle", BundleViewSet) diff --git a/python/api/stack/views.py b/python/api/stack/views.py index e1e6848c8d..fbec4fe467 100644 --- a/python/api/stack/views.py +++ b/python/api/stack/views.py @@ -11,31 +11,7 @@ # limitations under the License. -from api.action.serializers import StackActionSerializer -from api.base_view import GenericUIViewSet, ModelPermOrReadOnlyForAuth -from api.stack.serializers import ( - ADCMPrototypeDetailSerializer, - ADCMPrototypeSerializer, - BundleSerializer, - BundleServiceUIPrototypeSerializer, - ClusterPrototypeDetailSerializer, - ClusterPrototypeSerializer, - ComponentPrototypeDetailSerializer, - ComponentPrototypeSerializer, - ComponentPrototypeUISerializer, - HostPrototypeDetailSerializer, - HostPrototypeSerializer, - LoadBundleSerializer, - PrototypeDetailSerializer, - PrototypeSerializer, - PrototypeUISerializer, - ProviderPrototypeDetailSerializer, - ProviderPrototypeSerializer, - ServiceDetailPrototypeSerializer, - ServicePrototypeSerializer, - UploadBundleSerializer, -) -from api.utils import check_obj +from adcm.permissions import DjangoObjectPermissionsAudit, IsAuthenticatedAudit from audit.utils import audit from cm.api import accept_license, get_license, load_service_map from cm.bundle import delete_bundle, load_bundle, update_bundle, upload_file @@ -68,7 +44,31 @@ ) from rest_framework.viewsets import ModelViewSet -from adcm.permissions import DjangoObjectPermissionsAudit, IsAuthenticatedAudit +from api.action.serializers import StackActionSerializer +from api.base_view import GenericUIViewSet, ModelPermOrReadOnlyForAuth +from api.stack.serializers import ( + ADCMPrototypeDetailSerializer, + ADCMPrototypeSerializer, + BundleSerializer, + BundleServiceUIPrototypeSerializer, + ClusterPrototypeDetailSerializer, + ClusterPrototypeSerializer, + ComponentPrototypeDetailSerializer, + ComponentPrototypeSerializer, + ComponentPrototypeUISerializer, + HostPrototypeDetailSerializer, + HostPrototypeSerializer, + LoadBundleSerializer, + PrototypeDetailSerializer, + PrototypeSerializer, + PrototypeUISerializer, + ProviderPrototypeDetailSerializer, + ProviderPrototypeSerializer, + ServiceDetailPrototypeSerializer, + ServicePrototypeSerializer, + UploadBundleSerializer, +) +from api.utils import check_obj @csrf_exempt @@ -99,7 +99,7 @@ def get_object(self): return instance - def retrieve(self, request: Request, *args, **kwargs) -> Response: + def retrieve(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 instance = self.get_object() serializer = self.get_serializer(instance) @@ -107,7 +107,7 @@ def retrieve(self, request: Request, *args, **kwargs) -> Response: class CsrfOffSessionAuthentication(SessionAuthentication): - def enforce_csrf(self, request): + def enforce_csrf(self, request): # noqa: ARG002 return @@ -120,7 +120,7 @@ class UploadBundleView(CreateModelMixin, GenericUIViewSet): ordering = ["id"] @audit - def create(self, request: Request, *args, **kwargs) -> Response: + def create(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 serializer = self.get_serializer(data=request.data) if not serializer.is_valid(): return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) @@ -136,7 +136,7 @@ class LoadBundleView(CreateModelMixin, GenericUIViewSet): ordering = ["id"] @audit - def create(self, request: Request, *args, **kwargs) -> Response: + def create(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 serializer = self.get_serializer(data=request.data) if not serializer.is_valid(): return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) @@ -146,7 +146,7 @@ def create(self, request: Request, *args, **kwargs) -> Response: ) -class BundleViewSet(ModelViewSet): # pylint: disable=too-many-ancestors +class BundleViewSet(ModelViewSet): queryset = Bundle.objects.all() serializer_class = BundleSerializer filterset_fields = ("name", "version") @@ -157,10 +157,7 @@ class BundleViewSet(ModelViewSet): # pylint: disable=too-many-ancestors ordering = ["id"] def get_permissions(self): - if self.action == "list": - permission_classes = (IsAuthenticated,) - else: - permission_classes = (ModelPermOrReadOnlyForAuth,) + permission_classes = (IsAuthenticated,) if self.action == "list" else (ModelPermOrReadOnlyForAuth,) return [permission() for permission in permission_classes] @@ -171,7 +168,7 @@ def get_queryset(self): return super().get_queryset() @audit - def destroy(self, request, *args, **kwargs) -> Response: + def destroy(self, request, *args, **kwargs) -> Response: # noqa: ARG002 bundle = self.get_object() delete_bundle(bundle) @@ -179,7 +176,7 @@ def destroy(self, request, *args, **kwargs) -> Response: @audit @action(methods=["put"], detail=True) - def update_bundle(self, request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def update_bundle(self, request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 bundle = check_obj(Bundle, kwargs["bundle_pk"], "BUNDLE_NOT_FOUND") update_bundle(bundle) serializer = self.get_serializer(bundle) @@ -188,7 +185,7 @@ def update_bundle(self, request, *args, **kwargs) -> Response: # pylint: disabl @staticmethod @action(methods=["get"], detail=True) - def license(request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def license(request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002, ARG004 bundle = check_obj(Bundle, kwargs["bundle_pk"], "BUNDLE_NOT_FOUND") proto = Prototype.objects.filter(bundle=bundle, name=bundle.name).first() body = get_license(proto) @@ -198,7 +195,7 @@ def license(request, *args, **kwargs) -> Response: # pylint: disable=unused-arg @audit @action(methods=["put"], detail=True) - def accept_license(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def accept_license(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 # self is necessary for audit bundle = check_obj(Bundle, kwargs["bundle_pk"], "BUNDLE_NOT_FOUND") @@ -208,7 +205,6 @@ def accept_license(self, request: Request, *args, **kwargs) -> Response: # pyli return Response() -# pylint:disable-next=too-many-ancestors class PrototypeViewSet(ListModelMixin, PrototypeRetrieveViewSet): queryset = Prototype.objects.all() serializer_class = PrototypeSerializer @@ -218,11 +214,7 @@ class PrototypeViewSet(ListModelMixin, PrototypeRetrieveViewSet): ordering = ["id"] def get_permissions(self): - if self.action == "list": - permission_classes = (IsAuthenticated,) - else: - permission_classes = (ModelPermOrReadOnlyForAuth,) - + permission_classes = (IsAuthenticated,) if self.action == "list" else (ModelPermOrReadOnlyForAuth,) return [permission() for permission in permission_classes] def get_serializer_class(self): @@ -235,7 +227,7 @@ def get_serializer_class(self): @staticmethod @action(methods=["get"], detail=True) - def license(request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def license(request: Request, *args, **kwargs) -> Response: # noqa: ARG002, ARG004 prototype = check_obj(Prototype, kwargs["prototype_pk"], "PROTOTYPE_NOT_FOUND") body = get_license(prototype) url = reverse(viewname="v1:accept-license", kwargs={"prototype_pk": prototype.pk}, request=request) @@ -244,7 +236,7 @@ def license(request: Request, *args, **kwargs) -> Response: # pylint: disable=u @audit @action(methods=["put"], detail=True) - def accept_license(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def accept_license(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 # self is necessary for audit prototype = check_obj(Prototype, kwargs["prototype_pk"], "PROTOTYPE_NOT_FOUND") @@ -259,7 +251,7 @@ class ProtoActionViewSet(RetrieveModelMixin, GenericUIViewSet): lookup_url_kwarg = "action_pk" ordering = ["id"] - def retrieve(self, request: Request, *args, **kwargs) -> Response: + def retrieve(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 obj = check_obj(Action, kwargs["action_pk"], "ACTION_NOT_FOUND") serializer = self.get_serializer(obj) @@ -283,7 +275,7 @@ def get_serializer_class(self): return super().get_serializer_class() - def retrieve(self, request, *args, **kwargs) -> Response: + def retrieve(self, request, *args, **kwargs) -> Response: # noqa: ARG002 instance = self.get_object() instance.actions = Action.objects.filter(prototype__type="service", prototype__pk=instance.pk) instance.components = Prototype.objects.filter(parent=instance, type="component") @@ -295,7 +287,7 @@ def retrieve(self, request, *args, **kwargs) -> Response: return Response(serializer.data) @action(methods=["get"], detail=True) - def actions(self, request: Request, prototype_pk: int) -> Response: # pylint: disable=unused-argument + def actions(self, request: Request, prototype_pk: int) -> Response: # noqa: ARG001, ARG002 return Response( StackActionSerializer( Action.objects.filter(prototype__type="service", prototype_id=prototype_pk), @@ -304,7 +296,6 @@ def actions(self, request: Request, prototype_pk: int) -> Response: # pylint: d ) -# pylint:disable-next=too-many-ancestors class ComponentPrototypeViewSet(ListModelMixin, PrototypeRetrieveViewSet): queryset = Prototype.objects.filter(type="component") serializer_class = ComponentPrototypeSerializer @@ -321,7 +312,6 @@ def get_serializer_class(self): return super().get_serializer_class() -# pylint:disable-next=too-many-ancestors class ProviderPrototypeViewSet(ListModelMixin, PrototypeRetrieveViewSet): queryset = Prototype.objects.filter(type="provider") serializer_class = ProviderPrototypeSerializer @@ -337,7 +327,6 @@ def get_serializer_class(self): return super().get_serializer_class() -# pylint:disable-next=too-many-ancestors class HostPrototypeViewSet(ListModelMixin, PrototypeRetrieveViewSet): queryset = Prototype.objects.filter(type="host") serializer_class = HostPrototypeSerializer @@ -352,7 +341,6 @@ def get_serializer_class(self): return super().get_serializer_class() -# pylint:disable-next=too-many-ancestors class ClusterPrototypeViewSet(ListModelMixin, PrototypeRetrieveViewSet): queryset = Prototype.objects.filter(type="cluster") serializer_class = ClusterPrototypeSerializer @@ -367,7 +355,6 @@ def get_serializer_class(self): return super().get_serializer_class() -# pylint:disable-next=too-many-ancestors class ADCMPrototypeViewSet(ListModelMixin, PrototypeRetrieveViewSet): queryset = Prototype.objects.filter(type="adcm") serializer_class = ADCMPrototypeSerializer diff --git a/python/api/stats/serializers.py b/python/api/stats/serializers.py index 6340245d2a..3b5890a2b7 100644 --- a/python/api/stats/serializers.py +++ b/python/api/stats/serializers.py @@ -10,9 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rest_framework.serializers import IntegerField - from adcm.serializers import EmptySerializer +from rest_framework.serializers import IntegerField class StatsSerializer(EmptySerializer): diff --git a/python/api/stats/urls.py b/python/api/stats/urls.py index 29c6942f40..b09d10aac8 100644 --- a/python/api/stats/urls.py +++ b/python/api/stats/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +from django.urls import path + from api.stats.root import StatsRoot from api.stats.views import JobStats, TaskStats -from django.urls import path urlpatterns = [ path("", StatsRoot.as_view(), {"pk": 0}, name="stats"), diff --git a/python/api/stats/views.py b/python/api/stats/views.py index a98317b1c2..673cdc3321 100644 --- a/python/api/stats/views.py +++ b/python/api/stats/views.py @@ -10,13 +10,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api.base_view import GenericUIView -from api.stats.serializers import StatsSerializer from cm.models import JobLog, JobStatus, TaskLog from guardian.mixins import PermissionListMixin from rest_framework import permissions from rest_framework.response import Response +from api.base_view import GenericUIView +from api.stats.serializers import StatsSerializer + class JobStats(PermissionListMixin, GenericUIView): queryset = JobLog.objects.all() @@ -25,7 +26,7 @@ class JobStats(PermissionListMixin, GenericUIView): permission_required = ["cm.view_joblog"] ordering = ["id"] - def get(self, request, pk): # pylint: disable=unused-argument + def get(self, request, pk): # noqa: ARG002 jobs = self.get_queryset().filter(id__gt=pk) return Response( @@ -47,7 +48,7 @@ class TaskStats(PermissionListMixin, GenericUIView): permission_required = ["cm.view_tasklog"] ordering = ["id"] - def get(self, request, pk): # pylint: disable=unused-argument + def get(self, request, pk): # noqa: ARG001, ARG002 tasks = self.get_queryset().filter(id__gt=pk) return Response( diff --git a/python/api/tests/test_action.py b/python/api/tests/test_action.py index cc34fe93b3..a93fd75fa7 100644 --- a/python/api/tests/test_action.py +++ b/python/api/tests/test_action.py @@ -12,6 +12,7 @@ from pathlib import Path +from adcm.tests.base import BaseTestCase from cm.models import ( ADCM, Action, @@ -27,8 +28,6 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_409_CONFLICT -from adcm.tests.base import BaseTestCase - class TestActionAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_adcm.py b/python/api/tests/test_adcm.py index ee57abe1e2..1d2561a8cd 100644 --- a/python/api/tests/test_adcm.py +++ b/python/api/tests/test_adcm.py @@ -10,13 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import ADCM, ConcernItem from django.urls import reverse from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.tests.base import BaseTestCase - class TestADCM(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_adcm_cluster_prototype.py b/python/api/tests/test_adcm_cluster_prototype.py index 10b620b396..7758282674 100644 --- a/python/api/tests/test_adcm_cluster_prototype.py +++ b/python/api/tests/test_adcm_cluster_prototype.py @@ -10,12 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import Bundle, Prototype from django.urls import reverse from rest_framework.response import Response -from adcm.tests.base import BaseTestCase - class TestPrototypeAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_api.py b/python/api/tests/test_api.py index 819e0cff8a..272d1d887b 100755 --- a/python/api/tests/test_api.py +++ b/python/api/tests/test_api.py @@ -9,11 +9,11 @@ # 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. -# pylint: disable=too-many-lines from unittest.mock import patch from uuid import uuid4 +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.api import save_hc from cm.hierarchy import Tree from cm.issue import lock_affected_objects @@ -51,8 +51,6 @@ HTTP_409_CONFLICT, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase - class TestAPI(BaseTestCase): def setUp(self) -> None: @@ -498,7 +496,7 @@ def test_cluster_service(self): self.assertEqual(response.status_code, HTTP_204_NO_CONTENT) - def test_hostcomponent(self): # pylint: disable=too-many-statements,too-many-locals + def test_hostcomponent(self): self.upload_and_load_bundle(path=self.test_files_dir / self.bundle_adh_name) self.upload_and_load_bundle(path=self.test_files_dir / self.bundle_ssh_name) @@ -680,7 +678,7 @@ def test_hostcomponent(self): # pylint: disable=too-many-statements,too-many-lo self.assertEqual(response.status_code, HTTP_409_CONFLICT) self.assertEqual(response.json()["code"], "BUNDLE_CONFLICT") - def test_config(self): # pylint: disable=too-many-statements + def test_config(self): self.upload_and_load_bundle(path=self.test_files_dir / self.bundle_adh_name) adh_bundle_id, proto_id = self.get_cluster_proto_id() service_proto_id = self.get_service_proto_id() @@ -837,45 +835,39 @@ class TestAPI2(BaseTestCase): def setUp(self): gen_adcm() self.bundle = Bundle.objects.create( - **{ - "name": "ADB", - "version": "2.5", - "version_order": 4, - "edition": "community", - "hash": "2232f33c6259d44c23046fce4382f16c450f8ba5", - "description": "", - "date": timezone.now(), - }, + name="ADB", + version="2.5", + version_order=4, + edition="community", + hash="2232f33c6259d44c23046fce4382f16c450f8ba5", + description="", + date=timezone.now(), ) self.prototype = Prototype.objects.create( - **{ - "bundle_id": self.bundle.id, - "type": "cluster", - "name": "ADB", - "display_name": "ADB", - "version": "2.5", - "license": "absent", - "license_path": None, - "license_hash": None, - "version_order": 11, - "required": False, - "shared": False, - "adcm_min_version": None, - "monitoring": "active", - "description": "", - }, - ) - self.object_config = ObjectConfig.objects.create(**{"current": 0, "previous": 0}) + bundle_id=self.bundle.id, + type="cluster", + name="ADB", + display_name="ADB", + version="2.5", + license="absent", + license_path=None, + license_hash=None, + version_order=11, + required=False, + shared=False, + adcm_min_version=None, + monitoring="active", + description="", + ) + self.object_config = ObjectConfig.objects.create(current=0, previous=0) self.cluster = Cluster.objects.create( - **{ - "prototype_id": self.prototype.id, - "name": "Fear Limpopo", - "description": "", - "config_id": self.object_config.id, - "state": "installed", - }, + prototype_id=self.prototype.id, + name="Fear Limpopo", + description="", + config_id=self.object_config.id, + state="installed", ) @patch("cm.api.load_service_map") @@ -915,10 +907,10 @@ def test_save_hc(self, mock_update_issues, mock_load_service_map): @patch("cm.api.update_hierarchy_issues") def test_save_hc__big_update__locked_hierarchy( self, - mock_issue, - mock_load, + mock_issue, # noqa: ARG002 + mock_load, # noqa: ARG002 ctx, - ): # pylint: disable=unused-argument + ): """ Update bigger HC map - move `component_2` from `host_2` to `host_3` On locked hierarchy (from ansible task) @@ -970,7 +962,7 @@ def test_save_hc__big_update__locked_hierarchy( @patch("cm.api.load_service_map") @patch("cm.api.update_hierarchy_issues") - def test_save_hc__big_update__unlocked_hierarchy(self, mock_update, mock_load): # pylint: disable=unused-argument + def test_save_hc__big_update__unlocked_hierarchy(self, mock_update, mock_load): # noqa: ARG001, ARG002 """ Update bigger HC map - move `component_2` from `host_2` to `host_3` On unlocked hierarchy (from API) diff --git a/python/api/tests/test_bundle.py b/python/api/tests/test_bundle.py index fe977323de..8b3bee8c17 100644 --- a/python/api/tests/test_bundle.py +++ b/python/api/tests/test_bundle.py @@ -13,18 +13,15 @@ from pathlib import Path from unittest.mock import patch +from adcm.tests.base import BaseTestCase from cm.models import Bundle, Prototype from django.conf import settings from django.urls import reverse from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_409_CONFLICT -from adcm.tests.base import BaseTestCase - class TestBundle(BaseTestCase): - # pylint: disable=too-many-public-methods - def setUp(self) -> None: super().setUp() diff --git a/python/api/tests/test_cluster.py b/python/api/tests/test_cluster.py index 48119ff4bb..4bcae13b63 100644 --- a/python/api/tests/test_cluster.py +++ b/python/api/tests/test_cluster.py @@ -10,6 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import ( Action, ActionType, @@ -23,8 +24,6 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.tests.base import BaseTestCase - class TestClusterAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_cluster_prototype.py b/python/api/tests/test_cluster_prototype.py index df758513e5..23d5c1c4c5 100644 --- a/python/api/tests/test_cluster_prototype.py +++ b/python/api/tests/test_cluster_prototype.py @@ -10,12 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import Action, ActionType, Bundle, Prototype from django.urls import reverse from rest_framework.response import Response -from adcm.tests.base import BaseTestCase - class TestClusterPrototypeAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_component.py b/python/api/tests/test_component.py index 2d429c78cb..93a602494f 100644 --- a/python/api/tests/test_component.py +++ b/python/api/tests/test_component.py @@ -13,6 +13,7 @@ from pathlib import Path from unittest.mock import patch +from adcm.tests.base import BaseTestCase from cm.job import ActionRunPayload from cm.models import ( Action, @@ -30,8 +31,6 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_409_CONFLICT -from adcm.tests.base import BaseTestCase - class TestComponentAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_component_prototype.py b/python/api/tests/test_component_prototype.py index 33b0f09623..21205ec02c 100644 --- a/python/api/tests/test_component_prototype.py +++ b/python/api/tests/test_component_prototype.py @@ -10,12 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import Action, ActionType, Bundle, Prototype from django.urls import reverse from rest_framework.response import Response -from adcm.tests.base import BaseTestCase - class TestComponentPrototypeAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_config.py b/python/api/tests/test_config.py index b22c632ee4..a20ed596df 100644 --- a/python/api/tests/test_config.py +++ b/python/api/tests/test_config.py @@ -13,14 +13,13 @@ from copy import deepcopy from pathlib import Path +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.adcm_config.ansible import ansible_decrypt from cm.models import ADCM, ConfigLog from django.urls import reverse from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_400_BAD_REQUEST -from adcm.tests.base import APPLICATION_JSON, BaseTestCase - class TestConfigPasswordAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_host.py b/python/api/tests/test_host.py index cf3ad1cc63..05f9b5ab35 100644 --- a/python/api/tests/test_host.py +++ b/python/api/tests/test_host.py @@ -13,6 +13,7 @@ from pathlib import Path from unittest.mock import patch +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.job import ActionRunPayload from cm.models import ( Action, @@ -31,8 +32,6 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_409_CONFLICT -from adcm.tests.base import APPLICATION_JSON, BaseTestCase - class TestHostAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_host_prototype.py b/python/api/tests/test_host_prototype.py index cb99e2d3ce..9aaf29631a 100644 --- a/python/api/tests/test_host_prototype.py +++ b/python/api/tests/test_host_prototype.py @@ -10,12 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import Action, ActionType, Bundle, Prototype from django.urls import reverse from rest_framework.response import Response -from adcm.tests.base import BaseTestCase - class TestComponentPrototypeAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_hostcomponent.py b/python/api/tests/test_hostcomponent.py index a9cd97d073..a43c2627dc 100644 --- a/python/api/tests/test_hostcomponent.py +++ b/python/api/tests/test_hostcomponent.py @@ -12,13 +12,12 @@ from pathlib import Path +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import HostComponent, ObjectType, Prototype, ServiceComponent from django.urls import reverse from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.tests.base import APPLICATION_JSON, BaseTestCase - class TestHostComponentOrdering(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_job.py b/python/api/tests/test_job.py index 15524cc5d0..52d1be7964 100644 --- a/python/api/tests/test_job.py +++ b/python/api/tests/test_job.py @@ -14,6 +14,7 @@ from pathlib import Path from unittest.mock import patch +from adcm.tests.base import BaseTestCase from cm.models import ADCM, Action, ActionType, Cluster, JobLog, Prototype, TaskLog from django.contrib.contenttypes.models import ContentType from django.urls import reverse @@ -22,8 +23,6 @@ from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED -from adcm.tests.base import BaseTestCase - class TestJobAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_log_storage.py b/python/api/tests/test_log_storage.py index 04edefdb82..055ea55de8 100644 --- a/python/api/tests/test_log_storage.py +++ b/python/api/tests/test_log_storage.py @@ -12,14 +12,13 @@ from datetime import timedelta +from adcm.tests.base import BaseTestCase from cm.models import JobLog, LogStorage from django.urls import reverse from django.utils import timezone from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_404_NOT_FOUND -from adcm.tests.base import BaseTestCase - class TestTaskAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_provider_prototype.py b/python/api/tests/test_provider_prototype.py index 3989ae28b2..15c461542b 100644 --- a/python/api/tests/test_provider_prototype.py +++ b/python/api/tests/test_provider_prototype.py @@ -10,12 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import Action, ActionType, Bundle, Prototype from django.urls import reverse from rest_framework.response import Response -from adcm.tests.base import BaseTestCase - class TestProviderPrototypeAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_service.py b/python/api/tests/test_service.py index af4ed536d2..4f24c9f06a 100644 --- a/python/api/tests/test_service.py +++ b/python/api/tests/test_service.py @@ -13,6 +13,7 @@ from pathlib import Path from unittest.mock import patch +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.job import ActionRunPayload from cm.models import ( Action, @@ -37,8 +38,6 @@ HTTP_409_CONFLICT, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase - class TestServiceAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_service_prototype.py b/python/api/tests/test_service_prototype.py index 73d40c9e2f..8603a0c85a 100644 --- a/python/api/tests/test_service_prototype.py +++ b/python/api/tests/test_service_prototype.py @@ -10,12 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import Action, ActionType, Bundle, Prototype from django.urls import reverse from rest_framework.response import Response -from adcm.tests.base import BaseTestCase - class TestServicePrototypeAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/tests/test_stack.py b/python/api/tests/test_stack.py index 8b0274bc0b..16765b2f37 100644 --- a/python/api/tests/test_stack.py +++ b/python/api/tests/test_stack.py @@ -12,13 +12,12 @@ from pathlib import Path +from adcm.tests.base import BaseTestCase from cm.models import Prototype from django.urls import reverse from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.tests.base import BaseTestCase - class TestPrototypeAPI(BaseTestCase): def test_cluster_prototype_retrieve_success(self): diff --git a/python/api/tests/test_task.py b/python/api/tests/test_task.py index 82258e5549..6112c48f4c 100644 --- a/python/api/tests/test_task.py +++ b/python/api/tests/test_task.py @@ -13,6 +13,7 @@ from datetime import timedelta from unittest.mock import patch +from adcm.tests.base import BaseTestCase from cm.models import ( ADCM, Action, @@ -29,8 +30,6 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.tests.base import BaseTestCase - class TestTaskAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api/urls.py b/python/api/urls.py index 603168343b..a13b70fd8f 100644 --- a/python/api/urls.py +++ b/python/api/urls.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api import docs, views from django.urls import include, path, register_converter from rbac.endpoints import token from rest_framework.authentication import SessionAuthentication, TokenAuthentication @@ -23,6 +22,8 @@ from rest_framework.schemas.coreapi import SchemaGenerator from rest_framework.schemas.views import SchemaView +from api import docs, views + register_converter(views.NameConverter, "name") generator = SchemaGenerator(title="ArenaData Chapel API", patterns=[path("api/v1/", include("api.urls"))]) authentication_classes = (SessionAuthentication, TokenAuthentication) diff --git a/python/api/utils.py b/python/api/utils.py index 481d47b1d6..274e62d809 100644 --- a/python/api/utils.py +++ b/python/api/utils.py @@ -19,12 +19,8 @@ from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_400_BAD_REQUEST -def check_obj(model, req, error=None): # pylint: disable=unused-argument - if isinstance(req, dict): - kwargs = req - else: - kwargs = {"id": req} - +def check_obj(model, req, error=None): # noqa: ARG001 + kwargs = req if isinstance(req, dict) else {"id": req} return model.obj.get(**kwargs) @@ -52,10 +48,7 @@ def update(serializer, **kwargs): def get_api_url_kwargs(obj, request, no_obj_type=False): obj_type = obj.prototype.type - if obj_type == "adcm": - kwargs = {"adcm_pk": obj.pk} - else: - kwargs = {f"{obj_type}_id": obj.id} + kwargs = {"adcm_pk": obj.pk} if obj_type == "adcm" else {f"{obj_type}_id": obj.id} # Do not include object_type in kwargs if no_obj_type == True if not no_obj_type: @@ -92,9 +85,8 @@ def fix_ordering(field, view): if view.__class__.__name__ not in ("BundleList",): fix = fix.replace("version", "version_order") - if view.__class__.__name__ in ["ServiceListView", "ComponentListView"]: - if "display_name" in fix: - fix = fix.replace("display_name", "prototype__display_name") + if view.__class__.__name__ in ["ServiceListView", "ComponentListView"] and "display_name" in fix: + fix = fix.replace("display_name", "prototype__display_name") return fix @@ -114,10 +106,10 @@ def get_url(self, obj, view_name, request, _format): class UrlField(HyperlinkedIdentityField): - def get_kwargs(self, obj): # pylint: disable=unused-argument + def get_kwargs(self, obj): # noqa: ARG002 return {} - def get_url(self, obj, view_name, request, _format): + def get_url(self, obj, view_name, request, _format): # noqa: ARG002 kwargs = self.get_kwargs(obj) return reverse(self.view_name, kwargs=kwargs, request=request, format=_format) diff --git a/python/api/views.py b/python/api/views.py index c4df318997..d5c189b157 100644 --- a/python/api/views.py +++ b/python/api/views.py @@ -10,6 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.utils import has_google_oauth, has_yandex_oauth from cm.stack import NAME_REGEX from django.conf import settings from rest_framework.permissions import AllowAny @@ -18,8 +19,6 @@ from rest_framework.schemas.coreapi import AutoSchema from rest_framework.views import APIView -from adcm.utils import has_google_oauth, has_yandex_oauth - class APIRoot(APIRootView): permission_classes = (AllowAny,) @@ -62,7 +61,7 @@ class ADCMInfo(APIView): schema = AutoSchema() @staticmethod - def get(request): # pylint: disable=unused-argument + def get(request): # noqa: ARG004 return Response( { "adcm_version": settings.ADCM_VERSION, diff --git a/python/api_ui/stack/serializers.py b/python/api_ui/stack/serializers.py index 2c2b62fa56..b829347a9a 100644 --- a/python/api_ui/stack/serializers.py +++ b/python/api_ui/stack/serializers.py @@ -10,11 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.serializers import EmptySerializer from cm.models import Prototype from rest_framework.serializers import CharField, IntegerField, SerializerMethodField -from adcm.serializers import EmptySerializer - class PrototypeVersionSerializer(EmptySerializer): prototype_id = IntegerField(source="pk") diff --git a/python/api_ui/stack/urls.py b/python/api_ui/stack/urls.py index 7f2843550a..3f33fbdfdd 100644 --- a/python/api_ui/stack/urls.py +++ b/python/api_ui/stack/urls.py @@ -10,11 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_ui.stack.root import StackUIRoot -from api_ui.stack.views import ClusterPrototypeUIViewSet, ProviderPrototypeUIViewSet from django.urls import path from rest_framework.routers import SimpleRouter +from api_ui.stack.root import StackUIRoot +from api_ui.stack.views import ClusterPrototypeUIViewSet, ProviderPrototypeUIViewSet + router = SimpleRouter() router.register("cluster", ClusterPrototypeUIViewSet, basename="cluster") router.register("provider", ProviderPrototypeUIViewSet, basename="provider") diff --git a/python/api_ui/stack/views.py b/python/api_ui/stack/views.py index 1c40af56ca..dc4b906ec5 100644 --- a/python/api_ui/stack/views.py +++ b/python/api_ui/stack/views.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_ui.stack.serializers import PrototypeUISerializer from cm.models import ObjectType, Prototype from django.db.models.query import QuerySet from rest_framework.mixins import ListModelMixin @@ -18,6 +17,8 @@ from rest_framework.schemas.coreapi import AutoSchema from rest_framework.viewsets import GenericViewSet +from api_ui.stack.serializers import PrototypeUISerializer + class PrototypeUIViewMixin: @staticmethod diff --git a/python/api_ui/tests/test_stack.py b/python/api_ui/tests/test_stack.py index aeb30b84e0..f769d49922 100644 --- a/python/api_ui/tests/test_stack.py +++ b/python/api_ui/tests/test_stack.py @@ -10,13 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import Bundle, ObjectType, Prototype from django.urls import reverse from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.tests.base import BaseTestCase - class TestStackClusterPrototypeUIAPI(BaseTestCase): def setUp(self) -> None: diff --git a/python/api_ui/urls.py b/python/api_ui/urls.py index 1ba32255f5..1ac4f3be71 100644 --- a/python/api_ui/urls.py +++ b/python/api_ui/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_ui import views from django.urls import include, path +from api_ui import views + urlpatterns = [ path("", views.APIRoot.as_view()), path("rbac/", include(("rbac.urls_ui", "rbac"), namespace="rbac-ui")), diff --git a/python/api_v2/action/serializers.py b/python/api_v2/action/serializers.py index 7c3ba3760a..32196c99b2 100644 --- a/python/api_v2/action/serializers.py +++ b/python/api_v2/action/serializers.py @@ -9,6 +9,7 @@ # 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. +from adcm.serializers import EmptySerializer from cm.models import Action from rest_framework.fields import IntegerField from rest_framework.serializers import ( @@ -20,8 +21,6 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer - class ActionListSerializer(ModelSerializer): start_impossible_reason = SerializerMethodField() diff --git a/python/api_v2/action/utils.py b/python/api_v2/action/utils.py index 5ef80c1e6d..1c8ef1ff79 100644 --- a/python/api_v2/action/utils.py +++ b/python/api_v2/action/utils.py @@ -9,13 +9,13 @@ # 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 json from collections import defaultdict from hashlib import sha256 from itertools import compress from typing import Iterable, Iterator, List, Literal +import json -from api_v2.config.utils import convert_attr_to_adcm_meta, get_config_schema +from adcm.permissions import RUN_ACTION_PERM_PREFIX from cm.adcm_config.config import get_default from cm.models import ( Action, @@ -31,7 +31,7 @@ from jinja_config import get_jinja_config from rbac.models import User -from adcm.permissions import RUN_ACTION_PERM_PREFIX +from api_v2.config.utils import convert_attr_to_adcm_meta, get_config_schema def get_str_hash(value: str) -> str: @@ -53,7 +53,7 @@ def check_run_perms(user: User, action: Action, obj: ADCMEntity) -> bool: def insert_service_ids( - hc_create_data: List[dict[Literal["host_id", "component_id"], int]] + hc_create_data: List[dict[Literal["host_id", "component_id"], int]], ) -> List[dict[Literal["host_id", "component_id", "service_id"], int]]: component_ids = {single_hc["component_id"] for single_hc in hc_create_data} component_service_map = { diff --git a/python/api_v2/action/views.py b/python/api_v2/action/views.py index d3266f25c4..52ddce0cd9 100644 --- a/python/api_v2/action/views.py +++ b/python/api_v2/action/views.py @@ -12,21 +12,7 @@ from itertools import compress -from api_v2.action.filters import ActionFilter -from api_v2.action.serializers import ( - ActionListSerializer, - ActionRetrieveSerializer, - ActionRunSerializer, -) -from api_v2.action.utils import ( - check_run_perms, - filter_actions_by_user_perm, - get_action_configuration, - insert_service_ids, -) -from api_v2.config.utils import convert_adcm_meta_to_attr, represent_string_as_json_type -from api_v2.task.serializers import TaskListSerializer -from api_v2.views import CamelCaseGenericViewSet +from adcm.mixins import GetParentObjectMixin from audit.utils import audit from cm.errors import AdcmEx from cm.job import ActionRunPayload, run_action @@ -44,17 +30,29 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.mixins import GetParentObjectMixin +from api_v2.action.filters import ActionFilter +from api_v2.action.serializers import ( + ActionListSerializer, + ActionRetrieveSerializer, + ActionRunSerializer, +) +from api_v2.action.utils import ( + check_run_perms, + filter_actions_by_user_perm, + get_action_configuration, + insert_service_ids, +) +from api_v2.config.utils import convert_adcm_meta_to_attr, represent_string_as_json_type +from api_v2.task.serializers import TaskListSerializer +from api_v2.views import CamelCaseGenericViewSet -class ActionViewSet( # pylint: disable=too-many-ancestors - ListModelMixin, RetrieveModelMixin, GetParentObjectMixin, CamelCaseGenericViewSet -): +class ActionViewSet(ListModelMixin, RetrieveModelMixin, GetParentObjectMixin, CamelCaseGenericViewSet): filter_backends = (DjangoFilterBackend,) filterset_class = ActionFilter - def get_queryset(self, *args, **kwargs): # pylint: disable=unused-argument - self.parent_object = self.get_parent_object() # pylint: disable=attribute-defined-outside-init + def get_queryset(self, *args, **kwargs): # noqa: ARG002 + self.parent_object = self.get_parent_object() if self.parent_object is None or not self.request.user.has_perm( f"cm.view_{self.parent_object.__class__.__name__.lower()}", self.parent_object @@ -64,7 +62,7 @@ def get_queryset(self, *args, **kwargs): # pylint: disable=unused-argument if self.parent_object.concerns.filter(type=ConcernType.LOCK).exists(): return Action.objects.none() - self.prototype_objects = {} # pylint: disable=attribute-defined-outside-init + self.prototype_objects = {} if isinstance(self.parent_object, Host) and self.parent_object.cluster: self.prototype_objects[self.parent_object.cluster.prototype] = self.parent_object.cluster @@ -102,7 +100,7 @@ def get_serializer_class( return ActionListSerializer - def list(self, request: Request, *args, **kwargs) -> Response: + def list(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 actions = self.filter_queryset(self.get_queryset()) allowed_actions_mask = [act.allowed(self.prototype_objects[act.prototype]) for act in actions] actions = list(compress(actions, allowed_actions_mask)) @@ -112,7 +110,7 @@ def list(self, request: Request, *args, **kwargs) -> Response: return Response(data=serializer.data) - def retrieve(self, request, *args, **kwargs): + def retrieve(self, request, *args, **kwargs): # noqa: ARG002 action_ = self.get_object() config_schema, config, adcm_meta = get_action_configuration(action_=action_, object_=self.parent_object) @@ -131,7 +129,7 @@ def retrieve(self, request, *args, **kwargs): @audit @action(methods=["post"], detail=True, url_path="run") - def run(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def run(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 target_action = self.get_object() if reason := target_action.get_start_impossible_reason(self.parent_object): @@ -181,6 +179,6 @@ def run(self, request: Request, *args, **kwargs) -> Response: # pylint: disable return Response(status=HTTP_200_OK, data=TaskListSerializer(instance=task).data) -class AdcmActionViewSet(ActionViewSet): # pylint: disable=too-many-ancestors +class AdcmActionViewSet(ActionViewSet): def get_parent_object(self): return ADCM.objects.first() diff --git a/python/api_v2/adcm/serializers.py b/python/api_v2/adcm/serializers.py index 7cf2562269..334e4f3e1d 100644 --- a/python/api_v2/adcm/serializers.py +++ b/python/api_v2/adcm/serializers.py @@ -10,11 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.concern.serializers import ConcernSerializer -from api_v2.prototype.serializers import PrototypeRelatedSerializer from cm.models import ADCM from rest_framework.serializers import ModelSerializer +from api_v2.concern.serializers import ConcernSerializer +from api_v2.prototype.serializers import PrototypeRelatedSerializer + class AdcmSerializer(ModelSerializer): prototype = PrototypeRelatedSerializer(read_only=True) diff --git a/python/api_v2/adcm/urls.py b/python/api_v2/adcm/urls.py index 1d06055645..575aa4194e 100644 --- a/python/api_v2/adcm/urls.py +++ b/python/api_v2/adcm/urls.py @@ -9,9 +9,10 @@ # 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. +from django.urls import path + from api_v2.action.views import AdcmActionViewSet from api_v2.adcm.views import ADCMConfigView, ADCMViewSet -from django.urls import path urlpatterns = [ path("", ADCMViewSet.as_view({"get": "retrieve"}), name="adcm-detail"), diff --git a/python/api_v2/adcm/views.py b/python/api_v2/adcm/views.py index 4a24561a4d..443875c446 100644 --- a/python/api_v2/adcm/views.py +++ b/python/api_v2/adcm/views.py @@ -9,27 +9,28 @@ # 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. -from api_v2.adcm.serializers import AdcmSerializer -from api_v2.config.utils import get_config_schema -from api_v2.config.views import ConfigLogViewSet -from api_v2.views import CamelCaseGenericViewSet from cm.models import ADCM, ConfigLog, PrototypeConfig from rest_framework.decorators import action from rest_framework.mixins import RetrieveModelMixin from rest_framework.response import Response from rest_framework.status import HTTP_200_OK +from api_v2.adcm.serializers import AdcmSerializer +from api_v2.config.utils import get_config_schema +from api_v2.config.views import ConfigLogViewSet +from api_v2.views import CamelCaseGenericViewSet + class ADCMViewSet(RetrieveModelMixin, CamelCaseGenericViewSet): queryset = ADCM.objects.prefetch_related("concerns").all() serializer_class = AdcmSerializer - def get_object(self, *args, **kwargs): # pylint: disable=unused-argument + def get_object(self, *args, **kwargs): # noqa: ARG001, ARG002 return super().get_queryset().first() -class ADCMConfigView(ConfigLogViewSet): # pylint: disable=too-many-ancestors - def get_queryset(self, *args, **kwargs): +class ADCMConfigView(ConfigLogViewSet): + def get_queryset(self, *args, **kwargs): # noqa: ARG002 return ( ConfigLog.objects.select_related("obj_ref__adcm__prototype") .filter(obj_ref__adcm__isnull=False) @@ -40,7 +41,7 @@ def get_parent_object(self) -> ADCM | None: return ADCM.objects.first() @action(methods=["get"], detail=True, url_path="config-schema", url_name="config-schema") - def config_schema(self, request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def config_schema(self, request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 instance = self.get_parent_object() schema = get_config_schema( object_=instance, diff --git a/python/api_v2/audit/urls.py b/python/api_v2/audit/urls.py index 51e9ab1272..193ae1c964 100644 --- a/python/api_v2/audit/urls.py +++ b/python/api_v2/audit/urls.py @@ -9,11 +9,12 @@ # 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. -from api_v2.audit.views import AuditLogViewSet, AuditSessionViewSet from audit.views import AuditRoot from django.urls import path from rest_framework.routers import SimpleRouter +from api_v2.audit.views import AuditLogViewSet, AuditSessionViewSet + router = SimpleRouter() router.register("operations", AuditLogViewSet) router.register("logins", AuditSessionViewSet) diff --git a/python/api_v2/audit/views.py b/python/api_v2/audit/views.py index 46b4af85a8..5ef5af284b 100644 --- a/python/api_v2/audit/views.py +++ b/python/api_v2/audit/views.py @@ -10,16 +10,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.audit.filters import AuditLogFilterSet, AuditSessionFilterSet -from api_v2.audit.serializers import AuditLogSerializer, AuditSessionSerializer -from api_v2.views import CamelCaseReadOnlyModelViewSet from audit.models import AuditLog, AuditSession from django_filters.rest_framework.backends import DjangoFilterBackend from guardian.mixins import PermissionListMixin from rest_framework.permissions import DjangoObjectPermissions +from api_v2.audit.filters import AuditLogFilterSet, AuditSessionFilterSet +from api_v2.audit.serializers import AuditLogSerializer, AuditSessionSerializer +from api_v2.views import CamelCaseReadOnlyModelViewSet + -# pylint: disable=too-many-ancestors class AuditSessionViewSet(PermissionListMixin, CamelCaseReadOnlyModelViewSet): queryset = AuditSession.objects.select_related("user").order_by("-login_time") serializer_class = AuditSessionSerializer diff --git a/python/api_v2/bundle/serializers.py b/python/api_v2/bundle/serializers.py index a810b74993..87698eecc3 100644 --- a/python/api_v2/bundle/serializers.py +++ b/python/api_v2/bundle/serializers.py @@ -9,7 +9,7 @@ # 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. -from api_v2.prototype.utils import get_license_text +from adcm.serializers import EmptySerializer from cm.models import Bundle, HostProvider, ObjectType, Prototype from rest_framework.fields import ( CharField, @@ -20,7 +20,7 @@ ) from rest_framework.serializers import ModelSerializer -from adcm.serializers import EmptySerializer +from api_v2.prototype.utils import get_license_text class BundleRelatedSerializer(ModelSerializer): diff --git a/python/api_v2/bundle/urls.py b/python/api_v2/bundle/urls.py index 78e5ee8122..e98afd80d6 100644 --- a/python/api_v2/bundle/urls.py +++ b/python/api_v2/bundle/urls.py @@ -9,9 +9,10 @@ # 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. -from api_v2.bundle.views import BundleViewSet from rest_framework.routers import SimpleRouter +from api_v2.bundle.views import BundleViewSet + router = SimpleRouter() router.register("", BundleViewSet) urlpatterns = [*router.urls] diff --git a/python/api_v2/bundle/views.py b/python/api_v2/bundle/views.py index dfdae10f57..42cab54fa3 100644 --- a/python/api_v2/bundle/views.py +++ b/python/api_v2/bundle/views.py @@ -9,9 +9,7 @@ # 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. -from api_v2.bundle.filters import BundleFilter -from api_v2.bundle.serializers import BundleListSerializer, UploadBundleSerializer -from api_v2.views import CamelCaseGenericViewSet +from adcm.permissions import DjangoModelPermissionsAudit from audit.utils import audit from cm.bundle import delete_bundle, load_bundle, upload_file from cm.models import Bundle, ObjectType @@ -26,12 +24,12 @@ from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED, HTTP_204_NO_CONTENT -from adcm.permissions import DjangoModelPermissionsAudit +from api_v2.bundle.filters import BundleFilter +from api_v2.bundle.serializers import BundleListSerializer, UploadBundleSerializer +from api_v2.views import CamelCaseGenericViewSet -class BundleViewSet( # pylint: disable=too-many-ancestors - ListModelMixin, RetrieveModelMixin, DestroyModelMixin, CreateModelMixin, CamelCaseGenericViewSet -): +class BundleViewSet(ListModelMixin, RetrieveModelMixin, DestroyModelMixin, CreateModelMixin, CamelCaseGenericViewSet): queryset = ( Bundle.objects.exclude(name="ADCM") .annotate( @@ -58,7 +56,7 @@ def get_serializer_class(self): return BundleListSerializer @audit - def create(self, request, *args, **kwargs) -> Response: + def create(self, request, *args, **kwargs) -> Response: # noqa: ARG002 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) file_path = upload_file(file=request.data["file"]) @@ -69,7 +67,7 @@ def create(self, request, *args, **kwargs) -> Response: ) @audit - def destroy(self, request, *args, **kwargs) -> Response: + def destroy(self, request, *args, **kwargs) -> Response: # noqa: ARG002 bundle = self.get_object() delete_bundle(bundle=bundle) diff --git a/python/api_v2/cluster/data_containers.py b/python/api_v2/cluster/data_containers.py index 2c686e2e28..6e39f934dd 100644 --- a/python/api_v2/cluster/data_containers.py +++ b/python/api_v2/cluster/data_containers.py @@ -33,7 +33,7 @@ class MappingEntryData: @dataclass -class MappingData: # pylint: disable=too-many-instance-attributes +class MappingData: cluster: ClusterData services: dict[int, ServiceData] components: dict[int, ComponentData] @@ -46,8 +46,8 @@ class MappingData: # pylint: disable=too-many-instance-attributes @cached_property def mapping_difference(self) -> dict[Literal["add", "remove", "remain"], list[MappingEntryData]]: - input_mapping_ids = set((map_.host.id, map_.component.id, map_.service.id) for map_ in self.mapping) - existing_mapping_ids = set((map_.host_id, map_.component_id, map_.service_id) for map_ in self.existing_mapping) + input_mapping_ids = {(map_.host.id, map_.component.id, map_.service.id) for map_ in self.mapping} + existing_mapping_ids = {(map_.host_id, map_.component_id, map_.service_id) for map_ in self.existing_mapping} return { "add": [ @@ -73,16 +73,16 @@ def mapping_difference(self) -> dict[Literal["add", "remove", "remain"], list[Ma @cached_property def mapping_names(self) -> dict[Literal["services", "components"], set[str]]: return { - "services": set( + "services": { self.prototypes[map_.service.prototype_id].name for map_ in self.mapping if self.prototypes[map_.service.prototype_id].type == "service" - ), - "components": set( + }, + "components": { self.prototypes[map_.service.prototype_id].name for map_ in self.mapping if self.prototypes[map_.service.prototype_id].type == "component" - ), + }, } @cached_property diff --git a/python/api_v2/cluster/serializers.py b/python/api_v2/cluster/serializers.py index d987d26c75..81424b699a 100644 --- a/python/api_v2/cluster/serializers.py +++ b/python/api_v2/cluster/serializers.py @@ -11,10 +11,7 @@ # limitations under the License. -from api_v2.cluster.utils import get_depend_on -from api_v2.concern.serializers import ConcernSerializer -from api_v2.prototype.serializers import PrototypeRelatedSerializer -from api_v2.prototype.utils import get_license_text +from adcm.serializers import EmptySerializer from cm.adcm_config.config import get_main_info from cm.models import ( Cluster, @@ -35,7 +32,10 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer +from api_v2.cluster.utils import get_depend_on +from api_v2.concern.serializers import ConcernSerializer +from api_v2.prototype.serializers import PrototypeRelatedSerializer +from api_v2.prototype.utils import get_license_text class ClusterSerializer(ModelSerializer): diff --git a/python/api_v2/cluster/urls.py b/python/api_v2/cluster/urls.py index 9c1e2140c2..f5fc83aea5 100644 --- a/python/api_v2/cluster/urls.py +++ b/python/api_v2/cluster/urls.py @@ -10,6 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from rest_framework_nested.routers import NestedSimpleRouter, SimpleRouter + from api_v2.action.views import ActionViewSet from api_v2.cluster.views import ClusterViewSet from api_v2.component.views import ComponentViewSet, HostComponentViewSet @@ -19,7 +21,6 @@ from api_v2.imports.views import ImportViewSet from api_v2.service.views import ServiceViewSet from api_v2.upgrade.views import UpgradeViewSet -from rest_framework_nested.routers import NestedSimpleRouter, SimpleRouter CLUSTER_PREFIX = "" ACTION_PREFIX = "actions" diff --git a/python/api_v2/cluster/utils.py b/python/api_v2/cluster/utils.py index fd4ae66105..42b2cc4f6e 100644 --- a/python/api_v2/cluster/utils.py +++ b/python/api_v2/cluster/utils.py @@ -14,8 +14,6 @@ from itertools import chain from typing import Literal -from api_v2.cluster.data_containers import MappingData, MappingEntryData -from api_v2.prototype.utils import get_license_text from cm.api import load_service_map from cm.api_context import CTX from cm.data_containers import ( @@ -54,6 +52,9 @@ from rbac.models import Policy from rest_framework.status import HTTP_409_CONFLICT +from api_v2.cluster.data_containers import MappingData, MappingEntryData +from api_v2.prototype.utils import get_license_text + def get_requires(requires: list[dict]) -> dict: new_requires = defaultdict(list) @@ -214,14 +215,12 @@ def _check_mapping_data(mapping_data: MappingData) -> None: seen.add(ids) if duplicates: - error_mapping_repr = ", ".join( - (f"component {map_ids[1]} - host {map_ids[0]}" for map_ids in sorted(duplicates)) - ) + error_mapping_repr = ", ".join(f"component {map_ids[1]} - host {map_ids[0]}" for map_ids in sorted(duplicates)) raise AdcmEx(code="INVALID_INPUT", msg=f"Mapping entries duplicates found: {error_mapping_repr}.") - hosts_mm_states_in_add_remove_groups = set( + hosts_mm_states_in_add_remove_groups = { diff.host.maintenance_mode for diff in mapping_data.mapping_difference["add"] - ).union(set(diff.host.maintenance_mode for diff in mapping_data.mapping_difference["remove"])) + }.union({diff.host.maintenance_mode for diff in mapping_data.mapping_difference["remove"]}) if MaintenanceMode.ON.value in hosts_mm_states_in_add_remove_groups: raise AdcmEx("INVALID_HC_HOST_IN_MM") @@ -282,7 +281,7 @@ def _save_mapping(mapping_data: MappingData) -> QuerySet[HostComponent]: HostComponent.objects.bulk_create(objs=mapping_objects) update_hierarchy_issues(obj=mapping_data.orm_objects["cluster"]) - for provider_id in set(host.provider_id for host in mapping_data.hosts.values()): + for provider_id in {host.provider_id for host in mapping_data.hosts.values()}: update_hierarchy_issues(obj=mapping_data.orm_objects["providers"][provider_id]) update_issue_after_deleting() @@ -293,7 +292,7 @@ def _save_mapping(mapping_data: MappingData) -> QuerySet[HostComponent]: def _handle_mapping_config_groups(mapping_data: MappingData) -> None: - remaining_host_service = set((diff.host.id, diff.service.id) for diff in mapping_data.mapping_difference["remain"]) + remaining_host_service = {(diff.host.id, diff.service.id) for diff in mapping_data.mapping_difference["remain"]} removed_hosts_not_in_mapping = { mapping_data.orm_objects["hosts"][removed_mapping.host.id] for removed_mapping in mapping_data.mapping_difference["remove"] diff --git a/python/api_v2/cluster/views.py b/python/api_v2/cluster/views.py index 1b02281bc8..24c9212021 100644 --- a/python/api_v2/cluster/views.py +++ b/python/api_v2/cluster/views.py @@ -11,26 +11,13 @@ # limitations under the License. -from api_v2.cluster.filters import ( - ClusterFilter, - ClusterHostFilter, - ClusterServiceFilter, -) -from api_v2.cluster.permissions import ClusterPermissions -from api_v2.cluster.serializers import ( - ClusterCreateSerializer, - ClusterSerializer, - ClusterUpdateSerializer, - MappingSerializer, - RelatedHostsStatusesSerializer, - RelatedServicesStatusesSerializer, - ServicePrototypeSerializer, +from adcm.permissions import ( + VIEW_CLUSTER_PERM, + VIEW_HC_PERM, + VIEW_HOST_PERM, + VIEW_SERVICE_PERM, + get_object_for_user, ) -from api_v2.cluster.utils import retrieve_mapping_data, save_mapping -from api_v2.component.serializers import ComponentMappingSerializer -from api_v2.config.utils import ConfigSchemaMixin -from api_v2.host.serializers import HostMappingSerializer -from api_v2.views import CamelCaseModelViewSet from audit.utils import audit from cm.api import add_cluster, delete_cluster from cm.errors import AdcmEx @@ -57,20 +44,33 @@ HTTP_409_CONFLICT, ) -from adcm.permissions import ( - VIEW_CLUSTER_PERM, - VIEW_HC_PERM, - VIEW_HOST_PERM, - VIEW_SERVICE_PERM, - get_object_for_user, +from api_v2.cluster.filters import ( + ClusterFilter, + ClusterHostFilter, + ClusterServiceFilter, ) +from api_v2.cluster.permissions import ClusterPermissions +from api_v2.cluster.serializers import ( + ClusterCreateSerializer, + ClusterSerializer, + ClusterUpdateSerializer, + MappingSerializer, + RelatedHostsStatusesSerializer, + RelatedServicesStatusesSerializer, + ServicePrototypeSerializer, +) +from api_v2.cluster.utils import retrieve_mapping_data, save_mapping +from api_v2.component.serializers import ComponentMappingSerializer +from api_v2.config.utils import ConfigSchemaMixin +from api_v2.host.serializers import HostMappingSerializer +from api_v2.views import CamelCaseModelViewSet class ClusterViewSet( PermissionListMixin, ConfigSchemaMixin, CamelCaseModelViewSet, -): # pylint:disable=too-many-ancestors +): queryset = ( Cluster.objects.prefetch_related("prototype", "concerns") .prefetch_related("clusterobject_set__prototype") @@ -80,7 +80,7 @@ class ClusterViewSet( filterset_class = ClusterFilter permission_classes = [ClusterPermissions] - def get_serializer_class(self): # pylint: disable=too-many-return-statements + def get_serializer_class(self): match self.action: case "create": return ClusterCreateSerializer @@ -98,7 +98,7 @@ def get_serializer_class(self): # pylint: disable=too-many-return-statements return ClusterSerializer @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) valid = serializer.validated_data @@ -113,7 +113,7 @@ def create(self, request, *args, **kwargs): return Response(data=ClusterSerializer(cluster).data, status=HTTP_201_CREATED) @audit - def update(self, request, *args, **kwargs): + def update(self, request, *args, **kwargs): # noqa: ARG002 instance = self.get_object() serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -130,14 +130,14 @@ def update(self, request, *args, **kwargs): return Response(status=HTTP_200_OK, data=ClusterSerializer(instance).data) @audit - def destroy(self, request, *args, **kwargs): + def destroy(self, request, *args, **kwargs): # noqa: ARG002 cluster = self.get_object() delete_cluster(cluster=cluster) return Response(status=HTTP_204_NO_CONTENT) @action(methods=["get"], detail=True, url_path="service-prototypes") - def service_prototypes(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def service_prototypes(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 cluster = self.get_object() prototypes = Prototype.objects.filter(type=ObjectType.SERVICE, bundle=cluster.prototype.bundle).order_by( "display_name" @@ -147,7 +147,7 @@ def service_prototypes(self, request: Request, *args, **kwargs) -> Response: # return Response(data=serializer.data) @action(methods=["get"], detail=True, url_path="service-candidates") - def service_candidates(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def service_candidates(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 cluster = self.get_object() prototypes = ( Prototype.objects.filter(type=ObjectType.SERVICE, bundle=cluster.prototype.bundle) @@ -166,7 +166,7 @@ def service_candidates(self, request: Request, *args, **kwargs) -> Response: # permission_required=[VIEW_SERVICE_PERM], filterset_class=ClusterServiceFilter, ) - def services_statuses(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def services_statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 cluster = get_object_for_user(user=request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=kwargs["pk"]) queryset = self.filter_queryset(queryset=self.get_queryset().filter(cluster=cluster)) @@ -182,7 +182,7 @@ def services_statuses(self, request: Request, *args, **kwargs) -> Response: # p permission_required=[VIEW_HOST_PERM], filterset_class=ClusterHostFilter, ) - def hosts_statuses(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def hosts_statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 cluster = get_object_for_user(user=request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=kwargs["pk"]) queryset = self.filter_queryset(queryset=self.get_queryset().filter(cluster=cluster)) @@ -197,7 +197,7 @@ def hosts_statuses(self, request: Request, *args, **kwargs) -> Response: # pyli pagination_class=None, filter_backends=[], ) - def mapping(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def mapping(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 cluster = self.get_object() if request.method == "GET": @@ -222,14 +222,14 @@ def mapping(self, request: Request, *args, **kwargs) -> Response: # pylint: dis return Response(data=self.get_serializer(instance=new_mapping, many=True).data, status=HTTP_201_CREATED) @action(methods=["get"], detail=True, url_path="mapping/hosts", url_name="mapping-hosts") - def mapping_hosts(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def mapping_hosts(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 cluster = self.get_object() serializer = self.get_serializer(instance=Host.objects.filter(cluster=cluster), many=True) return Response(status=HTTP_200_OK, data=serializer.data) @action(methods=["get"], detail=True, url_path="mapping/components", url_name="mapping-components") - def mapping_components(self, request: Request, *args, **kwargs): # pylint: disable=unused-argument + def mapping_components(self, request: Request, *args, **kwargs): # noqa: ARG001, ARG002 cluster = self.get_object() serializer = self.get_serializer( instance=ServiceComponent.objects.filter(cluster=cluster).order_by("pk"), many=True diff --git a/python/api_v2/component/serializers.py b/python/api_v2/component/serializers.py index 46927f6f12..482c28fc04 100644 --- a/python/api_v2/component/serializers.py +++ b/python/api_v2/component/serializers.py @@ -11,12 +11,6 @@ # limitations under the License. -from api_v2.cluster.serializers import ClusterRelatedSerializer -from api_v2.cluster.utils import get_depend_on -from api_v2.concern.serializers import ConcernSerializer -from api_v2.host.serializers import HostShortSerializer -from api_v2.prototype.serializers import PrototypeRelatedSerializer -from api_v2.service.serializers import ServiceNameSerializer, ServiceRelatedSerializer from cm.adcm_config.config import get_main_info from cm.models import Host, HostComponent, MaintenanceMode, ServiceComponent from cm.status_api import get_obj_status @@ -29,6 +23,13 @@ SerializerMethodField, ) +from api_v2.cluster.serializers import ClusterRelatedSerializer +from api_v2.cluster.utils import get_depend_on +from api_v2.concern.serializers import ConcernSerializer +from api_v2.host.serializers import HostShortSerializer +from api_v2.prototype.serializers import PrototypeRelatedSerializer +from api_v2.service.serializers import ServiceNameSerializer, ServiceRelatedSerializer + class ComponentMappingSerializer(ModelSerializer): service = ServiceNameSerializer(read_only=True) diff --git a/python/api_v2/component/views.py b/python/api_v2/component/views.py index a778022da7..718c6cc568 100644 --- a/python/api_v2/component/views.py +++ b/python/api_v2/component/views.py @@ -10,25 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.component.filters import ComponentFilter -from api_v2.component.serializers import ( - ComponentMaintenanceModeSerializer, - ComponentSerializer, - ComponentStatusSerializer, - HostComponentSerializer, -) -from api_v2.config.utils import ConfigSchemaMixin -from api_v2.views import CamelCaseGenericViewSet, CamelCaseReadOnlyModelViewSet -from audit.utils import audit -from cm.api import update_mm_objects -from cm.models import Cluster, ClusterObject, Host, ServiceComponent -from guardian.mixins import PermissionListMixin -from rest_framework.decorators import action -from rest_framework.mixins import ListModelMixin -from rest_framework.request import Request -from rest_framework.response import Response -from rest_framework.status import HTTP_200_OK - from adcm.permissions import ( CHANGE_MM_PERM, VIEW_CLUSTER_PERM, @@ -41,11 +22,28 @@ get_object_for_user, ) from adcm.utils import get_maintenance_mode_response +from audit.utils import audit +from cm.api import update_mm_objects +from cm.models import Cluster, ClusterObject, Host, ServiceComponent +from guardian.mixins import PermissionListMixin +from rest_framework.decorators import action +from rest_framework.mixins import ListModelMixin +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.status import HTTP_200_OK + +from api_v2.component.filters import ComponentFilter +from api_v2.component.serializers import ( + ComponentMaintenanceModeSerializer, + ComponentSerializer, + ComponentStatusSerializer, + HostComponentSerializer, +) +from api_v2.config.utils import ConfigSchemaMixin +from api_v2.views import CamelCaseGenericViewSet, CamelCaseReadOnlyModelViewSet -class ComponentViewSet( - PermissionListMixin, ConfigSchemaMixin, CamelCaseReadOnlyModelViewSet -): # pylint: disable=too-many-ancestors +class ComponentViewSet(PermissionListMixin, ConfigSchemaMixin, CamelCaseReadOnlyModelViewSet): queryset = ServiceComponent.objects.select_related("cluster", "service").order_by("pk") serializer_class = ComponentSerializer permission_classes = [DjangoModelPermissionsAudit] @@ -74,7 +72,7 @@ def get_serializer_class(self): @audit @update_mm_objects @action(methods=["post"], detail=True, url_path="maintenance-mode", permission_classes=[ChangeMMPermissions]) - def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 component = get_object_for_user( user=request.user, perms=VIEW_COMPONENT_PERM, klass=ServiceComponent, pk=kwargs["pk"] ) @@ -92,7 +90,7 @@ def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # py return response @action(methods=["get"], detail=True, url_path="statuses") - def statuses(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 component = get_object_for_user( user=request.user, perms=VIEW_COMPONENT_PERM, klass=ServiceComponent, id=kwargs["pk"] ) @@ -100,9 +98,7 @@ def statuses(self, request: Request, *args, **kwargs) -> Response: # pylint: di return Response(data=ComponentStatusSerializer(instance=component).data) -class HostComponentViewSet( - PermissionListMixin, ListModelMixin, CamelCaseGenericViewSet -): # pylint: disable=too-many-ancestors +class HostComponentViewSet(PermissionListMixin, ListModelMixin, CamelCaseGenericViewSet): queryset = ServiceComponent.objects.select_related("cluster", "service").order_by("prototype__name") serializer_class = HostComponentSerializer permission_classes = [DjangoModelPermissionsAudit] diff --git a/python/api_v2/config/utils.py b/python/api_v2/config/utils.py index 8b4b59ac39..2d85c70711 100644 --- a/python/api_v2/config/utils.py +++ b/python/api_v2/config/utils.py @@ -9,12 +9,12 @@ # 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 copy -import json from abc import ABC, abstractmethod from collections import OrderedDict, defaultdict from copy import deepcopy from typing import Any +import copy +import json from cm.adcm_config.config import get_default from cm.errors import AdcmEx @@ -33,7 +33,7 @@ from rest_framework.status import HTTP_200_OK -class Field(ABC): # pylint: disable=too-many-instance-attributes +class Field(ABC): def __init__(self, prototype_config: PrototypeConfig, object_: ADCMEntity | GroupConfig): self.object_ = object_ self.is_group_config = False @@ -655,7 +655,7 @@ def get_config_schema( class ConfigSchemaMixin: @action(methods=["get"], detail=True, url_path="config-schema", url_name="config-schema") - def config_schema(self, request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def config_schema(self, request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 instance = self.get_object() schema = get_config_schema( object_=instance, diff --git a/python/api_v2/config/views.py b/python/api_v2/config/views.py index e9b89c3e8b..6d3d4a4ba6 100644 --- a/python/api_v2/config/views.py +++ b/python/api_v2/config/views.py @@ -10,14 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.config.serializers import ConfigLogListSerializer, ConfigLogSerializer -from api_v2.config.utils import ( - convert_adcm_meta_to_attr, - convert_attr_to_adcm_meta, - represent_json_type_as_string, - represent_string_as_json_type, -) -from api_v2.views import CamelCaseGenericViewSet +from adcm.mixins import GetParentObjectMixin +from adcm.permissions import VIEW_CONFIG_PERM, check_config_perm from audit.utils import audit from cm.api import update_obj_config from cm.errors import AdcmEx @@ -29,8 +23,14 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.mixins import GetParentObjectMixin -from adcm.permissions import VIEW_CONFIG_PERM, check_config_perm +from api_v2.config.serializers import ConfigLogListSerializer, ConfigLogSerializer +from api_v2.config.utils import ( + convert_adcm_meta_to_attr, + convert_attr_to_adcm_meta, + represent_json_type_as_string, + represent_string_as_json_type, +) +from api_v2.views import CamelCaseGenericViewSet class ConfigLogViewSet( @@ -40,7 +40,7 @@ class ConfigLogViewSet( RetrieveModelMixin, GetParentObjectMixin, CamelCaseGenericViewSet, -): # pylint: disable=too-many-ancestors +): queryset = ConfigLog.objects.select_related( "obj_ref__cluster__prototype", "obj_ref__clusterobject__prototype", @@ -68,7 +68,7 @@ def get_serializer_class(self): return ConfigLogSerializer @audit - def create(self, request, *args, **kwargs) -> Response: + def create(self, request, *args, **kwargs) -> Response: # noqa: ARG002 parent_object = self.get_parent_object() parent_view_perm = f"cm.view_{parent_object.__class__.__name__.lower()}" @@ -106,7 +106,7 @@ def create(self, request, *args, **kwargs) -> Response: return Response(data=self.get_serializer(config_log).data, status=HTTP_201_CREATED) - def retrieve(self, request, *args, **kwargs) -> Response: + def retrieve(self, request, *args, **kwargs) -> Response: # noqa: ARG002 parent_object = self.get_parent_object() instance = self.get_object() instance.attr = convert_attr_to_adcm_meta(attr=instance.attr) diff --git a/python/api_v2/group_config/serializers.py b/python/api_v2/group_config/serializers.py index 75d062af7e..88516842dc 100644 --- a/python/api_v2/group_config/serializers.py +++ b/python/api_v2/group_config/serializers.py @@ -9,12 +9,13 @@ # 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. -from api_v2.host.serializers import HostShortSerializer from cm.models import GroupConfig from django.contrib.contenttypes.models import ContentType from rest_framework.exceptions import ValidationError from rest_framework.serializers import ModelSerializer +from api_v2.host.serializers import HostShortSerializer + class GroupConfigSerializer(ModelSerializer): hosts = HostShortSerializer(many=True, read_only=True) diff --git a/python/api_v2/group_config/views.py b/python/api_v2/group_config/views.py index d8212c90a0..741e5ade3b 100644 --- a/python/api_v2/group_config/views.py +++ b/python/api_v2/group_config/views.py @@ -9,11 +9,8 @@ # 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. -from api_v2.config.utils import ConfigSchemaMixin -from api_v2.group_config.permissions import GroupConfigPermissions -from api_v2.group_config.serializers import GroupConfigSerializer -from api_v2.host.serializers import HostGroupConfigSerializer -from api_v2.views import CamelCaseModelViewSet +from adcm.mixins import GetParentObjectMixin +from adcm.permissions import VIEW_GROUP_CONFIG_PERM, check_config_perm from audit.utils import audit from cm.models import GroupConfig from django.contrib.contenttypes.models import ContentType @@ -25,13 +22,14 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.mixins import GetParentObjectMixin -from adcm.permissions import VIEW_GROUP_CONFIG_PERM, check_config_perm +from api_v2.config.utils import ConfigSchemaMixin +from api_v2.group_config.permissions import GroupConfigPermissions +from api_v2.group_config.serializers import GroupConfigSerializer +from api_v2.host.serializers import HostGroupConfigSerializer +from api_v2.views import CamelCaseModelViewSet -class GroupConfigViewSet( - PermissionListMixin, GetParentObjectMixin, ConfigSchemaMixin, CamelCaseModelViewSet -): # pylint: disable=too-many-ancestors +class GroupConfigViewSet(PermissionListMixin, GetParentObjectMixin, ConfigSchemaMixin, CamelCaseModelViewSet): queryset = GroupConfig.objects.order_by("name") serializer_class = GroupConfigSerializer permission_classes = [GroupConfigPermissions] @@ -50,7 +48,7 @@ def get_queryset(self, *args, **kwargs): ) @audit - def create(self, request: Request, *args, **kwargs): + def create(self, request: Request, *args, **kwargs): # noqa: ARG002 parent_object = self.get_parent_object() parent_view_perm = f"cm.view_{parent_object.__class__.__name__.lower()}" @@ -79,7 +77,7 @@ def create(self, request: Request, *args, **kwargs): return Response(data=self.get_serializer(group_config).data, status=HTTP_201_CREATED) @action(methods=["get"], detail=True, url_path="host-candidates", url_name="host-candidates") - def host_candidates(self, request: Request, *args, **kwargs): # pylint: disable=unused-argument + def host_candidates(self, request: Request, *args, **kwargs): # noqa: ARG001, ARG002 group_config: GroupConfig = self.get_object() hosts = group_config.host_candidate() serializer = HostGroupConfigSerializer(instance=hosts, many=True) diff --git a/python/api_v2/host/serializers.py b/python/api_v2/host/serializers.py index 2a0e9551b1..4aa8b1c8f4 100644 --- a/python/api_v2/host/serializers.py +++ b/python/api_v2/host/serializers.py @@ -10,9 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.cluster.serializers import RelatedComponentStatusSerializer -from api_v2.concern.serializers import ConcernSerializer -from api_v2.prototype.serializers import PrototypeRelatedSerializer +from adcm import settings +from adcm.serializers import EmptySerializer from cm.models import Cluster, Host, HostProvider, MaintenanceMode, ServiceComponent from cm.status_api import get_obj_status from cm.validators import HostUniqueValidator, StartMidEndValidator @@ -25,8 +24,9 @@ SerializerMethodField, ) -from adcm import settings -from adcm.serializers import EmptySerializer +from api_v2.cluster.serializers import RelatedComponentStatusSerializer +from api_v2.concern.serializers import ConcernSerializer +from api_v2.prototype.serializers import PrototypeRelatedSerializer class HostProviderSerializer(ModelSerializer): diff --git a/python/api_v2/host/urls.py b/python/api_v2/host/urls.py index 1e9ff2b342..d092b7730e 100644 --- a/python/api_v2/host/urls.py +++ b/python/api_v2/host/urls.py @@ -10,10 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from rest_framework_nested.routers import NestedSimpleRouter, SimpleRouter + from api_v2.action.views import ActionViewSet from api_v2.config.views import ConfigLogViewSet from api_v2.host.views import HostViewSet -from rest_framework_nested.routers import NestedSimpleRouter, SimpleRouter host_router = SimpleRouter() host_router.register(prefix="", viewset=HostViewSet) diff --git a/python/api_v2/host/utils.py b/python/api_v2/host/utils.py index fd0487f9ba..b31154a439 100644 --- a/python/api_v2/host/utils.py +++ b/python/api_v2/host/utils.py @@ -10,7 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.host.serializers import HostChangeMaintenanceModeSerializer +from adcm.permissions import check_custom_perm +from adcm.utils import get_maintenance_mode_response from cm.adcm_config.config import init_object_config from cm.api import check_license, load_service_map from cm.api_context import CTX @@ -23,8 +24,7 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_409_CONFLICT -from adcm.permissions import check_custom_perm -from adcm.utils import get_maintenance_mode_response +from api_v2.host.serializers import HostChangeMaintenanceModeSerializer def add_new_host_and_map_it(provider: HostProvider, fqdn: str, cluster: Cluster | None = None) -> Host: diff --git a/python/api_v2/host/views.py b/python/api_v2/host/views.py index 8a30bd265a..a04f659993 100644 --- a/python/api_v2/host/views.py +++ b/python/api_v2/host/views.py @@ -12,24 +12,16 @@ from typing import Collection -from api_v2.config.utils import ConfigSchemaMixin -from api_v2.host.filters import HostClusterFilter, HostFilter -from api_v2.host.permissions import ( - GroupConfigHostsPermissions, - HostsClusterPermissions, - HostsPermissions, -) -from api_v2.host.serializers import ( - ClusterHostStatusSerializer, - HostAddSerializer, - HostChangeMaintenanceModeSerializer, - HostCreateSerializer, - HostGroupConfigSerializer, - HostSerializer, - HostUpdateSerializer, +from adcm.mixins import GetParentObjectMixin +from adcm.permissions import ( + VIEW_CLUSTER_PERM, + VIEW_HOST_PERM, + VIEW_PROVIDER_PERM, + ChangeMMPermissions, + check_config_perm, + check_custom_perm, + get_object_for_user, ) -from api_v2.host.utils import add_new_host_and_map_it, maintenance_mode -from api_v2.views import CamelCaseModelViewSet, CamelCaseReadOnlyModelViewSet from audit.utils import audit from cm.api import delete_host, remove_host_from_cluster from cm.errors import AdcmEx @@ -53,19 +45,26 @@ HTTP_404_NOT_FOUND, ) -from adcm.mixins import GetParentObjectMixin -from adcm.permissions import ( - VIEW_CLUSTER_PERM, - VIEW_HOST_PERM, - VIEW_PROVIDER_PERM, - ChangeMMPermissions, - check_config_perm, - check_custom_perm, - get_object_for_user, +from api_v2.config.utils import ConfigSchemaMixin +from api_v2.host.filters import HostClusterFilter, HostFilter +from api_v2.host.permissions import ( + GroupConfigHostsPermissions, + HostsClusterPermissions, + HostsPermissions, ) +from api_v2.host.serializers import ( + ClusterHostStatusSerializer, + HostAddSerializer, + HostChangeMaintenanceModeSerializer, + HostCreateSerializer, + HostGroupConfigSerializer, + HostSerializer, + HostUpdateSerializer, +) +from api_v2.host.utils import add_new_host_and_map_it, maintenance_mode +from api_v2.views import CamelCaseModelViewSet, CamelCaseReadOnlyModelViewSet -# pylint:disable-next=too-many-ancestors class HostViewSet(PermissionListMixin, ConfigSchemaMixin, CamelCaseModelViewSet): queryset = ( Host.objects.select_related("provider", "cluster", "cluster__prototype", "prototype") @@ -88,7 +87,7 @@ def get_serializer_class(self): return HostSerializer @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -114,14 +113,14 @@ def create(self, request, *args, **kwargs): ) @audit - def destroy(self, request, *args, **kwargs): + def destroy(self, request, *args, **kwargs): # noqa: ARG002 host = self.get_object() check_custom_perm(request.user, "remove", "host", host) delete_host(host=host) return Response(status=HTTP_204_NO_CONTENT) @audit - def update(self, request, *args, **kwargs): + def update(self, request, *args, **kwargs): # noqa: ARG002 partial = kwargs.pop("partial", False) instance = self.get_object() @@ -144,11 +143,11 @@ def update(self, request, *args, **kwargs): @audit @action(methods=["post"], detail=True, url_path="maintenance-mode", permission_classes=[ChangeMMPermissions]) - def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 return maintenance_mode(request=request, host=self.get_object()) -class HostClusterViewSet(PermissionListMixin, CamelCaseReadOnlyModelViewSet): # pylint:disable=too-many-ancestors +class HostClusterViewSet(PermissionListMixin, CamelCaseReadOnlyModelViewSet): permission_required = [VIEW_HOST_PERM] permission_classes = [HostsClusterPermissions] filterset_class = HostClusterFilter @@ -163,7 +162,7 @@ def get_serializer_class(self): return HostSerializer - def get_queryset(self, *args, **kwargs): + def get_queryset(self, *args, **kwargs): # noqa: ARG002 cluster = get_object_for_user( user=self.request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=self.kwargs["cluster_pk"] ) @@ -175,7 +174,7 @@ def get_queryset(self, *args, **kwargs): ) @audit - def create(self, request, *_, **kwargs): + def create(self, request, *_, **kwargs): # noqa: ARG002 cluster = get_object_for_user( user=request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=kwargs["cluster_pk"] ) @@ -218,7 +217,7 @@ def create(self, request, *_, **kwargs): ) @audit - def destroy(self, request, *args, **kwargs): # pylint:disable=unused-argument + def destroy(self, request, *args, **kwargs): # noqa: ARG002 host = self.get_object() cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_pk"]) check_custom_perm(request.user, "unmap_host_from", "cluster", cluster) @@ -227,11 +226,11 @@ def destroy(self, request, *args, **kwargs): # pylint:disable=unused-argument @audit @action(methods=["post"], detail=True, url_path="maintenance-mode", permission_classes=[ChangeMMPermissions]) - def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 return maintenance_mode(request=request, host=self.get_object()) @action(methods=["get"], detail=True, url_path="statuses") - def statuses(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 host = self.get_object() cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_pk"]) if host.cluster != cluster: @@ -240,7 +239,6 @@ def statuses(self, request: Request, *args, **kwargs) -> Response: # pylint: di return Response(data=ClusterHostStatusSerializer(instance=host).data) -# pylint: disable=too-many-ancestors class HostGroupConfigViewSet(PermissionListMixin, GetParentObjectMixin, CamelCaseReadOnlyModelViewSet): queryset = ( Host.objects.select_related("provider", "cluster") @@ -259,7 +257,7 @@ def get_serializer_class(self) -> type[HostGroupConfigSerializer | HostAddSerial return HostGroupConfigSerializer - def get_queryset(self, *args, **kwargs): + def get_queryset(self, *args, **kwargs): # noqa: ARG002 return self.queryset.filter(group_config__id=self.kwargs["group_config_pk"]) def get_group_for_change(self) -> GroupConfig: @@ -297,7 +295,7 @@ def create(self, request, *_, **__): return Response(status=HTTP_201_CREATED, data=HostGroupConfigSerializer(instance=host).data) @audit - def destroy(self, request, *_, **kwargs): # pylint: disable=unused-argument + def destroy(self, request, *_, **kwargs): # noqa: ARG001, ARG002 group_config = self.get_group_for_change() host = group_config.hosts.filter(pk=kwargs["pk"]).first() diff --git a/python/api_v2/hostprovider/serializers.py b/python/api_v2/hostprovider/serializers.py index d75a2bebc1..8fbfc0826d 100644 --- a/python/api_v2/hostprovider/serializers.py +++ b/python/api_v2/hostprovider/serializers.py @@ -10,8 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.concern.serializers import ConcernSerializer -from api_v2.prototype.serializers import PrototypeRelatedSerializer +from adcm.serializers import EmptySerializer from cm.adcm_config.config import get_main_info from cm.errors import AdcmEx from cm.models import HostProvider, ObjectType, Prototype @@ -23,7 +22,8 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer +from api_v2.concern.serializers import ConcernSerializer +from api_v2.prototype.serializers import PrototypeRelatedSerializer class HostProviderSerializer(ModelSerializer): diff --git a/python/api_v2/hostprovider/urls.py b/python/api_v2/hostprovider/urls.py index 9a4c319b2c..09187ee21e 100644 --- a/python/api_v2/hostprovider/urls.py +++ b/python/api_v2/hostprovider/urls.py @@ -9,14 +9,15 @@ # 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. +from rest_framework.routers import SimpleRouter +from rest_framework_nested.routers import NestedSimpleRouter + from api_v2.action.views import ActionViewSet from api_v2.config.views import ConfigLogViewSet from api_v2.group_config.views import GroupConfigViewSet from api_v2.host.views import HostGroupConfigViewSet from api_v2.hostprovider.views import HostProviderViewSet from api_v2.upgrade.views import UpgradeViewSet -from rest_framework.routers import SimpleRouter -from rest_framework_nested.routers import NestedSimpleRouter CONFIG_GROUPS_PREFIX = "config-groups" diff --git a/python/api_v2/hostprovider/views.py b/python/api_v2/hostprovider/views.py index 377abe7a7f..5693534f10 100644 --- a/python/api_v2/hostprovider/views.py +++ b/python/api_v2/hostprovider/views.py @@ -9,14 +9,7 @@ # 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. -from api_v2.config.utils import ConfigSchemaMixin -from api_v2.hostprovider.filters import HostProviderFilter -from api_v2.hostprovider.permissions import HostProviderPermissions -from api_v2.hostprovider.serializers import ( - HostProviderCreateSerializer, - HostProviderSerializer, -) -from api_v2.views import CamelCaseReadOnlyModelViewSet +from adcm.permissions import VIEW_PROVIDER_PERM from audit.utils import audit from cm.api import add_host_provider, delete_host_provider from cm.errors import AdcmEx @@ -27,12 +20,17 @@ from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED, HTTP_204_NO_CONTENT -from adcm.permissions import VIEW_PROVIDER_PERM +from api_v2.config.utils import ConfigSchemaMixin +from api_v2.hostprovider.filters import HostProviderFilter +from api_v2.hostprovider.permissions import HostProviderPermissions +from api_v2.hostprovider.serializers import ( + HostProviderCreateSerializer, + HostProviderSerializer, +) +from api_v2.views import CamelCaseReadOnlyModelViewSet -class HostProviderViewSet( # pylint:disable=too-many-ancestors - PermissionListMixin, ConfigSchemaMixin, CamelCaseReadOnlyModelViewSet -): +class HostProviderViewSet(PermissionListMixin, ConfigSchemaMixin, CamelCaseReadOnlyModelViewSet): queryset = HostProvider.objects.select_related("prototype").order_by("name") serializer_class = HostProviderSerializer permission_classes = [HostProviderPermissions] @@ -47,7 +45,7 @@ def get_serializer_class(self): return self.serializer_class @audit - def create(self, request, *args, **kwargs): # pylint: disable=unused-argument + def create(self, request, *args, **kwargs): # noqa: ARG001, ARG002 serializer = self.get_serializer(data=request.data) if not serializer.is_valid(): raise AdcmEx(code="HOSTPROVIDER_CREATE_ERROR") @@ -64,7 +62,7 @@ def create(self, request, *args, **kwargs): # pylint: disable=unused-argument return Response(data=HostProviderSerializer(host_provider).data, status=HTTP_201_CREATED) @audit - def destroy(self, request, *args, **kwargs): # pylint:disable=unused-argument + def destroy(self, request, *args, **kwargs): # noqa: ARG002 host_provider = self.get_object() delete_host_provider(host_provider) return Response(status=HTTP_204_NO_CONTENT) diff --git a/python/api_v2/imports/serializers.py b/python/api_v2/imports/serializers.py index cb77d81586..98e9e8d3d1 100644 --- a/python/api_v2/imports/serializers.py +++ b/python/api_v2/imports/serializers.py @@ -10,11 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.serializers import EmptySerializer from cm.models import ObjectType from rest_framework.fields import ChoiceField, IntegerField -from adcm.serializers import EmptySerializer - class SourceSerializer(EmptySerializer): id = IntegerField() diff --git a/python/api_v2/imports/utils.py b/python/api_v2/imports/utils.py index 45195b1405..29796b7082 100644 --- a/python/api_v2/imports/utils.py +++ b/python/api_v2/imports/utils.py @@ -10,18 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.imports.types import ( - ClusterImportCandidate, - CommonImportCandidate, - ServiceImportCandidate, - UIBind, - UIBindSource, - UICluster, - UIImportCluster, - UIImportServices, - UIObjectImport, - UIPrototype, -) from cm.api import DataForMultiBind, is_version_suitable from cm.errors import AdcmEx, raise_adcm_ex from cm.models import ( @@ -36,6 +24,19 @@ from cm.status_api import get_obj_status from django.db.models import QuerySet +from api_v2.imports.types import ( + ClusterImportCandidate, + CommonImportCandidate, + ServiceImportCandidate, + UIBind, + UIBindSource, + UICluster, + UIImportCluster, + UIImportServices, + UIObjectImport, + UIPrototype, +) + def _format_binds(binds: QuerySet[ClusterBind]) -> list[UIBind]: binds_data = [] @@ -183,7 +184,7 @@ def get_imports(obj: Cluster | ClusterObject) -> list[UIObjectImport]: cluster = obj service = None else: - raise ValueError("Wrong obj type") + raise TypeError("Wrong obj type") out_data = [] import_candidates = _get_import_candidates(prototype=obj.prototype) diff --git a/python/api_v2/imports/views.py b/python/api_v2/imports/views.py index 96708e19ae..0528d53c73 100644 --- a/python/api_v2/imports/views.py +++ b/python/api_v2/imports/views.py @@ -10,18 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.imports.serializers import ImportPostSerializer -from api_v2.imports.utils import cook_data_for_multibind, get_imports -from api_v2.views import CamelCaseGenericViewSet -from audit.utils import audit -from cm.api import multi_bind -from cm.models import Cluster, ClusterObject, PrototypeImport -from rest_framework.mixins import CreateModelMixin, ListModelMixin -from rest_framework.permissions import IsAuthenticated -from rest_framework.request import Request -from rest_framework.response import Response -from rest_framework.status import HTTP_201_CREATED - from adcm.permissions import ( CHANGE_IMPORT_PERM, VIEW_CLUSTER_BIND, @@ -31,9 +19,21 @@ check_custom_perm, get_object_for_user, ) +from audit.utils import audit +from cm.api import multi_bind +from cm.models import Cluster, ClusterObject, PrototypeImport +from rest_framework.mixins import CreateModelMixin, ListModelMixin +from rest_framework.permissions import IsAuthenticated +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.status import HTTP_201_CREATED + +from api_v2.imports.serializers import ImportPostSerializer +from api_v2.imports.utils import cook_data_for_multibind, get_imports +from api_v2.views import CamelCaseGenericViewSet -class ImportViewSet(ListModelMixin, CreateModelMixin, CamelCaseGenericViewSet): # pylint: disable=too-many-ancestors +class ImportViewSet(ListModelMixin, CreateModelMixin, CamelCaseGenericViewSet): queryset = PrototypeImport.objects.all() permission_classes = [IsAuthenticated] ordering = ["id"] @@ -67,12 +67,12 @@ def get_object_and_check_perm(self, request) -> Cluster | ClusterObject: return obj - def list(self, request: Request, *args, **kwargs) -> Response: + def list(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 obj = self.get_object_and_check_perm(request=request) return self.get_paginated_response(data=self.paginate_queryset(queryset=get_imports(obj=obj))) @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 obj = self.get_object_and_check_perm(request=request) serializer = self.get_serializer(data=request.data, many=True, context={"request": request, "cluster": obj}) serializer.is_valid(raise_exception=True) diff --git a/python/api_v2/job/permissions.py b/python/api_v2/job/permissions.py index e9f924a692..296c4c58f3 100644 --- a/python/api_v2/job/permissions.py +++ b/python/api_v2/job/permissions.py @@ -24,5 +24,5 @@ class JobPermissions(DjangoObjectPermissions): "DELETE": ["%(app_label)s.delete_%(model_name)s"], } - def has_permission(self, request, view): + def has_permission(self, request, view): # noqa: ARG002 return True diff --git a/python/api_v2/job/serializers.py b/python/api_v2/job/serializers.py index c526e1f037..1a3492a06e 100644 --- a/python/api_v2/job/serializers.py +++ b/python/api_v2/job/serializers.py @@ -10,10 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.task.serializers import JobListSerializer, TaskRetrieveByJobSerializer from cm.models import JobLog from rest_framework.fields import DateTimeField +from api_v2.task.serializers import JobListSerializer, TaskRetrieveByJobSerializer + class JobRetrieveSerializer(JobListSerializer): parent_task = TaskRetrieveByJobSerializer(source="task", allow_null=True) diff --git a/python/api_v2/job/urls.py b/python/api_v2/job/urls.py index 6d5331bb18..667b197a09 100644 --- a/python/api_v2/job/urls.py +++ b/python/api_v2/job/urls.py @@ -10,11 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.job.views import JobViewSet -from api_v2.log_storage.views import LogStorageViewSet from rest_framework.routers import SimpleRouter from rest_framework_nested.routers import NestedSimpleRouter +from api_v2.job.views import JobViewSet +from api_v2.log_storage.views import LogStorageViewSet + router = SimpleRouter() router.register("", JobViewSet) diff --git a/python/api_v2/job/views.py b/python/api_v2/job/views.py index 266d572ed1..9c1fb3d2e6 100644 --- a/python/api_v2/job/views.py +++ b/python/api_v2/job/views.py @@ -9,10 +9,9 @@ # 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. -from api_v2.job.permissions import JobPermissions -from api_v2.job.serializers import JobRetrieveSerializer -from api_v2.task.serializers import JobListSerializer -from api_v2.views import CamelCaseGenericViewSet + +from adcm.permissions import VIEW_JOBLOG_PERMISSION +from adcm.serializers import EmptySerializer from audit.utils import audit from cm.models import JobLog from django.contrib.contenttypes.models import ContentType @@ -23,13 +22,13 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.permissions import VIEW_JOBLOG_PERMISSION -from adcm.serializers import EmptySerializer +from api_v2.job.permissions import JobPermissions +from api_v2.job.serializers import JobRetrieveSerializer +from api_v2.task.serializers import JobListSerializer +from api_v2.views import CamelCaseGenericViewSet -class JobViewSet( - PermissionListMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, CamelCaseGenericViewSet -): # pylint: disable=too-many-ancestors +class JobViewSet(PermissionListMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, CamelCaseGenericViewSet): queryset = JobLog.objects.select_related("task__action").order_by("pk") filter_backends = [] permission_classes = [JobPermissions] @@ -52,7 +51,7 @@ def get_serializer_class(self): @audit @action(methods=["post"], detail=True) - def terminate(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def terminate(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 job = self.get_object() job.cancel() diff --git a/python/api_v2/log_storage/serializers.py b/python/api_v2/log_storage/serializers.py index 0eb4febfba..eda3267c7c 100644 --- a/python/api_v2/log_storage/serializers.py +++ b/python/api_v2/log_storage/serializers.py @@ -10,14 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=duplicate-code -import json from contextlib import suppress +import json +from adcm import settings from cm.ansible_plugin import get_checklogs_data_by_job_id from cm.log import extract_log_content_from_fs from cm.models import LogStorage -from django.conf import settings from rest_framework.fields import SerializerMethodField from rest_framework.serializers import ModelSerializer @@ -54,15 +53,10 @@ def get_content(self, obj: LogStorage) -> str: and len(content) >= settings.STDOUT_STDERR_LOG_MAX_UNCUT_LENGTH ): cut_lines = "\n".join( - ( - line - if len(line) <= settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH - else ( - line[: settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH] - + settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE - ) - for line in content.splitlines()[-1500:] - ) + line + if len(line) <= settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH + else (line[: settings.STDOUT_STDERR_LOG_LINE_CUT_LENGTH] + settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE) + for line in content.splitlines()[-1500:] ) content = ( f"{settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE}\n" diff --git a/python/api_v2/log_storage/utils.py b/python/api_v2/log_storage/utils.py index eba6846fab..ee0e9cd931 100644 --- a/python/api_v2/log_storage/utils.py +++ b/python/api_v2/log_storage/utils.py @@ -10,12 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=duplicate-code -import io -import tarfile from datetime import datetime, timezone from pathlib import Path +import io +import tarfile +from adcm import settings +from adcm.utils import str_remove_non_alnum from cm.models import ( ActionType, ClusterObject, @@ -26,9 +27,6 @@ TaskLog, ) -from adcm import settings -from adcm.utils import str_remove_non_alnum - def get_task_download_archive_name(task: TaskLog) -> str: archive_name = f"{task.pk}.tar.gz" diff --git a/python/api_v2/log_storage/views.py b/python/api_v2/log_storage/views.py index 2993abb2b9..ad9efc456b 100644 --- a/python/api_v2/log_storage/views.py +++ b/python/api_v2/log_storage/views.py @@ -10,12 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import re from pathlib import Path +import re -from api_v2.log_storage.permissions import LogStoragePermissions -from api_v2.log_storage.serializers import LogStorageSerializer -from api_v2.views import CamelCaseGenericViewSet +from adcm import settings +from adcm.permissions import VIEW_LOGSTORAGE_PERMISSION from cm.models import JobLog, LogStorage from django.http import HttpResponse from guardian.mixins import PermissionListMixin @@ -25,11 +24,11 @@ from rest_framework.request import Request from rest_framework.response import Response -from adcm import settings -from adcm.permissions import VIEW_LOGSTORAGE_PERMISSION +from api_v2.log_storage.permissions import LogStoragePermissions +from api_v2.log_storage.serializers import LogStorageSerializer +from api_v2.views import CamelCaseGenericViewSet -# pylint:disable-next=too-many-ancestors class LogStorageViewSet(PermissionListMixin, ListModelMixin, RetrieveModelMixin, CamelCaseGenericViewSet): queryset = LogStorage.objects.select_related("job") serializer_class = LogStorageSerializer @@ -55,7 +54,7 @@ def retrieve(self, request, *args, **kwargs) -> Response: return super().retrieve(request, *args, **kwargs) @action(methods=["get"], detail=True) - def download(self, request: Request, **kwargs) -> HttpResponse: # pylint: disable=unused-argument + def download(self, request: Request, **kwargs) -> HttpResponse: # noqa: ARG001, ARG002 log_storage = self.get_object() job_pk = log_storage.job.pk @@ -65,10 +64,7 @@ def download(self, request: Request, **kwargs) -> HttpResponse: # pylint: disab filename = f"{job_pk}-{log_storage.name}.{log_storage.format}" filename = re.sub(r"\s+", "_", filename) - if log_storage.format == "txt": - mime_type = "text/plain" - else: - mime_type = "application/json" + mime_type = "text/plain" if log_storage.format == "txt" else "application/json" if log_storage.body is None: file_path = Path( diff --git a/python/api_v2/login/serializers.py b/python/api_v2/login/serializers.py index 3ea476b7c2..fb5ca5fc7c 100644 --- a/python/api_v2/login/serializers.py +++ b/python/api_v2/login/serializers.py @@ -10,9 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rest_framework.fields import CharField - from adcm.serializers import EmptySerializer +from rest_framework.fields import CharField class LoginSerializer(EmptySerializer): diff --git a/python/api_v2/login/views.py b/python/api_v2/login/views.py index 7600507e12..dddbb7b13d 100644 --- a/python/api_v2/login/views.py +++ b/python/api_v2/login/views.py @@ -9,7 +9,6 @@ # 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. -from api_v2.login.serializers import LoginSerializer from cm.errors import AdcmEx from django.contrib.auth import authenticate, login from django.contrib.auth.models import User as AuthUser @@ -28,6 +27,8 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK +from api_v2.login.serializers import LoginSerializer + class BaseLoginView(GenericAPIView): permission_classes = (AllowAny,) @@ -50,6 +51,6 @@ def perform_login(self, request: Request) -> AuthUser: class LoginView(BaseLoginView): - def post(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def post(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 self.perform_login(request=request) return Response(status=HTTP_200_OK) diff --git a/python/api_v2/logout/views.py b/python/api_v2/logout/views.py index b416864ee1..78151c8a3c 100644 --- a/python/api_v2/logout/views.py +++ b/python/api_v2/logout/views.py @@ -10,6 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.serializers import EmptySerializer from django.contrib.auth import logout from djangorestframework_camel_case.parser import ( CamelCaseFormParser, @@ -26,8 +27,6 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.serializers import EmptySerializer - class LogoutView(GenericAPIView): permission_classes = (IsAuthenticated,) @@ -36,7 +35,7 @@ class LogoutView(GenericAPIView): parser_classes = [CamelCaseJSONParser, CamelCaseMultiPartParser, CamelCaseFormParser] renderer_classes = [CamelCaseJSONRenderer, CamelCaseBrowsableAPIRenderer] - def post(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def post(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 logout(request) return Response(status=HTTP_200_OK) diff --git a/python/api_v2/profile/serializers.py b/python/api_v2/profile/serializers.py index 613954796a..13aa91877b 100644 --- a/python/api_v2/profile/serializers.py +++ b/python/api_v2/profile/serializers.py @@ -33,16 +33,15 @@ class Meta: read_only_fields = ["username", "email", "first_name", "last_name", "is_super_user", "auth_settings"] @staticmethod - def get_auth_settings(user: User) -> dict: # pylint: disable=unused-argument + def get_auth_settings(user: User) -> dict: # noqa: ARG001, ARG004 adcm = ADCM.objects.first() auth_policy = ConfigLog.objects.filter(obj_ref=adcm.config).last().config["auth_policy"] - auth_settings = { + return { "minPasswordLength": auth_policy["min_password_length"], "maxPasswordLength": auth_policy["max_password_length"], "loginAttemptLimit": auth_policy["login_attempt_limit"], "blockTime": auth_policy["block_time"], } - return auth_settings class ProfileUpdateSerializer(ModelSerializer): diff --git a/python/api_v2/profile/views.py b/python/api_v2/profile/views.py index 3ef6f1c6b0..712f52f46b 100644 --- a/python/api_v2/profile/views.py +++ b/python/api_v2/profile/views.py @@ -9,7 +9,6 @@ # 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. -from api_v2.profile.serializers import ProfileSerializer, ProfileUpdateSerializer from audit.utils import audit from django.conf import settings from djangorestframework_camel_case.parser import ( @@ -26,6 +25,8 @@ from rest_framework.generics import RetrieveUpdateAPIView from rest_framework.response import Response +from api_v2.profile.serializers import ProfileSerializer, ProfileUpdateSerializer + class ProfileView(RetrieveUpdateAPIView): queryset = User.objects.exclude(username__in=settings.ADCM_HIDDEN_USERS) @@ -42,7 +43,7 @@ def get_serializer_class(self) -> type[ProfileSerializer | ProfileUpdateSerializ return ProfileSerializer @audit - def update(self, request, *args, **kwargs): + def update(self, request, *args, **kwargs): # noqa: ARG002 instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=True) serializer.is_valid(raise_exception=True) diff --git a/python/api_v2/prototype/serializers.py b/python/api_v2/prototype/serializers.py index 6abbafcaee..468b984b34 100644 --- a/python/api_v2/prototype/serializers.py +++ b/python/api_v2/prototype/serializers.py @@ -10,13 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.bundle.serializers import BundleRelatedSerializer -from api_v2.prototype.utils import get_license_text +from adcm.serializers import EmptySerializer from cm.models import Prototype from rest_framework.fields import CharField, IntegerField, SerializerMethodField from rest_framework.serializers import ModelSerializer -from adcm.serializers import EmptySerializer +from api_v2.bundle.serializers import BundleRelatedSerializer +from api_v2.prototype.utils import get_license_text class PrototypeListSerializer(ModelSerializer): diff --git a/python/api_v2/prototype/urls.py b/python/api_v2/prototype/urls.py index 17041152a9..fb953b62cb 100644 --- a/python/api_v2/prototype/urls.py +++ b/python/api_v2/prototype/urls.py @@ -9,9 +9,10 @@ # 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. -from api_v2.prototype.views import PrototypeViewSet from rest_framework.routers import SimpleRouter +from api_v2.prototype.views import PrototypeViewSet + router = SimpleRouter() router.register("", PrototypeViewSet) diff --git a/python/api_v2/prototype/views.py b/python/api_v2/prototype/views.py index f241abac5f..1522f50017 100644 --- a/python/api_v2/prototype/views.py +++ b/python/api_v2/prototype/views.py @@ -10,13 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.prototype.filters import PrototypeFilter, PrototypeVersionFilter -from api_v2.prototype.serializers import ( - PrototypeListSerializer, - PrototypeTypeSerializer, -) -from api_v2.prototype.utils import accept_license -from api_v2.views import CamelCaseReadOnlyModelViewSet +from adcm.permissions import VIEW_CLUSTER_PERM, DjangoModelPermissionsAudit +from adcm.serializers import EmptySerializer from audit.utils import audit from cm.models import ObjectType, Prototype from django.db.models import QuerySet @@ -25,11 +20,16 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.permissions import VIEW_CLUSTER_PERM, DjangoModelPermissionsAudit -from adcm.serializers import EmptySerializer +from api_v2.prototype.filters import PrototypeFilter, PrototypeVersionFilter +from api_v2.prototype.serializers import ( + PrototypeListSerializer, + PrototypeTypeSerializer, +) +from api_v2.prototype.utils import accept_license +from api_v2.views import CamelCaseReadOnlyModelViewSet -class PrototypeViewSet(CamelCaseReadOnlyModelViewSet): # pylint: disable=too-many-ancestors +class PrototypeViewSet(CamelCaseReadOnlyModelViewSet): queryset = Prototype.objects.exclude(type="adcm").select_related("bundle").order_by("name") permission_classes = [DjangoModelPermissionsAudit] permission_required = [VIEW_CLUSTER_PERM] @@ -45,13 +45,13 @@ def get_serializer_class(self): return PrototypeListSerializer @action(methods=["get"], detail=False, filterset_class=PrototypeVersionFilter) - def versions(self, request): # pylint: disable=unused-argument + def versions(self, request): # noqa: ARG001, ARG002 queryset = self.get_filtered_prototypes_unique_by_display_name() return Response(data=self.get_serializer(queryset, many=True).data) @audit @action(methods=["post"], detail=True, url_path="license/accept", url_name="accept-license") - def accept(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def accept(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 prototype = self.get_object() accept_license(prototype=prototype) return Response(status=HTTP_200_OK) diff --git a/python/api_v2/rbac/group/serializers.py b/python/api_v2/rbac/group/serializers.py index 10567a5fbf..3b55be4853 100644 --- a/python/api_v2/rbac/group/serializers.py +++ b/python/api_v2/rbac/group/serializers.py @@ -9,6 +9,7 @@ # 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. +from adcm.serializers import EmptySerializer from django.conf import settings from rbac.models import Group, User from rest_framework.fields import IntegerField @@ -19,8 +20,6 @@ PrimaryKeyRelatedField, ) -from adcm.serializers import EmptySerializer - class RelatedUserSerializer(ModelSerializer): username = CharField(read_only=True) diff --git a/python/api_v2/rbac/group/urls.py b/python/api_v2/rbac/group/urls.py index 4799639323..407db2c78d 100644 --- a/python/api_v2/rbac/group/urls.py +++ b/python/api_v2/rbac/group/urls.py @@ -10,8 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.rbac.group.views import GroupViewSet from rest_framework.routers import SimpleRouter +from api_v2.rbac.group.views import GroupViewSet + group_router = SimpleRouter() group_router.register(prefix="groups", viewset=GroupViewSet) diff --git a/python/api_v2/rbac/group/views.py b/python/api_v2/rbac/group/views.py index c965fd70b4..5e93603e25 100644 --- a/python/api_v2/rbac/group/views.py +++ b/python/api_v2/rbac/group/views.py @@ -10,13 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.rbac.group.filters import GroupFilter -from api_v2.rbac.group.serializers import ( - GroupCreateSerializer, - GroupSerializer, - GroupUpdateSerializer, -) -from api_v2.views import CamelCaseModelViewSet +from adcm.permissions import VIEW_GROUP_PERMISSION, CustomModelPermissionsByMethod from audit.utils import audit from cm.errors import AdcmEx from guardian.mixins import PermissionListMixin @@ -29,10 +23,16 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.permissions import VIEW_GROUP_PERMISSION, CustomModelPermissionsByMethod +from api_v2.rbac.group.filters import GroupFilter +from api_v2.rbac.group.serializers import ( + GroupCreateSerializer, + GroupSerializer, + GroupUpdateSerializer, +) +from api_v2.views import CamelCaseModelViewSet -class GroupViewSet(PermissionListMixin, CamelCaseModelViewSet): # pylint:disable=too-many-ancestors +class GroupViewSet(PermissionListMixin, CamelCaseModelViewSet): queryset = Group.objects.order_by("display_name").prefetch_related("user_set") filterset_class = GroupFilter permission_classes = (CustomModelPermissionsByMethod,) @@ -52,7 +52,7 @@ def get_serializer_class(self) -> type[GroupSerializer | GroupCreateSerializer | return GroupSerializer @audit - def create(self, request: Request, *args, **kwargs) -> Response: + def create(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -66,7 +66,7 @@ def create(self, request: Request, *args, **kwargs) -> Response: return Response(data=GroupSerializer(instance=group).data, status=HTTP_201_CREATED) @audit - def update(self, request: Request, *args, **kwargs) -> Response: + def update(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -94,4 +94,4 @@ def destroy(self, request: Request, *args, **kwargs) -> Response: if instance.policy_set.exists(): raise AdcmEx(code="GROUP_DELETE_ERROR", msg="Group with policy should not be deleted") - return super().destroy(request=request, *args, **kwargs) + return super().destroy(*args, request=request, **kwargs) diff --git a/python/api_v2/rbac/policy/serializers.py b/python/api_v2/rbac/policy/serializers.py index 2b2d65e2b0..aeea24ad70 100644 --- a/python/api_v2/rbac/policy/serializers.py +++ b/python/api_v2/rbac/policy/serializers.py @@ -10,8 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.rbac.group.serializers import GroupRelatedSerializer -from api_v2.rbac.role.serializers import RoleRelatedSerializer from rbac.endpoints.policy.serializers import ObjectField from rbac.endpoints.serializers import BaseRelatedSerializer from rbac.models import Group, Policy, Role, RoleTypes @@ -20,6 +18,9 @@ from rest_framework.relations import ManyRelatedField, PrimaryKeyRelatedField from rest_framework.serializers import ModelSerializer +from api_v2.rbac.group.serializers import GroupRelatedSerializer +from api_v2.rbac.role.serializers import RoleRelatedSerializer + class PolicyObjectField(ObjectField): def to_representation(self, value): diff --git a/python/api_v2/rbac/policy/urls.py b/python/api_v2/rbac/policy/urls.py index 414d568f1b..7743077216 100644 --- a/python/api_v2/rbac/policy/urls.py +++ b/python/api_v2/rbac/policy/urls.py @@ -10,8 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.rbac.policy.views import PolicyViewSet from rest_framework.routers import SimpleRouter +from api_v2.rbac.policy.views import PolicyViewSet + policy_router = SimpleRouter() policy_router.register(prefix="policies", viewset=PolicyViewSet) diff --git a/python/api_v2/rbac/policy/views.py b/python/api_v2/rbac/policy/views.py index 33d8cd1978..ba7379d788 100644 --- a/python/api_v2/rbac/policy/views.py +++ b/python/api_v2/rbac/policy/views.py @@ -10,9 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.rbac.policy.filters import PolicyFilter -from api_v2.rbac.policy.serializers import PolicyCreateSerializer, PolicySerializer -from api_v2.views import CamelCaseModelViewSet +from adcm.permissions import VIEW_POLICY_PERMISSION, CustomModelPermissionsByMethod from audit.utils import audit from cm.errors import AdcmEx, raise_adcm_ex from django_filters.rest_framework.backends import DjangoFilterBackend @@ -23,10 +21,12 @@ from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED -from adcm.permissions import VIEW_POLICY_PERMISSION, CustomModelPermissionsByMethod +from api_v2.rbac.policy.filters import PolicyFilter +from api_v2.rbac.policy.serializers import PolicyCreateSerializer, PolicySerializer +from api_v2.views import CamelCaseModelViewSet -class PolicyViewSet(PermissionListMixin, CamelCaseModelViewSet): # pylint: disable=too-many-ancestors +class PolicyViewSet(PermissionListMixin, CamelCaseModelViewSet): queryset = Policy.objects.select_related("role").prefetch_related("group", "object").order_by("name") filter_backends = (DjangoFilterBackend,) filterset_class = PolicyFilter @@ -45,14 +45,14 @@ def get_serializer_class(self) -> type[PolicySerializer | PolicyCreateSerializer return PolicySerializer @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer_class()(data=request.data) serializer.is_valid(raise_exception=True) policy = policy_create(**serializer.validated_data) return Response(data=PolicySerializer(policy).data, status=HTTP_201_CREATED) @audit - def update(self, request, *args, **kwargs): + def update(self, request, *args, **kwargs): # noqa: ARG002 policy = self.get_object() if policy.built_in: diff --git a/python/api_v2/rbac/role/filters.py b/python/api_v2/rbac/role/filters.py index 1dfc316975..f11a69e0ed 100644 --- a/python/api_v2/rbac/role/filters.py +++ b/python/api_v2/rbac/role/filters.py @@ -23,7 +23,7 @@ class RoleFilter(FilterSet): type = ChoiceFilter(choices=[(k, v) for k, v in RoleTypes.choices if k != RoleTypes.HIDDEN]) @staticmethod - def filter_category(queryset: QuerySet, name: str, value: str): # pylint: disable=unused-argument + def filter_category(queryset: QuerySet, name: str, value: str): # noqa: ARG001, ARG004 return queryset.filter(Q(category__value=value) | Q(any_category=True)) class Meta: diff --git a/python/api_v2/rbac/role/views.py b/python/api_v2/rbac/role/views.py index 394e89402f..e03ca305d7 100644 --- a/python/api_v2/rbac/role/views.py +++ b/python/api_v2/rbac/role/views.py @@ -11,9 +11,7 @@ # limitations under the License. from collections import defaultdict -from api_v2.rbac.role.filters import RoleFilter -from api_v2.rbac.role.serializers import RoleCreateUpdateSerializer, RoleSerializer -from api_v2.views import CamelCaseModelViewSet +from adcm.permissions import VIEW_ROLE_PERMISSION, CustomModelPermissionsByMethod from audit.utils import audit from cm.errors import AdcmEx from cm.models import Cluster, ClusterObject, Host, HostProvider, ProductCategory @@ -27,10 +25,12 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.permissions import VIEW_ROLE_PERMISSION, CustomModelPermissionsByMethod +from api_v2.rbac.role.filters import RoleFilter +from api_v2.rbac.role.serializers import RoleCreateUpdateSerializer, RoleSerializer +from api_v2.views import CamelCaseModelViewSet -class RoleViewSet(PermissionListMixin, CamelCaseModelViewSet): # pylint: disable=too-many-ancestors +class RoleViewSet(PermissionListMixin, CamelCaseModelViewSet): queryset = ( Role.objects.prefetch_related( Prefetch(lookup="child", queryset=Role.objects.exclude(type=RoleTypes.HIDDEN)), "category", "policy_set" @@ -53,7 +53,7 @@ def get_serializer_class(self): return RoleSerializer @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) role = role_create(**serializer.validated_data) @@ -61,7 +61,7 @@ def create(self, request, *args, **kwargs): return Response(data=RoleSerializer(instance=role).data, status=HTTP_201_CREATED) @audit - def update(self, request, *args, **kwargs): + def update(self, request, *args, **kwargs): # noqa: ARG002 partial = kwargs.pop("partial", False) instance = self.get_object() @@ -87,11 +87,11 @@ def destroy(self, request, *args, **kwargs): return super().destroy(request, *args, **kwargs) @action(methods=["get"], detail=False) - def categories(self, request, *args, **kwargs): # pylint: disable=unused-argument + def categories(self, request, *args, **kwargs): # noqa: ARG001, ARG002 return Response(data=sorted(category.value for category in ProductCategory.objects.all()), status=HTTP_200_OK) @action(methods=["get"], detail=True, url_path="object-candidates", url_name="object-candidates") - def object_candidates(self, request, *args, **kwargs): # pylint: disable=unused-argument + def object_candidates(self, request, *args, **kwargs): # noqa: ARG001, ARG002 role = self.get_object() if role.type != RoleTypes.ROLE: return Response({"cluster": [], "provider": [], "service": [], "host": []}) diff --git a/python/api_v2/rbac/urls.py b/python/api_v2/rbac/urls.py index 23451720af..27cf8a7d93 100644 --- a/python/api_v2/rbac/urls.py +++ b/python/api_v2/rbac/urls.py @@ -10,13 +10,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +from django.urls import path +from rest_framework.routers import SimpleRouter + from api_v2.rbac.group.urls import group_router from api_v2.rbac.policy.urls import policy_router from api_v2.rbac.role.views import RoleViewSet from api_v2.rbac.user.urls import user_router from api_v2.rbac.views import RbacRoot -from django.urls import path -from rest_framework.routers import SimpleRouter role_router = SimpleRouter() role_router.register("roles", RoleViewSet) diff --git a/python/api_v2/rbac/user/filters.py b/python/api_v2/rbac/user/filters.py index be9fcc635c..19be323cf2 100644 --- a/python/api_v2/rbac/user/filters.py +++ b/python/api_v2/rbac/user/filters.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.rbac.user.constants import UserStatusChoices, UserTypeChoices from django.db.models import QuerySet from django_filters.rest_framework import ( CharFilter, @@ -19,6 +18,8 @@ OrderingFilter, ) +from api_v2.rbac.user.constants import UserStatusChoices, UserTypeChoices + class UserFilterSet(FilterSet): username = CharFilter(field_name="username", label="username", lookup_expr="icontains") @@ -27,7 +28,7 @@ class UserFilterSet(FilterSet): ordering = OrderingFilter(fields={"username": "username"}, field_labels={"username": "username"}, label="ordering") @staticmethod - def filter_status(queryset: QuerySet, name: str, value: str) -> QuerySet: # pylint: disable=unused-argument + def filter_status(queryset: QuerySet, name: str, value: str) -> QuerySet: # noqa: ARG001, ARG004 filter_value = False if value == UserStatusChoices.ACTIVE: @@ -36,7 +37,7 @@ def filter_status(queryset: QuerySet, name: str, value: str) -> QuerySet: # pyl return queryset.filter(blocked_at__isnull=filter_value) @staticmethod - def filter_type(queryset: QuerySet, name: str, value: str) -> QuerySet: # pylint: disable=unused-argument + def filter_type(queryset: QuerySet, name: str, value: str) -> QuerySet: # noqa: ARG001, ARG004 filter_value = UserTypeChoices.LOCAL.value if value == UserTypeChoices.LDAP: diff --git a/python/api_v2/rbac/user/serializers.py b/python/api_v2/rbac/user/serializers.py index 4f498eb0a6..204dbfa0c7 100644 --- a/python/api_v2/rbac/user/serializers.py +++ b/python/api_v2/rbac/user/serializers.py @@ -9,7 +9,6 @@ # 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. -from api_v2.rbac.user.constants import UserStatusChoices from django.conf import settings from django.contrib.auth.models import Group as AuthGroup from rbac.models import User @@ -22,6 +21,8 @@ ) from rest_framework.serializers import ModelSerializer +from api_v2.rbac.user.constants import UserStatusChoices + class RelatedGroupSerializer(ModelSerializer): display_name = SerializerMethodField() diff --git a/python/api_v2/rbac/user/urls.py b/python/api_v2/rbac/user/urls.py index 613e371c40..b7fca22529 100644 --- a/python/api_v2/rbac/user/urls.py +++ b/python/api_v2/rbac/user/urls.py @@ -10,8 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.rbac.user.views import UserViewSet from rest_framework.routers import SimpleRouter +from api_v2.rbac.user.views import UserViewSet + user_router = SimpleRouter() user_router.register(prefix="users", viewset=UserViewSet) diff --git a/python/api_v2/rbac/user/views.py b/python/api_v2/rbac/user/views.py index 77410ef0de..8b5d321001 100644 --- a/python/api_v2/rbac/user/views.py +++ b/python/api_v2/rbac/user/views.py @@ -9,14 +9,7 @@ # 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. -from api_v2.rbac.user.filters import UserFilterSet -from api_v2.rbac.user.serializers import ( - UserCreateSerializer, - UserSerializer, - UserUpdateSerializer, -) -from api_v2.rbac.user.utils import unblock_user -from api_v2.views import CamelCaseModelViewSet +from adcm.permissions import VIEW_USER_PERMISSION, CustomModelPermissionsByMethod from audit.utils import audit from cm.errors import AdcmEx from django.conf import settings @@ -33,10 +26,17 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.permissions import VIEW_USER_PERMISSION, CustomModelPermissionsByMethod +from api_v2.rbac.user.filters import UserFilterSet +from api_v2.rbac.user.serializers import ( + UserCreateSerializer, + UserSerializer, + UserUpdateSerializer, +) +from api_v2.rbac.user.utils import unblock_user +from api_v2.views import CamelCaseModelViewSet -class UserViewSet(PermissionListMixin, CamelCaseModelViewSet): # pylint: disable=too-many-ancestors +class UserViewSet(PermissionListMixin, CamelCaseModelViewSet): queryset = ( User.objects.prefetch_related(Prefetch(lookup="groups", queryset=AuthGroup.objects.select_related("group"))) .exclude(username__in=settings.ADCM_HIDDEN_USERS) @@ -61,7 +61,7 @@ def get_serializer_class(self) -> type[UserSerializer] | type[UserUpdateSerializ return UserSerializer @audit - def create(self, request: Request, *args, **kwargs) -> Response: + def create(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -71,7 +71,7 @@ def create(self, request: Request, *args, **kwargs) -> Response: return Response(data=UserSerializer(instance=user).data, status=HTTP_201_CREATED) @audit - def partial_update(self, request: Request, *args, **kwargs) -> Response: + def partial_update(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 instance: User = self.get_object() serializer = self.get_serializer(instance=instance, data=request.data) serializer.is_valid(raise_exception=True) @@ -91,7 +91,7 @@ def partial_update(self, request: Request, *args, **kwargs) -> Response: @audit @action(methods=["post"], detail=True) - def unblock(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def unblock(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 if not request.user.is_superuser: raise AdcmEx(code="USER_UNBLOCK_ERROR") @@ -105,4 +105,4 @@ def destroy(self, request: Request, *args, **kwargs) -> Response: if user.built_in: raise AdcmEx(code="USER_DELETE_ERROR") - return super().destroy(request=request, *args, **kwargs) + return super().destroy(*args, request=request, **kwargs) diff --git a/python/api_v2/service/filters.py b/python/api_v2/service/filters.py index cf480874e7..509f5cd6e9 100644 --- a/python/api_v2/service/filters.py +++ b/python/api_v2/service/filters.py @@ -35,7 +35,7 @@ class Meta: fields = ["name", "display_name", "status"] @staticmethod - def filter_status(queryset: QuerySet, name: str, value: str) -> QuerySet: # pylint: disable=unused-argument + def filter_status(queryset: QuerySet, name: str, value: str) -> QuerySet: # noqa: ARG001, ARG004 if value == ADCMEntityStatus.UP: exclude_pks = {service.pk for service in queryset if get_service_status(service=service) != 0} else: @@ -44,5 +44,5 @@ def filter_status(queryset: QuerySet, name: str, value: str) -> QuerySet: # pyl return queryset.exclude(pk__in=exclude_pks) @staticmethod - def filter_name(queryset: QuerySet, name: str, value: str) -> QuerySet: # pylint: disable=unused-argument + def filter_name(queryset: QuerySet, name: str, value: str) -> QuerySet: # noqa: ARG001, ARG004 return queryset.filter(prototype__type=ObjectType.SERVICE, prototype__name__icontains=value) diff --git a/python/api_v2/service/serializers.py b/python/api_v2/service/serializers.py index d01dbc78ee..d2ab5f6a79 100644 --- a/python/api_v2/service/serializers.py +++ b/python/api_v2/service/serializers.py @@ -10,9 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.cluster.serializers import ClusterRelatedSerializer -from api_v2.concern.serializers import ConcernSerializer -from api_v2.prototype.serializers import PrototypeRelatedSerializer +from adcm.serializers import EmptySerializer from cm.adcm_config.config import get_main_info from cm.models import ClusterObject, MaintenanceMode, ServiceComponent from cm.status_api import get_obj_status @@ -23,7 +21,9 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer +from api_v2.cluster.serializers import ClusterRelatedSerializer +from api_v2.concern.serializers import ConcernSerializer +from api_v2.prototype.serializers import PrototypeRelatedSerializer class ServiceRetrieveSerializer(ModelSerializer): diff --git a/python/api_v2/service/utils.py b/python/api_v2/service/utils.py index b76c7c44eb..15fd9ee8cc 100644 --- a/python/api_v2/service/utils.py +++ b/python/api_v2/service/utils.py @@ -65,7 +65,7 @@ def bulk_init_config(objects: QuerySet[ADCMEntity]) -> None: # SQLite support. We need ids of created objects, bulk_create on SQLite does not return ids cursor = connection.cursor() cursor.execute( - f"""INSERT INTO "cm_objectconfig" ("current", "previous") VALUES + f"""INSERT INTO "cm_objectconfig" ("current", "previous") VALUES {', '.join(['(0, 0)'] * objects.count())} RETURNING id;""" ) object_config_ids = [item[0] for item in cursor.fetchall()] @@ -111,16 +111,16 @@ def validate_service_prototypes( if not prototypes.exists(): return None, AdcmEx(code="PROTOTYPE_NOT_FOUND") - if set(proto.type for proto in prototypes).difference({ObjectType.SERVICE.value}): + if {proto.type for proto in prototypes}.difference({ObjectType.SERVICE.value}): return None, AdcmEx(code="OBJ_TYPE_ERROR", msg=f"All prototypes must be `{ObjectType.SERVICE}` type") - if "unaccepted" in set(proto.license for proto in prototypes): + if "unaccepted" in {proto.license for proto in prototypes}: return None, AdcmEx(code="LICENSE_ERROR", msg="All licenses must be accepted") if ClusterObject.objects.filter(prototype__in=prototypes, cluster=cluster).exists(): return None, AdcmEx(code="SERVICE_CONFLICT") - if set(proto.bundle.pk for proto in prototypes if not proto.shared).difference({cluster.prototype.bundle.pk}): + if {proto.bundle.pk for proto in prototypes if not proto.shared}.difference({cluster.prototype.bundle.pk}): return None, AdcmEx( code="SERVICE_CONFLICT", msg=f"Some service prototype does not belong to bundle " diff --git a/python/api_v2/service/views.py b/python/api_v2/service/views.py index 6859f69282..7a50a7542c 100644 --- a/python/api_v2/service/views.py +++ b/python/api_v2/service/views.py @@ -9,20 +9,16 @@ # 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. -from api_v2.config.utils import ConfigSchemaMixin -from api_v2.service.filters import ServiceFilter -from api_v2.service.permissions import ServicePermissions -from api_v2.service.serializers import ( - ServiceCreateSerializer, - ServiceMaintenanceModeSerializer, - ServiceRetrieveSerializer, - ServiceStatusSerializer, -) -from api_v2.service.utils import ( - bulk_add_services_to_cluster, - validate_service_prototypes, +from adcm.permissions import ( + ADD_SERVICE_PERM, + CHANGE_MM_PERM, + VIEW_CLUSTER_PERM, + VIEW_SERVICE_PERM, + ChangeMMPermissions, + check_custom_perm, + get_object_for_user, ) -from api_v2.views import CamelCaseGenericViewSet +from adcm.utils import delete_service_from_api, get_maintenance_mode_response from audit.utils import audit from cm.api import update_mm_objects from cm.models import Cluster, ClusterObject @@ -39,19 +35,23 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.permissions import ( - ADD_SERVICE_PERM, - CHANGE_MM_PERM, - VIEW_CLUSTER_PERM, - VIEW_SERVICE_PERM, - ChangeMMPermissions, - check_custom_perm, - get_object_for_user, +from api_v2.config.utils import ConfigSchemaMixin +from api_v2.service.filters import ServiceFilter +from api_v2.service.permissions import ServicePermissions +from api_v2.service.serializers import ( + ServiceCreateSerializer, + ServiceMaintenanceModeSerializer, + ServiceRetrieveSerializer, + ServiceStatusSerializer, ) -from adcm.utils import delete_service_from_api, get_maintenance_mode_response +from api_v2.service.utils import ( + bulk_add_services_to_cluster, + validate_service_prototypes, +) +from api_v2.views import CamelCaseGenericViewSet -class ServiceViewSet( # pylint: disable=too-many-ancestors +class ServiceViewSet( PermissionListMixin, ConfigSchemaMixin, CreateModelMixin, @@ -85,7 +85,7 @@ def get_serializer_class(self): return self.serializer_class @audit - def create(self, request: Request, *args, **kwargs): + def create(self, request: Request, *args, **kwargs): # noqa: ARG002 cluster = get_object_for_user( user=request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, pk=kwargs["cluster_pk"] ) @@ -112,14 +112,14 @@ def create(self, request: Request, *args, **kwargs): return Response(status=HTTP_201_CREATED, data=ServiceRetrieveSerializer(instance=added_services[0]).data) @audit - def destroy(self, request: Request, *args, **kwargs): + def destroy(self, request: Request, *args, **kwargs): # noqa: ARG002 instance = self.get_object() return delete_service_from_api(service=instance) @audit @update_mm_objects @action(methods=["post"], detail=True, url_path="maintenance-mode", permission_classes=[ChangeMMPermissions]) - def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 service = get_object_for_user(user=request.user, perms=VIEW_SERVICE_PERM, klass=ClusterObject, pk=kwargs["pk"]) check_custom_perm( user=request.user, action_type=CHANGE_MM_PERM, model=service.__class__.__name__.lower(), obj=service @@ -135,7 +135,7 @@ def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # py return response @action(methods=["get"], detail=True, url_path="statuses") - def statuses(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 service = get_object_for_user(user=request.user, perms=VIEW_SERVICE_PERM, klass=ClusterObject, id=kwargs["pk"]) return Response(data=ServiceStatusSerializer(instance=service).data) diff --git a/python/api_v2/task/filters.py b/python/api_v2/task/filters.py index 2c8e0b1dbd..380767832d 100644 --- a/python/api_v2/task/filters.py +++ b/python/api_v2/task/filters.py @@ -51,7 +51,7 @@ def filter_object_name(self, queryset: QuerySet, _: str, value: str) -> QuerySet providers = HostProvider.objects.filter(name__icontains=value).values_list("id") hosts = Host.objects.filter(fqdn__icontains=value).values_list("id") - queryset = ( + return ( queryset.filter(object_type=ContentType.objects.get_for_model(Cluster), object_id__in=clusters) | queryset.filter(object_type=ContentType.objects.get_for_model(ClusterObject), object_id__in=services) | queryset.filter(object_type=ContentType.objects.get_for_model(ServiceComponent), object_id__in=components) @@ -59,8 +59,6 @@ def filter_object_name(self, queryset: QuerySet, _: str, value: str) -> QuerySet | queryset.filter(object_type=ContentType.objects.get_for_model(Host), object_id__in=hosts) ) - return queryset - class Meta: model = TaskLog fields = ["id", "job_name", "object_name", "status", "ordering"] diff --git a/python/api_v2/task/permissions.py b/python/api_v2/task/permissions.py index bac84e767e..1bc7befac2 100644 --- a/python/api_v2/task/permissions.py +++ b/python/api_v2/task/permissions.py @@ -24,5 +24,5 @@ class TaskPermissions(DjangoObjectPermissions): "DELETE": ["%(app_label)s.delete_%(model_name)s"], } - def has_permission(self, request, view): + def has_permission(self, request, view): # noqa: ARG002 return True diff --git a/python/api_v2/task/serializers.py b/python/api_v2/task/serializers.py index 65ae9fd967..442fd86ed9 100644 --- a/python/api_v2/task/serializers.py +++ b/python/api_v2/task/serializers.py @@ -10,11 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.action.serializers import ActionNameSerializer from cm.models import Action, JobLog, JobStatus, SubAction, TaskLog from rest_framework.fields import CharField, DateTimeField, SerializerMethodField from rest_framework.serializers import ModelSerializer +from api_v2.action.serializers import ActionNameSerializer + OBJECT_ORDER = { "adcm": 0, "cluster": 1, @@ -99,10 +100,7 @@ class Meta: @staticmethod def get_is_terminatable(obj: TaskLog): - if obj.action: - allow_to_terminate = obj.action.allow_to_terminate - else: - allow_to_terminate = False + allow_to_terminate = obj.action.allow_to_terminate if obj.action else False if allow_to_terminate and obj.status in {JobStatus.CREATED, JobStatus.RUNNING}: return True diff --git a/python/api_v2/task/urls.py b/python/api_v2/task/urls.py index 464f1a26d0..161baa0771 100644 --- a/python/api_v2/task/urls.py +++ b/python/api_v2/task/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.task.views import TaskViewSet from rest_framework.routers import SimpleRouter +from api_v2.task.views import TaskViewSet + router = SimpleRouter() router.register("", TaskViewSet) diff --git a/python/api_v2/task/views.py b/python/api_v2/task/views.py index 8003f76a46..5ca8797bb6 100644 --- a/python/api_v2/task/views.py +++ b/python/api_v2/task/views.py @@ -9,14 +9,8 @@ # 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. -from api_v2.log_storage.utils import ( - get_task_download_archive_file_handler, - get_task_download_archive_name, -) -from api_v2.task.filters import TaskFilter -from api_v2.task.permissions import TaskPermissions -from api_v2.task.serializers import TaskListSerializer -from api_v2.views import CamelCaseGenericViewSet + +from adcm.permissions import VIEW_TASKLOG_PERMISSION from audit.utils import audit from cm.models import TaskLog from django.contrib.contenttypes.models import ContentType @@ -29,12 +23,17 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK -from adcm.permissions import VIEW_TASKLOG_PERMISSION +from api_v2.log_storage.utils import ( + get_task_download_archive_file_handler, + get_task_download_archive_name, +) +from api_v2.task.filters import TaskFilter +from api_v2.task.permissions import TaskPermissions +from api_v2.task.serializers import TaskListSerializer +from api_v2.views import CamelCaseGenericViewSet -class TaskViewSet( - PermissionListMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, CamelCaseGenericViewSet -): # pylint: disable=too-many-ancestors +class TaskViewSet(PermissionListMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, CamelCaseGenericViewSet): queryset = TaskLog.objects.select_related("action").order_by("-pk") serializer_class = TaskListSerializer filterset_class = TaskFilter @@ -50,14 +49,14 @@ def get_queryset(self, *args, **kwargs): @audit @action(methods=["post"], detail=True) - def terminate(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def terminate(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 task = self.get_object() task.cancel() return Response(status=HTTP_200_OK, data=TaskListSerializer(instance=task).data) @action(methods=["get"], detail=True, url_path="logs/download") - def download(self, request: Request, *args, **kwargs): # pylint: disable=unused-argument + def download(self, request: Request, *args, **kwargs): # noqa: ARG001, ARG002 task = self.get_object() response = HttpResponse( content=get_task_download_archive_file_handler(task=task).getvalue(), diff --git a/python/api_v2/tests/base.py b/python/api_v2/tests/base.py index 792e4e9743..f77bb04ce7 100644 --- a/python/api_v2/tests/base.py +++ b/python/api_v2/tests/base.py @@ -13,6 +13,7 @@ from shutil import rmtree from typing import Any, TypeAlias +from adcm.tests.base import BusinessLogicMixin, ParallelReadyTestCase from audit.models import AuditLog, AuditSession from cm.models import ( ADCM, @@ -30,8 +31,6 @@ from rbac.upgrade.role import init_roles from rest_framework.test import APITestCase -from adcm.tests.base import BusinessLogicMixin, ParallelReadyTestCase - AuditTarget: TypeAlias = ( Bundle | Cluster | ClusterObject | ServiceComponent | HostProvider | Host | User | Group | Role | Policy ) diff --git a/python/api_v2/tests/test_actions.py b/python/api_v2/tests/test_actions.py index b5742b0533..878fc33642 100644 --- a/python/api_v2/tests/test_actions.py +++ b/python/api_v2/tests/test_actions.py @@ -9,13 +9,12 @@ # 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 json from functools import partial from operator import itemgetter from typing import TypeAlias from unittest.mock import patch +import json -from api_v2.tests.base import BaseAPITestCase from cm.models import ( Action, Cluster, @@ -30,6 +29,8 @@ from django.urls import reverse from rest_framework.status import HTTP_200_OK, HTTP_404_NOT_FOUND, HTTP_409_CONFLICT +from api_v2.tests.base import BaseAPITestCase + ObjectWithActions: TypeAlias = Cluster | ClusterObject | ServiceComponent | HostProvider | Host @@ -49,7 +50,7 @@ def get_viewname_and_kwargs_for_object(object_: ObjectWithActions) -> tuple[str, return f"v2:{classname.replace('hostp', 'p')}-action-list", {f"{classname}_pk": object_.pk} -class TestActionsFiltering(BaseAPITestCase): # pylint: disable=too-many-instance-attributes +class TestActionsFiltering(BaseAPITestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_adcm.py b/python/api_v2/tests/test_adcm.py index 7c14cb8f2d..d83cf201ed 100644 --- a/python/api_v2/tests/test_adcm.py +++ b/python/api_v2/tests/test_adcm.py @@ -10,11 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from cm.models import ADCM, Action from rest_framework.reverse import reverse from rest_framework.status import HTTP_200_OK +from api_v2.tests.base import BaseAPITestCase + class TestADCM(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_adcm.py b/python/api_v2/tests/test_audit/test_adcm.py index 6e8b537dfe..4418e1302f 100644 --- a/python/api_v2/tests/test_audit/test_adcm.py +++ b/python/api_v2/tests/test_audit/test_adcm.py @@ -11,7 +11,6 @@ # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from cm.models import ADCM, Action from rbac.services.user import create_user from rest_framework.reverse import reverse @@ -23,6 +22,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class TestADCMAudit(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_authorization.py b/python/api_v2/tests/test_audit/test_authorization.py index f6b42a8277..f6a0d24fb8 100644 --- a/python/api_v2/tests/test_audit/test_authorization.py +++ b/python/api_v2/tests/test_audit/test_authorization.py @@ -12,12 +12,13 @@ from datetime import timedelta -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditSession from rbac.models import User from rest_framework.reverse import reverse from rest_framework.status import HTTP_200_OK, HTTP_401_UNAUTHORIZED, HTTP_404_NOT_FOUND +from api_v2.tests.base import BaseAPITestCase + class TestAuthorizationAudit(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_bundle.py b/python/api_v2/tests/test_audit/test_bundle.py index 969a4ddb9c..91d30ae078 100644 --- a/python/api_v2/tests/test_audit/test_bundle.py +++ b/python/api_v2/tests/test_audit/test_bundle.py @@ -11,7 +11,6 @@ # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditLogOperationType, AuditObject from cm.models import Bundle, Prototype from django.conf import settings @@ -26,6 +25,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class TestBundleAudit(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_cluster.py b/python/api_v2/tests/test_audit/test_cluster.py index 56d3d85852..94fa5f7056 100644 --- a/python/api_v2/tests/test_audit/test_cluster.py +++ b/python/api_v2/tests/test_audit/test_cluster.py @@ -10,9 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-lines - -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditObject from cm.models import ( Action, @@ -36,8 +33,10 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + -class TestClusterAudit(BaseAPITestCase): # pylint:disable=too-many-public-methods, too-many-instance-attributes +class TestClusterAudit(BaseAPITestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_audit/test_component.py b/python/api_v2/tests/test_audit/test_component.py index 4fc53beae3..6d45315b0d 100644 --- a/python/api_v2/tests/test_audit/test_component.py +++ b/python/api_v2/tests/test_audit/test_component.py @@ -11,7 +11,6 @@ # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from cm.models import Action, ClusterObject, ServiceComponent from rbac.services.user import create_user from rest_framework.reverse import reverse @@ -23,6 +22,8 @@ HTTP_404_NOT_FOUND, ) +from api_v2.tests.base import BaseAPITestCase + class TestComponentAudit(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_group.py b/python/api_v2/tests/test_audit/test_group.py index 4a05712c30..5e65d93f44 100644 --- a/python/api_v2/tests/test_audit/test_group.py +++ b/python/api_v2/tests/test_audit/test_group.py @@ -11,7 +11,6 @@ # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditObject from django.utils import timezone from rbac.models import Group @@ -27,6 +26,8 @@ HTTP_404_NOT_FOUND, ) +from api_v2.tests.base import BaseAPITestCase + class TestGroupAudit(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_group_config.py b/python/api_v2/tests/test_audit/test_group_config.py index fc961fad60..f5615165d0 100644 --- a/python/api_v2/tests/test_audit/test_group_config.py +++ b/python/api_v2/tests/test_audit/test_group_config.py @@ -10,9 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-lines - -from api_v2.tests.base import BaseAPITestCase from cm.models import GroupConfig, ServiceComponent from django.contrib.contenttypes.models import ContentType from rbac.services.user import create_user @@ -26,8 +23,10 @@ HTTP_404_NOT_FOUND, ) +from api_v2.tests.base import BaseAPITestCase + -class TestGroupConfigAudit(BaseAPITestCase): # pylint: disable=too-many-public-methods,too-many-instance-attributes +class TestGroupConfigAudit(BaseAPITestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_audit/test_host.py b/python/api_v2/tests/test_audit/test_host.py index a6a540c412..9beaccf5fd 100644 --- a/python/api_v2/tests/test_audit/test_host.py +++ b/python/api_v2/tests/test_audit/test_host.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditObject from cm.models import Host, ObjectType, Prototype from rbac.services.user import create_user @@ -24,8 +23,10 @@ HTTP_404_NOT_FOUND, ) +from api_v2.tests.base import BaseAPITestCase + -class TestHostAudit(BaseAPITestCase): # pylint:disable=too-many-public-methods +class TestHostAudit(BaseAPITestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_audit/test_host_provider.py b/python/api_v2/tests/test_audit/test_host_provider.py index 8b380b5c71..d372fe87e0 100644 --- a/python/api_v2/tests/test_audit/test_host_provider.py +++ b/python/api_v2/tests/test_audit/test_host_provider.py @@ -11,7 +11,6 @@ # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditObject from cm.models import Action, HostProvider, Prototype, Upgrade from rbac.services.user import create_user @@ -26,8 +25,10 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + -class TestHostProviderAudit(BaseAPITestCase): # pylint: disable=too-many-public-methods +class TestHostProviderAudit(BaseAPITestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_audit/test_login.py b/python/api_v2/tests/test_audit/test_login.py index 6d0fd8d9f9..2e73eff103 100644 --- a/python/api_v2/tests/test_audit/test_login.py +++ b/python/api_v2/tests/test_audit/test_login.py @@ -10,13 +10,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditSession, AuditSessionLoginResult from rbac.services.user import create_user from rest_framework.response import Response from rest_framework.reverse import reverse from rest_framework.status import HTTP_200_OK, HTTP_401_UNAUTHORIZED +from api_v2.tests.base import BaseAPITestCase + class TestLoginAudit(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_object_renaming.py b/python/api_v2/tests/test_audit/test_object_renaming.py index ff113cfe4b..f75f0bc79c 100644 --- a/python/api_v2/tests/test_audit/test_object_renaming.py +++ b/python/api_v2/tests/test_audit/test_object_renaming.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from django.urls import reverse from rbac.models import Role from rbac.services.group import create as create_group @@ -18,6 +17,8 @@ from rbac.services.role import role_create from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED +from api_v2.tests.base import BaseAPITestCase + class TestAuditObjectNameChanged(BaseAPITestCase): def test_cluster_rename(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_policy.py b/python/api_v2/tests/test_audit/test_policy.py index ead571d39f..f1c8de82e5 100644 --- a/python/api_v2/tests/test_audit/test_policy.py +++ b/python/api_v2/tests/test_audit/test_policy.py @@ -11,7 +11,6 @@ # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditObject from rbac.models import Policy, Role from rbac.services.group import create as create_group @@ -29,8 +28,10 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + -class TestPolicyAudit(BaseAPITestCase): # pylint: disable=too-many-instance-attributes +class TestPolicyAudit(BaseAPITestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_audit/test_role.py b/python/api_v2/tests/test_audit/test_role.py index 2d24d5b767..4680e2877e 100644 --- a/python/api_v2/tests/test_audit/test_role.py +++ b/python/api_v2/tests/test_audit/test_role.py @@ -11,7 +11,6 @@ # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditObject from rbac.models import Role from rbac.services.role import role_create @@ -27,6 +26,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class TestRoleAudit(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_service.py b/python/api_v2/tests/test_audit/test_service.py index 2f4caac3f9..237549c2a2 100644 --- a/python/api_v2/tests/test_audit/test_service.py +++ b/python/api_v2/tests/test_audit/test_service.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from cm.models import Action, ClusterObject, ObjectType from rbac.services.user import create_user from rest_framework.reverse import reverse @@ -23,8 +22,10 @@ HTTP_404_NOT_FOUND, ) +from api_v2.tests.base import BaseAPITestCase + -class TestServiceAudit(BaseAPITestCase): # pylint: disable=too-many-public-methods +class TestServiceAudit(BaseAPITestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_audit/test_task.py b/python/api_v2/tests/test_audit/test_task.py index df65802cc8..2ed6c8ac87 100644 --- a/python/api_v2/tests/test_audit/test_task.py +++ b/python/api_v2/tests/test_audit/test_task.py @@ -13,7 +13,6 @@ from datetime import timedelta from unittest.mock import patch -from api_v2.tests.base import BaseAPITestCase from cm.models import ADCM, Action, ActionType, JobLog, JobStatus, SubAction, TaskLog from django.contrib.contenttypes.models import ContentType from django.utils import timezone @@ -21,6 +20,8 @@ from rest_framework.reverse import reverse from rest_framework.status import HTTP_200_OK, HTTP_404_NOT_FOUND +from api_v2.tests.base import BaseAPITestCase + class TestTaskAudit(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_audit/test_user.py b/python/api_v2/tests/test_audit/test_user.py index adc8931aad..ec1a78f70d 100644 --- a/python/api_v2/tests/test_audit/test_user.py +++ b/python/api_v2/tests/test_audit/test_user.py @@ -11,7 +11,6 @@ # limitations under the License. import unittest -from api_v2.tests.base import BaseAPITestCase from audit.models import AuditObject from django.utils import timezone from rbac.models import User @@ -27,6 +26,8 @@ HTTP_404_NOT_FOUND, ) +from api_v2.tests.base import BaseAPITestCase + class TestUserAudit(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_bulk_operations.py b/python/api_v2/tests/test_bulk_operations.py index 3c3b9d97fb..5f19c52dd9 100644 --- a/python/api_v2/tests/test_bulk_operations.py +++ b/python/api_v2/tests/test_bulk_operations.py @@ -11,7 +11,6 @@ # limitations under the License. from itertools import chain, product -from api_v2.tests.base import BaseAPITestCase from cm.models import ( ClusterObject, ConfigLog, @@ -24,6 +23,8 @@ from rest_framework.reverse import reverse from rest_framework.status import HTTP_200_OK +from api_v2.tests.base import BaseAPITestCase + class TestBulkAddServices(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_bundle.py b/python/api_v2/tests/test_bundle.py index f75b346a20..7feb58f540 100644 --- a/python/api_v2/tests/test_bundle.py +++ b/python/api_v2/tests/test_bundle.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from cm.models import Bundle from django.conf import settings from rest_framework.reverse import reverse @@ -23,6 +22,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class TestBundle(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_cluster.py b/python/api_v2/tests/test_cluster.py index ed06a271b9..9325067eff 100644 --- a/python/api_v2/tests/test_cluster.py +++ b/python/api_v2/tests/test_cluster.py @@ -13,7 +13,6 @@ from typing import Callable from unittest.mock import patch -from api_v2.tests.base import BaseAPITestCase from cm.models import ( Action, ADCMEntityStatus, @@ -35,8 +34,10 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + -class TestCluster(BaseAPITestCase): # pylint:disable=too-many-public-methods +class TestCluster(BaseAPITestCase): def get_cluster_status_mock(self) -> Callable: def inner(cluster: Cluster) -> int: if cluster.pk == self.cluster_1.pk: @@ -443,7 +444,7 @@ def test_retrieve_action_with_hc_success(self): self.assertDictEqual(remove, {"action": "remove", "component": "component_2", "service": "service_1"}) -class TestClusterMM(BaseAPITestCase): # pylint:disable=too-many-instance-attributes +class TestClusterMM(BaseAPITestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_component.py b/python/api_v2/tests/test_component.py index cf2fc62146..d1ba81cad9 100644 --- a/python/api_v2/tests/test_component.py +++ b/python/api_v2/tests/test_component.py @@ -11,13 +11,14 @@ # limitations under the License. from unittest.mock import patch -from api_v2.tests.base import BaseAPITestCase from cm.issue import add_concern_to_object from cm.models import Action, ConcernType, MaintenanceMode, ServiceComponent from cm.tests.utils import gen_concern_item from django.urls import reverse from rest_framework.status import HTTP_200_OK, HTTP_405_METHOD_NOT_ALLOWED +from api_v2.tests.base import BaseAPITestCase + class TestComponentAPI(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_concerns.py b/python/api_v2/tests/test_concerns.py index 473b0d7bf6..7a24f52dc5 100644 --- a/python/api_v2/tests/test_concerns.py +++ b/python/api_v2/tests/test_concerns.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from cm.models import ( KnownNames, MessageTemplate, @@ -22,6 +21,8 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED +from api_v2.tests.base import BaseAPITestCase + class TestConcernsResponse(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_config.py b/python/api_v2/tests/test_config.py index afa92eef0d..28de94aa35 100644 --- a/python/api_v2/tests/test_config.py +++ b/python/api_v2/tests/test_config.py @@ -9,11 +9,9 @@ # 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 json from pathlib import Path +import json -from api_v2.config.utils import convert_adcm_meta_to_attr, convert_attr_to_adcm_meta -from api_v2.tests.base import BaseAPITestCase from cm.adcm_config.ansible import ansible_decrypt, ansible_encrypt_and_format from cm.inventory import get_obj_config from cm.models import ( @@ -36,7 +34,8 @@ HTTP_404_NOT_FOUND, ) -# pylint: disable=too-many-lines +from api_v2.config.utils import convert_adcm_meta_to_attr, convert_attr_to_adcm_meta +from api_v2.tests.base import BaseAPITestCase class TestClusterConfig(BaseAPITestCase): @@ -2129,7 +2128,7 @@ def test_schema(self): ) -class TestGroupConfigUpgrade(BaseAPITestCase): # pylint: disable=too-many-instance-attributes +class TestGroupConfigUpgrade(BaseAPITestCase): def setUp(self) -> None: self.client.login(username="admin", password="admin") diff --git a/python/api_v2/tests/test_group.py b/python/api_v2/tests/test_group.py index 799f3a5d3c..b79e9e4027 100644 --- a/python/api_v2/tests/test_group.py +++ b/python/api_v2/tests/test_group.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from django.urls import reverse from rbac.models import Group, OriginType from rest_framework.response import Response @@ -21,6 +20,8 @@ HTTP_400_BAD_REQUEST, ) +from api_v2.tests.base import BaseAPITestCase + class TestGroupAPI(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_group_config.py b/python/api_v2/tests/test_group_config.py index 7c0778d27f..1849a13cda 100644 --- a/python/api_v2/tests/test_group_config.py +++ b/python/api_v2/tests/test_group_config.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from cm.models import ConfigLog, GroupConfig, Host, ServiceComponent from django.contrib.contenttypes.models import ContentType from rest_framework.reverse import reverse @@ -23,6 +22,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class BaseClusterGroupConfigTestCase(BaseAPITestCase): def setUp(self) -> None: @@ -42,7 +43,7 @@ def setUp(self) -> None: self.add_host_to_cluster(cluster=self.cluster_1, host=self.new_host) -class BaseServiceGroupConfigTestCase(BaseClusterGroupConfigTestCase): # pylint: disable=too-many-ancestors +class BaseServiceGroupConfigTestCase(BaseClusterGroupConfigTestCase): def setUp(self) -> None: super().setUp() @@ -76,7 +77,7 @@ def setUp(self) -> None: ) -class TestClusterGroupConfig(BaseClusterGroupConfigTestCase): # pylint: disable=too-many-ancestors +class TestClusterGroupConfig(BaseClusterGroupConfigTestCase): def test_list_success(self): response = self.client.get( path=reverse(viewname="v2:cluster-group-config-list", kwargs={"cluster_pk": self.cluster_1.pk}) @@ -196,7 +197,7 @@ def test_delete_host_success(self): self.assertNotIn(self.host, self.cluster_1_group_config.hosts.all()) -class TestServiceGroupConfig(BaseServiceGroupConfigTestCase): # pylint: disable=too-many-ancestors +class TestServiceGroupConfig(BaseServiceGroupConfigTestCase): def test_list_success(self): response = self.client.get( path=reverse( @@ -469,7 +470,7 @@ def test_host_candidates_success(self): self.assertEqual(response.json()[0]["name"], self.host_for_service.name) -class TestComponentGroupConfig(BaseServiceGroupConfigTestCase): # pylint: disable=too-many-ancestors +class TestComponentGroupConfig(BaseServiceGroupConfigTestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_host.py b/python/api_v2/tests/test_host.py index eb4d390960..84f6d48ac3 100644 --- a/python/api_v2/tests/test_host.py +++ b/python/api_v2/tests/test_host.py @@ -11,7 +11,6 @@ # limitations under the License. from unittest.mock import patch -from api_v2.tests.base import BaseAPITestCase from cm.models import Action, Host, HostComponent, HostProvider, ServiceComponent from django.urls import reverse from rest_framework.status import ( @@ -23,6 +22,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class TestHost(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_host_provider.py b/python/api_v2/tests/test_host_provider.py index 9fc9096d74..50d5c68252 100644 --- a/python/api_v2/tests/test_host_provider.py +++ b/python/api_v2/tests/test_host_provider.py @@ -11,7 +11,6 @@ # limitations under the License. from unittest.mock import patch -from api_v2.tests.base import BaseAPITestCase from cm.models import Action, HostProvider from rest_framework.reverse import reverse from rest_framework.status import ( @@ -22,6 +21,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class TestHostProvider(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_import.py b/python/api_v2/tests/test_import.py index bd34f22892..c5e248c9d4 100644 --- a/python/api_v2/tests/test_import.py +++ b/python/api_v2/tests/test_import.py @@ -10,11 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from cm.models import ClusterBind from django.urls import reverse from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED +from api_v2.tests.base import BaseAPITestCase + class TestImport(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_jobs.py b/python/api_v2/tests/test_jobs.py index 5fe0dd321e..e954aed728 100644 --- a/python/api_v2/tests/test_jobs.py +++ b/python/api_v2/tests/test_jobs.py @@ -13,6 +13,7 @@ from datetime import timedelta from unittest.mock import patch +from adcm.tests.base import BaseTestCase from cm.models import ( ADCM, Action, @@ -31,10 +32,8 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_404_NOT_FOUND -from adcm.tests.base import BaseTestCase - -class TestJob(BaseTestCase): # pylint: disable=too-many-instance-attributes +class TestJob(BaseTestCase): TRUNCATED_LOG_MESSAGE = settings.STDOUT_STDERR_TRUNCATED_LOG_MESSAGE def setUp(self) -> None: @@ -89,7 +88,7 @@ def setUp(self) -> None: name="ansible", type="stdout", format="txt", - body="\n".join((self.word_10_symbols for _ in range(200_000))), + body="\n".join(self.word_10_symbols for _ in range(200_000)), ) self.long_line = "word" * 1000 self.short_line = "word" * 4 diff --git a/python/api_v2/tests/test_known_bugs.py b/python/api_v2/tests/test_known_bugs.py index c85cff149e..78fd419224 100644 --- a/python/api_v2/tests/test_known_bugs.py +++ b/python/api_v2/tests/test_known_bugs.py @@ -10,10 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from rest_framework.reverse import reverse from rest_framework.status import HTTP_200_OK +from api_v2.tests.base import BaseAPITestCase + class TestConfigBugs(BaseAPITestCase): def test_cluster_variant_bug_adcm_4778(self): diff --git a/python/api_v2/tests/test_mapping.py b/python/api_v2/tests/test_mapping.py index 50d458efb9..a6d1b46d4b 100644 --- a/python/api_v2/tests/test_mapping.py +++ b/python/api_v2/tests/test_mapping.py @@ -10,10 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-lines - -from api_v2.cluster.utils import get_requires -from api_v2.tests.base import BaseAPITestCase from cm.models import ( Cluster, ClusterObject, @@ -32,6 +28,9 @@ HTTP_409_CONFLICT, ) +from api_v2.cluster.utils import get_requires +from api_v2.tests.base import BaseAPITestCase + class TestMapping(BaseAPITestCase): def setUp(self) -> None: @@ -190,7 +189,7 @@ def test_get_requires(self): self.assertDictEqual(new_requires, {"service1": ["component1"]}) -class TestMappingConstraints(BaseAPITestCase): # pylint: disable=too-many-public-methods +class TestMappingConstraints(BaseAPITestCase): def setUp(self) -> None: self.client.login(username="admin", password="admin") diff --git a/python/api_v2/tests/test_policy.py b/python/api_v2/tests/test_policy.py index 19b76499d1..2fd0823209 100644 --- a/python/api_v2/tests/test_policy.py +++ b/python/api_v2/tests/test_policy.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.tests.base import BaseAPITestCase from django.urls import reverse from rbac.models import Group, Policy, Role from rbac.services.policy import policy_create @@ -22,6 +21,8 @@ HTTP_400_BAD_REQUEST, ) +from api_v2.tests.base import BaseAPITestCase + class TestPolicy(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_profile.py b/python/api_v2/tests/test_profile.py index 25c75ff7ef..f1d11381b9 100644 --- a/python/api_v2/tests/test_profile.py +++ b/python/api_v2/tests/test_profile.py @@ -10,11 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from django.urls import reverse from rest_framework.status import HTTP_401_UNAUTHORIZED -from adcm.tests.base import BaseTestCase - class TestProfile(BaseTestCase): def test_unauthenticated_access_adcm_4946_fail(self): diff --git a/python/api_v2/tests/test_prototype.py b/python/api_v2/tests/test_prototype.py index 5faf118c82..62ba92a670 100644 --- a/python/api_v2/tests/test_prototype.py +++ b/python/api_v2/tests/test_prototype.py @@ -11,7 +11,6 @@ # limitations under the License. from operator import itemgetter -from api_v2.tests.base import BaseAPITestCase from cm.models import Bundle, ObjectType, ProductCategory, Prototype from rest_framework.reverse import reverse from rest_framework.status import ( @@ -21,6 +20,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class TestPrototype(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_role.py b/python/api_v2/tests/test_role.py index e0b2f52098..51af02f75f 100644 --- a/python/api_v2/tests/test_role.py +++ b/python/api_v2/tests/test_role.py @@ -9,7 +9,6 @@ # 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. -from api_v2.tests.base import BaseAPITestCase from django.db.models import Count from django.urls import reverse from rbac.models import Role @@ -25,6 +24,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class TestRole(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/tests/test_service.py b/python/api_v2/tests/test_service.py index 58497733f3..90f9d04edb 100644 --- a/python/api_v2/tests/test_service.py +++ b/python/api_v2/tests/test_service.py @@ -13,7 +13,6 @@ from typing import Callable, NamedTuple from unittest.mock import patch -from api_v2.tests.base import BaseAPITestCase from cm.job import ActionRunPayload, run_action from cm.models import ( Action, @@ -38,6 +37,8 @@ HTTP_409_CONFLICT, ) +from api_v2.tests.base import BaseAPITestCase + class FakePopenResponse(NamedTuple): pid: int diff --git a/python/api_v2/tests/test_tasks.py b/python/api_v2/tests/test_tasks.py index 7d809d5bcb..8a618f2376 100644 --- a/python/api_v2/tests/test_tasks.py +++ b/python/api_v2/tests/test_tasks.py @@ -14,7 +14,6 @@ from operator import itemgetter from unittest.mock import patch -from api_v2.tests.base import BaseAPITestCase from cm.job import create_task from cm.models import ( ADCM, @@ -33,8 +32,10 @@ from rbac.services.user import create_user from rest_framework.status import HTTP_200_OK, HTTP_404_NOT_FOUND +from api_v2.tests.base import BaseAPITestCase + -class TestTask(BaseAPITestCase): # pylint: disable=too-many-instance-attributes +class TestTask(BaseAPITestCase): def setUp(self) -> None: super().setUp() @@ -165,7 +166,7 @@ def test_adcm_5158_adcm_task_view_for_not_superuser_fail(self): self.assertNotIn(self.adcm_task.pk, [task["id"] for task in response.json()["results"]]) -class TestTaskObjects(BaseAPITestCase): # pylint: disable=too-many-instance-attributes +class TestTaskObjects(BaseAPITestCase): def setUp(self) -> None: super().setUp() @@ -257,7 +258,7 @@ def create_task( object_: Cluster | ClusterObject | ServiceComponent | HostProvider | Host | ADCM, action_name: str, *, - host: Host | None = None + host: Host | None = None, ): action = Action.objects.get(name=action_name, prototype=object_.prototype) hosts = [] if not host else [host.pk] diff --git a/python/api_v2/tests/test_upgrade.py b/python/api_v2/tests/test_upgrade.py index 2447ccadde..0e4285a651 100644 --- a/python/api_v2/tests/test_upgrade.py +++ b/python/api_v2/tests/test_upgrade.py @@ -13,7 +13,6 @@ from pathlib import Path from unittest.mock import patch -from api_v2.tests.base import BaseAPITestCase from cm.models import ( ADCM, ConfigLog, @@ -33,8 +32,10 @@ from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_404_NOT_FOUND from rest_framework.test import APIClient, APITestCase +from api_v2.tests.base import BaseAPITestCase + -class TestUpgrade(BaseAPITestCase): # pylint:disable=too-many-public-methods, too-many-instance-attributes +class TestUpgrade(BaseAPITestCase): def setUp(self) -> None: super().setUp() diff --git a/python/api_v2/tests/test_user.py b/python/api_v2/tests/test_user.py index fb0fdba321..bfe586f163 100644 --- a/python/api_v2/tests/test_user.py +++ b/python/api_v2/tests/test_user.py @@ -9,8 +9,6 @@ # 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. -from api_v2.rbac.user.constants import UserTypeChoices -from api_v2.tests.base import BaseAPITestCase from django.conf import settings from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType @@ -26,6 +24,9 @@ HTTP_409_CONFLICT, ) +from api_v2.rbac.user.constants import UserTypeChoices +from api_v2.tests.base import BaseAPITestCase + class TestUserAPI(BaseAPITestCase): def setUp(self) -> None: diff --git a/python/api_v2/token/views.py b/python/api_v2/token/views.py index 974b497276..4886b79a0b 100644 --- a/python/api_v2/token/views.py +++ b/python/api_v2/token/views.py @@ -10,17 +10,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -from api_v2.login.views import BaseLoginView from rest_framework.authentication import TokenAuthentication from rest_framework.authtoken.models import Token from rest_framework.request import Request from rest_framework.response import Response +from api_v2.login.views import BaseLoginView + class TokenView(BaseLoginView): authentication_classes = (TokenAuthentication,) - def post(self, request: Request, *args, **kwargs) -> Response: # pylint: disable=unused-argument + def post(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 user = self.perform_login(request=request) token, _ = Token.objects.get_or_create(user=user) diff --git a/python/api_v2/upgrade/serializers.py b/python/api_v2/upgrade/serializers.py index acca0f7699..637ef9c216 100644 --- a/python/api_v2/upgrade/serializers.py +++ b/python/api_v2/upgrade/serializers.py @@ -12,10 +12,11 @@ from typing import Any -from api_v2.bundle.serializers import UpgradeBundleSerializer from cm.models import Upgrade from rest_framework.serializers import ModelSerializer, SerializerMethodField +from api_v2.bundle.serializers import UpgradeBundleSerializer + class UpgradeListSerializer(ModelSerializer): class Meta: diff --git a/python/api_v2/upgrade/views.py b/python/api_v2/upgrade/views.py index e598a6078e..80ba6c9817 100644 --- a/python/api_v2/upgrade/views.py +++ b/python/api_v2/upgrade/views.py @@ -9,12 +9,15 @@ # 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. -from api_v2.action.serializers import ActionRunSerializer -from api_v2.action.utils import get_action_configuration, insert_service_ids -from api_v2.config.utils import convert_adcm_meta_to_attr, represent_string_as_json_type -from api_v2.task.serializers import TaskListSerializer -from api_v2.upgrade.serializers import UpgradeListSerializer, UpgradeRetrieveSerializer -from api_v2.views import CamelCaseGenericViewSet +from adcm.mixins import GetParentObjectMixin +from adcm.permissions import ( + VIEW_CLUSTER_PERM, + VIEW_CLUSTER_UPGRADE_PERM, + VIEW_PROVIDER_PERM, + VIEW_PROVIDER_UPGRADE_PERM, + check_custom_perm, + get_object_for_user, +) from audit.utils import audit from cm.errors import AdcmEx from cm.models import Cluster, HostProvider, PrototypeConfig, TaskLog, Upgrade @@ -29,18 +32,15 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_204_NO_CONTENT -from adcm.mixins import GetParentObjectMixin -from adcm.permissions import ( - VIEW_CLUSTER_PERM, - VIEW_CLUSTER_UPGRADE_PERM, - VIEW_PROVIDER_PERM, - VIEW_PROVIDER_UPGRADE_PERM, - check_custom_perm, - get_object_for_user, -) +from api_v2.action.serializers import ActionRunSerializer +from api_v2.action.utils import get_action_configuration, insert_service_ids +from api_v2.config.utils import convert_adcm_meta_to_attr, represent_string_as_json_type +from api_v2.task.serializers import TaskListSerializer +from api_v2.upgrade.serializers import UpgradeListSerializer, UpgradeRetrieveSerializer +from api_v2.views import CamelCaseGenericViewSet -class UpgradeViewSet( # pylint: disable=too-many-ancestors +class UpgradeViewSet( ListModelMixin, GetParentObjectMixin, RetrieveModelMixin, @@ -85,8 +85,7 @@ def get_object(self): queryset = self.filter_queryset(self.get_queryset()) lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} - obj = get_object_or_404(queryset, **filter_kwargs) - return obj + return get_object_or_404(queryset, **filter_kwargs) def get_parent_object_for_user(self, user: User) -> Cluster | HostProvider: parent: Cluster | HostProvider | None = self.get_parent_object() @@ -119,13 +118,13 @@ def get_upgrade(self, parent: Cluster | HostProvider): return upgrade - def list(self, request: Request, *args, **kwargs) -> Response: + def list(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 parent: Cluster | HostProvider = self.get_parent_object_for_user(user=request.user) upgrades = get_upgrade(obj=parent) serializer = self.get_serializer_class()(instance=upgrades, many=True) return Response(data=serializer.data) - def retrieve(self, request: Request, *args, **kwargs) -> Response: + def retrieve(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 parent: Cluster | HostProvider = self.get_parent_object_for_user(user=request.user) upgrade = self.get_upgrade(parent=parent) diff --git a/python/api_v2/urls.py b/python/api_v2/urls.py index a7f2ed845b..0eb3dac34a 100644 --- a/python/api_v2/urls.py +++ b/python/api_v2/urls.py @@ -9,11 +9,6 @@ # 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. -from api_v2.login.views import LoginView -from api_v2.logout.views import LogoutView -from api_v2.profile.views import ProfileView -from api_v2.token.views import TokenView -from api_v2.views import APIRoot from django.urls import include, path from drf_spectacular.views import ( SpectacularAPIView, @@ -21,6 +16,12 @@ SpectacularSwaggerSplitView, ) +from api_v2.login.views import LoginView +from api_v2.logout.views import LogoutView +from api_v2.profile.views import ProfileView +from api_v2.token.views import TokenView +from api_v2.views import APIRoot + urlpatterns = [ path("", APIRoot.as_view(), name="api-root-v2"), path("rbac/", include(("api_v2.rbac.urls", "rbac"))), @@ -32,7 +33,7 @@ path("audit/", include(("api_v2.audit.urls", "audit"))), path("jobs/", include("api_v2.job.urls")), path("tasks/", include("api_v2.task.urls")), - path("adcm/", include(("api_v2.adcm.urls"))), + path("adcm/", include("api_v2.adcm.urls")), path("login/", LoginView.as_view(), name="login"), path("logout/", LogoutView.as_view(), name="logout"), path("profile/", ProfileView.as_view(), name="profile"), diff --git a/python/api_v2/views.py b/python/api_v2/views.py index 098876e73f..e71391be79 100644 --- a/python/api_v2/views.py +++ b/python/api_v2/views.py @@ -54,11 +54,9 @@ class CamelCaseGenericViewSet(GenericViewSet): class CamelCaseModelViewSet( CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, ListModelMixin, CamelCaseGenericViewSet -): # pylint: disable=too-many-ancestors +): pass -class CamelCaseReadOnlyModelViewSet( - RetrieveModelMixin, ListModelMixin, CamelCaseGenericViewSet -): # pylint: disable=too-many-ancestors +class CamelCaseReadOnlyModelViewSet(RetrieveModelMixin, ListModelMixin, CamelCaseGenericViewSet): pass diff --git a/python/audit/apps.py b/python/audit/apps.py index 612a5d9fa9..f64ceffd30 100644 --- a/python/audit/apps.py +++ b/python/audit/apps.py @@ -18,6 +18,6 @@ class AuditConfig(AppConfig): name = "audit" def ready(self): - from audit.signals import ( # pylint: disable=import-outside-toplevel,unused-import + from audit.signals import ( # noqa: F401, PLC0415 mark_deleted_audit_object_handler, ) diff --git a/python/audit/cases/adcm.py b/python/audit/cases/adcm.py index 2978ba4bfe..267ab7675d 100644 --- a/python/audit/cases/adcm.py +++ b/python/audit/cases/adcm.py @@ -9,6 +9,10 @@ # 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. +from cm.models import ADCM +from django.views import View +from requests import Response + from audit.cases.common import ( _get_audit_operation, get_or_create_audit_obj, @@ -20,9 +24,6 @@ AuditObjectType, AuditOperation, ) -from cm.models import ADCM -from django.views import View -from requests import Response def adcm_case( @@ -33,7 +34,7 @@ def adcm_case( if api_version == 1: match path: - case (["adcm", adcm_pk, "config", "history"] | ["adcm", adcm_pk, "config", "history", _, "restore"]): + case ["adcm", adcm_pk, "config", "history"] | ["adcm", adcm_pk, "config", "history", _, "restore"]: audit_operation, audit_object = obj_pk_case( obj_type=AuditObjectType.ADCM, operation_type=AuditLogOperationType.UPDATE, diff --git a/python/audit/cases/bundle.py b/python/audit/cases/bundle.py index 49d699e422..324bd401a8 100644 --- a/python/audit/cases/bundle.py +++ b/python/audit/cases/bundle.py @@ -10,6 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from cm.models import Bundle +from django.views import View + from audit.cases.common import get_or_create_audit_obj from audit.models import ( AuditLogOperationType, @@ -17,8 +20,6 @@ AuditObjectType, AuditOperation, ) -from cm.models import Bundle -from django.views import View def bundle_case( @@ -30,7 +31,7 @@ def bundle_case( audit_object = None match path: - case (["bundles", bundle_pk]): + case ["bundles", bundle_pk]: if view.request.method != "DELETE": return audit_operation, audit_object @@ -54,7 +55,7 @@ def bundle_case( object_type=AuditObjectType.BUNDLE, ) - case (["bundles"]): + case ["bundles"]: if view.request.method == "POST": audit_operation = AuditOperation( name="Bundle uploaded", diff --git a/python/audit/cases/cases.py b/python/audit/cases/cases.py index 67d4f8b381..c8708d2a1c 100644 --- a/python/audit/cases/cases.py +++ b/python/audit/cases/cases.py @@ -9,6 +9,11 @@ # 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. +from django.db.models import Model +from django.views import View +from rest_framework.generics import GenericAPIView +from rest_framework.response import Response + from audit.cases.adcm import adcm_case from audit.cases.bundle import bundle_case from audit.cases.cluster import cluster_case @@ -21,13 +26,9 @@ from audit.cases.service import service_case from audit.cases.stack import stack_case from audit.models import AuditObject, AuditOperation -from django.db.models import Model -from django.views import View -from rest_framework.generics import GenericAPIView -from rest_framework.response import Response -def get_audit_operation_and_object( # pylint: disable=too-many-branches +def get_audit_operation_and_object( view: View | GenericAPIView, response: Response | None, deleted_obj: Model, @@ -48,7 +49,7 @@ def get_audit_operation_and_object( # pylint: disable=too-many-branches deleted_obj=deleted_obj, ) elif ( - "cluster" in path # pylint: disable=too-many-boolean-expressions + "cluster" in path or ("clusters" in path and "config-groups" not in path) or "component" in path or ("host" in path and "config" in path) diff --git a/python/audit/cases/cluster.py b/python/audit/cases/cluster.py index eef9d7a87a..76abc2e9c0 100644 --- a/python/audit/cases/cluster.py +++ b/python/audit/cases/cluster.py @@ -11,6 +11,11 @@ # limitations under the License. from operator import itemgetter +from cm.models import Cluster, ClusterBind, ClusterObject, Host, Prototype +from django.views import View +from rest_framework.generics import GenericAPIView +from rest_framework.response import Response + from audit.cases.common import ( get_obj_name, get_or_create_audit_obj, @@ -24,10 +29,6 @@ AuditObjectType, AuditOperation, ) -from cm.models import Cluster, ClusterBind, ClusterObject, Host, Prototype -from django.views import View -from rest_framework.generics import GenericAPIView -from rest_framework.response import Response CONFIGURATION_STR = "configuration " @@ -70,7 +71,6 @@ def make_export_name(cluster_name: str, service_name: str) -> str: return export_name -# pylint: disable-next=too-many-locals,too-many-branches,too-many-statements def cluster_case( path: list[str], view: GenericAPIView | View, @@ -143,13 +143,18 @@ def cluster_case( object_type=AuditObjectType.CLUSTER, ) - case ["cluster", cluster_pk, "host", host_pk] | ["clusters", cluster_pk, "hosts", host_pk] | [ - "cluster", - cluster_pk, - "host", - host_pk, - "maintenance-mode", - ] | ["clusters", cluster_pk, "hosts", host_pk, "maintenance-mode"]: + case ( + ["cluster", cluster_pk, "host", host_pk] + | ["clusters", cluster_pk, "hosts", host_pk] + | [ + "cluster", + cluster_pk, + "host", + host_pk, + "maintenance-mode", + ] + | ["clusters", cluster_pk, "hosts", host_pk, "maintenance-mode"] + ): if view.request.method == "DELETE": name = "host removed" operation_type = AuditLogOperationType.UPDATE @@ -446,11 +451,14 @@ def cluster_case( ["component", component_pk] | ["component", component_pk, _] | [ - "cluster" | "clusters", + "cluster" + | "clusters", _, - "service" | "services", + "service" + | "services", _, - "component" | "components", + "component" + | "components", component_pk, "maintenance-mode", ] diff --git a/python/audit/cases/common.py b/python/audit/cases/common.py index ba99d9a878..e3a0c18618 100644 --- a/python/audit/cases/common.py +++ b/python/audit/cases/common.py @@ -9,15 +9,6 @@ # 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. -from audit.models import ( - AUDIT_OBJECT_TYPE_TO_MODEL_MAP, - MODEL_TO_AUDIT_OBJECT_TYPE_MAP, - PATH_STR_TO_OBJ_CLASS_MAP, - AuditLogOperationType, - AuditObject, - AuditObjectType, - AuditOperation, -) from cm.models import ( ADCM, Action, @@ -30,16 +21,23 @@ ) from rest_framework.response import Response +from audit.models import ( + AUDIT_OBJECT_TYPE_TO_MODEL_MAP, + MODEL_TO_AUDIT_OBJECT_TYPE_MAP, + PATH_STR_TO_OBJ_CLASS_MAP, + AuditLogOperationType, + AuditObject, + AuditObjectType, + AuditOperation, +) + def _get_audit_operation( obj_type: AuditObjectType, operation_type: AuditLogOperationType, operation_aux_str: str | None = None, ): - if obj_type == AuditObjectType.ADCM: - operation_name = obj_type.upper() - else: - operation_name = obj_type.capitalize() + operation_name = obj_type.upper() if obj_type == AuditObjectType.ADCM else obj_type.capitalize() if operation_aux_str: operation_name = f"{operation_name} {operation_aux_str}" @@ -57,10 +55,7 @@ def _task_case(task_pk: str, action: str) -> tuple[AuditOperation, AuditObject | task = TaskLog.objects.filter(pk=task_pk).first() - if task and task.action: - action_name = task.action.display_name - else: - action_name = "Task" + action_name = task.action.display_name if task and task.action else "Task" audit_operation = AuditOperation( name=f"{action_name} {action}ed", @@ -118,15 +113,15 @@ def _job_case(job_pk: str, version=1) -> tuple[AuditOperation, AuditObject | Non def get_obj_name(obj: ClusterObject | ServiceComponent | ADCMEntity, obj_type: str) -> str: if obj_type == "service": obj_name = obj.display_name - cluster = getattr(obj, "cluster") + cluster = obj.cluster if cluster: obj_name = f"{cluster.name}/{obj_name}" elif obj_type == "component": obj_name = obj.display_name - service = getattr(obj, "service") + service = obj.service if service: obj_name = f"{service.display_name}/{obj_name}" - cluster = getattr(service, "cluster") + cluster = service.cluster if cluster: obj_name = f"{cluster.name}/{obj_name}" else: diff --git a/python/audit/cases/config.py b/python/audit/cases/config.py index e720fe3bcd..fcf08635c1 100644 --- a/python/audit/cases/config.py +++ b/python/audit/cases/config.py @@ -11,6 +11,12 @@ # limitations under the License. from contextlib import suppress +from adcm.utils import get_obj_type +from cm.models import GroupConfig, Host, ObjectConfig, get_cm_model_by_type +from django.contrib.contenttypes.models import ContentType +from rest_framework.response import Response +from rest_framework.viewsets import ViewSet + from audit.cases.common import get_obj_name, get_or_create_audit_obj from audit.models import ( MODEL_TO_AUDIT_OBJECT_TYPE_MAP, @@ -19,15 +25,8 @@ AuditObject, AuditOperation, ) -from cm.models import GroupConfig, Host, ObjectConfig, get_cm_model_by_type -from django.contrib.contenttypes.models import ContentType -from rest_framework.response import Response -from rest_framework.viewsets import ViewSet - -from adcm.utils import get_obj_type -# pylint: disable-next=too-many-locals,too-many-branches,too-many-statements def config_case( path: list[str], view: ViewSet, @@ -61,10 +60,7 @@ def config_case( object_name=object_name, object_type=object_type, ) - if object_type == "adcm": - object_type = "ADCM" - else: - object_type = object_type.capitalize() + object_type = "ADCM" if object_type == "adcm" else object_type.capitalize() operation_name = f"{object_type} {audit_operation.name}" else: diff --git a/python/audit/cases/host.py b/python/audit/cases/host.py index 1e107522fc..2d7743e501 100644 --- a/python/audit/cases/host.py +++ b/python/audit/cases/host.py @@ -9,6 +9,10 @@ # 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. +from cm.models import Host +from django.views import View +from rest_framework.response import Response + from audit.cases.common import get_or_create_audit_obj, obj_pk_case, response_case from audit.models import ( AuditLogOperationType, @@ -16,9 +20,6 @@ AuditObjectType, AuditOperation, ) -from cm.models import Host -from django.views import View -from rest_framework.response import Response def host_case( diff --git a/python/audit/cases/license.py b/python/audit/cases/license.py index be6f836298..ebbaeb55bb 100644 --- a/python/audit/cases/license.py +++ b/python/audit/cases/license.py @@ -10,6 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +from cm.models import Bundle, Prototype +from django.views import View +from rest_framework.response import Response + from audit.cases.common import get_or_create_audit_obj from audit.models import ( AuditLogOperationType, @@ -17,9 +21,6 @@ AuditObjectType, AuditOperation, ) -from cm.models import Bundle, Prototype -from django.views import View -from rest_framework.response import Response def license_case( @@ -31,7 +32,7 @@ def license_case( audit_object = None match path: - case (["bundles", bundle_pk]): + case ["bundles", bundle_pk]: if view.request.method == "PUT" and "accept" in path and response.status_code == 200: audit_operation = AuditOperation( name="Bundle license accepted", @@ -43,7 +44,7 @@ def license_case( object_name=bundle.name, object_type=AuditObjectType.BUNDLE, ) - case (["prototypes", prototype_pk, "license", "accept"]): + case ["prototypes", prototype_pk, "license", "accept"]: if view.request.method == "POST": prototype = Prototype.objects.filter(pk=prototype_pk).first() audit_operation = AuditOperation( diff --git a/python/audit/cases/provider.py b/python/audit/cases/provider.py index 9f7327bd84..5c4ce6468b 100644 --- a/python/audit/cases/provider.py +++ b/python/audit/cases/provider.py @@ -9,6 +9,9 @@ # 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. +from cm.models import HostProvider +from rest_framework.response import Response + from audit.cases.common import get_or_create_audit_obj, obj_pk_case, response_case from audit.models import ( AuditLogOperationType, @@ -16,8 +19,6 @@ AuditObjectType, AuditOperation, ) -from cm.models import HostProvider -from rest_framework.response import Response def provider_case( diff --git a/python/audit/cases/rbac.py b/python/audit/cases/rbac.py index 09f5a4a78b..e90adb0e7c 100644 --- a/python/audit/cases/rbac.py +++ b/python/audit/cases/rbac.py @@ -12,6 +12,11 @@ from dataclasses import dataclass +from django.core.exceptions import ObjectDoesNotExist +from django.db.models import Model +from django.views import View +from rest_framework.response import Response + from audit.cases.common import get_audit_object_from_resp, get_or_create_audit_obj from audit.models import ( AUDIT_OBJECT_TYPE_TO_MODEL_MAP, @@ -20,10 +25,6 @@ AuditObjectType, AuditOperation, ) -from django.core.exceptions import ObjectDoesNotExist -from django.db.models import Model -from django.views import View -from rest_framework.response import Response @dataclass @@ -131,12 +132,17 @@ def rbac_case( response=response, ) - case ["rbac", "user" | "users", user_pk] | [ - "rbac", - "user" | "users", - user_pk, - "reset_failed_login_attempts" | "unblock", - ]: + case ( + ["rbac", "user" | "users", user_pk] + | [ + "rbac", + "user" + | "users", + user_pk, + "reset_failed_login_attempts" + | "unblock", + ] + ): data = RbacCaseData(view=view, deleted_obj=deleted_obj, obj_pk=user_pk) audit_operation, audit_object = _rbac_case( obj_type=AuditObjectType.USER, diff --git a/python/audit/cases/service.py b/python/audit/cases/service.py index 395ba4a421..cd37c9cf65 100644 --- a/python/audit/cases/service.py +++ b/python/audit/cases/service.py @@ -9,6 +9,11 @@ # 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. +from cm.models import Cluster, ClusterBind, ClusterObject +from django.db.models import Model +from django.views import View +from rest_framework.response import Response + from audit.cases.cluster import get_export_cluster_and_service_names, make_export_name from audit.cases.common import get_obj_name, get_or_create_audit_obj, get_service_name from audit.models import ( @@ -17,13 +22,9 @@ AuditObjectType, AuditOperation, ) -from cm.models import Cluster, ClusterBind, ClusterObject -from django.db.models import Model -from django.views import View -from rest_framework.response import Response -def service_case( # pylint: disable=too-many-branches +def service_case( path: list[str, ...], view: View, response: Response, diff --git a/python/audit/cases/stack.py b/python/audit/cases/stack.py index 95a182af92..b3403ddf82 100644 --- a/python/audit/cases/stack.py +++ b/python/audit/cases/stack.py @@ -9,6 +9,10 @@ # 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. +from cm.models import Bundle, Prototype +from django.db.models import Model +from rest_framework.response import Response + from audit.cases.common import get_or_create_audit_obj, obj_pk_case, response_case from audit.models import ( AuditLogOperationType, @@ -16,9 +20,6 @@ AuditObjectType, AuditOperation, ) -from cm.models import Bundle, Prototype -from django.db.models import Model -from rest_framework.response import Response def stack_case( diff --git a/python/audit/cef_logger.py b/python/audit/cef_logger.py index db39cb2541..286a807559 100644 --- a/python/audit/cef_logger.py +++ b/python/audit/cef_logger.py @@ -11,12 +11,13 @@ # limitations under the License. -import logging from collections import OrderedDict +import logging + +from django.conf import settings from audit.apps import AuditConfig from audit.models import AuditLog, AuditLogOperationResult, AuditSession -from django.conf import settings audit_logger = logging.getLogger(AuditConfig.name) diff --git a/python/audit/filters.py b/python/audit/filters.py index 089b6fe28b..2ea2800d84 100644 --- a/python/audit/filters.py +++ b/python/audit/filters.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from audit.models import AuditLog, AuditObjectType, AuditSession from django_filters.rest_framework import ( CharFilter, ChoiceFilter, @@ -19,6 +18,8 @@ IsoDateTimeFromToRangeFilter, ) +from audit.models import AuditLog, AuditObjectType, AuditSession + class AuditLogListFilter(FilterSet): object_type = ChoiceFilter( diff --git a/python/audit/management/commands/clearaudit.py b/python/audit/management/commands/clearaudit.py index ad31c91042..2ebae6f0ed 100644 --- a/python/audit/management/commands/clearaudit.py +++ b/python/audit/management/commands/clearaudit.py @@ -10,26 +10,26 @@ # See the License for the specific language governing permissions and # limitations under the License. -import csv -import logging -import os from datetime import timedelta from pathlib import Path from shutil import rmtree from tarfile import TarFile +import os +import csv +import logging -from audit.models import AuditLog, AuditLogOperationResult, AuditObject, AuditSession -from audit.utils import make_audit_log from cm.adcm_config.config import get_adcm_config from django.conf import settings from django.core.management.base import BaseCommand from django.db.models import Count, Q from django.utils import timezone +from audit.models import AuditLog, AuditLogOperationResult, AuditObject, AuditSession +from audit.utils import make_audit_log + logger = logging.getLogger("background_tasks") -# pylint: disable=protected-access class Command(BaseCommand): config_key = "audit_data_retention" archive_base_dir = "/adcm/data/audit/" @@ -55,10 +55,10 @@ class Command(BaseCommand): AuditObject: "objects", } - def handle(self, *args, **options): + def handle(self, *args, **options): # noqa: ARG002 try: self.__handle() - except Exception as e: # pylint: disable=broad-except + except Exception as e: # noqa: BLE001 make_audit_log("audit", AuditLogOperationResult.FAIL, "completed") self.__log(e, "exception") diff --git a/python/audit/middleware.py b/python/audit/middleware.py index e8536bbf88..d969c62de7 100644 --- a/python/audit/middleware.py +++ b/python/audit/middleware.py @@ -9,12 +9,9 @@ # 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 json from json.decoder import JSONDecodeError +import json -from audit.cef_logger import cef_logger -from audit.models import AuditSession, AuditSessionLoginResult, AuditUser -from audit.utils import get_client_ip from cm.models import ADCM, ConfigLog from django.conf import settings from django.contrib.auth.models import AnonymousUser, User @@ -23,6 +20,10 @@ from django.utils import timezone from rbac.models import User as RBACUser +from audit.cef_logger import cef_logger +from audit.models import AuditSession, AuditSessionLoginResult, AuditUser +from audit.utils import get_client_ip + class LoginMiddleware: def __init__(self, get_response): @@ -63,7 +64,7 @@ def _audit( return user, result @staticmethod - def _process_login_attempts( # pylint: disable=too-many-branches + def _process_login_attempts( user: RBACUser | User, result: AuditSessionLoginResult, ) -> HttpResponseForbidden | None: diff --git a/python/audit/serializers.py b/python/audit/serializers.py index a9f7dabea0..55f33f5629 100644 --- a/python/audit/serializers.py +++ b/python/audit/serializers.py @@ -11,7 +11,6 @@ # limitations under the License. -from audit.models import AuditLog, AuditSession from rest_framework.serializers import ( CharField, HyperlinkedModelSerializer, @@ -19,6 +18,8 @@ SerializerMethodField, ) +from audit.models import AuditLog, AuditSession + class AuditLogSerializer(HyperlinkedModelSerializer): object_id = IntegerField(read_only=True, source="audit_object.object_id", allow_null=True) diff --git a/python/audit/signals.py b/python/audit/signals.py index 7dd0512f8a..5d80d6917a 100644 --- a/python/audit/signals.py +++ b/python/audit/signals.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from audit.models import MODEL_TO_AUDIT_OBJECT_TYPE_MAP, AuditObject, AuditUser from cm.models import ( ADCM, Bundle, @@ -28,6 +27,8 @@ from rbac.models import Group, Policy, Role from rbac.models import User as RBACUser +from audit.models import MODEL_TO_AUDIT_OBJECT_TYPE_MAP, AuditObject, AuditUser + @receiver(signal=post_delete, sender=Cluster) @receiver(signal=post_delete, sender=ClusterObject) @@ -41,7 +42,7 @@ @receiver(signal=post_delete, sender=Group) @receiver(signal=post_delete, sender=Role) @receiver(signal=post_delete, sender=Policy) -def mark_deleted_audit_object_handler(sender, instance, **kwargs) -> None: # pylint: disable=unused-argument +def mark_deleted_audit_object_handler(sender, instance, **kwargs) -> None: # noqa: ARG001 audit_objs = [] for audit_obj in AuditObject.objects.filter( object_id=instance.pk, object_type=MODEL_TO_AUDIT_OBJECT_TYPE_MAP[sender] @@ -54,7 +55,7 @@ def mark_deleted_audit_object_handler(sender, instance, **kwargs) -> None: # py @receiver(signal=post_save, sender=AuthUser) @receiver(signal=post_save, sender=RBACUser) -def create_audit_user(sender, instance, created, **kwargs): # pylint: disable=unused-argument +def create_audit_user(sender, instance, created, **kwargs): # noqa: ARG001 if kwargs["raw"]: return @@ -68,7 +69,7 @@ def create_audit_user(sender, instance, created, **kwargs): # pylint: disable=u @receiver(signal=post_delete, sender=AuthUser) @receiver(signal=post_delete, sender=RBACUser) -def set_deleted_at_audit_user(sender, instance, **kwargs): # pylint: disable=unused-argument +def set_deleted_at_audit_user(sender, instance, **kwargs): # noqa: ARG001 audit_user = AuditUser.objects.filter(username=instance.username).order_by("-pk").first() audit_user.deleted_at = now() audit_user.save(update_fields=["deleted_at"]) diff --git a/python/audit/tests/test_action.py b/python/audit/tests/test_action.py index 316ac2c805..09663ec8a6 100644 --- a/python/audit/tests/test_action.py +++ b/python/audit/tests/test_action.py @@ -14,12 +14,7 @@ from datetime import datetime from unittest.mock import patch -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import BaseTestCase from cm.job import finish_task from cm.models import ( ADCM, @@ -40,7 +35,12 @@ from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED, HTTP_404_NOT_FOUND -from adcm.tests.base import BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestActionAudit(BaseTestCase): diff --git a/python/audit/tests/test_adcm.py b/python/audit/tests/test_adcm.py index c913ec2a65..bc085079f2 100644 --- a/python/audit/tests/test_adcm.py +++ b/python/audit/tests/test_adcm.py @@ -12,12 +12,7 @@ from datetime import datetime -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ADCM, Action, ConfigLog, TaskLog from django.contrib.contenttypes.models import ContentType from django.urls import reverse @@ -26,7 +21,12 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestADCMAudit(BaseTestCase): diff --git a/python/audit/tests/test_api.py b/python/audit/tests/test_api.py index eb3efcdc21..e1874d9ec8 100644 --- a/python/audit/tests/test_api.py +++ b/python/audit/tests/test_api.py @@ -12,12 +12,12 @@ from datetime import timedelta -from audit.models import AuditLog, AuditSession +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ADCM from django.urls import reverse from rest_framework.response import Response -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import AuditLog, AuditSession class TestAuditAPI(BaseTestCase): diff --git a/python/audit/tests/test_audit_object_rename.py b/python/audit/tests/test_audit_object_rename.py index 33d42e00e8..a1960b214f 100644 --- a/python/audit/tests/test_audit_object_rename.py +++ b/python/audit/tests/test_audit_object_rename.py @@ -10,7 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from audit.models import AuditLog +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ( Bundle, Cluster, @@ -25,7 +25,7 @@ from django.urls import reverse from rbac.models import Group, Policy, Role, RoleTypes -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import AuditLog class TestAuditObjectRename(BaseTestCase): diff --git a/python/audit/tests/test_audit_objects.py b/python/audit/tests/test_audit_objects.py index 3f9e971d78..b08fd70048 100644 --- a/python/audit/tests/test_audit_objects.py +++ b/python/audit/tests/test_audit_objects.py @@ -12,13 +12,13 @@ import json -from audit.models import AuditObject, AuditObjectType +from adcm.tests.base import BaseTestCase from cm.models import Bundle, Prototype, PrototypeConfig from django.urls import reverse from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED, HTTP_204_NO_CONTENT -from adcm.tests.base import BaseTestCase +from audit.models import AuditObject, AuditObjectType class TestAuditObjects(BaseTestCase): diff --git a/python/audit/tests/test_authentication.py b/python/audit/tests/test_authentication.py index b3d13a63e8..28fd0ae017 100644 --- a/python/audit/tests/test_authentication.py +++ b/python/audit/tests/test_authentication.py @@ -10,11 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from audit.models import AuditSession, AuditSessionLoginResult +from adcm.tests.base import BaseTestCase from django.urls import reverse from rbac.models import User -from adcm.tests.base import BaseTestCase +from audit.models import AuditSession, AuditSessionLoginResult class TestAuthenticationAudit(BaseTestCase): diff --git a/python/audit/tests/test_bundle.py b/python/audit/tests/test_bundle.py index b685515484..6c50cc8f56 100644 --- a/python/audit/tests/test_bundle.py +++ b/python/audit/tests/test_bundle.py @@ -14,12 +14,7 @@ from pathlib import Path from unittest.mock import patch -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import BaseTestCase from cm.models import Bundle, Cluster, Prototype from django.conf import settings from django.urls import reverse @@ -31,12 +26,15 @@ HTTP_403_FORBIDDEN, ) -from adcm.tests.base import BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestBundleAudit(BaseTestCase): - # pylint: disable=too-many-public-methods - def setUp(self) -> None: super().setUp() diff --git a/python/audit/tests/test_cluster.py b/python/audit/tests/test_cluster.py index 08304ec189..b303a8a4be 100644 --- a/python/audit/tests/test_cluster.py +++ b/python/audit/tests/test_cluster.py @@ -9,19 +9,12 @@ # 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. -# pylint: disable=too-many-lines from datetime import datetime from pathlib import Path from unittest.mock import patch -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObject, - AuditObjectType, -) +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ( Action, Bundle, @@ -50,12 +43,16 @@ HTTP_404_NOT_FOUND, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObject, + AuditObjectType, +) class TestClusterAudit(BaseTestCase): - # pylint: disable=too-many-instance-attributes,too-many-public-methods - def setUp(self) -> None: super().setUp() diff --git a/python/audit/tests/test_component.py b/python/audit/tests/test_component.py index b16bc84c68..4d3b1a9c7d 100644 --- a/python/audit/tests/test_component.py +++ b/python/audit/tests/test_component.py @@ -13,12 +13,7 @@ from datetime import datetime from unittest.mock import patch -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ( Action, Bundle, @@ -34,7 +29,12 @@ from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED, HTTP_403_FORBIDDEN -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestComponentAudit(BaseTestCase): diff --git a/python/audit/tests/test_config_log.py b/python/audit/tests/test_config_log.py index 76e89626f0..23ecb866a4 100644 --- a/python/audit/tests/test_config_log.py +++ b/python/audit/tests/test_config_log.py @@ -12,12 +12,7 @@ from datetime import datetime -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import BaseTestCase from cm.models import Bundle, Cluster, ConfigLog, GroupConfig, ObjectConfig, Prototype from django.contrib.contenttypes.models import ContentType from django.urls import reverse @@ -25,7 +20,12 @@ from rest_framework.response import Response from rest_framework.status import HTTP_403_FORBIDDEN -from adcm.tests.base import BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestConfigLogAudit(BaseTestCase): diff --git a/python/audit/tests/test_group.py b/python/audit/tests/test_group.py index 7d0982977c..cb5d637c8b 100644 --- a/python/audit/tests/test_group.py +++ b/python/audit/tests/test_group.py @@ -12,18 +12,18 @@ from datetime import datetime +from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from django.urls import reverse +from rbac.models import Group, User +from rest_framework.response import Response +from rest_framework.status import HTTP_403_FORBIDDEN + from audit.models import ( AuditLog, AuditLogOperationResult, AuditLogOperationType, AuditObjectType, ) -from django.urls import reverse -from rbac.models import Group, User -from rest_framework.response import Response -from rest_framework.status import HTTP_403_FORBIDDEN - -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class TestGroupAudit(BaseTestCase): diff --git a/python/audit/tests/test_group_config.py b/python/audit/tests/test_group_config.py index 5e35e9d4ed..cbb069df27 100644 --- a/python/audit/tests/test_group_config.py +++ b/python/audit/tests/test_group_config.py @@ -13,12 +13,7 @@ from datetime import datetime from pathlib import Path -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ( Bundle, Cluster, @@ -42,12 +37,15 @@ HTTP_403_FORBIDDEN, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestGroupConfigAudit(BaseTestCase): - # pylint: disable=too-many-public-methods,too-many-instance-attributes - def setUp(self) -> None: super().setUp() diff --git a/python/audit/tests/test_host.py b/python/audit/tests/test_host.py index f25469b3ab..749bb53d27 100644 --- a/python/audit/tests/test_host.py +++ b/python/audit/tests/test_host.py @@ -13,12 +13,7 @@ from datetime import datetime from unittest.mock import patch -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ( Action, Bundle, @@ -40,12 +35,15 @@ HTTP_404_NOT_FOUND, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestHostAudit(BaseTestCase): - # pylint: disable=too-many-public-methods,too-many-instance-attributes - def setUp(self) -> None: super().setUp() diff --git a/python/audit/tests/test_logrotate.py b/python/audit/tests/test_logrotate.py index ada625a078..9111106de7 100644 --- a/python/audit/tests/test_logrotate.py +++ b/python/audit/tests/test_logrotate.py @@ -12,7 +12,7 @@ from datetime import datetime, timedelta -from audit.models import AuditLog, AuditLogOperationResult, AuditLogOperationType +from adcm.tests.base import BaseTestCase from cm.models import ( ADCM, Bundle, @@ -27,7 +27,7 @@ from django.utils import timezone from rbac.models import User -from adcm.tests.base import BaseTestCase +from audit.models import AuditLog, AuditLogOperationResult, AuditLogOperationType class TestLogrotate(BaseTestCase): diff --git a/python/audit/tests/test_policy.py b/python/audit/tests/test_policy.py index 32f6fb40e5..53d13d98a9 100644 --- a/python/audit/tests/test_policy.py +++ b/python/audit/tests/test_policy.py @@ -9,27 +9,25 @@ # 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. - from datetime import datetime +import contextlib -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import Bundle, Cluster, HostProvider, ObjectType, Prototype from django.urls import reverse from rbac.models import Policy, Role, RoleTypes, User from rest_framework.response import Response from rest_framework.status import HTTP_403_FORBIDDEN -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestPolicyAudit(BaseTestCase): - # pylint: disable=too-many-instance-attributes - def setUp(self) -> None: super().setUp() @@ -334,7 +332,7 @@ def test_update_patch_denied(self): ) def test_update_patch_failed(self): - try: + with contextlib.suppress(KeyError): self.client.patch( path=reverse(viewname=self.detail_name, kwargs={"pk": self.policy.pk}), data={ @@ -345,8 +343,6 @@ def test_update_patch_failed(self): }, content_type=APPLICATION_JSON, ) - except KeyError: - pass log: AuditLog = AuditLog.objects.order_by("operation_time").last() diff --git a/python/audit/tests/test_provider.py b/python/audit/tests/test_provider.py index 1f4c7321d8..29cf8c24c2 100644 --- a/python/audit/tests/test_provider.py +++ b/python/audit/tests/test_provider.py @@ -13,12 +13,7 @@ from datetime import datetime from unittest.mock import patch -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ( Action, Bundle, @@ -39,7 +34,12 @@ HTTP_404_NOT_FOUND, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestProviderAudit(BaseTestCase): diff --git a/python/audit/tests/test_role.py b/python/audit/tests/test_role.py index 80ff71aba5..db378ff5e4 100644 --- a/python/audit/tests/test_role.py +++ b/python/audit/tests/test_role.py @@ -12,18 +12,18 @@ from datetime import datetime +from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from django.urls import reverse +from rbac.models import Role, RoleTypes, User +from rest_framework.response import Response +from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN + from audit.models import ( AuditLog, AuditLogOperationResult, AuditLogOperationType, AuditObjectType, ) -from django.urls import reverse -from rbac.models import Role, RoleTypes, User -from rest_framework.response import Response -from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN - -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class TestRoleAudit(BaseTestCase): diff --git a/python/audit/tests/test_service.py b/python/audit/tests/test_service.py index d9233534dc..2bc0359f22 100644 --- a/python/audit/tests/test_service.py +++ b/python/audit/tests/test_service.py @@ -14,12 +14,7 @@ from pathlib import Path from unittest.mock import patch -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ( Action, Bundle, @@ -42,12 +37,15 @@ HTTP_404_NOT_FOUND, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestServiceAudit(BaseTestCase): - # pylint: disable=too-many-instance-attributes,too-many-public-methods - def setUp(self) -> None: super().setUp() diff --git a/python/audit/tests/test_task.py b/python/audit/tests/test_task.py index 645ee012fd..222069f7f3 100644 --- a/python/audit/tests/test_task.py +++ b/python/audit/tests/test_task.py @@ -13,12 +13,7 @@ from datetime import datetime from unittest.mock import patch -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObjectType, -) +from adcm.tests.base import BaseTestCase from cm.models import ADCM, TaskLog from django.contrib.contenttypes.models import ContentType from django.urls import reverse @@ -27,7 +22,12 @@ from rest_framework.response import Response from rest_framework.status import HTTP_404_NOT_FOUND -from adcm.tests.base import BaseTestCase +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObjectType, +) class TestTaskAudit(BaseTestCase): diff --git a/python/audit/tests/test_user.py b/python/audit/tests/test_user.py index 4618b6cbad..732b38d083 100644 --- a/python/audit/tests/test_user.py +++ b/python/audit/tests/test_user.py @@ -14,6 +14,13 @@ from pathlib import Path from secrets import token_hex +from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from cm.models import ObjectType, Prototype +from django.urls import reverse +from rbac.models import User +from rest_framework.response import Response +from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN + from audit.models import ( AuditLog, AuditLogOperationResult, @@ -22,13 +29,6 @@ AuditSession, AuditUser, ) -from cm.models import ObjectType, Prototype -from django.urls import reverse -from rbac.models import User -from rest_framework.response import Response -from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN - -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class TestUserAudit(BaseTestCase): diff --git a/python/audit/tests/test_views.py b/python/audit/tests/test_views.py index 8e5f084040..8232aca633 100644 --- a/python/audit/tests/test_views.py +++ b/python/audit/tests/test_views.py @@ -12,6 +12,13 @@ from datetime import datetime +from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from django.urls import reverse +from django.utils import timezone +from init_db import init as init_adcm +from rest_framework.response import Response +from rest_framework.status import HTTP_200_OK, HTTP_403_FORBIDDEN + from audit.models import ( AuditLog, AuditLogOperationResult, @@ -22,18 +29,9 @@ AuditSessionLoginResult, AuditUser, ) -from django.urls import reverse -from django.utils import timezone -from init_db import init as init_adcm -from rest_framework.response import Response -from rest_framework.status import HTTP_200_OK, HTTP_403_FORBIDDEN - -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class TestAuditViews(BaseTestCase): - # pylint: disable=too-many-instance-attributes - def setUp(self) -> None: super().setUp() diff --git a/python/audit/urls.py b/python/audit/urls.py index e631d24506..a9cf4b07c9 100644 --- a/python/audit/urls.py +++ b/python/audit/urls.py @@ -11,10 +11,11 @@ # limitations under the License. -from audit.views import AuditLogViewSet, AuditRoot, AuditSessionViewSet from django.urls import path from rest_framework.routers import SimpleRouter +from audit.views import AuditLogViewSet, AuditRoot, AuditSessionViewSet + router = SimpleRouter() router.register("operation", AuditLogViewSet) router.register("login", AuditSessionViewSet) diff --git a/python/audit/utils.py b/python/audit/utils.py index d0320b365a..718a85775a 100644 --- a/python/audit/utils.py +++ b/python/audit/utils.py @@ -10,9 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -import re from contextlib import suppress from functools import wraps +import re from api.cluster.serializers import ClusterAuditSerializer from api.component.serializers import ComponentAuditSerializer @@ -30,16 +30,6 @@ ServiceAuditSerializer as ServiceAuditSerializerV2, ) from api_v2.views import CamelCaseModelViewSet -from audit.cases.cases import get_audit_operation_and_object -from audit.cef_logger import cef_logger -from audit.models import ( - AuditLog, - AuditLogOperationResult, - AuditLogOperationType, - AuditObject, - AuditOperation, - AuditUser, -) from cm.errors import AdcmEx from cm.models import ( Action, @@ -74,6 +64,17 @@ ) from rest_framework.viewsets import ModelViewSet +from audit.cases.cases import get_audit_operation_and_object +from audit.cef_logger import cef_logger +from audit.models import ( + AuditLog, + AuditLogOperationResult, + AuditLogOperationType, + AuditObject, + AuditOperation, + AuditUser, +) + AUDITED_HTTP_METHODS = frozenset(("POST", "DELETE", "PUT", "PATCH")) URL_PATH_PATTERN = re.compile(r".*/api/v(?P\d+)/(?P.*?)/?$") @@ -101,8 +102,6 @@ def _get_view_and_request(args) -> tuple[GenericAPIView, WSGIRequest]: def _get_deleted_obj( view: GenericAPIView, request: WSGIRequest, kwargs: dict, api_version: int, path: list[str] ) -> Model | None: - # pylint: disable=too-many-branches, too-many-statements - try: deleted_obj = view.get_object() except AssertionError: @@ -118,7 +117,7 @@ def _get_deleted_obj( except (AdcmEx, Http404) as e: # when denied returns 404 from PermissionListMixin if api_version == 1: try: - if getattr(view, "queryset") is None: + if view.queryset is None: raise TypeError from e if view.queryset.count() == 1: @@ -131,10 +130,7 @@ def _get_deleted_obj( else: deleted_obj = None except TypeError: - if "role" in request.path: - deleted_obj = Role.objects.filter(pk=view.kwargs["pk"]).first() - else: - deleted_obj = None + deleted_obj = Role.objects.filter(pk=view.kwargs["pk"]).first() if "role" in request.path else None except (IndexError, ObjectDoesNotExist): deleted_obj = None elif api_version == 2: @@ -175,7 +171,7 @@ def get_target_object_by_path(path: list[str]) -> Model | None: return None -def get_target_model_and_id_by_path( # pylint: disable=too-many-return-statements +def get_target_model_and_id_by_path( path: list[str], ) -> tuple[type[Model], str] | None: match path: @@ -215,7 +211,6 @@ def get_target_model_and_id_by_path( # pylint: disable=too-many-return-statemen return None -# pylint: disable=too-many-branches def _get_object_changes(prev_data: dict, current_obj: Model, api_version: int) -> dict: serializer_class = None if isinstance(current_obj, Group): @@ -269,8 +264,6 @@ def _get_object_changes(prev_data: dict, current_obj: Model, api_version: int) - def _get_obj_changes_data(view: GenericAPIView | ModelViewSet) -> tuple[dict | None, Model | None]: - # pylint: disable=too-many-branches,too-many-statements - prev_data = None current_obj = None serializer_class = None @@ -328,10 +321,8 @@ def _get_obj_changes_data(view: GenericAPIView | ModelViewSet) -> tuple[dict | N pk = view.kwargs["pk"] if serializer_class: - if hasattr(view, "audit_model_hint"): # for cases when get_queryset() raises error - model = view.audit_model_hint - else: - model = view.get_queryset().model + # for cases when get_queryset() raises error + model = view.audit_model_hint if hasattr(view, "audit_model_hint") else view.get_queryset().model try: current_obj = model.objects.filter(pk=pk).first() @@ -395,10 +386,7 @@ def _detect_status_code_and_deleted_object_for_v1( error: AdcmEx | ValidationError | Http404 | NotFound, deleted_obj, kwargs ) -> int: if not deleted_obj: - if isinstance(error, Http404): - status_code = HTTP_404_NOT_FOUND - else: - status_code = error.status_code + status_code = HTTP_404_NOT_FOUND if isinstance(error, Http404) else error.status_code if status_code != HTTP_404_NOT_FOUND: return status_code @@ -411,7 +399,7 @@ def _detect_status_code_and_deleted_object_for_v1( return status_code # when denied returns 404 from PermissionListMixin - if getattr(error, "msg", None) and ( # pylint: disable=too-many-boolean-expressions + if getattr(error, "msg", None) and ( "There is host" in error.msg or "belong to cluster" in error.msg or "host associated with a cluster" in error.msg @@ -450,7 +438,7 @@ def _all_child_objects_exist(path: list[str]) -> bool: return True -def _all_objects_in_path_exist(path: list[str]) -> bool: # pylint: disable=too-many-return-statements +def _all_objects_in_path_exist(path: list[str]) -> bool: match path: case ["rbac", rbac_type, pk, *_]: with suppress(KeyError, ValueError): @@ -470,11 +458,8 @@ def _all_objects_in_path_exist(path: list[str]) -> bool: # pylint: disable=too- def audit(func): - # pylint: disable=too-many-statements @wraps(func) def wrapped(*args, **kwargs): - # pylint: disable=too-many-branches,too-many-statements,too-many-locals - audit_operation: AuditOperation audit_object: AuditObject operation_name: str @@ -515,19 +500,13 @@ def wrapped(*args, **kwargs): return res # Correctly finished request (when will be `bool(res) is False`?) - if res: - status_code = res.status_code - else: - status_code = HTTP_403_FORBIDDEN + status_code = res.status_code if res else HTTP_403_FORBIDDEN except (AdcmEx, ValidationError, Http404, NotFound) as exc: error = exc res = None if api_version == 2: - if isinstance(error, Http404): - status_code = HTTP_404_NOT_FOUND - else: - status_code = error.status_code + status_code = HTTP_404_NOT_FOUND if isinstance(error, Http404) else error.status_code if status_code == HTTP_404_NOT_FOUND and _all_objects_in_path_exist(path=path): status_code = HTTP_403_FORBIDDEN diff --git a/python/audit/views.py b/python/audit/views.py index e34fbe0eb9..620e70c6c5 100644 --- a/python/audit/views.py +++ b/python/audit/views.py @@ -10,15 +10,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -from audit.filters import AuditLogListFilter, AuditSessionListFilter -from audit.models import AuditLog, AuditSession -from audit.serializers import AuditLogSerializer, AuditSessionSerializer +from adcm.permissions import SuperuserOnlyMixin from rest_framework.permissions import AllowAny from rest_framework.routers import APIRootView from rest_framework.schemas.coreapi import AutoSchema from rest_framework.viewsets import ReadOnlyModelViewSet -from adcm.permissions import SuperuserOnlyMixin +from audit.filters import AuditLogListFilter, AuditSessionListFilter +from audit.models import AuditLog, AuditSession +from audit.serializers import AuditLogSerializer, AuditSessionSerializer class AuditRoot(APIRootView): @@ -29,7 +29,6 @@ class AuditRoot(APIRootView): } -# pylint: disable=too-many-ancestors class AuditLogViewSet(SuperuserOnlyMixin, ReadOnlyModelViewSet): not_superuser_error_code = "AUDIT_OPERATIONS_FORBIDDEN" queryset = AuditLog.objects.select_related("audit_object", "user").order_by("-operation_time", "-pk") @@ -38,7 +37,6 @@ class AuditLogViewSet(SuperuserOnlyMixin, ReadOnlyModelViewSet): schema = AutoSchema() -# pylint: disable=too-many-ancestors class AuditSessionViewSet(SuperuserOnlyMixin, ReadOnlyModelViewSet): not_superuser_error_code = "AUDIT_LOGINS_FORBIDDEN" queryset = AuditSession.objects.select_related("user").order_by("-login_time", "-pk") diff --git a/python/backupdb.py b/python/backupdb.py index 5078bf7606..eb745e429b 100755 --- a/python/backupdb.py +++ b/python/backupdb.py @@ -10,18 +10,18 @@ # 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. -# pylint: disable=wrong-import-order -from django.utils import timezone import os import sqlite3 + +import adcm.init_django # noqa: F401, isort:skip + +from cm.logger import logger from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.db import DEFAULT_DB_ALIAS, connections from django.db.migrations.executor import MigrationExecutor - -import adcm.init_django # pylint: disable=unused-import -from cm.logger import logger +from django.utils import timezone def check_migrations(): diff --git a/python/check_adcm_bundle.py b/python/check_adcm_bundle.py index 63fa0bca90..9eea4a575a 100755 --- a/python/check_adcm_bundle.py +++ b/python/check_adcm_bundle.py @@ -11,23 +11,23 @@ # See the License for the specific language governing permissions and # limitations under the License. -import argparse import os -import shutil import sys +import shutil import tarfile +import argparse from check_adcm_config import check_config from django.conf import settings -TMP_DIR = "/tmp/adcm_bundle_tmp" +TMP_DIR = "/tmp/adcm_bundle_tmp" # noqa: S108 def untar(bundle_file): if os.path.isdir(TMP_DIR): shutil.rmtree(TMP_DIR) - tar = tarfile.open(bundle_file) # pylint: disable=consider-using-with + tar = tarfile.open(bundle_file) # noqa: SIM115 tar.extractall(path=TMP_DIR) tar.close() diff --git a/python/check_adcm_config.py b/python/check_adcm_config.py index b5ed6c41d3..c9b9436028 100755 --- a/python/check_adcm_config.py +++ b/python/check_adcm_config.py @@ -10,26 +10,25 @@ # 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. -# pylint: disable=wrong-import-order -import argparse -import sys from pathlib import Path +import sys +import argparse -import cm.checker -import ruyaml from django.conf import settings -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401, isort:skip +import ruyaml +import cm.checker -def check_config(data_file, schema_file, print_ok=True): # pylint: disable=too-many-return-statements +def check_config(data_file, schema_file, print_ok=True): rules = ruyaml.round_trip_load( - open(schema_file, encoding=settings.ENCODING_UTF_8), # pylint: disable=consider-using-with + open(schema_file, encoding=settings.ENCODING_UTF_8), # noqa: SIM115 ) try: data = ruyaml.round_trip_load( - open(data_file, encoding=settings.ENCODING_UTF_8), # pylint: disable=consider-using-with + open(data_file, encoding=settings.ENCODING_UTF_8), # noqa: SIM115 version="1.1", ) except FileNotFoundError as e: diff --git a/python/cm/adcm_config/checks.py b/python/cm/adcm_config/checks.py index c7cf7bc3a1..1510eaa32a 100644 --- a/python/cm/adcm_config/checks.py +++ b/python/cm/adcm_config/checks.py @@ -12,11 +12,12 @@ from typing import Any +from django.conf import settings + from cm.adcm_config.utils import config_is_ro, group_keys_to_flat, proto_ref from cm.checker import FormatError, SchemaError, process_rule from cm.errors import raise_adcm_ex from cm.models import GroupConfig, Prototype, StagePrototype -from django.conf import settings def check_agreement_group_attr(group_keys: dict, custom_group_keys: dict, spec: dict) -> None: @@ -37,7 +38,7 @@ def check_group_keys_attr(attr: dict, spec: dict, group_config: GroupConfig) -> check_agreement_group_attr(group_keys=group_keys, custom_group_keys=custom_group_keys, spec=spec) -def check_attr( # pylint: disable=too-many-branches +def check_attr( proto: Prototype, obj, attr: dict, @@ -53,7 +54,7 @@ def check_attr( # pylint: disable=too-many-branches if not isinstance(attr, dict): raise_adcm_ex(code="ATTRIBUTE_ERROR", msg="`attr` should be a map") - for key, value in attr.items(): + for key in attr: if key in ["group_keys", "custom_group_keys"]: if not is_group_config: raise_adcm_ex(code="ATTRIBUTE_ERROR", msg=f"not allowed key `{key}` for object ({ref})") @@ -120,9 +121,8 @@ def check_structure_for_group_attr(group_keys: dict, spec: dict, key_name: str) raise_adcm_ex(code="ATTRIBUTE_ERROR", msg=f"invalid type `{key}` field in `{key_name}`") for key, value in spec.items(): - if value.type != "group": - if key not in flat_group_attr: - raise_adcm_ex(code="ATTRIBUTE_ERROR", msg=f"there is no `{key}` field in `{key_name}`") + if value.type != "group" and key not in flat_group_attr: + raise_adcm_ex(code="ATTRIBUTE_ERROR", msg=f"there is no `{key}` field in `{key_name}`") def _check_empty_values(key: str, current: dict, new: dict) -> bool: @@ -143,7 +143,7 @@ def _check_str(value: Any, idx: Any, key: str, subkey: str, ref: str, label: str ) -def check_config_type( # pylint: disable=too-many-branches,too-many-statements,too-many-locals +def check_config_type( prototype: StagePrototype | Prototype, key: str, subkey: str, @@ -153,17 +153,14 @@ def check_config_type( # pylint: disable=too-many-branches,too-many-statements, inactive: bool = False, ) -> None: ref = proto_ref(prototype=prototype) - if default: - label = "Default value" - else: - label = "Value" + label = "Default value" if default else "Value" tmpl1 = f'{label} of config key "{key}/{subkey}" {{}} ({ref})' tmpl2 = f'{label} ("{value}") of config key "{key}/{subkey}" {{}} ({ref})' should_not_be_empty = "should be not empty" if ( - value is None # pylint: disable=too-many-boolean-expressions + value is None or (spec["type"] == "map" and value == {}) or (spec["type"] == "secretmap" and value == {}) or (spec["type"] == "list" and value == []) @@ -176,9 +173,12 @@ def check_config_type( # pylint: disable=too-many-branches,too-many-statements, else: return - if isinstance(value, (list, dict)) and spec["type"] not in settings.STACK_COMPLEX_FIELD_TYPES: - if spec["type"] != "group": - raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl1.format("should be flat")) + if ( + isinstance(value, (list, dict)) + and spec["type"] not in settings.STACK_COMPLEX_FIELD_TYPES + and spec["type"] != "group" + ): + raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl1.format("should be flat")) if spec["type"] == "list": if not isinstance(value, list): @@ -214,9 +214,8 @@ def check_config_type( # pylint: disable=too-many-branches,too-many-statements, if value == "": raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl1.format(should_not_be_empty)) - if default: - if len(value) > 2048: - raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl1.format("is too long")) + if default and len(value) > 2048: + raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl1.format("is too long")) if spec["type"] == "structure": schema = spec["limits"]["yspec"] @@ -256,12 +255,10 @@ def check_config_type( # pylint: disable=too-many-branches,too-many-statements, if spec["type"] == "variant": source = spec["limits"]["source"] - if source["strict"]: - if source["type"] == "inline" and value not in source["value"]: + if source["strict"] and source["type"] == "inline" and value not in source["value"]: + msg = f'not in variant list: "{source["value"]}"' + raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl2.format(msg)) + + if not default and source["type"] in ("config", "builtin") and value not in source["value"]: msg = f'not in variant list: "{source["value"]}"' raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl2.format(msg)) - - if not default: - if source["type"] in ("config", "builtin") and value not in source["value"]: - msg = f'not in variant list: "{source["value"]}"' - raise_adcm_ex(code="CONFIG_VALUE_ERROR", msg=tmpl2.format(msg)) diff --git a/python/cm/adcm_config/config.py b/python/cm/adcm_config/config.py index ade22cfd5f..e1a2a7096c 100644 --- a/python/cm/adcm_config/config.py +++ b/python/cm/adcm_config/config.py @@ -10,14 +10,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import copy -import json -import re from collections import OrderedDict from pathlib import Path from typing import Any +import re +import copy +import json from ansible.errors import AnsibleError +from django.conf import settings +from django.db.models import QuerySet +from jinja_config import get_jinja_config + from cm.adcm_config.ansible import ansible_decrypt, ansible_encrypt_and_format from cm.adcm_config.checks import check_attr, check_config_type from cm.adcm_config.utils import ( @@ -49,9 +53,6 @@ ) from cm.utils import deep_merge, dict_to_obj, obj_to_dict from cm.variant import get_variant, process_variant -from django.conf import settings -from django.db.models import QuerySet -from jinja_config import get_jinja_config def read_bundle_file(proto: Prototype | StagePrototype, fname: str, bundle_hash: str, ref=None) -> str | None: @@ -68,7 +69,7 @@ def read_bundle_file(proto: Prototype | StagePrototype, fname: str, bundle_hash: path = Path(settings.BUNDLE_DIR, bundle_hash, fname) try: - file_descriptor = open(path, encoding=settings.ENCODING_UTF_8) # pylint: disable=consider-using-with + file_descriptor = open(path, encoding=settings.ENCODING_UTF_8) # noqa: SIM115 except FileNotFoundError: raise_adcm_ex(code="CONFIG_TYPE_ERROR", msg=f'{bundle_hash} "{path}" is not found ({ref})') except PermissionError: @@ -143,7 +144,7 @@ def make_object_config(obj: ADCMEntity, prototype: Prototype) -> None: obj.save() -def switch_config( # pylint: disable=too-many-locals,too-many-branches,too-many-statements +def switch_config( obj: ADCMEntity, new_prototype: Prototype, old_prototype: Prototype, @@ -275,7 +276,7 @@ def _clear_group_keys(group_keys: dict, spec: dict) -> dict: correct_group_keys[field]["value"] = group_keys[field]["value"] correct_group_keys[field]["fields"] = {} - for key in info["fields"].keys(): + for key in info["fields"]: correct_group_keys[field]["fields"][key] = group_keys[field]["fields"][key] else: correct_group_keys[field] = group_keys[field] @@ -379,12 +380,10 @@ def save_file_type(obj, key, subkey, value): # So when we create that key from playbook and save it in ADCM we get # "Load key : invalid format" on next connect to host. - if key == "ansible_ssh_private_key_file": - if value != "": - if value[-1] == "-": - value += "\n" + if key == "ansible_ssh_private_key_file" and value != "" and value[-1] == "-": + value += "\n" - file_descriptor = open(filename, "w", encoding=settings.ENCODING_UTF_8) # pylint: disable=consider-using-with + file_descriptor = open(filename, "w", encoding=settings.ENCODING_UTF_8) # noqa: SIM115 file_descriptor.write(value) file_descriptor.close() Path(filename).chmod(0o0600) @@ -393,8 +392,6 @@ def save_file_type(obj, key, subkey, value): def process_file_type(obj: Any, spec: dict, conf: dict): - # pylint: disable=too-many-branches,disable=too-many-nested-blocks - for key in conf: if "type" in spec[key]: if spec[key]["type"] == "file": @@ -435,7 +432,7 @@ def process_file_type(obj: Any, spec: dict, conf: dict): save_file_type(obj, key, subkey, value) -def process_config( # pylint: disable=too-many-branches +def process_config( obj: ADCMEntity, spec: dict, old_conf: dict, @@ -444,7 +441,7 @@ def process_config( # pylint: disable=too-many-branches return old_conf conf = copy.deepcopy(old_conf) - for key in conf: # pylint: disable=too-many-nested-blocks + for key in conf: if "type" in spec[key]: if conf[key] is not None: if spec[key]["type"] in {"file", "secretfile"}: @@ -476,7 +473,7 @@ def process_config( # pylint: disable=too-many-branches return conf -def ui_config(obj, config_log): # pylint: disable=too-many-locals +def ui_config(obj, config_log): conf = [] _, spec, _, _ = get_prototype_config(obj.prototype) obj_conf = config_log.config @@ -536,7 +533,7 @@ def get_action_variant(obj: ADCMEntity, prototype_configs: QuerySet[PrototypeCon conf.limits["source"]["value"] = get_variant(obj, config_log.config, conf.limits) -def restore_read_only(obj, spec, conf, old_conf): # pylint: disable=too-many-branches +def restore_read_only(obj, spec, conf, old_conf): # Do not remove! # This patch fix old error when sometimes group config values can be lost # during bundle upgrade @@ -551,18 +548,15 @@ def restore_read_only(obj, spec, conf, old_conf): # pylint: disable=too-many-br ) # end of patch - for key in spec: # pylint: disable=too-many-nested-blocks + for key in spec: if "type" in spec[key]: - if config_is_ro(obj, key, spec[key]["limits"]) and key not in conf: - if key in old_conf: - conf[key] = old_conf[key] + if config_is_ro(obj, key, spec[key]["limits"]) and key not in conf and key in old_conf: + conf[key] = old_conf[key] else: for subkey in spec[key]: if config_is_ro(obj=obj, key=f"{key}/{subkey}", limits=spec[key][subkey]["limits"]): - if key in conf: - if subkey not in conf: - if key in old_conf and subkey in old_conf[key]: - conf[key][subkey] = old_conf[key][subkey] + if key in conf and subkey not in conf and key in old_conf and subkey in old_conf[key]: + conf[key][subkey] = old_conf[key][subkey] elif key in old_conf and subkey in old_conf[key]: conf[key] = {subkey: old_conf[key][subkey]} @@ -586,12 +580,10 @@ def process_json_config( process_variant(obj, spec, new_config) check_config_spec(proto=prototype, obj=obj, spec=spec, flat_spec=flat_spec, conf=new_config, attr=new_attr) - new_config = process_config_spec(obj=group or obj, spec=spec, new_config=new_config) - - return new_config + return process_config_spec(obj=group or obj, spec=spec, new_config=new_config) -def check_config_spec( # pylint: disable=too-many-branches +def check_config_spec( proto: Prototype, obj: ADCMEntity | Action, spec: dict, @@ -799,56 +791,43 @@ def get_option_value(value: str, limits: dict) -> str | int | float: return raise_adcm_ex("CONFIG_OPTION_ERROR") -def get_default( # pylint: disable=too-many-branches +def get_default( conf: PrototypeConfig, prototype: Prototype | None = None, ) -> Any: value = conf.default if conf.default == "": value = None - elif conf.type == "string": - value = conf.default - elif conf.type == "text": + elif conf.type == "string" or conf.type == "text": value = conf.default - elif conf.type in settings.SECURE_PARAM_TYPES: - if conf.default: - value = ansible_encrypt_and_format(msg=conf.default) + elif conf.type in settings.SECURE_PARAM_TYPES and conf.default: + value = ansible_encrypt_and_format(msg=conf.default) elif conf.type in settings.STACK_COMPLEX_FIELD_TYPES: - if isinstance(conf.default, str): - value = json.loads(s=conf.default) - else: - value = conf.default + value = json.loads(s=conf.default) if isinstance(conf.default, str) else conf.default elif conf.type == "integer": value = int(conf.default) elif conf.type == "float": value = float(conf.default) elif conf.type == "boolean": - if isinstance(conf.default, bool): - value = conf.default - else: - value = bool(conf.default.lower() in {"true", "yes"}) + value = conf.default if isinstance(conf.default, bool) else bool(conf.default.lower() in {"true", "yes"}) elif conf.type == "option": value = get_option_value(value=value, limits=conf.limits) - elif conf.type == "file": - if prototype: - if conf.default: - value = read_bundle_file( - proto=prototype, - fname=conf.default, - bundle_hash=prototype.bundle.hash, - ref=f'config key "{conf.name}/{conf.subname}" default file', - ) - elif conf.type == "secretfile": - if prototype: - if conf.default: - value = ansible_encrypt_and_format( - msg=read_bundle_file( - proto=prototype, - fname=conf.default, - bundle_hash=prototype.bundle.hash, - ref=f'config key "{conf.name}/{conf.subname}" default file', - ), - ) + elif conf.type == "file" and prototype and conf.default: + value = read_bundle_file( + proto=prototype, + fname=conf.default, + bundle_hash=prototype.bundle.hash, + ref=f'config key "{conf.name}/{conf.subname}" default file', + ) + elif conf.type == "secretfile" and prototype and conf.default: + value = ansible_encrypt_and_format( + msg=read_bundle_file( + proto=prototype, + fname=conf.default, + bundle_hash=prototype.bundle.hash, + ref=f'config key "{conf.name}/{conf.subname}" default file', + ), + ) if conf.type == "secretmap" and conf.default: new_value = {} diff --git a/python/cm/adcm_config/utils.py b/python/cm/adcm_config/utils.py index 62acb28597..f5e485e39c 100644 --- a/python/cm/adcm_config/utils.py +++ b/python/cm/adcm_config/utils.py @@ -12,6 +12,8 @@ from pathlib import Path from typing import Mapping, Union +from django.conf import settings + from cm.errors import raise_adcm_ex from cm.models import ( Action, @@ -21,7 +23,6 @@ PrototypeConfig, StagePrototype, ) -from django.conf import settings def group_keys_to_flat(origin: dict, spec: dict) -> dict: @@ -98,7 +99,6 @@ def cook_file_type_name(obj: Union["ADCMEntity", "GroupConfig"], key: str, sub_k def config_is_ro(obj: ADCMEntity | Action, key: str, limits: dict) -> bool: - # pylint: disable=too-many-return-statements if not limits: return False @@ -143,9 +143,8 @@ def key_is_required(obj: ADCMEntity | Action, key: str, subkey: str, spec: dict) def is_inactive(key: str, attr: dict, flat_spec: dict) -> bool: - if attr and flat_spec[f"{key}/"].type == "group": - if key in attr and "active" in attr[key]: - return not bool(attr[key]["active"]) + if attr and flat_spec[f"{key}/"].type == "group" and key in attr and "active" in attr[key]: + return not bool(attr[key]["active"]) return False @@ -154,8 +153,4 @@ def sub_key_is_required(key: str, attr: dict, flat_spec: dict, spec: dict, obj: if is_inactive(key=key, attr=attr, flat_spec=flat_spec): return False - for subkey in spec[key]: - if key_is_required(obj=obj, key=key, subkey=subkey, spec=spec): - return True - - return False + return any(key_is_required(obj=obj, key=key, subkey=subkey, spec=spec) for subkey in spec[key]) diff --git a/python/cm/ansible_plugin.py b/python/cm/ansible_plugin.py index 9fc9e58528..e39bf0847b 100644 --- a/python/cm/ansible_plugin.py +++ b/python/cm/ansible_plugin.py @@ -9,11 +9,11 @@ # 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 fcntl -import json from collections import defaultdict from copy import deepcopy from typing import Any +import json +import fcntl # isort: off from ansible.errors import AnsibleError @@ -84,7 +84,7 @@ def job_lock(job_id): - file_descriptor = open( # pylint: disable=consider-using-with + file_descriptor = open( # noqa: SIM115 settings.RUN_DIR / f"{job_id}/config.json", encoding=settings.ENCODING_UTF_8, ) @@ -448,7 +448,7 @@ def update_config(obj: ADCMEntity, conf: dict, attr: dict) -> dict | int | str: new_attr.update(attr) - for key in attr.keys(): + for key in attr: for subkey, value in config_log.config[key].items(): if not new_config[key] or subkey not in new_config[key]: new_config[key][subkey] = value @@ -512,9 +512,8 @@ def set_component_config(component_id: int, config: dict, attr: dict): def check_missing_ok(obj: ADCMEntity, multi_state: str, missing_ok): - if missing_ok is False: - if multi_state not in obj.multi_state: - raise AnsibleError(MSG_NO_MULTI_STATE_TO_DELETE) + if missing_ok is False and multi_state not in obj.multi_state: + raise AnsibleError(MSG_NO_MULTI_STATE_TO_DELETE) def _unset_object_multi_state(obj: ADCMEntity, multi_state: str, missing_ok) -> ADCMEntity: @@ -563,10 +562,7 @@ def log_group_check(group: GroupCheckLog, fail_msg: str, success_msg: str): logs = CheckLog.objects.filter(group=group).values("result") result = all(log["result"] for log in logs) - if result: - msg = success_msg - else: - msg = fail_msg + msg = success_msg if result else fail_msg group.message = msg group.result = result diff --git a/python/cm/api.py b/python/cm/api.py index ade67ab6d1..826a3665dd 100644 --- a/python/cm/api.py +++ b/python/cm/api.py @@ -9,14 +9,19 @@ # 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. -# pylint: disable=too-many-lines -import json from collections import defaultdict from functools import partial, wraps from typing import Literal, TypedDict +import json from adcm_version import compare_prototype_versions +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import MultipleObjectsReturned +from django.db.transaction import atomic, on_commit +from rbac.models import Policy, re_apply_object_policy +from rbac.roles import apply_policy_for_new_config + from cm.adcm_config.config import ( init_object_config, process_json_config, @@ -65,11 +70,6 @@ send_host_component_map_update_event, ) from cm.utils import obj_ref -from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import MultipleObjectsReturned -from django.db.transaction import atomic, on_commit -from rbac.models import Policy, re_apply_object_policy -from rbac.roles import apply_policy_for_new_config def check_license(prototype: Prototype) -> None: @@ -81,19 +81,21 @@ def check_license(prototype: Prototype) -> None: def is_version_suitable(version: str, prototype_import: PrototypeImport) -> bool: - if prototype_import.min_strict: - if compare_prototype_versions(version, prototype_import.min_version) <= 0: - return False - elif prototype_import.min_version: - if compare_prototype_versions(version, prototype_import.min_version) < 0: - return False - - if prototype_import.max_strict: - if compare_prototype_versions(version, prototype_import.max_version) >= 0: - return False - elif prototype_import.max_version: - if compare_prototype_versions(version, prototype_import.max_version) > 0: - return False + if ( + prototype_import.min_strict + and compare_prototype_versions(version, prototype_import.min_version) <= 0 + or prototype_import.min_version + and compare_prototype_versions(version, prototype_import.min_version) < 0 + ): + return False + + if ( + prototype_import.max_strict + and compare_prototype_versions(version, prototype_import.max_version) >= 0 + or prototype_import.max_version + and compare_prototype_versions(version, prototype_import.max_version) > 0 + ): + return False return True @@ -446,13 +448,12 @@ def add_service_to_cluster(cluster: Cluster, proto: Prototype) -> ClusterObject: raise_adcm_ex(code="OBJ_TYPE_ERROR", msg=f"Prototype type should be service, not {proto.type}") check_license(prototype=proto) - if not proto.shared: - if cluster.prototype.bundle != proto.bundle: - raise_adcm_ex( - code="SERVICE_CONFLICT", - msg=f"{proto_ref(prototype=proto)} does not belong to bundle " - f'"{cluster.prototype.bundle.name}" {cluster.prototype.version}', - ) + if not proto.shared and cluster.prototype.bundle != proto.bundle: + raise_adcm_ex( + code="SERVICE_CONFLICT", + msg=f"{proto_ref(prototype=proto)} does not belong to bundle " + f'"{cluster.prototype.bundle.name}" {cluster.prototype.version}', + ) with atomic(): service = ClusterObject.objects.create(cluster=cluster, prototype=proto) @@ -657,8 +658,6 @@ def still_existed_hc(cluster: Cluster, host_comp_list: list[tuple[ClusterObject, def save_hc( cluster: Cluster, host_comp_list: list[tuple[ClusterObject, Host, ServiceComponent]] ) -> list[HostComponent]: - # pylint: disable=too-many-locals - hc_queryset = HostComponent.objects.filter(cluster=cluster).order_by("id") service_set = {hc.service for hc in hc_queryset} old_hosts = {i.host for i in hc_queryset.select_related("host")} @@ -729,13 +728,36 @@ def save_hc( return host_component_list +def set_host_component( + cluster: Cluster, host_component_objects: list[tuple[ClusterObject, Host, ServiceComponent]] +) -> list[HostComponent]: + """ + Save given hosts-components mapping if all sanity checks pass + """ + + check_hc_requires(shc_list=host_component_objects) + + check_bound_components(shc_list=host_component_objects) + + for service in ClusterObject.objects.select_related("prototype").filter(cluster=cluster): + check_component_constraint( + cluster=cluster, + service_prototype=service.prototype, + hc_in=[i for i in host_component_objects if i[0] == service], + ) + check_service_requires(cluster=cluster, proto=service.prototype) + + check_maintenance_mode(cluster=cluster, host_comp_list=host_component_objects) + + with atomic(): + return save_hc(cluster=cluster, host_comp_list=host_component_objects) + + def add_hc(cluster: Cluster, hc_in: list[dict]) -> list[HostComponent]: host_comp_list = check_hc(cluster=cluster, hc_in=hc_in) with atomic(): - new_host_component = save_hc(cluster=cluster, host_comp_list=host_comp_list) - - return new_host_component + return save_hc(cluster=cluster, host_comp_list=host_comp_list) def get_bind( @@ -858,9 +880,8 @@ def check_import_default(import_obj: Cluster | ClusterObject, export_obj: Cluste return for name in json.loads(prototype_import.default): - if name in config_log.attr: - if "active" in config_log.attr[name] and not config_log.attr[name]["active"]: - raise_adcm_ex("BIND_ERROR", f'Default import "{name}" for {obj_ref(import_obj)} is inactive') + if name in config_log.attr and "active" in config_log.attr[name] and not config_log.attr[name]["active"]: + raise_adcm_ex("BIND_ERROR", f'Default import "{name}" for {obj_ref(import_obj)} is inactive') def get_bind_obj(cluster: Cluster, service: ClusterObject | None) -> Cluster | ClusterObject: diff --git a/python/cm/api_context.py b/python/cm/api_context.py index af61d8c711..f3d42d9fc7 100644 --- a/python/cm/api_context.py +++ b/python/cm/api_context.py @@ -19,8 +19,8 @@ Implemented as singleton module, just `import ctx from cm.api_context` and use `ctx.*` when needed """ -import os from pathlib import Path +import os from cm import models from cm.logger import logger diff --git a/python/cm/apps.py b/python/cm/apps.py index 02476fbc4b..31b108d920 100644 --- a/python/cm/apps.py +++ b/python/cm/apps.py @@ -17,7 +17,7 @@ class CmConfig(AppConfig): name = "cm" def ready(self): - from cm.signals import ( # pylint: disable=import-outside-toplevel,unused-import + from cm.signals import ( # noqa: F401, PLC0415 rename_audit_object, rename_audit_object_host, ) diff --git a/python/cm/bundle.py b/python/cm/bundle.py index c513105a08..7a9783f830 100644 --- a/python/cm/bundle.py +++ b/python/cm/bundle.py @@ -10,17 +10,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-lines - -import functools -import hashlib +from collections.abc import Iterable +from pathlib import Path import os import shutil +import hashlib import tarfile -from collections.abc import Iterable -from pathlib import Path +import functools from adcm_version import compare_adcm_versions, compare_prototype_versions +from django.conf import settings +from django.db import IntegrityError, transaction +from django.db.transaction import atomic +from gnupg import GPG, ImportResult +from rbac.models import Role +from rbac.upgrade.role import prepare_action_roles + from cm.adcm_config.config import init_object_config, switch_config from cm.adcm_config.utils import cook_file_type_name, proto_ref from cm.errors import AdcmEx, raise_adcm_ex @@ -50,12 +55,6 @@ Upgrade, ) from cm.stack import get_config_files, read_definition, save_definition -from django.conf import settings -from django.db import IntegrityError, transaction -from django.db.transaction import atomic -from gnupg import GPG, ImportResult -from rbac.models import Role -from rbac.upgrade.role import prepare_action_roles STAGE = ( StagePrototype, @@ -107,10 +106,9 @@ def load_bundle(bundle_file: str) -> Bundle: untar_and_cleanup(bundle_archive=bundle_archive, signature_file=signature_file, bundle_hash=bundle_hash) with atomic(): - bundle = prepare_bundle( + return prepare_bundle( bundle_file=bundle_file, bundle_hash=bundle_hash, path=path, verification_status=verification_status ) - return bundle def get_bundle_and_signature_paths(path: Path) -> tuple[Path | None, Path | None]: @@ -149,7 +147,7 @@ def get_verification_status(bundle_archive: Path | None, signature_file: Path | if bundle_archive is None or signature_file is None: return SignatureStatus.ABSENT - gpg = GPG(gpgbinary=os.popen("which gpg").read().strip()) + gpg = GPG(gpgbinary=os.popen("which gpg").read().strip()) # noqa: S605, S607 gpg.encoding = settings.ENCODING_UTF_8 key_filepath = cook_file_type_name(obj=ADCM.objects.get(), key="global", sub_key="verification_public_key") @@ -253,7 +251,7 @@ def untar(bundle_hash: str, bundle: Path) -> Path: ), ) - tar = tarfile.open(bundle) # pylint: disable=consider-using-with + tar = tarfile.open(bundle) # noqa: SIM115 tar.extractall(path=path) tar.close() @@ -273,7 +271,7 @@ def get_hash_safe(path: str) -> str: def get_hash(bundle_file: str) -> str: - sha1 = hashlib.sha1() + sha1 = hashlib.sha1() # noqa: S324 with open(bundle_file, "rb") as f: for data in iter(lambda: f.read(16384), b""): sha1.update(data) @@ -291,7 +289,7 @@ def load_adcm(adcm_file: Path = Path(settings.BASE_DIR, "conf", "adcm", "config. with atomic(): prototypes, _ = save_definition( - path=Path(""), fname=adcm_file, conf=conf, obj_list={}, bundle_hash="adcm", adcm_=True + path=Path(), fname=adcm_file, conf=conf, obj_list={}, bundle_hash="adcm", adcm_=True ) process_adcm() StagePrototype.objects.filter(id__in=[prototype.id for prototype in prototypes]).delete() @@ -574,7 +572,7 @@ def check_predicate(predicate, _args): check_variant_host(i["args"], ref) -def re_check_config() -> None: # pylint: disable=too-many-branches +def re_check_config() -> None: sp_service = None same_stage_prototype_config = None @@ -956,7 +954,7 @@ def copy_stage(bundle_hash: str, bundle_proto, verification_status: SignatureSta def update_bundle_from_stage( bundle, -): # pylint: disable=too-many-locals,too-many-statements +): for stage_prototype in StagePrototype.objects.order_by("id"): try: prototype = Prototype.objects.get( diff --git a/python/cm/checker.py b/python/cm/checker.py index d6e6bdf9a8..bccafbbe29 100644 --- a/python/cm/checker.py +++ b/python/cm/checker.py @@ -10,12 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. from typing import Callable +import contextlib import ruyaml -# pylint: disable=W0212 - - MATCH_DICT_RESERVED_DIRECTIVES = ("invisible_items",) @@ -44,14 +42,10 @@ def round_trip_load(stream, version=None, preserve_quotes=None, allow_duplicate_ return loader._constructor.get_single_data() finally: loader._parser.dispose() - try: + with contextlib.suppress(AttributeError): loader._reader.reset_reader() - except AttributeError: - pass - try: + with contextlib.suppress(AttributeError): loader._scanner.reset_scanner() - except AttributeError: - pass class FormatError(Exception): @@ -104,7 +98,7 @@ def match_none(data, rules, rule, path, parent=None): raise FormatError(path, msg, data, rule, parent) -def match_any(data, rules, rule, path, parent=None): # pylint: disable=unused-argument +def match_any(data, rules, rule, path, parent=None): # noqa: ARG001 pass diff --git a/python/cm/daemon.py b/python/cm/daemon.py index 17f83fc661..82943d72e6 100644 --- a/python/cm/daemon.py +++ b/python/cm/daemon.py @@ -10,11 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import atexit +from signal import SIGTERM import os import sys import time -from signal import SIGTERM +import atexit from django.conf import settings @@ -64,7 +64,7 @@ def daemonize(self): sys.exit(1) try: - pidfile = open(self.pidfile, "w+", encoding=settings.ENCODING_UTF_8) # pylint: disable=consider-using-with + pidfile = open(self.pidfile, "w+", encoding=settings.ENCODING_UTF_8) # noqa: SIM115 except OSError as e: sys.stderr.write(f"Can't open pid file {self.pidfile}\n") sys.stderr.write(f"{e.strerror}\n") @@ -72,9 +72,9 @@ def daemonize(self): sys.stdout.flush() sys.stderr.flush() - stdin_file = open(self.stdin, encoding=settings.ENCODING_UTF_8) # pylint: disable=consider-using-with - stdout_file = open(self.stdout, "a+", encoding=settings.ENCODING_UTF_8) # pylint: disable=consider-using-with - stderr_file = open(self.stderr, "w+", encoding=settings.ENCODING_UTF_8) # pylint: disable=consider-using-with + stdin_file = open(self.stdin, encoding=settings.ENCODING_UTF_8) # noqa: SIM115 + stdout_file = open(self.stdout, "a+", encoding=settings.ENCODING_UTF_8) # noqa: SIM115 + stderr_file = open(self.stderr, "w+", encoding=settings.ENCODING_UTF_8) # noqa: SIM115 os.dup2(stdin_file.fileno(), sys.stdin.fileno()) os.dup2(stdout_file.fileno(), sys.stdout.fileno()) os.dup2(stderr_file.fileno(), sys.stderr.fileno()) @@ -88,7 +88,7 @@ def delpid(self): def getpid(self): try: - file_handler = open(self.pidfile, encoding=settings.ENCODING_UTF_8) # pylint: disable=consider-using-with + file_handler = open(self.pidfile, encoding=settings.ENCODING_UTF_8) # noqa: SIM115 try: pid = int(file_handler.read().strip()) except ValueError: @@ -102,9 +102,7 @@ def getpid(self): def checkpid(self): pid = self.getpid() - if pid is None: - return False - elif pid == 0: + if pid is None or pid == 0: return False try: diff --git a/python/cm/data_containers.py b/python/cm/data_containers.py index 97a5641d80..0ad6c84e59 100644 --- a/python/cm/data_containers.py +++ b/python/cm/data_containers.py @@ -12,7 +12,7 @@ from typing import Any, Optional -from pydantic import BaseModel # pylint: disable=no-name-in-module +from pydantic import BaseModel class DBModel(BaseModel): diff --git a/python/cm/errors.py b/python/cm/errors.py index d539f1b70f..7fc0fdef89 100644 --- a/python/cm/errors.py +++ b/python/cm/errors.py @@ -10,7 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from cm.logger import logger from django.conf import settings from django.db.utils import OperationalError from rest_framework.exceptions import APIException, ValidationError @@ -26,6 +25,8 @@ ) from rest_framework.views import exception_handler +from cm.logger import logger + WARN = "warning" ERR = "error" CRIT = "critical" diff --git a/python/cm/flag.py b/python/cm/flag.py index 364dc47434..3965f8197f 100644 --- a/python/cm/flag.py +++ b/python/cm/flag.py @@ -35,7 +35,7 @@ def create_flag(obj: ADCMEntity, msg: str = "") -> ConcernItem: if msg: reason["message"] = f"{reason['message']}: {msg}" - flag = ConcernItem.objects.create( + return ConcernItem.objects.create( type=ConcernType.FLAG, name=get_flag_name(obj, msg), reason=reason, @@ -43,7 +43,6 @@ def create_flag(obj: ADCMEntity, msg: str = "") -> ConcernItem: cause=ConcernCause.CONFIG, blocking=False, ) - return flag def remove_flag(obj: ADCMEntity, msg: str = "") -> None: diff --git a/python/cm/hierarchy.py b/python/cm/hierarchy.py index 90562cd6e0..e21503025d 100644 --- a/python/cm/hierarchy.py +++ b/python/cm/hierarchy.py @@ -121,11 +121,10 @@ def _make_node(self, obj: ADCMEntity) -> Node: cached = self._nodes.get(Node.get_obj_key(obj)) if cached: return cached - else: - node = Node(value=obj) - self._nodes[node.key] = node + node = Node(value=obj) + self._nodes[node.key] = node - return node + return node def _build_tree_down(self, node: Node) -> None: children_values = [] @@ -165,15 +164,9 @@ def _build_tree_up(self, node: Node) -> None: if node.type == "cluster": parent_values = [None] elif node.type == "service": - if node.value.maintenance_mode == MaintenanceMode.OFF: - parent_values = [node.value.cluster] - else: - parent_values = [] + parent_values = [node.value.cluster] if node.value.maintenance_mode == MaintenanceMode.OFF else [] elif node.type == "component": - if node.value.maintenance_mode == MaintenanceMode.OFF: - parent_values = [node.value.service] - else: - parent_values = [] + parent_values = [node.value.service] if node.value.maintenance_mode == MaintenanceMode.OFF else [] elif node.type == "host": parent_values = [ hc.component @@ -198,8 +191,7 @@ def get_node(self, obj: ADCMEntity) -> Node: cached = self._nodes.get(key) if cached: return cached - else: - raise HierarchyError(f"Object {key} is not part of tree") + raise HierarchyError(f"Object {key} is not part of tree") def get_directly_affected(self, node: Node) -> set[Node]: """Collect directly affected nodes for issues re-calc""" diff --git a/python/cm/inventory.py b/python/cm/inventory.py index c6dd08b24e..ac2a6681ec 100644 --- a/python/cm/inventory.py +++ b/python/cm/inventory.py @@ -10,9 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json from itertools import chain from typing import Iterable +import json + +from django.conf import settings +from django.contrib.contenttypes.models import ContentType from cm.adcm_config.config import get_prototype_config, process_config from cm.logger import logger @@ -38,8 +41,6 @@ get_default_before_upgrade, get_object_cluster, ) -from django.conf import settings -from django.contrib.contenttypes.models import ContentType class HcAclAction: @@ -61,10 +62,7 @@ def fix_fields_for_inventory(prototype_configs: Iterable[PrototypeConfig], confi name = prototype_config.name sub_name = prototype_config.subname - if prototype_config.type == "map": - fix_value = {} - else: - fix_value = [] + fix_value = {} if prototype_config.type == "map" else [] if sub_name and name in config and sub_name in config[name]: if config[name][sub_name] is None: @@ -82,10 +80,7 @@ def process_config_and_attr( flat_spec: dict | None = None, ) -> dict: if not spec: - if isinstance(obj, GroupConfig): - prototype = obj.object.prototype - else: - prototype = obj.prototype + prototype = obj.object.prototype if isinstance(obj, GroupConfig) else obj.prototype spec, flat_spec, _, _ = get_prototype_config(prototype=prototype) @@ -121,27 +116,21 @@ def get_prototype_imports(obj: Cluster | ClusterObject, imports: dict) -> dict: return imports -def get_import(cluster: Cluster) -> dict: # pylint: disable=too-many-branches +def get_import(cluster: Cluster) -> dict: imports = {} for obj in chain([cluster], ClusterObject.objects.filter(cluster=cluster)): imports = get_prototype_imports(obj=obj, imports=imports) first = True for bind in ClusterBind.objects.filter(cluster=cluster): - if bind.source_service: - obj = bind.source_service - else: - obj = bind.source_cluster + obj = bind.source_service if bind.source_service else bind.source_cluster conf_ref = obj.config export_proto = obj.prototype config_log = ConfigLog.objects.get(obj_ref=conf_ref, id=conf_ref.current) conf = process_config_and_attr(obj=obj, conf=config_log.config, attr=config_log.attr) - if bind.service: - proto = bind.service.prototype - else: - proto = bind.cluster.prototype + proto = bind.service.prototype if bind.service else bind.cluster.prototype actual_import = PrototypeImport.objects.get(prototype=proto, name=obj.prototype.name) @@ -369,7 +358,7 @@ def get_provider_config(provider_id: int) -> dict: return {"provider": get_provider_variables(provider=provider)} -def get_host_groups( # pylint: disable=too-many-branches +def get_host_groups( cluster: Cluster, delta: dict | None = None, action_host: Host | None = None, @@ -475,26 +464,23 @@ def get_provider_hosts(provider: HostProvider, action_host: list[Host] | None = def get_host(host_id: int) -> dict: host = Host.objects.get(id=host_id) - groups = { + return { "HOST": { "hosts": get_hosts(host_list=[host], obj=host), "vars": get_provider_config(provider_id=host.provider.id), } } - return groups def get_target_host(host_id: int) -> dict: host = Host.objects.get(id=host_id) - groups = { + return { "target": { "hosts": get_hosts(host_list=[host], obj=host, include_mm_hosts=True), "vars": get_cluster_config(cluster=host.cluster), } } - return groups - def get_inventory_data( obj: ADCMEntity, @@ -540,9 +526,7 @@ def prepare_job_inventory( logger.info("prepare inventory for job #%s, object: %s", job_id, obj) with open( - file=settings.RUN_DIR / f"{job_id}/inventory.json", - mode="w", - encoding=settings.ENCODING_UTF_8, + settings.RUN_DIR / f"{job_id}/inventory.json", mode="w", encoding=settings.ENCODING_UTF_8 ) as file_descriptor: inventory_data = get_inventory_data(obj=obj, action=action, action_host=action_host, delta=delta) json.dump(obj=inventory_data, fp=file_descriptor, separators=(",", ":")) diff --git a/python/cm/issue.py b/python/cm/issue.py index f2abf50250..163bf937c5 100755 --- a/python/cm/issue.py +++ b/python/cm/issue.py @@ -13,6 +13,9 @@ from typing import Iterable from api_v2.concern.serializers import ConcernSerializer +from django.db.transaction import on_commit +from djangorestframework_camel_case.util import camelize + from cm.adcm_config.config import get_prototype_config from cm.adcm_config.utils import proto_ref from cm.data_containers import PrototypeData @@ -42,23 +45,19 @@ ) from cm.status_api import send_concern_creation_event, send_concern_delete_event from cm.utils import obj_ref -from django.db.transaction import on_commit -from djangorestframework_camel_case.util import camelize -def check_config(obj: ADCMEntity) -> bool: # pylint: disable=too-many-branches +def check_config(obj: ADCMEntity) -> bool: spec, _, _, _ = get_prototype_config(prototype=obj.prototype) conf, attr = get_obj_config(obj=obj) - for key, value in spec.items(): # pylint: disable=too-many-nested-blocks + for key, value in spec.items(): if "required" in value: - if value["required"]: - if key in conf and conf[key] is None: - logger.debug("required config key %s of %s is missing", key, obj_ref(obj=obj)) - return False + if value["required"] and key in conf and conf[key] is None: + logger.debug("required config key %s of %s is missing", key, obj_ref(obj=obj)) + return False else: - if key in attr: - if "active" in attr[key] and not attr[key]["active"]: - continue + if key in attr and "active" in attr[key] and not attr[key]["active"]: + continue for subkey in value: if value[subkey]["required"]: if key not in conf: @@ -214,7 +213,7 @@ def check_hc_requires(shc_list: list[tuple[ClusterObject, Host, ServiceComponent continue if not any( - { + { # noqa: C419 (shc[0].prototype.name == require["service"] and shc[2].prototype.name == req_comp) for shc in shc_list } @@ -418,14 +417,13 @@ def _create_concern_item(obj: ADCMEntity, issue_cause: ConcernCause) -> ConcernI kwargs = get_kwargs_for_issue(msg_name=msg_name, source=obj) reason = MessageTemplate.get_message_from_template(name=msg_name.value, **kwargs) issue_name = _gen_issue_name(obj=obj, cause=issue_cause) - issue = ConcernItem.objects.create( + return ConcernItem.objects.create( type=ConcernType.ISSUE, name=issue_name, reason=reason, owner=obj, cause=issue_cause, ) - return issue def create_issue(obj: ADCMEntity, issue_cause: ConcernCause) -> None: diff --git a/python/cm/job.py b/python/cm/job.py index 7d75c3d2bf..fcac6ac3e8 100644 --- a/python/cm/job.py +++ b/python/cm/job.py @@ -10,15 +10,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -import copy -import json -import subprocess from collections.abc import Hashable from configparser import ConfigParser from dataclasses import dataclass, field from functools import partial from pathlib import Path from typing import Any, Literal +import copy +import json +import subprocess from audit.cases.common import get_or_create_audit_obj from audit.cef_logger import cef_logger @@ -28,6 +28,12 @@ AuditLogOperationResult, AuditLogOperationType, ) +from django.conf import settings +from django.db.models import JSONField +from django.db.transaction import atomic, on_commit +from django.utils import timezone +from rbac.roles import re_apply_policy_for_jobs + from cm.adcm_config.checks import check_attr from cm.adcm_config.config import ( check_config_spec, @@ -93,11 +99,6 @@ ) from cm.utils import get_env_with_venv_path from cm.variant import process_variant -from django.conf import settings -from django.db.models import JSONField -from django.db.transaction import atomic, on_commit -from django.utils import timezone -from rbac.roles import re_apply_policy_for_jobs @dataclass @@ -119,10 +120,7 @@ def run_action( if hosts: check_action_hosts(action=action, obj=obj, cluster=cluster, hosts=hosts) - if action.host_action: - action_target = get_host_object(action=action, cluster=cluster) - else: - action_target = obj + action_target = get_host_object(action=action, cluster=cluster) if action.host_action else obj object_locks = action_target.concerns.filter(type=ConcernType.LOCK) @@ -261,9 +259,8 @@ def check_action_hc( action: Action, ) -> bool: for item in action_hc: - if item["service"] == service and item["component"] == component: - if item["action"] == action: - return True + if item["service"] == service and item["component"] == component and item["action"] == action: + return True return False @@ -272,7 +269,7 @@ def cook_comp_key(name, subname): return f"{name}.{subname}" -def cook_delta( # pylint: disable=too-many-branches +def cook_delta( cluster: Cluster, new_hc: list[tuple[ClusterObject, Host, ServiceComponent]], action_hc: list[dict], @@ -427,8 +424,7 @@ def check_upgrade_hc(action, new_hc): def check_service_task(cluster_id: int, action: Action) -> ClusterObject | None: cluster = Cluster.obj.get(id=cluster_id) try: - service = ClusterObject.objects.get(cluster=cluster, prototype=action.prototype) - return service + return ClusterObject.objects.get(cluster=cluster, prototype=action.prototype) # noqa: TRY300 except ClusterObject.DoesNotExist: msg = f"service #{action.prototype.pk} for action " f'"{action.name}" is not installed in cluster #{cluster.pk}' raise_adcm_ex("CLUSTER_SERVICE_NOT_FOUND", msg) @@ -582,8 +578,6 @@ def prepare_job_config( conf: dict | JSONField | None, verbose: bool, ) -> dict: - # pylint: disable=too-many-branches,too-many-statements - job_conf = { "adcm": {"config": get_adcm_config()}, "context": prepare_context(action, obj), @@ -825,10 +819,7 @@ def audit_task( object_name=object_.name, object_type=obj_type, ) - if status == "success": - operation_result = AuditLogOperationResult.SUCCESS - else: - operation_result = AuditLogOperationResult.FAIL + operation_result = AuditLogOperationResult.SUCCESS if status == "success" else AuditLogOperationResult.FAIL audit_log = AuditLog.objects.create( audit_object=audit_object, @@ -882,13 +873,13 @@ def finish_task(task: TaskLog, job: JobLog | None, status: str) -> None: try: load_mm_objects() - except Exception as error: # pylint: disable=broad-except + except Exception as error: # noqa: BLE001 logger.warning("Error loading mm objects on task finish") logger.exception(error) def run_task(task: TaskLog, args: str = ""): - err_file = open( # pylint: disable=consider-using-with + err_file = open( # noqa: SIM115 Path(settings.LOG_DIR, "task_runner.err"), "a+", encoding=settings.ENCODING_UTF_8, @@ -899,7 +890,7 @@ def run_task(task: TaskLog, args: str = ""): args, ] logger.info("task run cmd: %s", " ".join(cmd)) - proc = subprocess.Popen( # pylint: disable=consider-using-with + proc = subprocess.Popen( # noqa: SIM115 args=cmd, stderr=err_file, env=get_env_with_venv_path(venv=task.action.venv) ) logger.info("task run #%s, python process %s", task.pk, proc.pid) @@ -929,10 +920,8 @@ def prepare_ansible_config(job_id: int, action: Action, sub_action: SubAction): if "jinja2_native" in params: config_parser["defaults"]["jinja2_native"] = str(params["jinja2_native"]) - with open( - Path(settings.RUN_DIR, f"{job_id}", "ansible.cfg"), - "w", - encoding=settings.ENCODING_UTF_8, + with Path(settings.RUN_DIR, f"{job_id}", "ansible.cfg").open( + mode="w", encoding=settings.ENCODING_UTF_8 ) as config_file: config_parser.write(config_file) @@ -977,5 +966,4 @@ def getattr_first(attr: str, *objects: Any, default: Any = None) -> Any: return result if default is not None: return default - else: - return result # it could any falsy value from objects + return result # it could any falsy value from objects diff --git a/python/cm/management/commands/collect_statistics.py b/python/cm/management/commands/collect_statistics.py index ebc4212c90..52d8e51650 100644 --- a/python/cm/management/commands/collect_statistics.py +++ b/python/cm/management/commands/collect_statistics.py @@ -10,8 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json -import os from dataclasses import asdict, dataclass from datetime import datetime as dt from hashlib import md5 @@ -23,17 +21,20 @@ from time import sleep, time from typing import NamedTuple from urllib.parse import urlunparse +import os +import json -import requests from audit.models import AuditLogOperationResult from audit.utils import make_audit_log -from cm.adcm_config.config import get_adcm_config -from cm.models import ADCM, Bundle, Cluster, HostComponent, HostProvider from django.conf import settings as adcm_settings from django.core.management.base import BaseCommand from django.db.models import Count, Prefetch, QuerySet from rbac.models import Policy, Role, User from rest_framework.status import HTTP_201_CREATED, HTTP_405_METHOD_NOT_ALLOWED +import requests + +from cm.adcm_config.config import get_adcm_config +from cm.models import ADCM, Bundle, Cluster, HostComponent, HostProvider @dataclass @@ -100,10 +101,8 @@ class RetryError(Exception): logger = getLogger("background_tasks") -class StatisticsSettings: # pylint: disable=too-many-instance-attributes +class StatisticsSettings: def __init__(self): - # pylint: disable=invalid-envvar-default - adcm_uuid = str(ADCM.objects.get().uuid) self.enabled = self._get_enabled() @@ -119,7 +118,7 @@ def __init__(self): self.adcm_uuid = adcm_uuid self.date_format = "%Y-%m-%d %H:%M:%S" - self.data_name = f"{dt.now().date().strftime('%Y_%m_%d')}_statistics" + self.data_name = f"{dt.now().date().strftime('%Y_%m_%d')}_statistics" # noqa: DTZ005 @staticmethod def _get_enabled() -> bool: @@ -152,18 +151,16 @@ def __init__(self, *args, **kwargs): self.settings = StatisticsSettings() super().__init__(*args, **kwargs) - def handle(self, *args, **options): - # pylint: disable=attribute-defined-outside-init + def handle(self, *args, **options): # noqa: ARG002 try: self.tmp_dir = Path(mkdtemp()).absolute() self.main() - except Exception: # pylint: disable=broad-exception-caught + except Exception: # noqa: BLE001ion-caught self.log(msg="Unexpected error during statistics collection", method="exception") finally: rmtree(path=self.tmp_dir) def main(self): - # pylint: disable=attribute-defined-outside-init if not self.settings.enabled: self.log(msg="disabled") return @@ -321,7 +318,7 @@ def _get_hostcomponent_data(cluster: Cluster) -> list[dict]: out_data.append( asdict( HostComponentData( - host_name=md5( + host_name=md5( # noqa: S324 hostcomponent.host.name.encode(encoding=adcm_settings.ENCODING_UTF_8) ).hexdigest(), component_name=hostcomponent.component.name, diff --git a/python/cm/management/commands/dumpcluster.py b/python/cm/management/commands/dumpcluster.py index 86c1f0c259..8c428f613b 100644 --- a/python/cm/management/commands/dumpcluster.py +++ b/python/cm/management/commands/dumpcluster.py @@ -10,12 +10,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-locals - +from pathlib import Path +import sys +import json import base64 import getpass -import json -import sys + +from cryptography.fernet import Fernet +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC +from django.conf import settings +from django.core.management.base import BaseCommand from cm.models import ( Bundle, @@ -30,12 +36,6 @@ Prototype, ServiceComponent, ) -from cryptography.fernet import Fernet -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC -from django.conf import settings -from django.core.management.base import BaseCommand def serialize_datetime_fields(obj, fields=None): @@ -89,8 +89,7 @@ def get_bundle(prototype_id): """ fields = ("name", "version", "edition", "hash", "description") prototype = Prototype.objects.get(id=prototype_id) - bundle = get_object(Bundle, prototype.bundle_id, fields) - return bundle + return get_object(Bundle, prototype.bundle_id, fields) def get_bundle_hash(prototype_id): @@ -292,8 +291,7 @@ def get_host_component(host_component_id): "component", "state", ) - host_component = get_object(HostComponent, host_component_id, fields) - return host_component + return get_object(HostComponent, host_component_id, fields) def encrypt_data(pass_from_user, result): @@ -307,8 +305,7 @@ def encrypt_data(pass_from_user, result): ) key = base64.urlsafe_b64encode(kdf.derive(password)) f = Fernet(key) - encrypted = f.encrypt(result) - return encrypted + return f.encrypt(result) def dump(cluster_id, output): @@ -380,7 +377,7 @@ def dump(cluster_id, output): encrypted = encrypt_data(password, result) if output is not None: - with open(output, "wb") as f: + with Path(output).open(mode="wb") as f: f.write(encrypted) sys.stdout.write(f"Dump successfully done to file {output}\n") else: @@ -412,7 +409,7 @@ def add_arguments(self, parser): ) parser.add_argument("-o", "--output", help="Specifies file to which the output is written.") - def handle(self, *args, **options): + def handle(self, *args, **options): # noqa: ARG002 """Handler method""" cluster_id = options["cluster_id"] output = options["output"] diff --git a/python/cm/management/commands/loadcluster.py b/python/cm/management/commands/loadcluster.py index a219eb2506..a840354373 100644 --- a/python/cm/management/commands/loadcluster.py +++ b/python/cm/management/commands/loadcluster.py @@ -10,15 +10,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-locals, global-statement - +from datetime import datetime +from pathlib import Path +import sys +import json import base64 import getpass -import json -import sys -from datetime import datetime from ansible.parsing.vault import VaultAES256, VaultSecret +from cryptography.fernet import Fernet, InvalidToken +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC +from django.conf import settings +from django.contrib.contenttypes.models import ContentType +from django.core.management.base import BaseCommand +from django.db.transaction import atomic +from django.db.utils import IntegrityError + from cm.adcm_config.config import save_file_type from cm.errors import AdcmEx from cm.models import ( @@ -35,15 +44,6 @@ PrototypeConfig, ServiceComponent, ) -from cryptography.fernet import Fernet, InvalidToken -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC -from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from django.core.management.base import BaseCommand -from django.db.transaction import atomic -from django.db.utils import IntegrityError OLD_ADCM_PASSWORD = None @@ -71,8 +71,7 @@ def get_prototype(**kwargs): :rtype: models.Prototype """ bundle = Bundle.objects.get(hash=kwargs.pop("bundle_hash")) - prototype = Prototype.objects.get(bundle=bundle, **kwargs) - return prototype + return Prototype.objects.get(bundle=bundle, **kwargs) def create_config(config, prototype=None): @@ -104,8 +103,7 @@ def create_config(config, prototype=None): conf.previous = previous_id conf.save() return conf - else: - return None + return None def create_group(group, ex_hosts_list, obj): @@ -210,7 +208,7 @@ def create_provider(provider): same_name_provider = HostProvider.objects.get(name=provider["name"]) if same_name_provider.prototype.bundle.hash != bundle_hash: raise IntegrityError("Name of provider already in use in another bundle") - create_file_from_config(same_name_provider, provider["config"]) + create_file_from_config(same_name_provider, provider["config"]) # noqa: TRY300 return ex_id, same_name_provider except HostProvider.DoesNotExist: prototype = get_prototype(bundle_hash=bundle_hash, type="provider") @@ -335,14 +333,13 @@ def create_host_component(host_component, cluster, host, service, component): :rtype: models.HostComponent """ host_component.pop("cluster") - host_component = HostComponent.objects.create( + return HostComponent.objects.create( cluster=cluster, host=host, service=service, component=component, **host_component, ) - return host_component def check(data): @@ -352,7 +349,7 @@ def check(data): :param data: Data from file :type data: dict """ - if settings.ADCM_VERSION != data["ADCM_VERSION"]: + if data["ADCM_VERSION"] != settings.ADCM_VERSION: raise AdcmEx( "DUMP_LOAD_ADCM_VERSION_ERROR", msg=( @@ -381,9 +378,7 @@ def decrypt_file(pass_from_user, file): backend=default_backend(), ) key = base64.urlsafe_b64encode(kdf.derive(password)) - f = Fernet(key) - decrypted = f.decrypt(file.encode()) - return decrypted + return Fernet(key).decrypt(file.encode()) def set_old_password(password): @@ -401,7 +396,7 @@ def load(file_path): """ try: password = getpass.getpass() - with open(file_path, encoding=settings.ENCODING_UTF_8) as f: + with Path(file_path).open(encoding=settings.ENCODING_UTF_8) as f: encrypted = f.read() decrypted = decrypt_file(password, encrypted) data = json.loads(decrypted.decode(settings.ENCODING_UTF_8)) @@ -473,7 +468,7 @@ def add_arguments(self, parser): """Parsing command line arguments""" parser.add_argument("file_path", nargs="?") - def handle(self, *args, **options): + def handle(self, *args, **options): # noqa: ARG002 """Handler method""" file_path = options.get("file_path") load(file_path) diff --git a/python/cm/management/commands/logrotate.py b/python/cm/management/commands/logrotate.py index 1c67ea64ca..40f4129078 100644 --- a/python/cm/management/commands/logrotate.py +++ b/python/cm/management/commands/logrotate.py @@ -9,15 +9,21 @@ # 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 logging -import os -import shutil from datetime import datetime, timedelta from enum import Enum +from pathlib import Path from subprocess import STDOUT, CalledProcessError, check_output +import os +import shutil +import logging from audit.models import AuditLogOperationResult from audit.utils import make_audit_log +from django.conf import settings +from django.core.management.base import BaseCommand +from django.db import transaction +from django.utils import timezone + from cm.models import ( ADCM, Cluster, @@ -31,10 +37,6 @@ ServiceComponent, TaskLog, ) -from django.conf import settings -from django.core.management.base import BaseCommand -from django.db import transaction -from django.utils import timezone logger = logging.getLogger("background_tasks") @@ -79,7 +81,7 @@ def add_arguments(self, parser): ) parser.add_argument("--disable_logs", action="store_true", help="Disable logging") - def handle(self, *args, **options): + def handle(self, *args, **options): # noqa: ARG002 __target_method_map = { TargetType.ALL.value: [ self.__run_nginx_log_rotation, @@ -91,7 +93,6 @@ def handle(self, *args, **options): TargetType.NGINX.value: [self.__run_nginx_log_rotation], } - # pylint: disable=attribute-defined-outside-init self.verbose = not options["disable_logs"] target = options["target"] self.config = self.__get_logrotate_config() @@ -102,7 +103,7 @@ def handle(self, *args, **options): def __execute_cmd(self, cmd): self.__log(f"executing cmd: `{cmd}`", "info") try: - out = check_output(cmd, shell=True, stderr=STDOUT) + out = check_output(cmd, shell=True, stderr=STDOUT) # noqa: S602 out = out.decode(settings.ENCODING_UTF_8).strip("\n") if out: self.__log(out, "debug") @@ -131,7 +132,7 @@ def __generate_logrotate_conf_file(self): "no_compress": "" if self.config["logrotate"]["nginx"]["compress"] else "#", "num_rotations": self.config["logrotate"]["nginx"]["max_history"], } - with open(self.__nginx_logrotate_conf, "w", encoding=settings.ENCODING_UTF_8) as conf_file: + with Path(self.__nginx_logrotate_conf).open("w", encoding=settings.ENCODING_UTF_8) as conf_file: conf_file.write(LOGROTATE_CONF_FILE_TEMPLATE.format(**conf_file_args)) self.__log(f"conf file `{self.__nginx_logrotate_conf}` generated", "debug") @@ -186,7 +187,7 @@ def __run_configlog_rotation(self): "info", ) - except Exception as e: # pylint: disable=broad-except + except Exception as e: # noqa: BLE001 make_audit_log("config", AuditLogOperationResult.FAIL, "completed") self.__log("Error in ConfigLog rotation", "warning") self.__log(e, "exception") @@ -211,7 +212,7 @@ def __has_related_records(obj_conf: ObjectConfig) -> bool: return False def __run_joblog_rotation(self): - try: # pylint: disable=too-many-nested-blocks + try: days_delta_db = self.config["config"]["log_rotation_in_db"] days_delta_fs = self.config["config"]["log_rotation_on_fs"] if days_delta_db <= 0 and days_delta_fs <= 0: @@ -243,20 +244,20 @@ def __run_joblog_rotation(self): if not name.startswith("."): # a line of code is used for development path = settings.RUN_DIR / name try: - m_time = datetime.fromtimestamp(os.path.getmtime(path), tz=timezone.get_current_timezone()) + m_time = datetime.fromtimestamp(os.path.getmtime(path), tz=timezone.get_current_timezone()) # noqa: PTH204 if timezone.now() - m_time > timedelta(days=days_delta_fs): is_deleted = True - if os.path.isdir(path): + if os.path.isdir(path): # noqa: PTH112 shutil.rmtree(path) else: - os.remove(path) + os.remove(path) # noqa: PTH107 except FileNotFoundError: pass if is_deleted: make_audit_log("task", AuditLogOperationResult.SUCCESS, "launched") make_audit_log("task", AuditLogOperationResult.SUCCESS, "completed") self.__log("fs JobLog rotated", "info") - except Exception as e: # pylint: disable=broad-except + except Exception as e: # noqa: BLE001 make_audit_log("task", AuditLogOperationResult.FAIL, "completed") self.__log("Error in JobLog rotation", "warning") self.__log(e, "exception") diff --git a/python/cm/management/commands/run_ldap_sync.py b/python/cm/management/commands/run_ldap_sync.py index b711fb8f7d..3b1b18fa5d 100644 --- a/python/cm/management/commands/run_ldap_sync.py +++ b/python/cm/management/commands/run_ldap_sync.py @@ -10,16 +10,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging from datetime import timedelta +import logging from audit.models import AuditLogOperationResult from audit.utils import make_audit_log -from cm.job import ActionRunPayload, run_action -from cm.models import ADCM, Action, ConfigLog, JobStatus, TaskLog from django.core.management.base import BaseCommand from django.utils import timezone +from cm.job import ActionRunPayload, run_action +from cm.models import ADCM, Action, ConfigLog, JobStatus, TaskLog + logger = logging.getLogger("background_tasks") @@ -34,7 +35,7 @@ def get_settings(adcm_object): class Command(BaseCommand): help = "Run synchronization with ldap if sync_interval is specified in ADCM settings" - def handle(self, *args, **options): + def handle(self, *args, **options): # noqa: ARG002 adcm_object = ADCM.objects.first() action = Action.objects.get(name="run_ldap_sync", prototype=adcm_object.prototype) period = get_settings(adcm_object) diff --git a/python/cm/migrations/0067_tasklog_object_type.py b/python/cm/migrations/0067_tasklog_object_type.py index 1f303a3f0b..4d4fc25b28 100644 --- a/python/cm/migrations/0067_tasklog_object_type.py +++ b/python/cm/migrations/0067_tasklog_object_type.py @@ -15,6 +15,8 @@ import django.db.models.deletion from django.db import migrations, models +from adcm.utils import OBJECT_TYPES_DICT + def fix_tasklog(apps, schema_editor): TaskLog = apps.get_model("cm", "TaskLog") @@ -29,16 +31,8 @@ def fix_tasklog(apps, schema_editor): cash = {} def get_content(context): - content = { - "component": "servicecomponent", - "service": "clusterobject", - "host": "host", - "provider": "hostprovider", - "cluster": "cluster", - "adcm": "adcm", - } if context not in cash: - cash[context] = ContentType.objects.get(app_label="cm", model=content[context]) + cash[context] = ContentType.objects.get(app_label="cm", model=OBJECT_TYPES_DICT[context]) return cash[context] def get_task_obj(action, obj_id): diff --git a/python/cm/migrations/0106_set_nginx_rotate_config_to_defaults.py b/python/cm/migrations/0106_set_nginx_rotate_config_to_defaults.py index 4b2b45c06b..18bf335c89 100644 --- a/python/cm/migrations/0106_set_nginx_rotate_config_to_defaults.py +++ b/python/cm/migrations/0106_set_nginx_rotate_config_to_defaults.py @@ -18,7 +18,7 @@ def migrate_nginx_logrotate_config(apps, schema_editor) -> None: adcm_model = apps.get_model("cm", "ADCM") config_log_model = apps.get_model("cm", "ConfigLog") - prototype_config_model = apps.get_model("cm", "PrototypeConfig") + prototype_config_model = apps.get_model("cm", "PrototypeConfig") # noqa: F841 logrotate_conf_field_name = "logrotate" try: diff --git a/python/cm/models.py b/python/cm/models.py index 375d57bd69..8c760e22ca 100644 --- a/python/cm/models.py +++ b/python/cm/models.py @@ -10,24 +10,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-lines,unsupported-membership-test,unsupported-delete-operation, -# too-many-instance-attributes -# pylint could not understand that JSON fields are dicts - - -import os.path -import signal -import time from collections.abc import Iterable, Mapping from copy import deepcopy from enum import Enum from itertools import chain from typing import Optional, TypeAlias from uuid import uuid4 +import time +import signal +import os.path -from cm.adcm_config.ansible import ansible_decrypt -from cm.errors import AdcmEx -from cm.logger import logger from django.conf import settings from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType @@ -36,6 +28,10 @@ from django.db.models.signals import post_delete from django.dispatch import receiver +from cm.adcm_config.ansible import ansible_decrypt +from cm.errors import AdcmEx +from cm.logger import logger + def validate_line_break_character(value: str) -> None: """Check line break character in CharField""" @@ -149,7 +145,6 @@ def from_db(cls, db, field_names, values): instance._state.adding = False instance._state.db = db # customization to store the original field values on the instance - # pylint: disable=attribute-defined-outside-init instance._loaded_values = dict(zip(field_names, values)) return instance @@ -282,8 +277,7 @@ def object(self): ] for object_type in object_types: if hasattr(self, object_type): - obj = getattr(self, object_type) - return obj + return getattr(self, object_type) return None @@ -323,11 +317,7 @@ def get_own_issue(self, cause: "ConcernCause") -> Optional["ConcernItem"]: ).first() def requires_service_name(self, service_name: str) -> bool: - for item in self.requires: - if item.get("service") == service_name: - return True - - return False + return any(item.get("service") == service_name for item in self.requires) def __str__(self): own_name = getattr(self, "name", None) @@ -418,12 +408,7 @@ def allowed(self, obj: ADCMEntity) -> bool: if self.state_available: available = self.state_available - if obj.state in available: - return True - elif available == "any": - return True - else: - return False + return obj.state in available or available == "any" else: if self.action: return self.action.allowed(obj=obj) @@ -774,7 +759,7 @@ class Meta: @receiver(post_delete, sender=ServiceComponent) -def auto_delete_config_with_servicecomponent(sender, instance, **kwargs): # pylint: disable=unused-argument +def auto_delete_config_with_servicecomponent(sender, instance, **kwargs): # noqa: ARG001 if instance.config is not None: instance.config.delete() @@ -907,9 +892,7 @@ def get_config_attr(self): """Return attr for group config without group_keys and custom_group_keys params""" config_log = ConfigLog.obj.get(id=self.config.current) - attr = {k: v for k, v in config_log.attr.items() if k not in ("group_keys", "custom_group_keys")} - - return attr + return {k: v for k, v in config_log.attr.items() if k not in ("group_keys", "custom_group_keys")} def get_config_and_attr(self): """Return merge object config with group config and merge attr""" @@ -975,28 +958,23 @@ def prepare_files_for_config(self, config=None): ) filepath = str(settings.FILE_DIR / filename) - if field.subname: - value = config[field.name][field.subname] - else: - value = config[field.name] + value = config[field.name][field.subname] if field.subname else config[field.name] if field.type == "secretfile": value = ansible_decrypt(msg=value) if value is not None: # See cm.adcm_config.py:313 - if field.name == "ansible_ssh_private_key_file": - if value != "": - if value[-1] == "-": - value += "\n" + if field.name == "ansible_ssh_private_key_file" and value != "" and value[-1] == "-": + value += "\n" - with open(filepath, "w", encoding=settings.ENCODING_UTF_8) as f: + with open(filepath, mode="w", encoding=settings.ENCODING_UTF_8) as f: f.write(value) - os.chmod(filepath, 0o0600) + os.chmod(filepath, 0o0600) # noqa: PTH101 else: - if os.path.exists(filename): - os.remove(filename) + if os.path.exists(filename): # noqa: PTH101, PTH110 + os.remove(filename) # noqa: PTH107 @transaction.atomic() def save(self, *args, **kwargs): @@ -1080,9 +1058,8 @@ def venv(self): Bundle developer could mark one action with exact venv he needs, or mark all actions on prototype. """ - if self._venv == "default": - if self.prototype is not None: - return self.prototype.venv + if self._venv == "default" and self.prototype is not None: + return self.prototype.venv return self._venv @venv.setter @@ -1117,12 +1094,11 @@ def prototype_type(self): def get_id_chain(self, target_ids: dict) -> dict: """Get action ID chain for front-end URL generation in message templates""" target_ids["action_id"] = self.pk - result = { + return { "type": f"{self.prototype.type}_action_run", "name": self.display_name or self.name, "params": target_ids, } - return result def allowed(self, obj: ADCMEntity) -> bool: """Check if action is allowed to be run on object""" @@ -1138,24 +1114,26 @@ def allowed(self, obj: ADCMEntity) -> bool: return False state_allowed = False - if self.state_available == "any": - state_allowed = True - elif isinstance(self.state_available, list) and obj.state in self.state_available: + if ( + self.state_available == "any" + or isinstance(self.state_available, list) + and obj.state in self.state_available + ): state_allowed = True multi_state_allowed = False - if self.multi_state_available == "any": - multi_state_allowed = True - elif isinstance(self.multi_state_available, list) and obj.has_multi_state_intersection( - self.multi_state_available, + if ( + self.multi_state_available == "any" + or isinstance(self.multi_state_available, list) + and obj.has_multi_state_intersection( + self.multi_state_available, + ) ): multi_state_allowed = True return state_allowed and multi_state_allowed def get_start_impossible_reason(self, obj: ADCMEntity) -> str | None: - # pylint: disable=too-many-branches, too-many-return-statements - if obj.prototype.type == "adcm": obj: ADCM @@ -1219,9 +1197,8 @@ def get_start_impossible_reason(self, obj: ADCMEntity) -> str | None: elif obj.prototype.type == "host": obj: Host - if not self.allow_in_maintenance_mode: - if obj.maintenance_mode == MaintenanceMode.ON: - return HOST_IN_MM + if not self.allow_in_maintenance_mode and obj.maintenance_mode == MaintenanceMode.ON: + return HOST_IN_MM return None diff --git a/python/cm/schemas.py b/python/cm/schemas.py index 926463aede..0e4e4e11ef 100644 --- a/python/cm/schemas.py +++ b/python/cm/schemas.py @@ -10,7 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from pydantic import BaseModel # pylint: disable=no-name-in-module +from pydantic import BaseModel class ComponentRequiresSchema(BaseModel): diff --git a/python/cm/services/cluster.py b/python/cm/services/cluster.py index fb02b2203d..7942df52b9 100644 --- a/python/cm/services/cluster.py +++ b/python/cm/services/cluster.py @@ -12,14 +12,15 @@ from typing import Collection, Iterable -from cm.api import load_service_map -from cm.models import Cluster, Host from core.cluster.operations import add_hosts_to_cluster from core.cluster.types import HostClusterPair from core.types import ClusterID, HostID from django.db.transaction import atomic from rbac.models import re_apply_object_policy +from cm.api import load_service_map +from cm.models import Cluster, Host + class HostClusterDB: __slots__ = () diff --git a/python/cm/signals.py b/python/cm/signals.py index 5dd15fa7c7..696a13dc0c 100644 --- a/python/cm/signals.py +++ b/python/cm/signals.py @@ -13,13 +13,14 @@ from functools import partial from audit.models import MODEL_TO_AUDIT_OBJECT_TYPE_MAP, AuditObject -from cm.models import Cluster, ConcernItem, Host -from cm.status_api import send_concern_delete_event from django.db.models.signals import pre_delete, pre_save from django.db.transaction import on_commit from django.dispatch import receiver from rbac.models import Group, Policy +from cm.models import Cluster, ConcernItem, Host +from cm.status_api import send_concern_delete_event + @receiver(signal=pre_save, sender=Cluster) @receiver(signal=pre_save, sender=Group) @@ -62,7 +63,7 @@ def rename_audit_object_host(sender, instance, **kwargs) -> None: @receiver(signal=pre_delete, sender=ConcernItem) -def send_delete_event(sender, instance, **kwargs): # pylint: disable=unused-argument +def send_delete_event(sender, instance, **kwargs): # noqa: ARG001 for object_ in instance.related_objects: on_commit( func=partial( diff --git a/python/cm/stack.py b/python/cm/stack.py index 3e1e181410..2d02ecce29 100644 --- a/python/cm/stack.py +++ b/python/cm/stack.py @@ -9,20 +9,33 @@ # 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. -# pylint: disable=line-too-long,too-many-statements, too-many-lines -import hashlib -import json -import os -import re -import warnings from copy import copy, deepcopy from pathlib import Path from typing import Any, List, Literal +import os +import re +import json +import hashlib +import warnings -import ruyaml -import yaml from adcm_version import compare_prototype_versions +from django.conf import settings +from django.db import IntegrityError +from jinja2 import Template +from jinja2.exceptions import TemplateError +from rest_framework import status +from rest_framework.exceptions import NotFound +from ruyaml.composer import ComposerError +from ruyaml.constructor import DuplicateKeyError +from ruyaml.error import ReusedAnchorWarning +from ruyaml.parser import ParserError as RuYamlParserError +from ruyaml.scanner import ScannerError as RuYamlScannerError +from yaml.parser import ParserError as YamlParserError +from yaml.scanner import ScannerError as YamlScannerError +import yaml +import ruyaml + from cm.adcm_config.checks import check_config_type from cm.adcm_config.config import read_bundle_file from cm.adcm_config.utils import proto_ref @@ -41,19 +54,6 @@ StageSubAction, StageUpgrade, ) -from django.conf import settings -from django.db import IntegrityError -from jinja2 import Template -from jinja2.exceptions import TemplateError -from rest_framework import status -from rest_framework.exceptions import NotFound -from ruyaml.composer import ComposerError -from ruyaml.constructor import DuplicateKeyError -from ruyaml.error import ReusedAnchorWarning -from ruyaml.parser import ParserError as RuYamlParserError -from ruyaml.scanner import ScannerError as RuYamlScannerError -from yaml.parser import ParserError as YamlParserError -from yaml.scanner import ScannerError as YamlScannerError ANY = "any" AVAILABLE = "available" @@ -193,10 +193,10 @@ def check_adcm_config(conf_file: Path) -> Any: warnings.simplefilter(action="error", category=ReusedAnchorWarning) schema_file = Path(settings.CODE_DIR, "cm", "adcm_schema.yaml") - with open(schema_file, encoding=settings.ENCODING_UTF_8) as f: + with Path(schema_file).open(encoding=settings.ENCODING_UTF_8) as f: rules = ruyaml.round_trip_load(f) try: - with open(conf_file, encoding=settings.ENCODING_UTF_8) as f: + with Path(conf_file).open(encoding=settings.ENCODING_UTF_8) as f: data = round_trip_load(f, version="1.1", allow_duplicate_keys=True) except (RuYamlParserError, RuYamlScannerError, NotImplementedError) as e: raise_adcm_ex(code="STACK_LOAD_ERROR", msg=f'YAML decode "{conf_file}" error: {e}') @@ -209,7 +209,7 @@ def check_adcm_config(conf_file: Path) -> Any: raise_adcm_ex(code="STACK_LOAD_ERROR", msg=f"YAML Composer error: {e}") try: check(data, rules) - return data + return data # noqa: TRY300 except FormatError as e: error_msgs = [] if e.errors: @@ -554,7 +554,7 @@ def save_import(proto: StagePrototype, conf: dict) -> None: if "versions" in conf["import"][key]: check_versions(proto, conf["import"][key], f'import "{key}"') set_version(stage_prototype_import, conf["import"][key]) - if stage_prototype_import.min_version and stage_prototype_import.max_version: + if stage_prototype_import.min_version and stage_prototype_import.max_version: # noqa: SIM102 if ( compare_prototype_versions( str(stage_prototype_import.min_version), @@ -579,10 +579,9 @@ def check_action_hc(proto: StagePrototype, conf: dict) -> None: return for idx, item in enumerate(conf["hc_acl"]): - if "service" not in item: - if proto.type == "service": - item["service"] = proto.name - conf["hc_acl"][idx]["service"] = proto.name + if "service" not in item and proto.type == "service": + item["service"] = proto.name + conf["hc_acl"][idx]["service"] = proto.name def save_sub_actions(conf, action): @@ -814,19 +813,15 @@ def check_variant(config: dict) -> dict: vtype = config["source"]["type"] source = {"type": vtype, "args": None} - if "strict" in config["source"]: - source["strict"] = config["source"]["strict"] - else: - source["strict"] = True + source["strict"] = config["source"].get("strict", True) if vtype == "inline": source["value"] = config["source"]["value"] elif vtype in ("config", "builtin"): source["name"] = config["source"]["name"] - if vtype == "builtin": - if "args" in config["source"]: - source["args"] = config["source"]["args"] + if vtype == "builtin" and "args" in config["source"]: + source["args"] = config["source"]["args"] return source @@ -849,13 +844,12 @@ def process_limits(config: dict, name: str, subname: str, prototype: StageProtot limits["yspec"] = get_yspec( prototype=prototype, bundle_hash=bundle_hash, conf=config, name=name, subname=subname ) - elif config["type"] == "group": - if "activatable" in config: - limits["activatable"] = config["activatable"] - limits["active"] = False + elif config["type"] == "group" and "activatable" in config: + limits["activatable"] = config["activatable"] + limits["active"] = False - if "active" in config: - limits["active"] = config["active"] + if "active" in config: + limits["active"] = config["active"] if "read_only" in config and "writable" in config: key_ref = f'(config key "{name}/{subname}" of {proto_ref(prototype=prototype)})' @@ -919,7 +913,8 @@ def cook_conf( except IntegrityError: raise_adcm_ex( code="INVALID_CONFIG_DEFINITION", - msg=f"Duplicate config on {prototype.type} {prototype}, action {action}, with name {name} and subname {subname}", + msg=f"Duplicate config on {prototype.type} {prototype}, action {action}, " + f"with name {name} and subname {subname}", ) @@ -1013,7 +1008,8 @@ def check_display_name(obj: StagePrototype) -> None: if another_comps: raise_adcm_ex( code="WRONG_NAME", - msg=f"Display name for component within one service must be unique. Incorrect definition of {proto_ref(prototype=obj)}", + msg=f"Display name for component within one service must be unique. " + f"Incorrect definition of {proto_ref(prototype=obj)}", ) @@ -1031,9 +1027,8 @@ def in_dict(dictionary: dict, key: str) -> bool: if key in dictionary: if dictionary[key] is None: return False - else: - return True - else: + return True + else: # noqa: RET505 return False @@ -1044,15 +1039,13 @@ def dict_to_obj(dictionary, key, obj, obj_key=None): if not isinstance(dictionary, dict): return - if key in dictionary: - if dictionary[key] is not None: - setattr(obj, obj_key, dictionary[key]) + if key in dictionary and dictionary[key] is not None: + setattr(obj, obj_key, dictionary[key]) def dict_json_to_obj(dictionary: dict, key: str, obj: StagePrototypeConfig) -> None: - if isinstance(dictionary, dict): - if key in dictionary: - setattr(obj, key, json.dumps(dictionary[key])) + if isinstance(dictionary, dict) and key in dictionary: + setattr(obj, key, json.dumps(dictionary[key])) def _deep_get(deep_dict: dict, *nested_keys: str, default: Any) -> Any: diff --git a/python/cm/status_api.py b/python/cm/status_api.py index 54cbcd2e32..f239323b3f 100644 --- a/python/cm/status_api.py +++ b/python/cm/status_api.py @@ -10,12 +10,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json from collections import defaultdict from collections.abc import Iterable from urllib.parse import urljoin +import json +from django.conf import settings +from requests import Response +from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED import requests + from cm.logger import logger from cm.models import ( ADCMEntity, @@ -27,9 +31,6 @@ ServiceComponent, TaskLog, ) -from django.conf import settings -from requests import Response -from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED class EventTypes: @@ -58,7 +59,7 @@ def api_request(method: str, url: str, data: dict = None) -> Response | None: response = requests.request(method, url, **kwargs) if response.status_code not in {HTTP_200_OK, HTTP_201_CREATED}: logger.error("%s %s error %d: %s", method, url, response.status_code, response.text) - return response + return response # noqa: TRY300 except requests.exceptions.Timeout: logger.error("%s request to %s timed out", method, url) return None @@ -153,8 +154,7 @@ def get_raw_status(url: str) -> int: if "status" in json_data: return json_data["status"] - else: - return settings.EMPTY_STATUS_STATUS_CODE + return settings.EMPTY_STATUS_STATUS_CODE def get_status(obj: ADCMEntity, url: str) -> int: diff --git a/python/cm/tests/test_action.py b/python/cm/tests/test_action.py index 803c075c90..41df864975 100644 --- a/python/cm/tests/test_action.py +++ b/python/cm/tests/test_action.py @@ -11,6 +11,11 @@ # limitations under the License. from pathlib import Path +from adcm.tests.base import BaseTestCase +from django.urls import reverse +from rest_framework.response import Response +from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_409_CONFLICT + from cm.api import add_hc, add_service_to_cluster from cm.models import Action, MaintenanceMode, Prototype, ServiceComponent from cm.tests.utils import ( @@ -21,11 +26,6 @@ gen_prototype, gen_provider, ) -from django.urls import reverse -from rest_framework.response import Response -from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_409_CONFLICT - -from adcm.tests.base import BaseTestCase plausible_action_variants = { "unlimited": { @@ -138,7 +138,6 @@ class ActionAllowTest(BaseTestCase): - # pylint: disable=too-many-instance-attributes def setUp(self) -> None: super().setUp() self.test_files_dir = self.base_dir / "python" / "cm" / "tests" / "files" diff --git a/python/cm/tests/test_adcm_config.py b/python/cm/tests/test_adcm_config.py index a45c428871..787dbfa9c0 100644 --- a/python/cm/tests/test_adcm_config.py +++ b/python/cm/tests/test_adcm_config.py @@ -12,8 +12,7 @@ from unittest.mock import Mock, call, patch -from cm.adcm_config.config import process_config -from cm.models import ADCM, ConfigLog +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.urls import reverse @@ -21,7 +20,8 @@ from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED, HTTP_403_FORBIDDEN -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from cm.adcm_config.config import process_config +from cm.models import ADCM, ConfigLog class TestAdcmConfig(BaseTestCase): diff --git a/python/cm/tests/test_adcm_entity.py b/python/cm/tests/test_adcm_entity.py index 0bae1bbb53..c771bd7408 100644 --- a/python/cm/tests/test_adcm_entity.py +++ b/python/cm/tests/test_adcm_entity.py @@ -9,6 +9,8 @@ # 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. +from adcm.tests.base import BaseTestCase + from cm.issue import add_concern_to_object, remove_concern_from_object from cm.models import ( ConcernCause, @@ -19,8 +21,6 @@ ) from cm.tests.utils import gen_concern_item, generate_hierarchy -from adcm.tests.base import BaseTestCase - class ADCMEntityConcernTest(BaseTestCase): def setUp(self): diff --git a/python/cm/tests/test_bundle.py b/python/cm/tests/test_bundle.py index 9732e97c15..25d7173438 100644 --- a/python/cm/tests/test_bundle.py +++ b/python/cm/tests/test_bundle.py @@ -10,20 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json from pathlib import Path +import json -from cm.adcm_config.ansible import ansible_decrypt -from cm.api import delete_host_provider -from cm.bundle import delete_bundle -from cm.errors import AdcmEx -from cm.models import ConfigLog -from cm.tests.test_upgrade import ( - cook_cluster, - cook_cluster_bundle, - cook_provider, - cook_provider_bundle, -) +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from django.conf import settings from django.db import IntegrityError from django.urls import reverse @@ -35,7 +25,17 @@ HTTP_409_CONFLICT, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from cm.adcm_config.ansible import ansible_decrypt +from cm.api import delete_host_provider +from cm.bundle import delete_bundle +from cm.errors import AdcmEx +from cm.models import ConfigLog +from cm.tests.test_upgrade import ( + cook_cluster, + cook_cluster_bundle, + cook_provider, + cook_provider_bundle, +) class TestBundle(BaseTestCase): diff --git a/python/cm/tests/test_cluster.py b/python/cm/tests/test_cluster.py index 971b039d83..1c615c1d8b 100644 --- a/python/cm/tests/test_cluster.py +++ b/python/cm/tests/test_cluster.py @@ -12,11 +12,11 @@ import string -from cm.models import Bundle, Cluster, Prototype +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from django.urls import reverse from rest_framework import status -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from cm.models import Bundle, Cluster, Prototype class TestCluster(BaseTestCase): diff --git a/python/cm/tests/test_component.py b/python/cm/tests/test_component.py index abbc693e02..5d2d81d7b1 100644 --- a/python/cm/tests/test_component.py +++ b/python/cm/tests/test_component.py @@ -10,6 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from django.urls import reverse + from cm.models import ( Bundle, Cluster, @@ -20,9 +23,6 @@ Prototype, ServiceComponent, ) -from django.urls import reverse - -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class TestComponent(BaseTestCase): diff --git a/python/cm/tests/test_config_group.py b/python/cm/tests/test_config_group.py index 3c0204367b..b64acbf5fe 100644 --- a/python/cm/tests/test_config_group.py +++ b/python/cm/tests/test_config_group.py @@ -11,11 +11,11 @@ # limitations under the License. +from adcm.tests.base import BaseTestCase + from cm.models import ConfigLog from cm.tests.utils import gen_cluster, gen_config, gen_group, gen_prototype_config -from adcm.tests.base import BaseTestCase - class GroupConfigTest(BaseTestCase): def setUp(self) -> None: diff --git a/python/cm/tests/test_flag.py b/python/cm/tests/test_flag.py index f112840982..ec50b8a4c7 100644 --- a/python/cm/tests/test_flag.py +++ b/python/cm/tests/test_flag.py @@ -10,13 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase + from cm.flag import create_flag, get_flag_name, remove_flag, update_object_flag from cm.hierarchy import Tree from cm.models import ConcernCause, ConcernItem, ConcernType from cm.tests.utils import generate_hierarchy -from adcm.tests.base import BaseTestCase - class FlagTest(BaseTestCase): """Tests for `cm.issue.create_issues()`""" diff --git a/python/cm/tests/test_hc.py b/python/cm/tests/test_hc.py index 6d5607c504..1ace21cd35 100644 --- a/python/cm/tests/test_hc.py +++ b/python/cm/tests/test_hc.py @@ -12,6 +12,12 @@ from pathlib import Path +from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from django.conf import settings +from django.urls import reverse +from rest_framework.response import Response +from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED + from cm.api import add_host_to_cluster, save_hc from cm.errors import AdcmEx from cm.job import check_hostcomponentmap @@ -22,12 +28,6 @@ cook_provider, cook_provider_bundle, ) -from django.conf import settings -from django.urls import reverse -from rest_framework.response import Response -from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED - -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class TestHC(BaseTestCase): diff --git a/python/cm/tests/test_hierarchy.py b/python/cm/tests/test_hierarchy.py index 0e706eb9aa..5c89fbcd4b 100644 --- a/python/cm/tests/test_hierarchy.py +++ b/python/cm/tests/test_hierarchy.py @@ -9,9 +9,10 @@ # 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. -# pylint: disable=wrong-import-order +from adcm.tests.base import BaseTestCase + from cm.hierarchy import HierarchyError, Tree from cm.tests.utils import ( gen_bundle, @@ -24,10 +25,8 @@ gen_service, ) -from adcm.tests.base import BaseTestCase - -def generate_hierarchy(): # pylint: disable=too-many-locals,too-many-statements +def generate_hierarchy(): """ Generates two hierarchies: cluster_1 - service_11 - component_111 - host_11 - provider_1 @@ -165,7 +164,7 @@ def test_get_node(self): "host_31", ) for name in expected: - assert tree.get_node(hierarchy_objects[name]) + assert tree.get_node(hierarchy_objects[name]) # noqa: S101 not_expected = ( "cluster_2", diff --git a/python/cm/tests/test_host.py b/python/cm/tests/test_host.py index 399b13dcd8..25269de9df 100644 --- a/python/cm/tests/test_host.py +++ b/python/cm/tests/test_host.py @@ -10,10 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -import string from pathlib import Path +import string -from cm.models import Bundle, Cluster, Host, HostProvider, MaintenanceMode, Prototype +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from django.urls import reverse from rest_framework.response import Response from rest_framework.status import ( @@ -25,7 +25,7 @@ HTTP_409_CONFLICT, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from cm.models import Bundle, Cluster, Host, HostProvider, MaintenanceMode, Prototype class TestHostAPI(BaseTestCase): @@ -120,7 +120,7 @@ def check_maintenance_mode_can_be_changed(self, host: Host): self.assertEqual(response.status_code, HTTP_200_OK) self.assertEqual(response.json()["maintenance_mode"], new_mm) - def test_host(self): # pylint: disable=too-many-statements + def test_host(self): host = "test.server.net" host_url = reverse(viewname="v1:host") diff --git a/python/cm/tests/test_inventory/base.py b/python/cm/tests/test_inventory/base.py index 204c77fbd9..36a36db281 100644 --- a/python/cm/tests/test_inventory/base.py +++ b/python/cm/tests/test_inventory/base.py @@ -9,12 +9,15 @@ # 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 json from functools import reduce from pathlib import Path from typing import Any, Callable, Iterable, Literal, Mapping, TypeAlias +import json +from adcm.tests.base import BaseTestCase, BusinessLogicMixin from api_v2.config.utils import convert_adcm_meta_to_attr, convert_attr_to_adcm_meta +from jinja2 import Template + from cm.adcm_config.ansible import ansible_decrypt from cm.api import add_hc, update_obj_config from cm.inventory import get_inventory_data @@ -30,9 +33,6 @@ ServiceComponent, ) from cm.utils import deep_merge -from jinja2 import Template - -from adcm.tests.base import BaseTestCase, BusinessLogicMixin TemplatesData: TypeAlias = Mapping[tuple[str, ...], tuple[Path, Mapping[str, Any]]] MappingEntry: TypeAlias = dict[Literal["host_id", "component_id", "service_id"], int] @@ -105,7 +105,7 @@ def change_configuration( target.refresh_from_db() current_config = ConfigLog.objects.get(id=target.config.current) - new_config = update_obj_config( + return update_obj_config( obj_conf=target.config, config=deep_merge(origin=preprocess_config(current_config.config), renovator=config_diff), attr=convert_adcm_meta_to_attr( @@ -114,8 +114,6 @@ def change_configuration( description="", ) - return new_config - def check_data_by_template(self, data: Mapping[str, dict], templates_data: TemplatesData) -> None: for key_chain, template_data in templates_data.items(): template_path, kwargs = template_data diff --git a/python/cm/tests/test_inventory/test_action_config.py b/python/cm/tests/test_inventory/test_action_config.py index ff48a6a38d..96d16a981c 100644 --- a/python/cm/tests/test_inventory/test_action_config.py +++ b/python/cm/tests/test_inventory/test_action_config.py @@ -9,10 +9,11 @@ # 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. +from django.conf import settings + from cm.job import prepare_job_config from cm.models import Action, ServiceComponent from cm.tests.test_inventory.base import BaseInventoryTestCase -from django.conf import settings class TestConfigAndImportsInInventory(BaseInventoryTestCase): diff --git a/python/cm/tests/test_inventory/test_before_upgrade.py b/python/cm/tests/test_inventory/test_before_upgrade.py index 25986e4ce3..00e7e0a2b8 100644 --- a/python/cm/tests/test_inventory/test_before_upgrade.py +++ b/python/cm/tests/test_inventory/test_before_upgrade.py @@ -12,6 +12,7 @@ from pathlib import Path from api_v2.service.utils import bulk_add_services_to_cluster + from cm.inventory import get_inventory_data from cm.models import ClusterObject, ObjectType, Prototype, ServiceComponent, Upgrade from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets diff --git a/python/cm/tests/test_inventory/test_cluster_hosts.py b/python/cm/tests/test_inventory/test_cluster_hosts.py index 39ed0b5c2d..5f9232fd6b 100644 --- a/python/cm/tests/test_inventory/test_cluster_hosts.py +++ b/python/cm/tests/test_inventory/test_cluster_hosts.py @@ -80,7 +80,7 @@ def test_add_1_host_on_cluster_actions(self): ), } - for obj, action, expected_topology, expected_data in ( + for obj, action, topology, data in ( (self.cluster_1, action_on_cluster, expected_topology, expected_data), ( host_1, @@ -90,7 +90,7 @@ def test_add_1_host_on_cluster_actions(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory(obj, action, expected_topology, expected_data) + self.assert_inventory(obj, action, topology, data) def test_add_2_hosts_on_cluster_actions(self): host_1 = self.add_host( @@ -125,7 +125,7 @@ def test_add_2_hosts_on_cluster_actions(self): ), } - for obj, action, expected_topology, expected_data in ( + for obj, action, topology, data in ( (self.cluster_1, action_on_cluster, expected_topology, expected_data), ( host_1, @@ -141,4 +141,4 @@ def test_add_2_hosts_on_cluster_actions(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory(obj, action, expected_topology, expected_data) + self.assert_inventory(obj, action, topology, data) diff --git a/python/cm/tests/test_inventory/test_components.py b/python/cm/tests/test_inventory/test_components.py index d34ad7ac14..a2597bcc3e 100644 --- a/python/cm/tests/test_inventory/test_components.py +++ b/python/cm/tests/test_inventory/test_components.py @@ -108,7 +108,7 @@ def test_1_component_1_host(self): ), } - for obj, action, expected_topology, expected_data in ( + for obj, action, topology, data in ( (self.cluster_1, action_on_cluster, expected_topology, expected_data), (service_one_component, action_on_service, expected_topology, expected_data), (component_1, action_on_component, expected_topology, expected_data), @@ -120,9 +120,7 @@ def test_1_component_1_host(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory( - obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data - ) + self.assert_inventory(obj=obj, action=action, expected_topology=topology, expected_data=data) def test_2_components_2_hosts_mapped_all_to_all(self): self.host_2 = self.add_host( @@ -184,7 +182,7 @@ def test_2_components_2_hosts_mapped_all_to_all(self): ), } - for obj, action, expected_topology, expected_data in ( + for obj, action, topology, data in ( (self.cluster_1, action_on_cluster, expected_hosts_topology, expected_data), (service_two_components, action_on_service, expected_hosts_topology, expected_data), (component_1, action_on_component_1, expected_hosts_topology, expected_data), @@ -203,9 +201,7 @@ def test_2_components_2_hosts_mapped_all_to_all(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory( - obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data - ) + self.assert_inventory(obj=obj, action=action, expected_topology=topology, expected_data=data) def test_2_components_2_hosts_mapped_in_pairs(self): self.host_2 = self.add_host( @@ -265,7 +261,7 @@ def test_2_components_2_hosts_mapped_in_pairs(self): ), } - for obj, action, expected_topology, expected_data in ( + for obj, action, topology, data in ( (self.cluster_1, action_on_cluster, expected_hosts_topology, expected_data), (service_two_components, action_on_service, expected_hosts_topology, expected_data), (component_1, action_on_component_1, expected_hosts_topology, expected_data), @@ -284,9 +280,7 @@ def test_2_components_2_hosts_mapped_in_pairs(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory( - obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data - ) + self.assert_inventory(obj=obj, action=action, expected_topology=topology, expected_data=data) def test_2_services_2_components_each_on_1_host(self): ( @@ -364,7 +358,7 @@ def test_2_services_2_components_each_on_1_host(self): ), } - for obj, action, expected_topology, expected_data in ( + for obj, action, topology, data in ( (self.cluster_1, action_on_cluster, expected_hosts_topology, expected_data), (service_two_components, action_on_service_1, expected_hosts_topology, expected_data), (another_service_two_components, action_on_service_2, expected_hosts_topology, expected_data), @@ -380,9 +374,7 @@ def test_2_services_2_components_each_on_1_host(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory( - obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data - ) + self.assert_inventory(obj=obj, action=action, expected_topology=topology, expected_data=data) def test_2_services_2_components_each_2_hosts_cross_mapping(self): self.host_2 = self.add_host( @@ -463,7 +455,7 @@ def test_2_services_2_components_each_2_hosts_cross_mapping(self): ), } - for obj, action, expected_topology, expected_data in ( + for obj, action, topology, data in ( (self.cluster_1, action_on_cluster, expected_hosts_topology, expected_data), (service_two_components, action_on_service_1, expected_hosts_topology, expected_data), (another_service_two_components, action_on_service_2, expected_hosts_topology, expected_data), @@ -485,6 +477,4 @@ def test_2_services_2_components_each_2_hosts_cross_mapping(self): ), ): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): - self.assert_inventory( - obj=obj, action=action, expected_topology=expected_topology, expected_data=expected_data - ) + self.assert_inventory(obj=obj, action=action, expected_topology=topology, expected_data=data) diff --git a/python/cm/tests/test_inventory/test_group_config.py b/python/cm/tests/test_inventory/test_group_config.py index c96c8924fd..0634650542 100644 --- a/python/cm/tests/test_inventory/test_group_config.py +++ b/python/cm/tests/test_inventory/test_group_config.py @@ -12,6 +12,8 @@ from typing import Iterable from api_v2.service.utils import bulk_add_services_to_cluster +from django.contrib.contenttypes.models import ContentType + from cm.inventory import get_inventory_data from cm.models import ( Action, @@ -23,7 +25,6 @@ ServiceComponent, ) from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets -from django.contrib.contenttypes.models import ContentType class TestGroupConfigsInInventory(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes diff --git a/python/cm/tests/test_inventory/test_hc_acl_actions.py b/python/cm/tests/test_inventory/test_hc_acl_actions.py index 1ef9c6bf6a..fc61b20223 100644 --- a/python/cm/tests/test_inventory/test_hc_acl_actions.py +++ b/python/cm/tests/test_inventory/test_hc_acl_actions.py @@ -79,10 +79,10 @@ def setUp(self) -> None: @staticmethod def _get_mapping_delta(cluster, new_mapping: list[MappingEntry]) -> Delta: - existing_mapping_ids = set( + existing_mapping_ids = { (hc.host.pk, hc.component.pk, hc.service.pk) for hc in HostComponent.objects.filter(cluster=cluster) - ) - new_mapping_ids = set((hc["host_id"], hc["component_id"], hc["service_id"]) for hc in new_mapping) + } + new_mapping_ids = {(hc["host_id"], hc["component_id"], hc["service_id"]) for hc in new_mapping} added = {} for host_id, component_id, service_id in new_mapping_ids.difference(existing_mapping_ids): diff --git a/python/cm/tests/test_inventory/test_host_action.py b/python/cm/tests/test_inventory/test_host_action.py index 5e54436102..5a7c785685 100644 --- a/python/cm/tests/test_inventory/test_host_action.py +++ b/python/cm/tests/test_inventory/test_host_action.py @@ -13,6 +13,7 @@ from pathlib import Path from api_v2.service.utils import bulk_add_services_to_cluster + from cm.inventory import get_inventory_data from cm.models import Action, ClusterObject, ObjectType, Prototype, ServiceComponent from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets diff --git a/python/cm/tests/test_inventory/test_inventory.py b/python/cm/tests/test_inventory/test_inventory.py index 5dad327348..26106e6a53 100644 --- a/python/cm/tests/test_inventory/test_inventory.py +++ b/python/cm/tests/test_inventory/test_inventory.py @@ -15,6 +15,14 @@ from pathlib import Path from unittest.mock import Mock, patch +from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from django.conf import settings +from django.urls import reverse +from django.utils import timezone +from init_db import init as init_adcm +from rest_framework.response import Response +from rest_framework.status import HTTP_201_CREATED + from cm.api import add_hc, add_service_to_cluster, update_obj_config from cm.inventory import ( MAINTENANCE_MODE, @@ -56,19 +64,9 @@ gen_provider, gen_service, ) -from django.conf import settings -from django.urls import reverse -from django.utils import timezone -from init_db import init as init_adcm -from rest_framework.response import Response -from rest_framework.status import HTTP_201_CREATED - -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class TestInventory(BaseTestCase): - # pylint: disable=too-many-instance-attributes - def setUp(self): super().setUp() @@ -319,8 +317,6 @@ def test_prepare_job_inventory(self, mock_open, mock_dump): mock_dump.reset_mock() def test_host_vars(self): - # pylint: disable=too-many-locals - service_pt_1 = gen_prototype(self.cluster_bundle, "service", "service_1") service_pt_2 = gen_prototype(self.cluster_bundle, "service", "service_2") component_pt_11 = gen_prototype(self.cluster_bundle, "component", "component_11") @@ -426,8 +422,6 @@ def test_host_vars(self): class TestInventoryAndMaintenanceMode(BaseTestCase): - # pylint: disable=too-many-instance-attributes - def setUp(self): super().setUp() init_adcm() @@ -568,10 +562,8 @@ def get_inventory_data(self, data: dict, kwargs: dict) -> dict: re_prepare_job(task=task, job=job) inventory_file = settings.RUN_DIR / str(job.pk) / "inventory.json" - with open(file=inventory_file, encoding=settings.ENCODING_UTF_8) as f: - inventory_data = loads(s=f.read())["all"]["children"] - - return inventory_data + with Path(inventory_file).open(encoding=settings.ENCODING_UTF_8) as f: + return loads(s=f.read())["all"]["children"] def test_groups_remove_host_not_in_mm_success(self): self.host_hc_acl_3.maintenance_mode = MaintenanceMode.ON diff --git a/python/cm/tests/test_inventory/test_maintenance_mode.py b/python/cm/tests/test_inventory/test_maintenance_mode.py index c46f419ec1..4808406e46 100644 --- a/python/cm/tests/test_inventory/test_maintenance_mode.py +++ b/python/cm/tests/test_inventory/test_maintenance_mode.py @@ -12,7 +12,9 @@ from pathlib import Path from typing import Mapping +from adcm.settings import ADCM_TURN_ON_MM_ACTION_NAME from api_v2.service.utils import bulk_add_services_to_cluster + from cm.models import ( Action, Cluster, @@ -26,8 +28,6 @@ ) from cm.tests.test_inventory.base import BaseInventoryTestCase -from adcm.settings import ADCM_TURN_ON_MM_ACTION_NAME - class TestMaintenanceMode(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes def setUp(self) -> None: @@ -65,12 +65,15 @@ def get_cluster_mm_config(self, obj: Cluster): def get_service_mm_config(self, obj: ClusterObject, component: ServiceComponent): mm_state = {MaintenanceMode.ON: "true", MaintenanceMode.OFF: "false"} - path, ids = self.templates_dir / "service_one_component.json.j2", { - "service_id": obj.id, - "service_mm": mm_state[obj.maintenance_mode], - "component_id": component.pk, - "component_mm": mm_state[component.maintenance_mode], - } + path, ids = ( + self.templates_dir / "service_one_component.json.j2", + { + "service_id": obj.id, + "service_mm": mm_state[obj.maintenance_mode], + "component_id": component.pk, + "component_mm": mm_state[component.maintenance_mode], + }, + ) return self.render_json_template(path, ids) @@ -218,7 +221,7 @@ def test_1_component_1_host(self): ), } - for obj, action, expected_topology, expected_data in ( + for obj, action, topology, data in ( ( service_one_component, action_on_service_mm_on, @@ -279,7 +282,7 @@ def test_1_component_1_host(self): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): obj.maintenance_mode = MaintenanceMode.ON obj.save() - self.assert_inventory(obj, action, expected_topology, expected_data) + self.assert_inventory(obj, action, topology, data) obj.maintenance_mode = MaintenanceMode.OFF obj.save() @@ -414,7 +417,7 @@ def test_2_components_2_hosts(self): ), } - for obj, action, expected_topology, expected_data in ( + for obj, action, topology, data in ( (self.service_two_components, action_on_service_mm_on, expected_hosts_topology, expected_data), (self.component_1, action_on_component_1_mm_on, expected_hosts_topology, expected_data), (self.component_2, action_on_component_2_mm_on, expected_hosts_topology, expected_data), @@ -434,6 +437,6 @@ def test_2_components_2_hosts(self): with self.subTest(msg=f"Object: {obj.prototype.type} #{obj.pk} {obj.name}, action: {action.name}"): obj.maintenance_mode = MaintenanceMode.ON obj.save() - self.assert_inventory(obj, action, expected_topology, expected_data) + self.assert_inventory(obj, action, topology, data) obj.maintenance_mode = MaintenanceMode.OFF obj.save() diff --git a/python/cm/tests/test_issue.py b/python/cm/tests/test_issue.py index 0c2ebfde1b..72e15787a1 100644 --- a/python/cm/tests/test_issue.py +++ b/python/cm/tests/test_issue.py @@ -13,6 +13,8 @@ from typing import Iterable from unittest.mock import patch +from adcm.tests.base import BaseTestCase + from cm.api import add_cluster, add_service_to_cluster from cm.hierarchy import Tree from cm.issue import ( @@ -36,8 +38,6 @@ from cm.services.cluster import perform_host_to_cluster_map from cm.tests.utils import gen_service, generate_hierarchy -from adcm.tests.base import BaseTestCase - mock_issue_check_map = { ConcernCause.CONFIG: lambda x: False, ConcernCause.IMPORT: lambda x: True, diff --git a/python/cm/tests/test_job.py b/python/cm/tests/test_job.py index 56a3282090..d35d8f872f 100644 --- a/python/cm/tests/test_job.py +++ b/python/cm/tests/test_job.py @@ -9,13 +9,20 @@ # 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. -# pylint: disable=wrong-import-order from pathlib import Path from signal import SIGTERM from unittest.mock import Mock, patch from urllib.parse import urljoin +from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from django.conf import settings +from django.urls import reverse +from django.utils import timezone +from init_db import init +from rest_framework.response import Response +from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_409_CONFLICT + from cm.api import add_cluster, add_service_to_cluster from cm.issue import lock_affected_objects from cm.job import ( @@ -57,19 +64,9 @@ gen_prototype, gen_task_log, ) -from django.conf import settings -from django.urls import reverse -from django.utils import timezone -from init_db import init -from rest_framework.response import Response -from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_409_CONFLICT - -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class TestJob(BaseTestCase): - # pylint: disable=too-many-public-methods - def setUp(self): super().setUp() @@ -215,8 +212,6 @@ def test_get_state_multi_job(self): self.assertListEqual(m_state_unset, exp_m_state_unset) def test_set_action_state(self): - # pylint: disable=too-many-locals - bundle = Bundle.objects.create() prototype = Prototype.objects.create(bundle=bundle) cluster = Cluster.objects.create(prototype=prototype) @@ -423,8 +418,6 @@ def test_prepare_job_config( mock_get_bundle_root, mock_cook_script, ): - # pylint: disable=too-many-locals - bundle = Bundle.objects.create() proto1 = Prototype.objects.create(bundle=bundle, type="cluster") cluster = Cluster.objects.create(prototype=proto1) @@ -532,8 +525,6 @@ def test_prepare_job_config( @patch("cm.job.get_actual_hc") @patch("cm.job.prepare_job") def test_re_prepare_job(self, mock_prepare_job, mock_get_actual_hc, mock_get_old_hc, mock_cook_delta): - # pylint: disable=too-many-locals - new_hc = Mock() mock_get_actual_hc.return_value = new_hc old_hc = Mock() diff --git a/python/cm/tests/test_management_commands.py b/python/cm/tests/test_management_commands.py index 143124a1eb..9614bc5d13 100644 --- a/python/cm/tests/test_management_commands.py +++ b/python/cm/tests/test_management_commands.py @@ -12,17 +12,18 @@ from api_v2.tests.base import BaseAPITestCase -from cm.models import ADCM, Bundle, ServiceComponent -from cm.tests.utils import gen_cluster, gen_provider from django.conf import settings from django.core.management import load_command_class from rbac.models import Policy, Role, User +from cm.models import ADCM, Bundle, ServiceComponent +from cm.tests.utils import gen_cluster, gen_provider + class TestStatistics(BaseAPITestCase): def setUp(self) -> None: super().setUp() - self.maxDiff = None # pylint: disable=invalid-name + self.maxDiff = None enterprise_bundle_cluster = Bundle.objects.create( name="enterprise_cluster", version="1.0", edition="enterprise" diff --git a/python/cm/tests/test_message_template.py b/python/cm/tests/test_message_template.py index 033e0769a9..619537a258 100644 --- a/python/cm/tests/test_message_template.py +++ b/python/cm/tests/test_message_template.py @@ -12,12 +12,12 @@ from uuid import uuid4 +from adcm.tests.base import BaseTestCase + from cm.errors import AdcmEx from cm.models import KnownNames, MessageTemplate from cm.tests.utils import gen_adcm -from adcm.tests.base import BaseTestCase - class MessageTemplateTest(BaseTestCase): def setUp(self): diff --git a/python/cm/tests/test_requires.py b/python/cm/tests/test_requires.py index aa130cb925..3ce369d16c 100644 --- a/python/cm/tests/test_requires.py +++ b/python/cm/tests/test_requires.py @@ -10,6 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase + from cm.api import add_hc, add_service_to_cluster from cm.errors import AdcmEx from cm.issue import update_hierarchy_issues @@ -23,8 +25,6 @@ ServiceComponent, ) -from adcm.tests.base import BaseTestCase - class TestComponent(BaseTestCase): def setUp(self) -> None: diff --git a/python/cm/tests/test_service.py b/python/cm/tests/test_service.py index 63643ac0c3..16eb67a91b 100644 --- a/python/cm/tests/test_service.py +++ b/python/cm/tests/test_service.py @@ -10,6 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from django.urls import reverse +from rest_framework.response import Response +from rest_framework.status import HTTP_204_NO_CONTENT, HTTP_409_CONFLICT + from cm.models import ( Bundle, Cluster, @@ -20,11 +25,6 @@ Prototype, ServiceComponent, ) -from django.urls import reverse -from rest_framework.response import Response -from rest_framework.status import HTTP_204_NO_CONTENT, HTTP_409_CONFLICT - -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class TestService(BaseTestCase): diff --git a/python/cm/tests/test_task_log.py b/python/cm/tests/test_task_log.py index 066d0d22f8..d6e9944f9e 100644 --- a/python/cm/tests/test_task_log.py +++ b/python/cm/tests/test_task_log.py @@ -11,10 +11,18 @@ # limitations under the License. +from adcm.tests.base import BaseTestCase from api.job.views import ( get_task_download_archive_file_handler, get_task_download_archive_name, ) +from django.conf import settings +from django.test import override_settings +from django.urls import reverse +from django.utils import timezone +from rest_framework.response import Response +from rest_framework.status import HTTP_200_OK + from cm.issue import lock_affected_objects, unlock_affected_objects from cm.models import ( Action, @@ -34,14 +42,6 @@ gen_job_log, gen_task_log, ) -from django.conf import settings -from django.test import override_settings -from django.urls import reverse -from django.utils import timezone -from rest_framework.response import Response -from rest_framework.status import HTTP_200_OK - -from adcm.tests.base import BaseTestCase class TaskLogLockTest(BaseTestCase): diff --git a/python/cm/tests/test_upgrade.py b/python/cm/tests/test_upgrade.py index 103465c51d..eac51c78e1 100644 --- a/python/cm/tests/test_upgrade.py +++ b/python/cm/tests/test_upgrade.py @@ -9,7 +9,8 @@ # 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. -# pylint: disable=wrong-import-order + +from adcm.tests.base import BaseTestCase from cm.adcm_config.config import save_object_config, switch_config from cm.api import ( @@ -38,8 +39,6 @@ from cm.tests.utils import gen_cluster from cm.upgrade import bundle_revert, check_upgrade, do_upgrade, switch_components -from adcm.tests.base import BaseTestCase - def cook_cluster_bundle(ver): bundle = Bundle.objects.create(name="ADH", version=ver) @@ -465,7 +464,7 @@ def test_cluster_upgrade(self): self.assertEqual(service_1.id, service_2.id) self.assertEqual(service_2.prototype.id, new_proto.id) - def test_hc(self): # pylint: disable=too-many-locals + def test_hc(self): bundle_1 = cook_cluster_bundle("1.0") bundle_2 = cook_cluster_bundle("2.0") bundle_3 = cook_provider_bundle("1.0") @@ -569,7 +568,7 @@ def test_provider_upgrade(self): class TestRevertUpgrade(BaseTestCase): - def test_simple_revert_upgrade(self): # pylint: disable=too-many-locals + def test_simple_revert_upgrade(self): bundle1 = cook_cluster_bundle(ver="1.0") bundle2 = cook_cluster_bundle(ver="2.0") service1_proto1 = Prototype.objects.get(bundle=bundle1, type="service", name="hadoop") diff --git a/python/cm/tests/test_variant.py b/python/cm/tests/test_variant.py index 658c1490ab..371a1e12e0 100644 --- a/python/cm/tests/test_variant.py +++ b/python/cm/tests/test_variant.py @@ -9,7 +9,8 @@ # 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. -# pylint: disable=wrong-import-order + +from adcm.tests.base import BaseTestCase from cm.api import add_host, add_host_provider, add_host_to_cluster from cm.errors import AdcmEx @@ -23,8 +24,6 @@ ) from cm.variant import VARIANT_HOST_FUNC, get_variant, var_host_solver, variant_host -from adcm.tests.base import BaseTestCase - def cook_cluster(): bundle = Bundle.objects.create(name="ADH", version="1.0") diff --git a/python/cm/tests/test_yaml_checker.py b/python/cm/tests/test_yaml_checker.py index 6fa36b6058..11c3b611c9 100644 --- a/python/cm/tests/test_yaml_checker.py +++ b/python/cm/tests/test_yaml_checker.py @@ -12,9 +12,10 @@ from copy import deepcopy -from cm.checker import FormatError, process_rule from django.test import TestCase +from cm.checker import FormatError, process_rule + test_data = { "cluster": [ { diff --git a/python/cm/tests/utils.py b/python/cm/tests/utils.py index c962e74cca..268f1e7fa3 100644 --- a/python/cm/tests/utils.py +++ b/python/cm/tests/utils.py @@ -12,6 +12,9 @@ from uuid import uuid4 +from django.contrib.contenttypes.models import ContentType +from django.utils import timezone + from cm.errors import AdcmEx from cm.models import ( ADCM, @@ -33,8 +36,6 @@ ServiceComponent, TaskLog, ) -from django.contrib.contenttypes.models import ContentType -from django.utils import timezone def gen_name(prefix: str): diff --git a/python/cm/upgrade.py b/python/cm/upgrade.py index d9e1d15b52..fb68890fb0 100644 --- a/python/cm/upgrade.py +++ b/python/cm/upgrade.py @@ -13,6 +13,10 @@ import functools from adcm_version import compare_prototype_versions +from django.contrib.contenttypes.models import ContentType +from django.db import transaction +from rbac.models import Policy + from cm.adcm_config.config import ( init_object_config, make_object_config, @@ -51,9 +55,6 @@ ) from cm.status_api import send_prototype_and_state_update_event from cm.utils import obj_ref -from django.contrib.contenttypes.models import ContentType -from django.db import transaction -from rbac.models import Policy def switch_object(obj: Host | ClusterObject, new_prototype: Prototype) -> None: @@ -151,7 +152,7 @@ def check_upgrade_state(obj: Cluster | HostProvider, upgrade: Upgrade) -> tuple[ if upgrade.allowed(obj): return True, "" - else: + else: # noqa: RET505 return False, "no available states" @@ -353,7 +354,7 @@ def revert_object(obj: ADCMEntity, old_proto: Prototype) -> None: obj.save(update_fields=["prototype", "config", "state", "before_upgrade"]) -def bundle_revert(obj: Cluster | HostProvider) -> None: # pylint: disable=too-many-locals +def bundle_revert(obj: Cluster | HostProvider) -> None: upgraded_bundle = obj.prototype.bundle old_bundle = Bundle.objects.get(pk=obj.before_upgrade["bundle_id"]) old_proto = Prototype.objects.filter(bundle=old_bundle, name=old_bundle.name).first() diff --git a/python/cm/utils.py b/python/cm/utils.py index ae5557f44d..7d01970181 100644 --- a/python/cm/utils.py +++ b/python/cm/utils.py @@ -10,12 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json -import os from collections.abc import Mapping from pathlib import Path from secrets import token_hex from typing import Any, Iterable, Protocol, TypeVar +import os +import json class WithPK(Protocol): @@ -99,7 +99,7 @@ def dict_to_obj(dictionary: dict, obj: Any, keys: Iterable) -> Any: return obj -def obj_ref(obj: type["ADCMEntity"]) -> str: +def obj_ref(obj: type["ADCMEntity"]) -> str: # noqa: F821 if hasattr(obj, "name"): name = obj.name elif hasattr(obj, "fqdn"): diff --git a/python/cm/validators.py b/python/cm/validators.py index 6ed9fc60ec..7377272bf9 100644 --- a/python/cm/validators.py +++ b/python/cm/validators.py @@ -12,10 +12,11 @@ import re -from cm.errors import AdcmEx from rest_framework.exceptions import ValidationError from rest_framework.validators import UniqueValidator +from cm.errors import AdcmEx + class HostUniqueValidator(UniqueValidator): def __call__(self, value, serializer_field): diff --git a/python/cm/variant.py b/python/cm/variant.py index bab3bd27b0..e530e7589a 100644 --- a/python/cm/variant.py +++ b/python/cm/variant.py @@ -12,6 +12,8 @@ from functools import wraps from typing import Callable +from django.core.exceptions import ObjectDoesNotExist + from cm.errors import AdcmEx from cm.errors import raise_adcm_ex as err from cm.logger import logger @@ -24,7 +26,6 @@ Prototype, ServiceComponent, ) -from django.core.exceptions import ObjectDoesNotExist def return_empty_on_not_found(func: Callable) -> Callable: @@ -91,7 +92,7 @@ def variant_service_to_add(**kwargs): return out -def var_host_and(cluster, args): # pylint: disable=unused-argument +def var_host_and(cluster, args): # noqa: ARG001 if not isinstance(args, list): err("CONFIG_VARIANT_ERROR", 'arguments of "and" predicate should be a list') @@ -101,7 +102,7 @@ def var_host_and(cluster, args): # pylint: disable=unused-argument return sorted(set.intersection(*[set(a) for a in args])) -def var_host_or(cluster, args): # pylint: disable=unused-argument +def var_host_or(cluster, args): # noqa: ARG001 if not isinstance(args, list): err("CONFIG_VARIANT_ERROR", 'arguments of "or" predicate should be a list') @@ -148,7 +149,7 @@ def var_host_not_in_service(cluster, args): return out -def var_host_in_cluster(cluster, args): # pylint: disable=unused-argument +def var_host_in_cluster(cluster, args): # noqa: ARG001 out = [] for host in Host.objects.filter(cluster=cluster).order_by("fqdn"): out.append(host.fqdn) @@ -183,7 +184,7 @@ def var_host_not_in_component(cluster, args): return out -def var_host_in_hc(cluster, args): # pylint: disable=unused-argument +def var_host_in_hc(cluster, args): # noqa: ARG001 out = [] for hostcomponent in HostComponent.objects.filter(cluster=cluster).order_by("host__fqdn"): out.append(hostcomponent.host.fqdn) @@ -191,7 +192,7 @@ def var_host_in_hc(cluster, args): # pylint: disable=unused-argument return out -def var_host_not_in_hc(cluster, args): # pylint: disable=unused-argument +def var_host_not_in_hc(cluster, args): # noqa: ARG001 out = [] for host in Host.objects.filter(cluster=cluster).order_by("fqdn"): if HostComponent.objects.filter(cluster=cluster, host=host): @@ -202,7 +203,7 @@ def var_host_not_in_hc(cluster, args): # pylint: disable=unused-argument return out -def var_host_inline_list(cluster, args): # pylint: disable=unused-argument +def var_host_inline_list(cluster, args): # noqa: ARG001 return args["list"] @@ -234,15 +235,13 @@ def check_key(key, _args): if isinstance(args, dict): if "predicate" not in args: return args - else: + else: # noqa: RET505 predicate = args["predicate"] if predicate not in func_map: err("CONFIG_VARIANT_ERROR", f'no "{predicate}" in list of host functions') check_key("args", args) - res = func_map[predicate](cluster, var_host_solver(cluster, func_map, args["args"])) - - return res + return func_map[predicate](cluster, var_host_solver(cluster, func_map, args["args"])) res = [] if not isinstance(args, list): @@ -271,9 +270,7 @@ def variant_host(**kwargs): if "predicate" not in kwargs["args"]: err("CONFIG_VARIANT_ERROR", 'no "predicate" key in variant host function arguments') - res = var_host_solver(cluster=cluster, func_map=VARIANT_HOST_FUNC, args=kwargs["args"]) - - return res + return var_host_solver(cluster=cluster, func_map=VARIANT_HOST_FUNC, args=kwargs["args"]) def variant_host_in_cluster(**kwargs): @@ -307,9 +304,9 @@ def variant_host_in_cluster(**kwargs): out.append(hostcomponent.host.fqdn) return out - else: + else: # noqa: RET505 for hostcomponent in HostComponent.objects.filter(cluster=cluster, service=service).order_by("host__fqdn"): - out.append(hostcomponent.host.fqdn) + out.append(hostcomponent.host.fqdn) # noqa: RET505 return out @@ -319,7 +316,7 @@ def variant_host_in_cluster(**kwargs): return out -def variant_host_not_in_clusters(**kwargs): # pylint: disable=unused-argument +def variant_host_not_in_clusters(**kwargs): # noqa: ARG001 out = [] for host in Host.objects.filter(cluster=None).order_by("fqdn"): out.append(host.fqdn) diff --git a/python/core/cluster/rules.py b/python/core/cluster/rules.py index 4dbc6e1ddf..6b7e6c9a87 100644 --- a/python/core/cluster/rules.py +++ b/python/core/cluster/rules.py @@ -27,7 +27,7 @@ def check_all_hosts_exist(host_candidates: Collection[int], existing_hosts: Coll def check_hosts_can_be_added_to_cluster(cluster_id: int, hosts: Collection[HostClusterPair]) -> None: - bound_hosts = set(entry for entry in hosts if entry.cluster_id) + bound_hosts = {entry for entry in hosts if entry.cluster_id} if not bound_hosts: return diff --git a/python/core/types.py b/python/core/types.py index e69f958fa1..4b7046824e 100644 --- a/python/core/types.py +++ b/python/core/types.py @@ -12,14 +12,10 @@ from typing import TypeAlias -# pylint: disable=invalid-name - ObjectID: TypeAlias = int ClusterID: TypeAlias = ObjectID HostID: TypeAlias = ObjectID -# pylint: enable=invalid-name - class ADCMCoreError(Exception): ... diff --git a/python/drf_docs.py b/python/drf_docs.py index 235502a6ea..e94900b34d 100755 --- a/python/drf_docs.py +++ b/python/drf_docs.py @@ -10,9 +10,8 @@ # 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. -# pylint: disable=wrong-import-order -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401, isort:skip import api.urls @@ -24,9 +23,8 @@ def fix_ordering(field, view): if view.__name__ == "ClusterServiceList": if "display_name" in fix: fix = fix.replace("prototype_display_name", "display_name") - elif view.__name__ == "ServiceComponentList": - if "display_name" in fix: - fix = fix.replace("component__display_name", "display_name") + elif view.__name__ == "ServiceComponentList" and "display_name" in fix: + fix = fix.replace("component__display_name", "display_name") return fix diff --git a/python/init_db.py b/python/init_db.py index 8c664f698a..2a3585ac71 100755 --- a/python/init_db.py +++ b/python/init_db.py @@ -10,13 +10,12 @@ # 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. -# pylint: disable=wrong-import-order -import json from pathlib import Path from secrets import token_hex +import json -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401, isort:skip from cm.bundle import load_adcm from cm.issue import update_hierarchy_issues @@ -40,7 +39,7 @@ def prepare_secrets_json(status_user_username: str, status_user_password: str | None) -> None: # we need to know status user's password to write it to secrets.json [old implementation] if not settings.SECRETS_FILE.is_file() and status_user_username is not None: - with open(settings.SECRETS_FILE, "w", encoding=settings.ENCODING_UTF_8) as f: + with Path(settings.SECRETS_FILE).open(mode="w", encoding=settings.ENCODING_UTF_8) as f: json.dump( { "adcmuser": {"user": status_user_username, "password": status_user_password}, diff --git a/python/jinja_config.py b/python/jinja_config.py index 2e6e35e288..262a09faac 100644 --- a/python/jinja_config.py +++ b/python/jinja_config.py @@ -36,11 +36,10 @@ def _get_attr(config: dict) -> dict: def _get_limits(config: dict, root_path: Path) -> dict: - # pylint: disable=too-many-branches limits = {} if "yspec" in config and config["type"] in settings.STACK_COMPLEX_FIELD_TYPES: - with open(file=Path(root_path, config["yspec"]), encoding=settings.ENCODING_UTF_8) as f: + with Path(root_path, config["yspec"]).open(encoding=settings.ENCODING_UTF_8) as f: data = f.read() limits["yspec"] = safe_load(stream=data) @@ -52,19 +51,15 @@ def _get_limits(config: dict, root_path: Path) -> dict: variant_type = config["source"]["type"] source = {"type": variant_type, "args": None} - if "strict" in config["source"]: - source["strict"] = config["source"]["strict"] - else: - source["strict"] = True + source["strict"] = config["source"].get("strict", True) if variant_type == "inline": source["value"] = config["source"]["value"] elif variant_type in ("config", "builtin"): source["name"] = config["source"]["name"] - if variant_type == "builtin": - if "args" in config["source"]: - source["args"] = config["source"]["args"] + if variant_type == "builtin" and "args" in config["source"]: + source["args"] = config["source"]["args"] limits["source"] = source @@ -118,7 +113,6 @@ def _normalize_config(config: dict, root_path: Path, name: str = "", subname: st def get_jinja_config(action: Action, obj: ADCMEntity) -> tuple[list[PrototypeConfig], dict]: - # pylint: disable=import-outside-toplevel, cyclic-import from cm.inventory import get_inventory_data inventory_data = get_inventory_data(obj=obj, action=action) diff --git a/python/job_runner.py b/python/job_runner.py index 9f9b529e0e..9b760f7f65 100755 --- a/python/job_runner.py +++ b/python/job_runner.py @@ -10,15 +10,14 @@ # 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. -# pylint: disable=wrong-import-order -import json +from pathlib import Path import os -import subprocess import sys -from pathlib import Path +import json +import subprocess -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401, isort:skip from cm.ansible_plugin import finish_check from cm.api import get_hc, save_hc @@ -36,27 +35,19 @@ def open_file(root, tag, job_id): fname = f"{root}/{job_id}/{tag}.txt" - f = open(fname, "w", encoding=settings.ENCODING_UTF_8) # pylint: disable=consider-using-with - - return f + return Path(fname).open(mode="w", encoding=settings.ENCODING_UTF_8) # noqa: SIM115 def read_config(job_id): - file_descriptor = open( # pylint: disable=consider-using-with - f"{settings.RUN_DIR}/{job_id}/config.json", - encoding=settings.ENCODING_UTF_8, - ) - conf = json.load(file_descriptor) - file_descriptor.close() - - return conf + with Path(f"{settings.RUN_DIR}/{job_id}/config.json").open(encoding=settings.ENCODING_UTF_8) as file_descriptor: + return json.load(file_descriptor) def set_job_status(job_id: int, return_code: int) -> int: if return_code == 0: set_job_final_status(job_id=job_id, status=JobStatus.SUCCESS) return 0 - elif return_code == -15: + elif return_code == -15: # noqa: RET505 set_job_final_status(job_id=job_id, status=JobStatus.ABORTED) return 15 else: @@ -112,8 +103,8 @@ def process_err_out_file(job_id, job_type): def start_subprocess(job_id, cmd, conf, out_file, err_file): logger.info("job run cmd: %s", " ".join(cmd)) - process = subprocess.Popen( # pylint: disable=consider-using-with - cmd, + process = subprocess.Popen( # noqa: SIM115 + cmd, # noqa: S603 env=get_configured_env(job_config=conf), stdout=out_file, stderr=err_file, @@ -148,9 +139,8 @@ def run_ansible(job_id: int) -> None: f"{settings.RUN_DIR}/{job_id}/inventory.json", playbook, ] - if "params" in conf["job"]: - if "ansible_tags" in conf["job"]["params"]: - cmd.append("--tags=" + conf["job"]["params"]["ansible_tags"]) + if "params" in conf["job"] and "ansible_tags" in conf["job"]["params"]: + cmd.append("--tags=" + conf["job"]["params"]["ansible_tags"]) if "verbose" in conf["job"] and conf["job"]["verbose"]: cmd.append("-vvvv") ret = start_subprocess(job_id, cmd, conf, out_file, err_file) @@ -244,7 +234,7 @@ def main(job_id): def do_job(): if len(sys.argv) < 2: - print(f"\nUsage:\n{os.path.basename(sys.argv[0])} job_id\n") + print(f"\nUsage:\n{os.path.basename(sys.argv[0])} job_id\n") # noqa: PTH119 sys.exit(4) else: main(sys.argv[1]) diff --git a/python/manage.py b/python/manage.py index 782789680b..559ddb6f83 100755 --- a/python/manage.py +++ b/python/manage.py @@ -22,12 +22,12 @@ # issue is really that Django is missing to avoid masking other # exceptions on Python 2. try: - import django # pylint: disable=unused-import + import django # noqa: F401 except ImportError: raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?", - ) from None + ) from None # noqa: TRY003 raise execute_from_command_line(sys.argv) diff --git a/python/rbac/apps.py b/python/rbac/apps.py index 2d2f18994c..bad70aebac 100644 --- a/python/rbac/apps.py +++ b/python/rbac/apps.py @@ -18,6 +18,6 @@ class RBACConfig(AppConfig): verbose_name = "Arenadata Web Platform role-based access control" def ready(self): - from rbac.signals import ( # pylint: disable=import-outside-toplevel,unused-import + from rbac.signals import ( # noqa: F401, PLC0415 handle_name_type_display_name, ) diff --git a/python/rbac/endpoints/group/serializers.py b/python/rbac/endpoints/group/serializers.py index c6dcc06f6a..0b2ccac4b1 100644 --- a/python/rbac/endpoints/group/serializers.py +++ b/python/rbac/endpoints/group/serializers.py @@ -10,8 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rbac.models import Group, User -from rbac.services import group as group_services +from adcm.serializers import EmptySerializer from rest_flex_fields.serializers import FlexFieldsSerializerMixin from rest_framework.fields import BooleanField, CharField, IntegerField, RegexField from rest_framework.relations import HyperlinkedIdentityField @@ -21,7 +20,8 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer +from rbac.models import Group, User +from rbac.services import group as group_services class GroupUserSerializer(EmptySerializer): diff --git a/python/rbac/endpoints/group/urls.py b/python/rbac/endpoints/group/urls.py index 945794b0c9..27d89d89d1 100644 --- a/python/rbac/endpoints/group/urls.py +++ b/python/rbac/endpoints/group/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rbac.endpoints.group.views import GroupViewSet from rest_framework.routers import SimpleRouter +from rbac.endpoints.group.views import GroupViewSet + router = SimpleRouter() router.register("", GroupViewSet, basename="group") urlpatterns = router.urls diff --git a/python/rbac/endpoints/group/views.py b/python/rbac/endpoints/group/views.py index 224764eb7c..8d9404c02d 100644 --- a/python/rbac/endpoints/group/views.py +++ b/python/rbac/endpoints/group/views.py @@ -10,17 +10,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.permissions import DjangoModelPermissionsAudit from audit.utils import audit from cm.errors import raise_adcm_ex from django_filters.rest_framework import CharFilter, DjangoFilterBackend, FilterSet from guardian.mixins import PermissionListMixin -from rbac.endpoints.group.serializers import GroupSerializer -from rbac.models import Group from rest_framework.filters import OrderingFilter from rest_framework.schemas.coreapi import AutoSchema from rest_framework.viewsets import ModelViewSet -from adcm.permissions import DjangoModelPermissionsAudit +from rbac.endpoints.group.serializers import GroupSerializer +from rbac.models import Group class GroupFilterSet(FilterSet): @@ -54,7 +54,7 @@ def filter_queryset(self, request, queryset, view): return queryset.order_by(*fix_ordering) -class GroupViewSet(PermissionListMixin, ModelViewSet): # pylint: disable=too-many-ancestors +class GroupViewSet(PermissionListMixin, ModelViewSet): queryset = Group.objects.all() serializer_class = GroupSerializer permission_classes = (DjangoModelPermissionsAudit,) diff --git a/python/rbac/endpoints/logout.py b/python/rbac/endpoints/logout.py index 96837a8112..a6d6fa726f 100644 --- a/python/rbac/endpoints/logout.py +++ b/python/rbac/endpoints/logout.py @@ -10,13 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import django.contrib.auth +from adcm.serializers import EmptySerializer from rest_framework import status from rest_framework.generics import GenericAPIView from rest_framework.response import Response from rest_framework.schemas.coreapi import AutoSchema - -from adcm.serializers import EmptySerializer +import django.contrib.auth class LogOutSerializer(EmptySerializer): @@ -28,7 +27,7 @@ class LogOut(GenericAPIView): schema = AutoSchema() @staticmethod - def post(request, *args, **kwargs): # pylint: disable=unused-argument + def post(request, *args, **kwargs): # noqa: ARG004 django.contrib.auth.logout(request) return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/python/rbac/endpoints/me/serializers.py b/python/rbac/endpoints/me/serializers.py index 07451adf86..afb23e0a1a 100644 --- a/python/rbac/endpoints/me/serializers.py +++ b/python/rbac/endpoints/me/serializers.py @@ -11,9 +11,10 @@ # limitations under the License. -from rbac.models import User from rest_framework.serializers import CharField, ModelSerializer +from rbac.models import User + class MeUserSerializer(ModelSerializer): password = CharField(trim_whitespace=False, required=False, write_only=True) diff --git a/python/rbac/endpoints/me/urls.py b/python/rbac/endpoints/me/urls.py index 3b1e7e9bcc..c83b8d7340 100644 --- a/python/rbac/endpoints/me/urls.py +++ b/python/rbac/endpoints/me/urls.py @@ -11,6 +11,7 @@ # limitations under the License. from django.urls import path + from rbac.endpoints.me.views import MyselfView urlpatterns = [path("", MyselfView.as_view(), name="me")] diff --git a/python/rbac/endpoints/me/views.py b/python/rbac/endpoints/me/views.py index 291e29e7bd..9537967f04 100644 --- a/python/rbac/endpoints/me/views.py +++ b/python/rbac/endpoints/me/views.py @@ -10,11 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +from rest_framework.generics import RetrieveUpdateAPIView +from rest_framework.schemas.coreapi import AutoSchema + from rbac.endpoints.me.serializers import MeUserSerializer from rbac.models import User from rbac.services.user import update_user -from rest_framework.generics import RetrieveUpdateAPIView -from rest_framework.schemas.coreapi import AutoSchema class MyselfView(RetrieveUpdateAPIView): diff --git a/python/rbac/endpoints/policy/serializers.py b/python/rbac/endpoints/policy/serializers.py index 10463277a2..785b7b172e 100644 --- a/python/rbac/endpoints/policy/serializers.py +++ b/python/rbac/endpoints/policy/serializers.py @@ -10,10 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import jsonschema +from adcm.utils import get_obj_type from cm.models import Cluster, ClusterObject, Host, HostProvider, ServiceComponent -from rbac.endpoints.serializers import BaseRelatedSerializer -from rbac.models import Group, Policy, Role, RoleTypes from rest_flex_fields.serializers import FlexFieldsSerializerMixin from rest_framework.exceptions import ValidationError from rest_framework.fields import ( @@ -24,8 +22,10 @@ ) from rest_framework.relations import HyperlinkedIdentityField, PrimaryKeyRelatedField from rest_framework.serializers import ModelSerializer +import jsonschema -from adcm.utils import get_obj_type +from rbac.endpoints.serializers import BaseRelatedSerializer +from rbac.models import Group, Policy, Role, RoleTypes class ObjectField(JSONField): diff --git a/python/rbac/endpoints/policy/urls.py b/python/rbac/endpoints/policy/urls.py index d9fc214b12..47031d892d 100644 --- a/python/rbac/endpoints/policy/urls.py +++ b/python/rbac/endpoints/policy/urls.py @@ -11,9 +11,10 @@ # limitations under the License. # Generated by Django 3.2.7 on 2021-10-26 13:48 -from rbac.endpoints.policy.views import PolicyViewSet from rest_framework.routers import SimpleRouter +from rbac.endpoints.policy.views import PolicyViewSet + router = SimpleRouter() router.register(r"", PolicyViewSet, basename="policy") urlpatterns = router.urls diff --git a/python/rbac/endpoints/policy/views.py b/python/rbac/endpoints/policy/views.py index 11156426ed..4be3205352 100644 --- a/python/rbac/endpoints/policy/views.py +++ b/python/rbac/endpoints/policy/views.py @@ -10,11 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.permissions import DjangoModelPermissionsAudit from audit.utils import audit from guardian.mixins import PermissionListMixin -from rbac.endpoints.policy.serializers import PolicySerializer -from rbac.models import Policy -from rbac.services.policy import policy_create, policy_update from rest_framework.response import Response from rest_framework.schemas.coreapi import AutoSchema from rest_framework.status import ( @@ -24,10 +22,12 @@ ) from rest_framework.viewsets import ModelViewSet -from adcm.permissions import DjangoModelPermissionsAudit +from rbac.endpoints.policy.serializers import PolicySerializer +from rbac.models import Policy +from rbac.services.policy import policy_create, policy_update -class PolicyViewSet(PermissionListMixin, ModelViewSet): # pylint: disable=too-many-ancestors +class PolicyViewSet(PermissionListMixin, ModelViewSet): queryset = Policy.objects.all() serializer_class = PolicySerializer permission_classes = (DjangoModelPermissionsAudit,) @@ -37,14 +37,14 @@ class PolicyViewSet(PermissionListMixin, ModelViewSet): # pylint: disable=too-m schema = AutoSchema() @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) policy = policy_create(**serializer.validated_data) return Response(data=self.get_serializer(policy).data, status=HTTP_201_CREATED) @audit - def update(self, request, *args, **kwargs): + def update(self, request, *args, **kwargs): # noqa: ARG002 partial = kwargs.pop("partial", False) policy = self.get_object() @@ -56,8 +56,7 @@ def update(self, request, *args, **kwargs): policy = policy_update(policy, **serializer.validated_data) return Response(data=self.get_serializer(policy).data) - else: - return Response(data=serializer.errors, status=HTTP_400_BAD_REQUEST) + return Response(data=serializer.errors, status=HTTP_400_BAD_REQUEST) @audit def destroy(self, request, *args, **kwargs): diff --git a/python/rbac/endpoints/role/serializers.py b/python/rbac/endpoints/role/serializers.py index 75a049efbb..65cb994831 100644 --- a/python/rbac/endpoints/role/serializers.py +++ b/python/rbac/endpoints/role/serializers.py @@ -10,13 +10,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rbac.endpoints.serializers import BaseRelatedSerializer -from rbac.models import Role from rest_flex_fields.serializers import FlexFieldsSerializerMixin from rest_framework.fields import RegexField, SerializerMethodField from rest_framework.relations import HyperlinkedIdentityField, PrimaryKeyRelatedField from rest_framework.serializers import ModelSerializer +from rbac.endpoints.serializers import BaseRelatedSerializer +from rbac.models import Role + class RoleChildSerializer(BaseRelatedSerializer): id = PrimaryKeyRelatedField(queryset=Role.objects.all()) diff --git a/python/rbac/endpoints/role/urls.py b/python/rbac/endpoints/role/urls.py index b1fd437318..8919a5eea4 100644 --- a/python/rbac/endpoints/role/urls.py +++ b/python/rbac/endpoints/role/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rbac.endpoints.role.views import RoleViewSet from rest_framework.routers import SimpleRouter +from rbac.endpoints.role.views import RoleViewSet + router = SimpleRouter() router.register(r"", RoleViewSet, basename="role") urlpatterns = router.urls diff --git a/python/rbac/endpoints/role/views.py b/python/rbac/endpoints/role/views.py index 5a2c81a533..d67bdfc835 100644 --- a/python/rbac/endpoints/role/views.py +++ b/python/rbac/endpoints/role/views.py @@ -10,15 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.permissions import DjangoModelPermissionsAudit from audit.utils import audit from cm.models import ProductCategory from django.db.models import Prefetch, Q from django_filters import rest_framework as filters from guardian.mixins import PermissionListMixin from guardian.shortcuts import get_objects_for_user -from rbac.endpoints.role.serializers import RoleSerializer -from rbac.models import Role, RoleTypes -from rbac.services.role import role_create, role_update from rest_flex_fields import is_expanded from rest_framework.decorators import action from rest_framework.response import Response @@ -31,7 +29,9 @@ ) from rest_framework.viewsets import ModelViewSet -from adcm.permissions import DjangoModelPermissionsAudit +from rbac.endpoints.role.serializers import RoleSerializer +from rbac.models import Role, RoleTypes +from rbac.services.role import role_create, role_update class _CategoryFilter(filters.CharFilter): @@ -56,7 +56,7 @@ class Meta: ) -class RoleViewSet(PermissionListMixin, ModelViewSet): # pylint: disable=too-many-ancestors +class RoleViewSet(PermissionListMixin, ModelViewSet): serializer_class = RoleSerializer permission_classes = (DjangoModelPermissionsAudit,) permission_required = ["rbac.view_role"] @@ -65,7 +65,7 @@ class RoleViewSet(PermissionListMixin, ModelViewSet): # pylint: disable=too-man search_fields = ("name", "display_name") schema = AutoSchema() - def get_queryset(self, *args, **kwargs): + def get_queryset(self, *args, **kwargs): # noqa: ARG002 queryset = get_objects_for_user(**self.get_get_objects_for_user_kwargs(Role.objects.all())) if is_expanded(self.request, "child"): return queryset.prefetch_related( @@ -74,17 +74,16 @@ def get_queryset(self, *args, **kwargs): return queryset @audit - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # noqa: ARG002 serializer = self.get_serializer(data=request.data) if serializer.is_valid(raise_exception=True): role = role_create(**serializer.validated_data) return Response(self.get_serializer(role).data, status=HTTP_201_CREATED) - else: - return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) @audit - def update(self, request, *args, **kwargs): + def update(self, request, *args, **kwargs): # noqa: ARG002 partial = kwargs.pop("partial", False) instance = self.get_object() @@ -97,8 +96,7 @@ def update(self, request, *args, **kwargs): role = role_update(instance, partial, **serializer.validated_data) return Response(self.get_serializer(role).data, status=HTTP_200_OK) - else: - return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) @audit def destroy(self, request, *args, **kwargs): @@ -108,5 +106,5 @@ def destroy(self, request, *args, **kwargs): return super().destroy(request, *args, **kwargs) @action(methods=["get"], detail=False) - def category(self, request): # pylint: disable=unused-argument + def category(self, request): # noqa: ARG002 return Response(sorted(b.value for b in ProductCategory.objects.all())) diff --git a/python/rbac/endpoints/serializers.py b/python/rbac/endpoints/serializers.py index 6411a2b5e6..27b48668b1 100644 --- a/python/rbac/endpoints/serializers.py +++ b/python/rbac/endpoints/serializers.py @@ -10,9 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rest_framework.serializers import ValidationError - from adcm.serializers import EmptySerializer +from rest_framework.serializers import ValidationError class BaseRelatedSerializer(EmptySerializer): diff --git a/python/rbac/endpoints/token.py b/python/rbac/endpoints/token.py index ebf189a110..f586841f19 100644 --- a/python/rbac/endpoints/token.py +++ b/python/rbac/endpoints/token.py @@ -12,14 +12,14 @@ """View and serializer for Authentication token""" -import django.contrib.auth -import rest_framework.authtoken.serializers from cm.errors import raise_adcm_ex from rest_framework import authentication, permissions from rest_framework.authtoken.models import Token from rest_framework.generics import GenericAPIView from rest_framework.response import Response from rest_framework.schemas.coreapi import AutoSchema +import django.contrib.auth +import rest_framework.authtoken.serializers class AuthSerializer(rest_framework.authtoken.serializers.AuthTokenSerializer): @@ -47,7 +47,7 @@ class GetAuthToken(GenericAPIView): serializer_class = AuthSerializer schema = AutoSchema() - def post(self, request, *args, **kwargs): # pylint: disable=unused-argument + def post(self, request, *args, **kwargs): # noqa: ARG002 """ Provide authentication token diff --git a/python/rbac/endpoints/user/serializers.py b/python/rbac/endpoints/user/serializers.py index a9a77be71b..3334568937 100644 --- a/python/rbac/endpoints/user/serializers.py +++ b/python/rbac/endpoints/user/serializers.py @@ -11,9 +11,8 @@ # limitations under the License. +from adcm.serializers import EmptySerializer from django.conf import settings -from rbac.models import Group, User -from rbac.services.user import create_user, update_user from rest_flex_fields.serializers import FlexFieldsSerializerMixin from rest_framework.fields import ( BooleanField, @@ -30,7 +29,8 @@ SerializerMethodField, ) -from adcm.serializers import EmptySerializer +from rbac.models import Group, User +from rbac.services.user import create_user, update_user class UserGroupSerializer(EmptySerializer): diff --git a/python/rbac/endpoints/user/urls.py b/python/rbac/endpoints/user/urls.py index 0a328186b3..88b7c4bb3b 100644 --- a/python/rbac/endpoints/user/urls.py +++ b/python/rbac/endpoints/user/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rbac.endpoints.user.views import UserViewSet from rest_framework.routers import SimpleRouter +from rbac.endpoints.user.views import UserViewSet + router = SimpleRouter() router.register("", UserViewSet) urlpatterns = router.urls diff --git a/python/rbac/endpoints/user/views.py b/python/rbac/endpoints/user/views.py index 9db620a816..f6c0b515e8 100644 --- a/python/rbac/endpoints/user/views.py +++ b/python/rbac/endpoints/user/views.py @@ -10,11 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.permissions import DjangoModelPermissionsAudit from audit.utils import audit from cm.errors import raise_adcm_ex from guardian.mixins import PermissionListMixin -from rbac.endpoints.user.serializers import UserSerializer -from rbac.models import User from rest_framework.decorators import action from rest_framework.request import Request from rest_framework.response import Response @@ -22,10 +21,11 @@ from rest_framework.status import HTTP_400_BAD_REQUEST from rest_framework.viewsets import ModelViewSet -from adcm.permissions import DjangoModelPermissionsAudit +from rbac.endpoints.user.serializers import UserSerializer +from rbac.models import User -class UserViewSet(PermissionListMixin, ModelViewSet): # pylint: disable=too-many-ancestors +class UserViewSet(PermissionListMixin, ModelViewSet): queryset = User.objects.prefetch_related("groups").all() serializer_class = UserSerializer permission_classes = (DjangoModelPermissionsAudit,) diff --git a/python/rbac/endpoints_ui/role/urls.py b/python/rbac/endpoints_ui/role/urls.py index 73ad6b60b6..807b22850b 100644 --- a/python/rbac/endpoints_ui/role/urls.py +++ b/python/rbac/endpoints_ui/role/urls.py @@ -10,9 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rbac.endpoints_ui.role.views import RoleViewSet from rest_framework.routers import SimpleRouter +from rbac.endpoints_ui.role.views import RoleViewSet + router = SimpleRouter() router.register("", RoleViewSet, basename="role") urlpatterns = router.urls diff --git a/python/rbac/endpoints_ui/role/views.py b/python/rbac/endpoints_ui/role/views.py index a28f8c6053..1372e12eaf 100644 --- a/python/rbac/endpoints_ui/role/views.py +++ b/python/rbac/endpoints_ui/role/views.py @@ -12,10 +12,10 @@ from collections import defaultdict +from adcm.permissions import DjangoObjectPermissionsAudit +from adcm.serializers import EmptySerializer from api.base_view import GenericUIViewSet from cm.models import Cluster, ClusterObject, Host, HostProvider, ObjectType -from rbac.models import ObjectType as RBACObjectType -from rbac.models import Role, RoleTypes from rest_framework.decorators import action from rest_framework.mixins import ListModelMixin from rest_framework.response import Response @@ -26,8 +26,8 @@ JSONField, ) -from adcm.permissions import DjangoObjectPermissionsAudit -from adcm.serializers import EmptySerializer +from rbac.models import ObjectType as RBACObjectType +from rbac.models import Role, RoleTypes class RoleUISerializer(EmptySerializer): @@ -43,7 +43,7 @@ class RoleViewSet(ListModelMixin, GenericUIViewSet): permission_classes = (DjangoObjectPermissionsAudit,) @action(methods=["get"], detail=True) - def object_candidate(self, request, **kwargs): # pylint: disable=unused-argument + def object_candidate(self, request, **kwargs): # noqa: ARG002 role = self.get_object() if role.type != RoleTypes.ROLE: return Response({"cluster": [], "provider": [], "service": [], "host": []}) diff --git a/python/rbac/ldap.py b/python/rbac/ldap.py index 2a5a04353b..23b4564903 100644 --- a/python/rbac/ldap.py +++ b/python/rbac/ldap.py @@ -11,11 +11,10 @@ # limitations under the License. +from contextlib import contextmanager, suppress import os import re -from contextlib import contextmanager, suppress -import ldap from cm.adcm_config.ansible import ansible_decrypt from cm.errors import raise_adcm_ex from cm.logger import logger @@ -24,6 +23,8 @@ from django.db.transaction import atomic from django_auth_ldap.backend import LDAPBackend, _LDAPUser from django_auth_ldap.config import LDAPSearch, MemberDNGroupType +import ldap + from rbac.models import Group, OriginType, User CERT_ENV_KEY = "LDAPTLS_CACERT" @@ -40,9 +41,8 @@ def _process_extra_filter(filterstr: str) -> str: # simple single filter ex: `primaryGroupID=513` if "(" not in filterstr and ")" not in filterstr: return f"({filterstr})" - else: - # assume that composed filter is syntactically valid - return filterstr + # assume that composed filter is syntactically valid + return filterstr def configure_tls( @@ -185,7 +185,7 @@ def get_ldap_default_settings() -> tuple[dict, str | None]: if is_tls(ldap_config["ldap_uri"]): cert_filepath = ldap_config.get("tls_ca_cert_file", "") - if not cert_filepath or not os.path.exists(cert_filepath): + if not cert_filepath or not os.path.exists(cert_filepath): # noqa: PTH110 msg = "NO_CERT_FILE" logger.warning(msg) return {}, msg @@ -211,10 +211,9 @@ def authenticate_ldap_user(self, ldap_user: User | _LDAPUser, password: str) -> try: if not self._check_user(ldap_user): return None - # pylint: disable=protected-access user_local_groups = self._get_local_groups_by_username(ldap_user._username) user_or_none = super().authenticate_ldap_user(ldap_user, password) - except Exception as e: # pylint: disable=broad-except + except Exception as e: # noqa: BLE001 logger.exception(e) return None @@ -232,11 +231,9 @@ def _group_search_enabled(self) -> bool: @staticmethod def _get_local_groups_by_username(username: str) -> list[Group]: - groups = [] with suppress(User.DoesNotExist): user = User.objects.get(username__iexact=username, type=OriginType.LDAP) - groups = [g.group for g in user.groups.order_by("id") if g.group.type == OriginType.LOCAL] - return groups + return [g.group for g in user.groups.order_by("id") if g.group.type == OriginType.LOCAL] def get_user_model(self) -> type[User]: return User @@ -292,7 +289,7 @@ def _check_user(self, ldap_user: _LDAPUser) -> bool: user_dn = ldap_user.dn if user_dn is None: return False - username = ldap_user._username # pylint: disable=protected-access + username = ldap_user._username if User.objects.filter(username__iexact=username, type=OriginType.LOCAL).exists(): logger.exception("usernames collision: `%s`", username) @@ -310,10 +307,8 @@ def _check_user(self, ldap_user: _LDAPUser) -> bool: @staticmethod def _get_ldap_group_dn(group_name: str, ldap_groups: list) -> str: - group_dn = "" with suppress(IndexError): - group_dn = [i for i in ldap_groups if i[0] == group_name][0][1] - return group_dn + return [i for i in ldap_groups if i[0] == group_name][0][1] @staticmethod def _get_rbac_group(group: Group | DjangoGroup, ldap_group_dn: str) -> Group: @@ -322,17 +317,16 @@ def _get_rbac_group(group: Group | DjangoGroup, ldap_group_dn: str) -> Group: """ if isinstance(group, Group): return group - elif isinstance(group, DjangoGroup): + elif isinstance(group, DjangoGroup): # noqa: RET505 try: # maybe we'll need more accurate filtering here return Group.objects.get(name=f"{group.name} [{OriginType.LDAP.value}]", type=OriginType.LDAP.value) except Group.DoesNotExist: with atomic(): - rbac_group = Group.objects.create( + return Group.objects.create( name=group.name, type=OriginType.LDAP, description=ldap_group_dn, ) - return rbac_group else: - raise ValueError("wrong group type") + raise TypeError("wrong group type") diff --git a/python/rbac/management/commands/createsuperuser.py b/python/rbac/management/commands/createsuperuser.py index 6e21b51c50..69aaf8e943 100644 --- a/python/rbac/management/commands/createsuperuser.py +++ b/python/rbac/management/commands/createsuperuser.py @@ -15,6 +15,7 @@ from django.contrib.auth.management.commands.createsuperuser import ( Command as AuthCommand, ) + from rbac.models import User diff --git a/python/rbac/management/commands/role_map.py b/python/rbac/management/commands/role_map.py index eab01f0a41..384b0383e4 100644 --- a/python/rbac/management/commands/role_map.py +++ b/python/rbac/management/commands/role_map.py @@ -14,18 +14,18 @@ from django.conf import settings from django.core.management.base import BaseCommand from django.db.models import Subquery + from rbac.models import Role def read_role(role: Role) -> dict: - data = { + return { "name": role.name, "type": role.type, "parametrized_by_type": role.parametrized_by_type, "category": [c.value for c in role.category.all()], "child": [read_role(r) for r in role.child.all()], } - return data class Command(BaseCommand): @@ -45,7 +45,7 @@ def add_arguments(self, parser): help="Specifies file to which the output is written.", ) - def handle(self, *args, **options): + def handle(self, *args, **options): # noqa: ARG002 indent = options["indent"] output = options["output"] data = [] @@ -57,6 +57,6 @@ def handle(self, *args, **options): ): data.append(read_role(role)) - with open(output, "w", encoding=settings.ENCODING_UTF_8) as f: + with open(output, mode="w", encoding=settings.ENCODING_UTF_8) as f: json.dump(data, f, indent=indent) self.stdout.write(self.style.SUCCESS(f"Result file: {output}")) diff --git a/python/rbac/management/commands/upgraderole.py b/python/rbac/management/commands/upgraderole.py index a901b7c702..0ad71ac75b 100644 --- a/python/rbac/management/commands/upgraderole.py +++ b/python/rbac/management/commands/upgraderole.py @@ -14,6 +14,7 @@ from cm.errors import AdcmEx from django.core.management.base import BaseCommand, CommandError + from rbac.upgrade.role import init_roles @@ -27,7 +28,7 @@ class Command(BaseCommand): help = "Upgrade roles" - def handle(self, *args, **options): + def handle(self, *args, **options): # noqa: ARG002 """Handler method""" try: msg = init_roles() diff --git a/python/rbac/models.py b/python/rbac/models.py index ac0e88c6ae..f15486555d 100644 --- a/python/rbac/models.py +++ b/python/rbac/models.py @@ -40,9 +40,10 @@ ) from django.db.transaction import atomic from guardian.models import GroupObjectPermission -from rbac.utils import get_query_tuple_str from rest_framework.exceptions import ValidationError +from rbac.utils import get_query_tuple_str + class ObjectType(TextChoices): CLUSTER = "cluster", "cluster" @@ -171,9 +172,7 @@ def get_permissions(self, role: "Role" = None): """, params=[role.id], ) - permissions = list(Permission.objects.filter(role__in=role_list).distinct()) - - return permissions + return list(Permission.objects.filter(role__in=role_list).distinct()) class RoleMigration(Model): @@ -228,7 +227,7 @@ def remove_permissions(self): SELECT policypermission_id FROM rbac_policy_model_perm WHERE policypermission_id in {get_query_tuple_str(tuple_items=permission_ids_to_delete)} AND policy_id != {self.pk}; - """ + """ # noqa: S608, W291 ) permission_ids_to_keep = {item[0] for item in cursor.fetchall()} @@ -247,7 +246,7 @@ def remove_permissions(self): SELECT permission_id FROM rbac_policypermission WHERE group_id IS NOT NULL AND id IN {permission_ids_to_delete_str} ) AND group_id IN {get_query_tuple_str(tuple_items=tuple(group_pks))}; - """, + """, # noqa: S608, W291 ) cursor.execute( @@ -262,7 +261,7 @@ def remove_permissions(self): DELETE FROM rbac_policypermission WHERE (user_id IS NOT NULL OR group_id IS NOT NULL) AND id IN {get_query_tuple_str(tuple_items=permission_ids_to_delete)}; - """, + """, # noqa: S608, W291 ) cursor.execute( @@ -281,7 +280,7 @@ def remove_permissions(self): WHERE groupobjectpermission_id in {get_query_tuple_str(tuple_items=groupobj_permission_ids_to_delete)} AND policy_id != {self.pk}; - """ + """ # noqa: S608, W291 ) groupobj_permission_ids_to_keep = {item[0] for item in cursor.fetchall()} @@ -301,11 +300,11 @@ def remove_permissions(self): f""" DELETE FROM rbac_policy_group_object_perm WHERE groupobjectpermission_id IN {groupobj_permission_ids_to_delete_str}; - """, + """, # noqa: S608, W291 ) cursor.execute( - f"DELETE FROM guardian_groupobjectpermission WHERE id IN {groupobj_permission_ids_to_delete_str};", + f"DELETE FROM guardian_groupobjectpermission WHERE id IN {groupobj_permission_ids_to_delete_str};", # noqa: S608, W291 ) def add_object(self, obj) -> None: @@ -344,10 +343,7 @@ def apply(self): def get_objects_for_policy(obj: ADCMEntity) -> dict[ADCMEntity, ContentType]: obj_type_map = {} - if hasattr(obj, "prototype"): - obj_type = obj.prototype.type - else: - obj_type = None + obj_type = obj.prototype.type if hasattr(obj, "prototype") else None if obj_type == "component": object_list = [obj, obj.service, obj.cluster] diff --git a/python/rbac/roles.py b/python/rbac/roles.py index 1fb81b3936..815b6efab5 100644 --- a/python/rbac/roles.py +++ b/python/rbac/roles.py @@ -30,6 +30,7 @@ from django.db.models import QuerySet from django.db.transaction import atomic from guardian.models import GroupObjectPermission + from rbac.models import ( Permission, Policy, @@ -61,7 +62,7 @@ def apply(self, policy: Policy, role: Role, param_obj=None) -> None: class ModelRole(AbstractRole): - def apply(self, policy: Policy, role: Role, param_obj=None) -> None: + def apply(self, policy: Policy, role: Role, param_obj=None) -> None: # noqa: ARG002 for perm in role.get_permissions(): for group in policy.group.all(): group.permissions.add(perm) @@ -337,7 +338,7 @@ def apply( policy: Policy, role: Role, param_obj=None, - ): # pylint: disable=too-many-branches, too-many-nested-blocks + ): for child_role in role.child.filter(class_name__in=("ModelRole", "ParentRole")): child_role.apply(policy=policy, obj=param_obj) diff --git a/python/rbac/services/group.py b/python/rbac/services/group.py index ca3effb275..3329765fed 100644 --- a/python/rbac/services/group.py +++ b/python/rbac/services/group.py @@ -16,6 +16,7 @@ from cm.errors import raise_adcm_ex from django.core.exceptions import ObjectDoesNotExist from django.db import IntegrityError, transaction + from rbac import models from rbac.utils import Empty, set_not_empty_attr diff --git a/python/rbac/services/policy.py b/python/rbac/services/policy.py index cfae9f45a0..6a85ac19e8 100644 --- a/python/rbac/services/policy.py +++ b/python/rbac/services/policy.py @@ -15,6 +15,7 @@ from django.contrib.contenttypes.models import ContentType from django.db import IntegrityError from django.db.transaction import atomic + from rbac.models import Group, Policy, PolicyObject, Role @@ -64,7 +65,7 @@ def policy_create(name: str, role: Role, built_in: bool = False, **kwargs) -> Po policy.apply() - return policy + return policy # noqa: TRY300 except IntegrityError as e: raise AdcmEx(code="POLICY_CREATE_ERROR", msg=f"Policy creation failed with error {e}") from e diff --git a/python/rbac/services/role.py b/python/rbac/services/role.py index 00af3e8ab6..8be9173213 100644 --- a/python/rbac/services/role.py +++ b/python/rbac/services/role.py @@ -13,9 +13,10 @@ from cm.errors import raise_adcm_ex from django.db import IntegrityError from django.db.transaction import atomic -from rbac.models import Role, RoleTypes from rest_framework.exceptions import ValidationError +from rbac.models import Role, RoleTypes + def check_role_child(child: list[Role], partial=False): param_set = set() @@ -65,7 +66,7 @@ def role_create(built_in=False, type_of_role=RoleTypes.ROLE, **kwargs) -> Role | ) role.child.add(*child) - return role + return role # noqa: TRY300 except IntegrityError: raise_adcm_ex("ROLE_CREATE_ERROR") diff --git a/python/rbac/services/user.py b/python/rbac/services/user.py index f643fc77ef..ec9170bd00 100644 --- a/python/rbac/services/user.py +++ b/python/rbac/services/user.py @@ -14,10 +14,11 @@ from django.contrib.auth.password_validation import validate_password from django.core.exceptions import ObjectDoesNotExist from django.db import IntegrityError, transaction +from rest_framework.authtoken.models import Token + from rbac.models import Group, OriginType, User from rbac.utils import Empty, set_not_empty_attr from rbac.validators import ADCMLengthPasswordValidator -from rest_framework.authtoken.models import Token def _set_password(user: User, value: str) -> None: @@ -90,8 +91,6 @@ def update_user( groups: list = Empty, is_active: bool = Empty, ) -> User: - # pylint: disable=too-many-locals - if (username is not Empty) and (username != user.username): raise AdcmEx(code="USER_CONFLICT", msg="Username could not be changed") @@ -159,10 +158,7 @@ def create_user( groups: list = None, is_active: bool = True, ) -> User: - if is_superuser: - func = User.objects.create_superuser - else: - func = User.objects.create_user + func = User.objects.create_superuser if is_superuser else User.objects.create_user user_exist = User.objects.filter(email=email).exists() if user_exist and (email != ""): diff --git a/python/rbac/settings.py b/python/rbac/settings.py index 89c1aa0f2c..e2e92bb2eb 100644 --- a/python/rbac/settings.py +++ b/python/rbac/settings.py @@ -29,14 +29,14 @@ from django.conf import settings from django.test.signals import setting_changed -BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # noqa: PTH120, PTH100 DEFAULTS = { # File with role specification - "ROLE_SPEC": os.path.join(BASE_DIR, "upgrade", "role_spec.yaml"), + "ROLE_SPEC": os.path.join(BASE_DIR, "upgrade", "role_spec.yaml"), # noqa: PTH118 # Schema for role specification file - "ROLE_SCHEMA": os.path.join(BASE_DIR, "upgrade", "role_schema.yaml"), + "ROLE_SCHEMA": os.path.join(BASE_DIR, "upgrade", "role_schema.yaml"), # noqa: PTH118 } @@ -89,7 +89,7 @@ def reload(self): api_settings = APISettings(None, DEFAULTS) -def reload_api_settings(*args, **kwargs): # pylint: disable=unused-argument +def reload_api_settings(*args, **kwargs): # noqa: ARG001 setting = kwargs["setting"] if setting == "ADWP_RBAC": api_settings.reload() diff --git a/python/rbac/signals.py b/python/rbac/signals.py index 9d3c53dd21..a628674f1d 100644 --- a/python/rbac/signals.py +++ b/python/rbac/signals.py @@ -15,11 +15,12 @@ from cm.errors import raise_adcm_ex from django.db.models.signals import pre_save from django.dispatch import receiver + from rbac.models import Group, OriginType @receiver(signal=pre_save, sender=Group) -def handle_name_type_display_name(sender, instance, **kwargs): # pylint: disable=unused-argument +def handle_name_type_display_name(sender, instance, **kwargs): # noqa: ARG001 if kwargs["raw"]: return diff --git a/python/rbac/tests/test_api.py b/python/rbac/tests/test_api.py index 4518d12b73..a03873bda8 100644 --- a/python/rbac/tests/test_api.py +++ b/python/rbac/tests/test_api.py @@ -11,13 +11,13 @@ # limitations under the License. -from rbac.models import Policy, Role +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from rest_framework import status from rest_framework.response import Response from rest_framework.reverse import reverse from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from rbac.models import Policy, Role class ApiTests(BaseTestCase): @@ -327,7 +327,7 @@ def test_patch_empty_role_id(self): self.assertEqual(response.status_code, HTTP_200_OK) - response = self.client.patch(path=path, data={**data_valid, **{"role": {}}}, content_type=APPLICATION_JSON) + response = self.client.patch(path=path, data={**data_valid, **{"role": {}}}, content_type=APPLICATION_JSON) # noqa: PIE800 self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) self.assertEqual(response.json()["desc"], "role - This field may not be empty.;") diff --git a/python/rbac/tests/test_base.py b/python/rbac/tests/test_base.py index 1bbc5b8ee7..b8f36615ea 100644 --- a/python/rbac/tests/test_base.py +++ b/python/rbac/tests/test_base.py @@ -10,12 +10,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import Bundle, Prototype from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType -from rbac.models import Role -from adcm.tests.base import BaseTestCase +from rbac.models import Role def cook_perm(codename, model, app="cm"): @@ -38,7 +38,7 @@ def cook_role(name, class_name, obj_type=None): ) -class RBACBaseTestCase(BaseTestCase): # pylint: disable=too-many-instance-attributes +class RBACBaseTestCase(BaseTestCase): def setUp(self) -> None: super().setUp() self.create_bundles_and_prototypes() diff --git a/python/rbac/tests/test_group.py b/python/rbac/tests/test_group.py index 9aeb7c481b..22e3467b86 100644 --- a/python/rbac/tests/test_group.py +++ b/python/rbac/tests/test_group.py @@ -10,11 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.errors import AdcmEx from django.contrib.auth.models import Group as AuthGroup -from rbac.models import Group, OriginType -from adcm.tests.base import BaseTestCase +from rbac.models import Group, OriginType class GroupTestCase(BaseTestCase): diff --git a/python/rbac/tests/test_policy/base.py b/python/rbac/tests/test_policy/base.py index ad2c5b7b34..3591319594 100644 --- a/python/rbac/tests/test_policy/base.py +++ b/python/rbac/tests/test_policy/base.py @@ -10,13 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import BaseTestCase from cm.models import Bundle, ClusterObject, Host, ObjectType, Prototype -from rbac.models import Group -from adcm.tests.base import BaseTestCase +from rbac.models import Group -class PolicyBaseTestCase(BaseTestCase): # pylint: disable=too-many-instance-attributes +class PolicyBaseTestCase(BaseTestCase): def setUp(self) -> None: super().setUp() diff --git a/python/rbac/tests/test_policy/test_cluster_admin_role.py b/python/rbac/tests/test_policy/test_cluster_admin_role.py index 93a8fa8541..9ed5805f0a 100644 --- a/python/rbac/tests/test_policy/test_cluster_admin_role.py +++ b/python/rbac/tests/test_policy/test_cluster_admin_role.py @@ -12,9 +12,9 @@ from unittest.mock import patch +from adcm.tests.base import APPLICATION_JSON from cm.models import Action, Host from django.urls import reverse -from rbac.tests.test_policy.base import PolicyBaseTestCase from rest_framework.response import Response from rest_framework.status import ( HTTP_200_OK, @@ -24,7 +24,7 @@ HTTP_404_NOT_FOUND, ) -from adcm.tests.base import APPLICATION_JSON +from rbac.tests.test_policy.base import PolicyBaseTestCase class PolicyWithClusterAdminRoleTestCase(PolicyBaseTestCase): @@ -35,7 +35,7 @@ def setUp(self) -> None: self.another_user_log_in(username=self.new_user.username, password=self.new_user_password) - def test_policy_with_cluster_admin_role(self): # pylint: disable=too-many-statements + def test_policy_with_cluster_admin_role(self): required_perms = {perm.codename for perm in self.new_user_group.permissions.all()} required_perms.update( {perm.permission.codename for perm in self.new_user_group.groupobjectpermission_set.all()} diff --git a/python/rbac/tests/test_policy/test_cluster_admin_service_admin_hostcomponent.py b/python/rbac/tests/test_policy/test_cluster_admin_service_admin_hostcomponent.py index f55420dc41..6b00e2a39a 100644 --- a/python/rbac/tests/test_policy/test_cluster_admin_service_admin_hostcomponent.py +++ b/python/rbac/tests/test_policy/test_cluster_admin_service_admin_hostcomponent.py @@ -11,14 +11,14 @@ # limitations under the License. +from adcm.tests.base import APPLICATION_JSON from cm.models import ClusterObject, Host, ServiceComponent from django.urls import reverse -from rbac.models import Group -from rbac.tests.test_policy.base import PolicyBaseTestCase from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED -from adcm.tests.base import APPLICATION_JSON +from rbac.models import Group +from rbac.tests.test_policy.base import PolicyBaseTestCase class ClusterAdminServiceAdminHostcomponentTestCase(PolicyBaseTestCase): diff --git a/python/rbac/tests/test_policy/test_group_policy.py b/python/rbac/tests/test_policy/test_group_policy.py index 3995503d37..389c743987 100644 --- a/python/rbac/tests/test_policy/test_group_policy.py +++ b/python/rbac/tests/test_policy/test_group_policy.py @@ -12,13 +12,13 @@ from pathlib import Path +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import Action, ConfigLog, ObjectType, ServiceComponent from django.urls import reverse -from rbac.models import Group from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from rbac.models import Group class GroupPolicyTestCase(BaseTestCase): diff --git a/python/rbac/tests/test_policy/test_no_right_user_have_no_access.py b/python/rbac/tests/test_policy/test_no_right_user_have_no_access.py index beff2e3d07..1febd8c7b4 100644 --- a/python/rbac/tests/test_policy/test_no_right_user_have_no_access.py +++ b/python/rbac/tests/test_policy/test_no_right_user_have_no_access.py @@ -10,13 +10,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import APPLICATION_JSON from cm.models import MaintenanceMode from django.urls import reverse -from rbac.tests.test_policy.base import PolicyBaseTestCase from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND -from adcm.tests.base import APPLICATION_JSON +from rbac.tests.test_policy.base import PolicyBaseTestCase class PolicyNoRightsUserHaveNoAccessTestCase(PolicyBaseTestCase): @@ -25,7 +25,7 @@ def setUp(self) -> None: self.another_user_log_in(username=self.new_user.username, password=self.new_user_password) - def test_no_rights_user_have_no_access(self): # pylint: disable=too-many-statements + def test_no_rights_user_have_no_access(self): response: Response = self.client.get( path=reverse(viewname="v1:cluster-details", kwargs={"cluster_id": self.cluster.pk}), ) diff --git a/python/rbac/tests/test_policy/test_permissions.py b/python/rbac/tests/test_policy/test_permissions.py index 5cd1283279..2fefb91b79 100644 --- a/python/rbac/tests/test_policy/test_permissions.py +++ b/python/rbac/tests/test_policy/test_permissions.py @@ -12,6 +12,7 @@ from django.contrib.auth.models import Group, Permission from guardian.models import GroupObjectPermission + from rbac.models import Group as RBACGroup from rbac.models import Policy from rbac.roles import assign_group_perm diff --git a/python/rbac/tests/test_policy/test_policy_cluster_admin_role_upgrade.py b/python/rbac/tests/test_policy/test_policy_cluster_admin_role_upgrade.py index a005c3a9a7..8ef3b54b25 100644 --- a/python/rbac/tests/test_policy/test_policy_cluster_admin_role_upgrade.py +++ b/python/rbac/tests/test_policy/test_policy_cluster_admin_role_upgrade.py @@ -12,13 +12,13 @@ from unittest.mock import patch +from adcm.tests.base import APPLICATION_JSON from cm.models import ServiceComponent, Upgrade from django.urls import reverse -from rbac.tests.test_policy.base import PolicyBaseTestCase from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.tests.base import APPLICATION_JSON +from rbac.tests.test_policy.base import PolicyBaseTestCase class PolicyWithClusterAdminRoleUpgradeTestCase(PolicyBaseTestCase): diff --git a/python/rbac/tests/test_policy/test_policy_delete.py b/python/rbac/tests/test_policy/test_policy_delete.py index 7a01a6ca3d..68b5c510b6 100644 --- a/python/rbac/tests/test_policy/test_policy_delete.py +++ b/python/rbac/tests/test_policy/test_policy_delete.py @@ -12,10 +12,11 @@ from cm.models import ObjectType from django.urls import reverse -from rbac.tests.test_policy.base import PolicyBaseTestCase from rest_framework.response import Response from rest_framework.status import HTTP_204_NO_CONTENT +from rbac.tests.test_policy.base import PolicyBaseTestCase + APPLICATION_JSON = "application/json" diff --git a/python/rbac/tests/test_policy/test_provider_admin_role.py b/python/rbac/tests/test_policy/test_provider_admin_role.py index dcda111dd3..d3decdb3a6 100644 --- a/python/rbac/tests/test_policy/test_provider_admin_role.py +++ b/python/rbac/tests/test_policy/test_provider_admin_role.py @@ -12,14 +12,14 @@ from unittest.mock import patch +from adcm.tests.base import APPLICATION_JSON from cm.models import ConfigLog, Host from django.db.models import ObjectDoesNotExist from django.urls import reverse -from rbac.tests.test_policy.base import PolicyBaseTestCase from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT -from adcm.tests.base import APPLICATION_JSON +from rbac.tests.test_policy.base import PolicyBaseTestCase class PolicyWithProviderAdminRole(PolicyBaseTestCase): diff --git a/python/rbac/tests/test_policy/test_rbac.py b/python/rbac/tests/test_policy/test_rbac.py index 282eaafd19..0bf349f335 100644 --- a/python/rbac/tests/test_policy/test_rbac.py +++ b/python/rbac/tests/test_policy/test_rbac.py @@ -19,11 +19,12 @@ Prototype, ServiceComponent, ) + from rbac.models import Group, Policy, User from rbac.tests.test_base import RBACBaseTestCase -class PolicyRBACTestCase(RBACBaseTestCase): # pylint: disable=too-many-instance-attributes +class PolicyRBACTestCase(RBACBaseTestCase): """Tests for applying policy with different combination of roles and object""" def setUp(self) -> None: diff --git a/python/rbac/tests/test_policy/test_remove_user_from_policy.py b/python/rbac/tests/test_policy/test_remove_user_from_policy.py index b524a0ca59..c0e81091ad 100644 --- a/python/rbac/tests/test_policy/test_remove_user_from_policy.py +++ b/python/rbac/tests/test_policy/test_remove_user_from_policy.py @@ -12,16 +12,16 @@ from cm.models import ClusterObject, ObjectType from django.urls import reverse -from rbac.models import Group -from rbac.tests.test_policy.base import PolicyBaseTestCase from rest_framework.response import Response from rest_framework.status import HTTP_200_OK +from rbac.models import Group +from rbac.tests.test_policy.base import PolicyBaseTestCase + APPLICATION_JSON = "application/json" class RemoveUserFromPolicyTestCase(PolicyBaseTestCase): - # pylint: disable=too-many-instance-attributes def setUp(self) -> None: super().setUp() diff --git a/python/rbac/tests/test_policy/test_service_admin_role.py b/python/rbac/tests/test_policy/test_service_admin_role.py index ed895f7422..ab1d43627f 100644 --- a/python/rbac/tests/test_policy/test_service_admin_role.py +++ b/python/rbac/tests/test_policy/test_service_admin_role.py @@ -10,6 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ( ClusterObject, ObjectConfig, @@ -18,11 +19,10 @@ ServiceComponent, ) from django.urls import reverse -from rbac.models import Group from rest_framework.response import Response from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from rbac.models import Group class PolicyWithServiceAdminRoleTestCase(BaseTestCase): diff --git a/python/rbac/tests/test_role.py b/python/rbac/tests/test_role.py index d14ce51f67..9cd3b162c5 100644 --- a/python/rbac/tests/test_role.py +++ b/python/rbac/tests/test_role.py @@ -10,9 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import hashlib import json +import hashlib +from adcm.permissions import check_custom_perm +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.api import add_host_to_cluster from cm.errors import AdcmEx from cm.models import ( @@ -32,17 +34,15 @@ from django.contrib.contenttypes.models import ContentType from django.urls import reverse from init_db import init as init_adcm +from rest_framework.exceptions import PermissionDenied +from rest_framework.status import HTTP_404_NOT_FOUND + from rbac.models import Role, RoleTypes from rbac.roles import ModelRole from rbac.services.policy import policy_create from rbac.services.role import role_create from rbac.tests.test_base import RBACBaseTestCase from rbac.upgrade.role import prepare_action_roles -from rest_framework.exceptions import PermissionDenied -from rest_framework.status import HTTP_404_NOT_FOUND - -from adcm.permissions import check_custom_perm -from adcm.tests.base import APPLICATION_JSON, BaseTestCase class RoleModelTest(BaseTestCase): @@ -247,7 +247,7 @@ def setUp(self): ) def make_roles_list(self): - roles = [ + return [ # hidden action roles { "name": "sample_bundle_1.0_community_cluster_Sample Cluster_cluster_action", @@ -472,8 +472,6 @@ def make_roles_list(self): }, ] - return roles - def test_cook_roles(self): prepare_action_roles(self.bundle_1) @@ -574,7 +572,6 @@ def check_roles(self): self.assertEqual(sa_role_count, 6, "Roles missing from base roles") -# pylint: disable=protected-access class TestMMRoles(RBACBaseTestCase): def setUp(self) -> None: super().setUp() diff --git a/python/rbac/tests/test_spec.py b/python/rbac/tests/test_spec.py index 86ae420801..79cf921893 100644 --- a/python/rbac/tests/test_spec.py +++ b/python/rbac/tests/test_spec.py @@ -11,12 +11,12 @@ # limitations under the License. -import os from pathlib import Path +import os -import ruyaml from django.conf import settings from django.test import TestCase +import ruyaml MANDATORY_KEYS = ["name", "type", "module_name", "class_name"] @@ -37,7 +37,7 @@ class TestRoleSpecification(TestCase): def setUp(self) -> None: - with open(Path(os.path.dirname(__file__), "../upgrade/role_spec.yaml"), encoding=settings.ENCODING_UTF_8) as f: + with Path(os.path.dirname(__file__), "../upgrade/role_spec.yaml").open(encoding=settings.ENCODING_UTF_8) as f: self.spec_data: dict = ruyaml.YAML().load(f) self.role_map: dict = {role["name"]: role for role in self.spec_data["roles"]} self.roots = self.role_map.copy() @@ -64,17 +64,12 @@ def test_children(self): @staticmethod def _is_in_set(allowed: list[set[str]], value: set): - for allowed_value in allowed: - if allowed_value == value: - return True - - return False + return any(allowed_value == value for allowed_value in allowed) def test_allowed_parametrization(self): for value in self.role_map.values(): - if "parametrized_by" in value: - if value["type"] == "business": - self.assertTrue(self._is_in_set(BUSINESS_PARAMETRISATION, set(value["parametrized_by"]))) + if "parametrized_by" in value and value["type"] == "business": + self.assertTrue(self._is_in_set(BUSINESS_PARAMETRISATION, set(value["parametrized_by"]))) def _tree_dive_in(self, roles: dict, visited: dict, path: list, role: dict, root): if role["name"] in visited: diff --git a/python/rbac/tests/test_user.py b/python/rbac/tests/test_user.py index 157dc84422..eb42905d1a 100644 --- a/python/rbac/tests/test_user.py +++ b/python/rbac/tests/test_user.py @@ -12,12 +12,12 @@ from datetime import timedelta +from adcm.tests.base import APPLICATION_JSON, BaseTestCase from cm.models import ADCM, ConfigLog from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.urls import reverse from django.utils import timezone -from rbac.models import OriginType, User from rest_framework.response import Response from rest_framework.status import ( HTTP_200_OK, @@ -28,7 +28,7 @@ HTTP_409_CONFLICT, ) -from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from rbac.models import OriginType, User class BaseUserTestCase(BaseTestCase): diff --git a/python/rbac/upgrade/role.py b/python/rbac/upgrade/role.py index 576dcd553d..142d2197e6 100644 --- a/python/rbac/upgrade/role.py +++ b/python/rbac/upgrade/role.py @@ -19,12 +19,13 @@ from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.db import transaction -from rbac.models import Permission, Policy, Role, RoleMigration, RoleTypes -from rbac.settings import api_settings from ruyaml import round_trip_load from ruyaml.parser import ParserError from ruyaml.scanner import ScannerError +from rbac.models import Permission, Policy, Role, RoleMigration, RoleTypes +from rbac.settings import api_settings + def upgrade(data: dict) -> None: new_roles = {} @@ -128,7 +129,7 @@ def get_role_spec(data: str, schema: str) -> dict: """ try: - with open(file=data, encoding=settings.ENCODING_UTF_8) as f: + with open(data, encoding=settings.ENCODING_UTF_8) as f: data = round_trip_load(stream=f) except FileNotFoundError: raise_adcm_ex(code="INVALID_ROLE_SPEC", msg=f'Can not open role file "{data}"') @@ -136,7 +137,7 @@ def get_role_spec(data: str, schema: str) -> dict: except (ParserError, ScannerError, NotImplementedError) as e: raise_adcm_ex(code="INVALID_ROLE_SPEC", msg=f'YAML decode "{data}" error: {e}') - with open(file=schema, encoding=settings.ENCODING_UTF_8) as f: + with open(schema, encoding=settings.ENCODING_UTF_8) as f: rules = round_trip_load(stream=f) try: @@ -163,10 +164,7 @@ def prepare_hidden_roles(bundle: Bundle) -> dict: name = f"{name_prefix} {action.display_name}" model = get_model_by_type(action.prototype.type) - if action.prototype.type == "component": - serv_name = f"service_{action.prototype.parent.name}_" - else: - serv_name = "" + serv_name = f"service_{action.prototype.parent.name}_" if action.prototype.type == "component" else "" role_name = ( f"{bundle.name}_{bundle.version}_{bundle.edition}_{serv_name}" diff --git a/python/rbac/urls.py b/python/rbac/urls.py index 7b32425c8a..ff4626f557 100644 --- a/python/rbac/urls.py +++ b/python/rbac/urls.py @@ -11,6 +11,7 @@ # limitations under the License. from django.urls import include, path + from rbac.endpoints.logout import LogOut from rbac.endpoints.root import RBACRoot from rbac.endpoints.token import GetAuthToken diff --git a/python/rbac/urls_ui.py b/python/rbac/urls_ui.py index 26e4f4b7dc..244adf4e11 100644 --- a/python/rbac/urls_ui.py +++ b/python/rbac/urls_ui.py @@ -13,6 +13,7 @@ """RBAC UI root URLs""" from django.urls import include, path + from rbac.endpoints_ui.root import RBACUIRoot urlpatterns = [ diff --git a/python/rbac/validators.py b/python/rbac/validators.py index e2cce520a8..7ef7e46b74 100644 --- a/python/rbac/validators.py +++ b/python/rbac/validators.py @@ -28,7 +28,7 @@ def __init__(self): self.min_password_length = config_log.config["auth_policy"]["min_password_length"] self.max_password_length = config_log.config["auth_policy"]["max_password_length"] - def validate(self, password: str, user: None = None) -> None: # pylint: disable=unused-argument + def validate(self, password: str, user: None = None) -> None: # noqa: ARG002 if not all((self.min_password_length, self.max_password_length)): return diff --git a/python/rbac/viewsets.py b/python/rbac/viewsets.py index bd39e38672..00c353e877 100644 --- a/python/rbac/viewsets.py +++ b/python/rbac/viewsets.py @@ -16,5 +16,5 @@ class DjangoOnlyObjectPermissions(DjangoObjectPermissions): - def has_permission(self, request, view): + def has_permission(self, request, view): # noqa: ARG002 return True diff --git a/python/task_runner.py b/python/task_runner.py index 4323924556..34871abd27 100755 --- a/python/task_runner.py +++ b/python/task_runner.py @@ -10,16 +10,15 @@ # 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. -# pylint: disable=wrong-import-order +from logging import getLogger import os -import signal -import subprocess import sys import time -from logging import getLogger +import signal +import subprocess -import adcm.init_django # pylint: disable=unused-import +import adcm.init_django # noqa: F401, isort:skip from cm.errors import AdcmEx from cm.job import finish_task, re_prepare_job @@ -48,7 +47,7 @@ def terminate_job(task, jobs): finish_task(task, None, JobStatus.ABORTED) -def terminate_task(signum, frame): # pylint: disable=unused-argument +def terminate_task(signum, frame): # noqa: ARG001 logger.info("cancel task #%s, signal: #%s", TASK_ID, signum) task = TaskLog.objects.get(id=TASK_ID) jobs = JobLog.objects.filter(task_id=TASK_ID) @@ -80,13 +79,12 @@ def run_job(task_id, job_id, err_file): logger.info("task run job cmd: %s", " ".join(cmd)) try: - # pylint: disable=consider-using-with + # noqa: SIM115 proc = subprocess.Popen( args=cmd, stderr=err_file, env=get_env_with_venv_path(venv=TaskLog.objects.get(id=task_id).action.venv) ) - res = proc.wait() - return res - except Exception as error: # pylint: disable=broad-except + return proc.wait() # noqa: TRY300 + except Exception as error: # noqa: BLE001 logger.error("exception running job %s: %s", job_id, error) return 1 @@ -104,7 +102,7 @@ def set_log_body(job): LogStorage.objects.filter(job=job, name=log_storage.name, type=log_storage.type).update(body=body) -def run_task(task_id: int, args: str | None = None) -> None: # pylint: disable=too-many-statements,too-many-branches +def run_task(task_id: int, args: str | None = None) -> None: logger.debug("task_runner.py called as: %s", sys.argv) try: task = TaskLog.objects.get(id=task_id) @@ -128,70 +126,63 @@ def run_task(task_id: int, args: str | None = None) -> None: # pylint: disable= return - err_file = open( # pylint: disable=consider-using-with - settings.LOG_DIR / "job_runner.err", - "a+", - encoding=settings.ENCODING_UTF_8, - ) - - logger.info("run task #%s", task_id) - - job = None - count = 0 - res = 0 - for job in jobs: - try: - job.refresh_from_db() - if args == "restart" and job.status == JobStatus.SUCCESS: - logger.info('skip job #%s status "%s" of task #%s', job.id, job.status, task_id) - continue - - task.refresh_from_db() - re_prepare_job(task, job) - res = run_job(task.id, job.id, err_file) - set_log_body(job) - - # For multi jobs task object state and/or config can be changed by adcm plugins - if task.task_object is not None: - try: - task.task_object.refresh_from_db() - except ObjectDoesNotExist: - task.object_id = 0 - task.object_type = None - - job.refresh_from_db() - count += 1 - if res != 0: - task.refresh_from_db() - if job.status == JobStatus.ABORTED and task.status != JobStatus.ABORTED: + with open(settings.LOG_DIR / "job_runner.err", mode="a+", encoding=settings.ENCODING_UTF_8) as err_file: + logger.info("run task #%s", task_id) + + job = None + count = 0 + res = 0 + for job in jobs: + try: + job.refresh_from_db() + if args == "restart" and job.status == JobStatus.SUCCESS: + logger.info('skip job #%s status "%s" of task #%s', job.id, job.status, task_id) continue + task.refresh_from_db() + re_prepare_job(task, job) + res = run_job(task.id, job.id, err_file) + set_log_body(job) + + # For multi jobs task object state and/or config can be changed by adcm plugins + if task.task_object is not None: + try: + task.task_object.refresh_from_db() + except ObjectDoesNotExist: + task.object_id = 0 + task.object_type = None + + job.refresh_from_db() + count += 1 + if res != 0: + task.refresh_from_db() + if job.status == JobStatus.ABORTED and task.status != JobStatus.ABORTED: + continue + + break + except Exception: # noqa: BLE001ion-caught + error_logger.exception("Task #%s: Error processing job #%s", task_id, job.pk) + res = 1 break - except Exception: # pylint: disable=broad-exception-caught - error_logger.exception("Task #%s: Error processing job #%s", task_id, job.pk) - res = 1 - break - - if job is not None: - job.refresh_from_db() - if job is not None and job.status == JobStatus.ABORTED: - finish_task(task, job, JobStatus.ABORTED) - elif res == 0: - finish_task(task, job, JobStatus.SUCCESS) - else: - finish_task(task, job, JobStatus.FAILED) + if job is not None: + job.refresh_from_db() - err_file.close() + if job is not None and job.status == JobStatus.ABORTED: + finish_task(task, job, JobStatus.ABORTED) + elif res == 0: + finish_task(task, job, JobStatus.SUCCESS) + else: + finish_task(task, job, JobStatus.FAILED) logger.info("finish task #%s, ret %s", task_id, res) def do_task(): - global TASK_ID # pylint: disable=global-statement + global TASK_ID if len(sys.argv) < 2: - print(f"\nUsage:\n{os.path.basename(sys.argv[0])} task_id [restart]\n") + print(f"\nUsage:\n{os.path.basename(sys.argv[0])} task_id [restart]\n") # noqa: PTH119 sys.exit(4) elif len(sys.argv) > 2: TASK_ID = sys.argv[1] diff --git a/spec/conf.py b/spec/conf.py index 042f6702b0..cdc02776b4 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Arenadata documentation build configuration file, created by # sphinx-quickstart on Mon Jul 31 16:56:10 2017. @@ -16,8 +15,8 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -import datetime from string import Template +import datetime # import sphinx_markdown_tables import sphinx_rtd_theme @@ -29,7 +28,7 @@ # The full version, including alpha/beta/rc tags. release = version -now = datetime.datetime.now() +now = datetime.datetime.now() # noqa: DTZ005 title = Template( @@ -102,9 +101,9 @@ # General information about the project. -project = u"Arenadata Cluster Manager Specs" -copyright = u"{}, Arenadata.io".format(now.year) -author = u"Arenadata.io" +project = "Arenadata Cluster Manager Specs" +copyright = "{}, Arenadata.io".format(now.year) # noqa: A001, UP032 +author = "Arenadata.io" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -170,7 +169,7 @@ # Output file base name for HTML help builder. htmlhelp_basename = "Arenadatadoc" -today = "{}, Arenadata™".format(now.year) +today = "{}, Arenadata™".format(now.year) # noqa: UP032 latex_keep_old_macro_names = True latex_logo = "_static/logo.png" @@ -293,14 +292,14 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "Arenadata.tex", u"Arenadata Documentation", u"Arenadata", "manual"), + (master_doc, "Arenadata.tex", "Arenadata Documentation", "Arenadata", "manual"), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "arenadata", u"Arenadata Documentation", [author], 1)] +man_pages = [(master_doc, "arenadata", "Arenadata Documentation", [author], 1)] # -- Options for Texinfo output ------------------------------------------- @@ -311,7 +310,7 @@ ( master_doc, "Arenadata", - u"Arenadata Documentation", + "Arenadata Documentation", author, "Arenadata", "One line description of project.", @@ -342,9 +341,7 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {"https://docs.python.org/": None} -extlinks = { - 'issue': ('https://arenadata.atlassian.net/browse/%s', '') -} +extlinks = {"issue": ("https://arenadata.atlassian.net/browse/%s", "")} def setup(app): From cefbc28e1f1903f6f81f5092e952d063542070d3 Mon Sep 17 00:00:00 2001 From: Dmitriy Bardin Date: Thu, 25 Jan 2024 12:24:35 +0000 Subject: [PATCH 055/151] ADCM-4995 - Remove old UI https://tracker.yandex.ru/ADCM-4995 --- .dependabot/config.yml | 10 - .dockerignore | 1 - .github/CODEOWNERS | 1 - CODEOWNERS | 1 - Makefile | 17 - README.md | 22 +- adcm-web/app/yarn.lock | 3980 +- spec/_static/css/theme_custom.css | 126 - spec/conf.py | 350 - spec/index.rst | 11 - spec/objects.rst | 219 - spec/system/components.rst | 34 - spec/system/index.rst | 8 - spec/ui/actions.rst | 259 - spec/ui/elements.rst | 327 - spec/ui/img/cluster_services_template.png | Bin 102729 -> 0 bytes spec/ui/img/cluster_template.png | Bin 156771 -> 0 bytes spec/ui/img/common_template.png | Bin 186739 -> 0 bytes spec/ui/img/form_dialog_create_cluster.png | Bin 19446 -> 0 bytes spec/ui/img/form_login_full.png | Bin 9932 -> 0 bytes spec/ui/img/form_login_short.png | Bin 5090 -> 0 bytes spec/ui/img/template_table_view_big.png | Bin 154305 -> 0 bytes spec/ui/index.rst | 9 - spec/usecase/action/index.rst | 10 - spec/usecase/action/locks/hostprovider.rst | 6 - spec/usecase/action/onhost.rst | 76 - .../usecase/action/onhost/cluster_on_host.rst | 81 - .../action/onhost/component_on_host.rst | 83 - spec/usecase/action/onhost/on_host_list.rst | 44 - .../usecase/action/onhost/service_on_host.rst | 87 - spec/usecase/action/onhost/target.rst | 49 - spec/usecase/glossary.rst | 33 - spec/usecase/index.rst | 9 - web/.browserslistrc | 12 - web/.editorconfig | 13 - web/.eslintrc.js | 17 - web/.gitignore | 46 - web/.storybook/main.js | 10 - web/.storybook/preview.js | 14 - web/.storybook/tsconfig.json | 20 - web/.storybook/typings.d.ts | 4 - web/README.md | 96 - web/angular.json | 142 - web/build.sh | 17 - web/build_static.sh | 29 - web/documentation.json | 68306 ---------------- web/e2e/app.e2e-spec.ts | 29 - web/e2e/app.po.ts | 18 - web/e2e/login/login.e2e-spec.ts | 41 - web/e2e/login/login.po.ts | 37 - web/e2e/start/start.e2e-spec.ts | 32 - web/e2e/start/start.po.ts | 22 - web/e2e/tsconfig.e2e.json | 14 - web/export/src/uml/host.png | Bin 76270 -> 0 bytes web/karma.conf.js | 42 - web/ng_test.sh | 7 - web/package.json | 88 - web/protractor.conf.js | 31 - web/proxy.conf.json | 27 - web/src/_mixins.scss | 5 - web/src/adcm-theme.scss | 143 - web/src/adcm2.scss | 40 - .../adwp-base-list.directive.ts | 46 - .../adwp-list.directive.ts | 88 - .../base-detail.abstract.directive.ts | 176 - .../concern-list.directive.ts | 45 - .../detail.abstract.directive.ts | 37 - .../app/abstract-directives/list.directive.ts | 242 - .../menu-item.abstract.directive.ts | 22 - .../popover-content.directive.ts | 17 - .../rbac-entity-list.directive.ts | 89 - .../rbac-options.directive.ts | 53 - .../status.abstract.directive.ts | 79 - .../deletable-entity.abstract.service.ts | 7 - web/src/app/abstract/entity-service.ts | 14 - .../app/abstract/entity.abstract.service.ts | 19 - .../having-status-tree.abstract.service.ts | 12 - web/src/app/admin/admin.module.ts | 124 - .../audit-login/audit-login.component.html | 13 - .../audit-login/audit-login.component.scss | 10 - .../audit-login/audit-login.component.ts | 114 - .../audit-operations.component.html | 13 - .../audit-operations.component.scss | 62 - .../audit-operations.component.ts | 188 - .../app/admin/groups/groups.component.html | 22 - .../app/admin/groups/groups.component.scss | 10 - web/src/app/admin/groups/groups.component.ts | 80 - web/src/app/admin/intro.component.ts | 80 - web/src/app/admin/pattern.component.ts | 119 - .../admin/policies/policies.component.html | 22 - .../admin/policies/policies.component.scss | 10 - .../app/admin/policies/policies.component.ts | 82 - web/src/app/admin/roles/roles.component.html | 22 - web/src/app/admin/roles/roles.component.scss | 10 - web/src/app/admin/roles/roles.component.ts | 77 - web/src/app/admin/settings.component.ts | 42 - web/src/app/admin/users/users.component.html | 25 - web/src/app/admin/users/users.component.scss | 10 - web/src/app/admin/users/users.component.ts | 138 - web/src/app/adwp/index.ts | 195 - .../app/adwp/lib/api/api-config.service.ts | 4 - web/src/app/adwp/lib/api/api-config.ts | 3 - web/src/app/adwp/lib/api/api.module.ts | 31 - .../app/adwp/lib/auth/auth-config.service.ts | 4 - web/src/app/adwp/lib/auth/auth-config.ts | 3 - web/src/app/adwp/lib/auth/auth.module.ts | 32 - web/src/app/adwp/lib/cdk/classes/assert.ts | 10 - web/src/app/adwp/lib/cdk/classes/index.ts | 1 - web/src/app/adwp/lib/cdk/components/index.ts | 1 - .../lib/cdk/components/portal-host/index.ts | 2 - .../portal-host/portal-host.component.ts | 79 - .../portal-host/portal-host.module.ts | 9 - .../portal-host/portal-host.style.scss | 22 - .../portal-host/portal-host.template.html | 2 - .../components/portal-host/portal.service.ts | 39 - web/src/app/adwp/lib/cdk/constants/empty.ts | 1 - .../app/adwp/lib/cdk/constants/identify.ts | 6 - web/src/app/adwp/lib/cdk/constants/index.ts | 6 - web/src/app/adwp/lib/cdk/constants/matcher.ts | 14 - .../adwp/lib/cdk/constants/polling-time.ts | 1 - .../app/adwp/lib/cdk/constants/stringify.ts | 6 - .../adwp/lib/cdk/constants/svg-node-filter.ts | 6 - .../adwp/lib/cdk/decorators/default-prop.ts | 82 - web/src/app/adwp/lib/cdk/decorators/index.ts | 2 - web/src/app/adwp/lib/cdk/decorators/pure.ts | 61 - web/src/app/adwp/lib/cdk/index.ts | 9 - web/src/app/adwp/lib/cdk/interfaces/index.ts | 1 - .../adwp/lib/cdk/interfaces/portal-host.ts | 11 - web/src/app/adwp/lib/cdk/observables/index.ts | 2 - .../lib/cdk/observables/typed-from-event.ts | 37 - .../app/adwp/lib/cdk/observables/zone-free.ts | 9 - .../lib/cdk/pipes/filter/filter.module.ts | 10 - .../adwp/lib/cdk/pipes/filter/filter.pipe.ts | 16 - .../app/adwp/lib/cdk/pipes/filter/index.ts | 2 - web/src/app/adwp/lib/cdk/pipes/index.ts | 3 - .../app/adwp/lib/cdk/pipes/mapper/index.ts | 2 - .../lib/cdk/pipes/mapper/mapper.module.ts | 9 - .../adwp/lib/cdk/pipes/mapper/mapper.pipe.ts | 16 - .../adwp/lib/cdk/services/destroy.service.ts | 10 - web/src/app/adwp/lib/cdk/services/index.ts | 1 - .../cdk/services/parents-scroll.service.ts | 32 - web/src/app/adwp/lib/cdk/types/event-with.ts | 17 - web/src/app/adwp/lib/cdk/types/handler.ts | 3 - web/src/app/adwp/lib/cdk/types/index.ts | 5 - web/src/app/adwp/lib/cdk/types/mapper.ts | 4 - web/src/app/adwp/lib/cdk/types/matcher.ts | 15 - .../app/adwp/lib/cdk/types/overscroll-mode.ts | 1 - .../app/adwp/lib/cdk/utils/array/concat-by.ts | 13 - .../adwp/lib/cdk/utils/array/difference.ts | 14 - web/src/app/adwp/lib/cdk/utils/array/index.ts | 2 - .../lib/cdk/utils/dom/get-closest-element.ts | 20 - .../lib/cdk/utils/dom/get-screen-width.ts | 6 - web/src/app/adwp/lib/cdk/utils/dom/index.ts | 2 - .../focus/get-closest-keyboard-focusable.ts | 48 - web/src/app/adwp/lib/cdk/utils/focus/index.ts | 4 - .../focus/is-native-keyboard-focusable.ts | 35 - .../utils/focus/is-native-mouse-focusable.ts | 8 - .../lib/cdk/utils/focus/set-native-focused.ts | 18 - .../app/adwp/lib/cdk/utils/format/index.ts | 1 - web/src/app/adwp/lib/cdk/utils/format/px.ts | 7 - web/src/app/adwp/lib/cdk/utils/index.ts | 7 - .../app/adwp/lib/cdk/utils/math/in-range.ts | 17 - web/src/app/adwp/lib/cdk/utils/math/index.ts | 1 - .../cdk/utils/miscellaneous/fallback-value.ts | 5 - .../adwp/lib/cdk/utils/miscellaneous/index.ts | 2 - .../lib/cdk/utils/miscellaneous/is-present.ts | 3 - .../lib/core/abstract/abstract-dropdown.ts | 113 - web/src/app/adwp/lib/core/abstract/index.ts | 1 - .../adwp/lib/core/animations/animations.ts | 40 - web/src/app/adwp/lib/core/animations/index.ts | 1 - .../dropdown-box/dropdown-box.component.ts | 359 - .../dropdown-box/dropdown-box.module.ts | 13 - .../dropdown-box/dropdown-box.style.scss | 32 - .../dropdown-box/dropdown-box.template.html | 10 - .../lib/core/components/dropdown-box/index.ts | 2 - web/src/app/adwp/lib/core/components/index.ts | 2 - .../adwp/lib/core/components/select/index.ts | 2 - .../components/select/select.component.html | 28 - .../components/select/select.component.scss | 54 - .../components/select/select.component.ts | 231 - .../core/components/select/select.module.ts | 30 - .../selection-list-actions.component.html | 24 - .../selection-list-actions.component.ts | 49 - .../selection-list.component.css | 12 - .../selection-list.component.html | 20 - .../selection-list.component.ts | 139 - .../selection-list/selection-list.module.ts | 37 - .../lib/core/constants/absolute-box-sizes.ts | 4 - web/src/app/adwp/lib/core/constants/index.ts | 1 - .../click-outside/click-outside.directive.ts | 24 - .../click-outside/click-outside.module.ts | 9 - .../core/directives/click-outside/index.ts | 2 - .../directives/dropdown/dropdown.directive.ts | 52 - .../directives/dropdown/dropdown.module.ts | 12 - .../lib/core/directives/dropdown/index.ts | 2 - web/src/app/adwp/lib/core/directives/index.ts | 2 - .../adwp/lib/core/enums/dropdown-animation.ts | 4 - web/src/app/adwp/lib/core/enums/index.ts | 1 - web/src/app/adwp/lib/core/index.ts | 10 - .../lib/core/interfaces/animation-options.ts | 5 - .../lib/core/interfaces/dropdown-directive.ts | 19 - web/src/app/adwp/lib/core/interfaces/index.ts | 1 - .../adwp/lib/core/tokens/animation-options.ts | 14 - .../lib/core/tokens/animations-duration.ts | 8 - .../lib/core/tokens/dropdown-directive.ts | 6 - web/src/app/adwp/lib/core/tokens/index.ts | 3 - web/src/app/adwp/lib/core/types/direction.ts | 7 - .../app/adwp/lib/core/types/dropdown-width.ts | 1 - web/src/app/adwp/lib/core/types/index.ts | 2 - .../core/utils/dom/check-fixed-position.ts | 12 - web/src/app/adwp/lib/core/utils/dom/index.ts | 1 - web/src/app/adwp/lib/core/utils/index.ts | 1 - web/src/app/adwp/lib/dialog/ComponentData.ts | 10 - .../app/adwp/lib/dialog/dialog.component.html | 20 - .../app/adwp/lib/dialog/dialog.component.scss | 7 - .../adwp/lib/dialog/dialog.component.spec.ts | 36 - .../app/adwp/lib/dialog/dialog.component.ts | 74 - web/src/app/adwp/lib/dialog/dialog.module.ts | 21 - web/src/app/adwp/lib/footer/footer.module.ts | 21 - .../lib/footer/footer/footer.component.html | 14 - .../lib/footer/footer/footer.component.scss | 0 .../lib/footer/footer/footer.component.ts | 24 - .../controls/controls.component.html | 6 - .../controls/controls.component.scss | 3 - .../controls/controls.component.spec.ts | 25 - .../controls/controls.component.ts | 24 - .../lib/form-element/field.directive.spec.ts | 8 - .../adwp/lib/form-element/field.directive.ts | 31 - .../lib/form-element/form-element.module.ts | 19 - .../input-select/input-select.component.html | 20 - .../input-select/input-select.component.scss | 14 - .../input-select/input-select.component.ts | 41 - .../form-element/input/input.component.html | 14 - .../form-element/input/input.component.scss | 1 - .../input/input.component.spec.ts | 29 - .../lib/form-element/input/input.component.ts | 24 - web/src/app/adwp/lib/header/header.module.ts | 24 - .../header/top-menu/top-menu.component.html | 20 - .../header/top-menu/top-menu.component.scss | 38 - .../lib/header/top-menu/top-menu.component.ts | 15 - web/src/app/adwp/lib/helpers/cookie.ts | 13 - web/src/app/adwp/lib/helpers/event-helper.ts | 9 - web/src/app/adwp/lib/helpers/guid.ts | 15 - .../http-interceptors/django-interceptor.ts | 28 - .../lib/list-storage/list-storage.module.ts | 8 - .../lib/list/cell/component-cell.component.ts | 36 - .../adwp/lib/list/cell/link-cell.component.ts | 51 - .../lib/list/component-holder.directive.ts | 39 - web/src/app/adwp/lib/list/hover.directive.ts | 22 - .../app/adwp/lib/list/list-config.service.ts | 4 - web/src/app/adwp/lib/list/list-config.ts | 3 - web/src/app/adwp/lib/list/list.module.ts | 84 - .../adwp/lib/list/list/list.component.html | 24 - .../adwp/lib/list/list/list.component.scss | 0 .../adwp/lib/list/list/list.component.spec.ts | 35 - .../app/adwp/lib/list/list/list.component.ts | 69 - .../list/paginator/paginator.component.html | 104 - .../list/paginator/paginator.component.scss | 77 - .../lib/list/paginator/paginator.component.ts | 48 - .../app/adwp/lib/list/pipes/as-string.pipe.ts | 12 - .../lib/list/pipes/calc-dynamic-cell.pipe.ts | 14 - .../lib/list/pipes/calc-link-cell.pipe.ts | 14 - .../lib/list/pipes/is-all-checked.pipe.ts | 14 - .../pipes/is-indeterminate-checked.pipe.ts | 14 - .../pipes/is-main-checkbox-disabled.pipe.ts | 15 - .../list/pipes/list-checkbox-disabled.pipe.ts | 13 - .../adwp/lib/list/pipes/list-value.pipe.ts | 13 - web/src/app/adwp/lib/list/pipes/pages.pipe.ts | 16 - .../app/adwp/lib/list/pipes/time.pipe.spec.ts | 8 - web/src/app/adwp/lib/list/pipes/time.pipe.ts | 15 - .../lib/list/row/component-row.component.ts | 24 - .../adwp/lib/list/table/table.component.html | 104 - .../adwp/lib/list/table/table.component.scss | 6 - .../lib/list/table/table.component.spec.ts | 25 - .../adwp/lib/list/table/table.component.ts | 136 - .../app/adwp/lib/loading/loading.component.ts | 27 - .../app/adwp/lib/loading/loading.module.ts | 19 - .../lib/login-form/login-form.component.html | 48 - .../lib/login-form/login-form.component.scss | 63 - .../lib/login-form/login-form.component.ts | 37 - .../adwp/lib/login-form/login-form.module.ts | 38 - .../lib/miscellaneous/miscellaneous.module.ts | 81 - web/src/app/adwp/lib/models/api-options.ts | 13 - web/src/app/adwp/lib/models/api-params.ts | 3 - .../app/adwp/lib/models/auth-credentials.ts | 5 - web/src/app/adwp/lib/models/base.directive.ts | 19 - web/src/app/adwp/lib/models/config-options.ts | 37 - .../lib/models/django-http-error-response.ts | 8 - .../app/adwp/lib/models/django-http-error.ts | 13 - web/src/app/adwp/lib/models/entity.ts | 3 - web/src/app/adwp/lib/models/field-options.ts | 57 - web/src/app/adwp/lib/models/list.ts | 113 - .../app/adwp/lib/models/login-credentials.ts | 5 - web/src/app/adwp/lib/models/menu-item.ts | 5 - web/src/app/adwp/lib/models/root.ts | 3 - web/src/app/adwp/lib/models/version-info.ts | 4 - .../lib/notification/notification.module.ts | 22 - web/src/app/adwp/lib/services/api.service.ts | 84 - web/src/app/adwp/lib/services/app.service.ts | 85 - web/src/app/adwp/lib/services/auth.service.ts | 40 - .../app/adwp/lib/services/config.service.ts | 50 - web/src/app/adwp/lib/services/index.ts | 3 - .../adwp/lib/services/list-storage.service.ts | 50 - .../adwp/lib/services/notification.service.ts | 54 - .../lib/services/socket-config.service.ts | 4 - .../app/adwp/lib/services/socket.service.ts | 35 - web/src/app/adwp/lib/socket/socket-config.ts | 3 - web/src/app/adwp/lib/socket/socket.module.ts | 26 - web/src/app/adwp/lib/store/api/api.effects.ts | 59 - web/src/app/adwp/lib/store/api/api.reducer.ts | 48 - .../app/adwp/lib/store/auth/auth.actions.ts | 7 - .../app/adwp/lib/store/auth/auth.effects.ts | 51 - .../app/adwp/lib/store/auth/auth.reducers.ts | 26 - .../app/adwp/lib/store/auth/auth.selectors.ts | 15 - web/src/app/adwp/lib/store/factory.ts | 23 - .../adwp/lib/store/socket/socket.actions.ts | 56 - .../adwp/lib/store/socket/socket.reducers.ts | 38 - .../adwp/lib/store/socket/socket.selectors.ts | 13 - web/src/app/adwp/lib/store/state.ts | 8 - .../lib/toolbar/crumbs/crumbs.component.html | 11 - .../lib/toolbar/crumbs/crumbs.component.scss | 17 - .../toolbar/crumbs/crumbs.component.spec.ts | 28 - .../lib/toolbar/crumbs/crumbs.component.ts | 11 - .../adwp/lib/toolbar/toolbar.component.html | 4 - .../adwp/lib/toolbar/toolbar.component.scss | 6 - .../app/adwp/lib/toolbar/toolbar.component.ts | 11 - .../app/adwp/lib/toolbar/toolbar.module.ts | 26 - web/src/app/adwp/lib/ui-widgets.module.ts | 25 - web/src/app/adwp/test.ts | 26 - web/src/app/app-routing.module.ts | 117 - web/src/app/app.component.ts | 110 - web/src/app/app.module.ts | 99 - .../actions-button.component.html | 14 - .../actions-button.component.scss | 0 .../actions-button.component.spec.ts | 25 - .../actions-button.component.ts | 25 - .../app/components/bell/bell.component.scss | 66 - web/src/app/components/bell/bell.component.ts | 285 - .../bundle-details.component.ts | 39 - .../cluster-details.component.ts | 46 - .../cluster-status.component.ts | 96 - .../cluster/hcmap/hcmap.component.ts | 17 - .../cluster/host/cluster-host.component.ts | 55 - .../cluster/services/services.component.ts | 50 - .../cluster-column.component.ts | 69 - .../download-button-column.component.html | 5 - .../download-button-column.component.scss | 0 .../download-button-column.component.ts | 21 - .../edition-column.component.scss | 3 - .../edition-column.component.ts | 25 - .../history-column.component.html | 5 - .../history-column.component.scss | 17 - .../history-column.component.ts | 55 - .../columns/job-name/job-name.component.scss | 7 - .../columns/job-name/job-name.component.ts | 34 - .../job-status-column.component.html | 24 - .../job-status-column.component.scss | 12 - .../job-status-column.component.ts | 50 - .../name-edit-column-field.component.ts | 65 - .../name-edit-column.component.html | 6 - .../name-edit-column.component.scss | 27 - .../name-edit-column.component.ts | 102 - .../signature-column.component.html | 5 - .../signature-column.component.scss | 36 - .../signature-column.component.ts | 22 - .../state-column/state-column.component.html | 2 - .../state-column/state-column.component.scss | 0 .../state-column.component.spec.ts | 31 - .../state-column/state-column.component.ts | 12 - .../status-column.component.html | 21 - .../status-column.component.scss | 0 .../status-column.component.spec.ts | 31 - .../status-column/status-column.component.ts | 25 - .../task-name/task-name.component.scss | 14 - .../columns/task-name/task-name.component.ts | 41 - .../task-objects/task-objects.component.html | 9 - .../task-objects/task-objects.component.scss | 8 - .../task-objects/task-objects.component.ts | 20 - .../task-status-column.component.html | 23 - .../task-status-column.component.scss | 6 - .../task-status-column.component.ts | 44 - .../wrapper-column.component.html | 1 - .../wrapper-column.component.scss | 25 - .../wrapper-column.component.ts | 63 - .../concern-item/concern-item.component.html | 44 - .../concern-item/concern-item.component.scss | 25 - .../concern-item/concern-item.component.ts | 34 - .../concern-list-ref.component.scss | 0 .../concern-list-ref.component.ts | 35 - .../concern-list/concern-list.component.scss | 6 - .../concern-list/concern-list.component.ts | 32 - .../components/concern/concern.component.html | 9 - .../components/concern/concern.component.scss | 0 .../components/concern/concern.component.ts | 36 - .../host-details/host-details.component.ts | 41 - .../host/host-list/host-list.component.scss | 19 - .../host/host-list/host-list.component.ts | 117 - .../host/host-status/host-status.component.ts | 59 - .../group-config-details.component.ts | 43 - .../hostprovider/hostprovider.component.ts | 58 - .../provider-details.component.ts | 41 - .../job/job-details/job-details.component.ts | 76 - .../components/job/jobs/jobs.component.scss | 37 - .../app/components/job/jobs/jobs.component.ts | 91 - .../maintenance-mode-button.component.html | 11 - .../maintenance-mode-button.component.scss | 5 - .../maintenance-mode-button.component.spec.ts | 28 - .../maintenance-mode-button.component.ts | 79 - .../navigation/navigation.component.spec.ts | 35 - .../navigation/navigation.component.ts | 142 - .../notifications.component.scss | 66 - .../notifications.component.spec.ts | 25 - .../notifications/notifications.component.ts | 109 - .../components/popover/popover.component.scss | 27 - .../components/popover/popover.component.ts | 63 - ...dit-operations-history-form.component.html | 4 - ...dit-operations-history-form.component.scss | 31 - ...audit-operations-history-form.component.ts | 65 - .../rbac-groups-as-options.directive.ts | 25 - .../options/rbac-groups-as-options.module.ts | 16 - .../group-form/rbac-group-form.component.html | 13 - .../group-form/rbac-group-form.component.ts | 44 - .../rbac/group-form/rbac-group-form.module.ts | 26 - .../rbac-permission-form.component.html | 42 - .../rbac-permission-form.component.scss | 85 - .../rbac-permission-form.component.ts | 57 - .../rbac-permission-form.module.ts | 33 - .../rbac-policy-form-step-one.component.html | 39 - .../rbac-policy-form-step-one.component.scss | 3 - .../rbac-policy-form-step-one.component.ts | 34 - .../validators/user-or-group-required.ts | 32 - ...rbac-policy-form-step-three.component.html | 1 - ...rbac-policy-form-step-three.component.scss | 0 .../rbac-policy-form-step-three.component.ts | 28 - .../parametrized-by-cluster.component.html | 9 - .../parametrized-by-cluster.component.scss | 3 - .../parametrized-by-cluster.component.ts | 25 - .../parametrized-by-host.component.html | 9 - .../parametrized-by-host.component.scss | 0 .../parametrized-by-host.component.ts | 20 - .../parametrized-by-provider.component.html | 9 - .../parametrized-by-provider.component.scss | 3 - .../parametrized-by-provider.component.ts | 21 - .../get-clusters-from-services.pipe.ts | 22 - .../parametrized-by-service.component.html | 34 - .../parametrized-by-service.component.scss | 3 - .../parametrized-by-service.component.ts | 30 - .../directives/parametrized-by.directive.ts | 19 - .../pipes/parametrized.pipe.ts | 20 - .../rbac-policy-form-step-two.component.html | 28 - .../rbac-policy-form-step-two.component.scss | 0 .../rbac-policy-form-step-two.component.ts | 80 - .../rbac-policy-form.component.html | 36 - .../policy-form/rbac-policy-form.component.ts | 131 - .../policy-form/rbac-policy-form.module.ts | 64 - .../validators/object-validator.ts | 75 - .../validators/provider-or-host.ts | 33 - .../rbac-roles-as-options.directive.ts | 29 - .../options/rbac-roles-as-options.module.ts | 14 - .../role-form/rbac-role-form.component.html | 19 - .../role-form/rbac-role-form.component.scss | 19 - .../role-form/rbac-role-form.component.ts | 93 - .../rbac/role-form/rbac-role-form.module.ts | 36 - .../rbac-users-as-options.directive.ts | 25 - .../options/rbac-users-as-options.module.ts | 16 - .../user-form/rbac-user-form.component.html | 30 - .../user-form/rbac-user-form.component.scss | 13 - .../user-form/rbac-user-form.component.ts | 244 - .../rbac/user-form/rbac-user-form.module.ts | 30 - .../service-component-details.component.ts | 42 - .../service-component-status.component.ts | 60 - .../service-components.component.ts | 43 - .../service-details.component.ts | 44 - .../service-status.component.ts | 72 - .../snack-bar/snack-bar.component.ts | 52 - .../status-tree/status-tree.component.html | 49 - .../status-tree/status-tree.component.scss | 20 - .../status-tree/status-tree.component.ts | 124 - .../config-group-add.component.ts | 47 - .../config-group-host-add.component.ts | 123 - web/src/app/config-groups/components/index.ts | 2 - .../app/config-groups/config-group.module.ts | 44 - web/src/app/config-groups/index.ts | 5 - web/src/app/config-groups/loader.ts | 3 - .../config-groups/model/config-group.model.ts | 9 - web/src/app/config-groups/model/index.ts | 1 - .../pages/group-list/group-list.component.ts | 45 - .../pages/host-list/host-list.component.ts | 52 - web/src/app/config-groups/pages/index.ts | 2 - .../service/config-group-add.service.ts | 46 - .../service/config-group-host-add.service.ts | 53 - .../service/config-group-host-list.service.ts | 53 - .../service/config-group-list.service.ts | 64 - .../service/config-group.service.ts | 46 - web/src/app/config-groups/service/index.ts | 5 - web/src/app/core/animations/index.ts | 25 - web/src/app/core/api/api.effects.ts | 61 - web/src/app/core/api/api.reducer.ts | 50 - web/src/app/core/api/api.service.ts | 79 - web/src/app/core/api/index.ts | 12 - web/src/app/core/auth/auth.guard.ts | 43 - web/src/app/core/auth/auth.service.ts | 60 - web/src/app/core/auth/auth.store.ts | 90 - web/src/app/core/core.module.ts | 33 - .../http-interseptors/auth-interseptor.ts | 84 - .../http-interseptors/caching-interseptor.ts | 51 - .../request-cache.service.ts | 63 - .../app/core/services/app/app.service.spec.ts | 29 - web/src/app/core/services/app/app.service.ts | 138 - .../app/core/services/channel.service.spec.ts | 23 - web/src/app/core/services/channel.service.ts | 66 - web/src/app/core/services/cluster.service.ts | 210 - web/src/app/core/services/config.service.ts | 52 - web/src/app/core/services/dom.service.spec.ts | 28 - web/src/app/core/services/dom.service.ts | 38 - .../core/services/fully-rendered.service.ts | 61 - web/src/app/core/services/index.ts | 18 - .../app/core/services/preloader.service.ts | 42 - .../core/services/router-history.service.ts | 73 - web/src/app/core/services/stack.service.ts | 49 - web/src/app/core/store/index.ts | 54 - web/src/app/core/store/issue.ts | 60 - web/src/app/core/store/profile/index.ts | 88 - .../app/core/store/profile/profile.service.ts | 91 - .../app/core/store/router/route-serializer.ts | 39 - .../app/core/store/router/router.actions.ts | 39 - .../app/core/store/router/router.effects.ts | 35 - .../app/core/store/sockets/socket.effect.ts | 31 - .../app/core/store/sockets/socket.reducer.ts | 105 - .../app/core/store/sockets/socket.service.ts | 43 - web/src/app/core/types/actions.ts | 46 - web/src/app/core/types/api.ts | 121 - web/src/app/core/types/context-manager.ts | 14 - web/src/app/core/types/func.spec.ts | 101 - web/src/app/core/types/func.ts | 94 - web/src/app/core/types/host-component.ts | 61 - web/src/app/core/types/import-export.ts | 29 - web/src/app/core/types/index.ts | 19 - web/src/app/core/types/stack.ts | 43 - web/src/app/core/types/task-job.ts | 71 - web/src/app/core/types/utils.ts | 34 - web/src/app/directives/popover.directive.ts | 97 - .../app/entry/bundle/bundle-list.component.ts | 151 - web/src/app/entry/bundle/bundle.module.ts | 49 - .../app/entry/cluster/cluster.component.scss | 20 - .../app/entry/cluster/cluster.component.ts | 62 - web/src/app/entry/cluster/cluster.module.ts | 165 - web/src/app/entry/entry.module.ts | 24 - web/src/app/entry/job/job-info.component.ts | 72 - web/src/app/entry/job/job-routing.module.ts | 37 - web/src/app/entry/job/job.component.ts | 42 - web/src/app/entry/job/job.module.ts | 40 - web/src/app/entry/job/log/check.component.ts | 63 - .../app/entry/job/log/log.component.spec.ts | 125 - web/src/app/entry/job/log/log.component.ts | 116 - web/src/app/entry/job/log/text.component.ts | 115 - .../app/entry/task/hover.directive.spec.ts | 83 - web/src/app/entry/task/hover.directive.ts | 31 - web/src/app/entry/task/task.module.ts | 50 - web/src/app/entry/task/tasks.component.html | 33 - web/src/app/entry/task/tasks.component.scss | 109 - web/src/app/entry/task/tasks.component.ts | 296 - web/src/app/factories/details.factory.ts | 46 - web/src/app/factories/list.factory.ts | 229 - web/src/app/helpers/date-helper.ts | 9 - web/src/app/helpers/issue-helper.ts | 21 - web/src/app/helpers/objects-helper.ts | 39 - web/src/app/main/login/login.component.html | 33 - web/src/app/main/login/login.component.scss | 63 - web/src/app/main/login/login.component.ts | 74 - web/src/app/main/main.module.ts | 54 - web/src/app/main/profile/profile.component.ts | 122 - web/src/app/main/progress.component.ts | 34 - web/src/app/main/server-status.component.ts | 35 - .../app/main/support/support.component.html | 3 - .../app/main/support/support.component.scss | 0 web/src/app/main/support/support.component.ts | 26 - web/src/app/main/top/top.component.html | 63 - web/src/app/main/top/top.component.scss | 55 - web/src/app/main/top/top.component.ts | 44 - web/src/app/models/action.ts | 13 - web/src/app/models/bundle.ts | 20 - web/src/app/models/cluster-service.ts | 13 - web/src/app/models/cluster.ts | 18 - web/src/app/models/component.ts | 14 - web/src/app/models/concern/concern-reason.ts | 107 - web/src/app/models/concern/concern.ts | 12 - web/src/app/models/details.ts | 45 - web/src/app/models/entity-names.ts | 3 - web/src/app/models/entity.ts | 12 - web/src/app/models/eventable-service.ts | 18 - web/src/app/models/host.ts | 15 - web/src/app/models/issue.ts | 15 - web/src/app/models/list-result.ts | 6 - .../app/models/rbac/rbac-audit-login.model.ts | 14 - .../rbac/rbac-audit-operations.model.ts | 24 - web/src/app/models/rbac/rbac-group.model.ts | 12 - .../app/models/rbac/rbac-object-candidate.ts | 31 - .../app/models/rbac/rbac-permission.model.ts | 6 - web/src/app/models/rbac/rbac-policy.model.ts | 16 - web/src/app/models/rbac/rbac-role.model.ts | 17 - web/src/app/models/rbac/rbac-user.model.ts | 22 - web/src/app/models/service-component.ts | 21 - web/src/app/models/status-tree.ts | 40 - .../app/models/universal-adcm-event-data.ts | 5 - web/src/app/pipes/bell-task-link.pipe.ts | 40 - .../entity-status-to-status-tree.pipe.ts | 20 - web/src/app/pipes/has-selected.pipe.ts | 14 - web/src/app/pipes/is-array.pipe.ts | 12 - .../issue-message-placeholder.pipe.spec.ts | 14 - .../pipes/issue-message-placeholder.pipe.ts | 12 - web/src/app/pipes/issue-path.pipe.ts | 40 - web/src/app/pipes/keys.pipe.ts | 12 - web/src/app/pipes/nav-item.pipe.ts | 119 - web/src/app/pipes/object-link-column.pipe.ts | 25 - web/src/app/pipes/pick-keys.pipe.ts | 12 - web/src/app/pipes/sort-objects.pipe.ts | 15 - web/src/app/pipes/status-tree-link.pipe.ts | 14 - web/src/app/pipes/to-data-source.pipe.ts | 21 - .../app/pipes/translate-object-keys.pipe.ts | 25 - web/src/app/services/bundle.service.ts | 27 - .../app/services/cluster-entity.service.ts | 102 - web/src/app/services/concern.service.ts | 36 - web/src/app/services/host.service.ts | 57 - .../services/issue-message.service.spec.ts | 55 - web/src/app/services/job.service.ts | 35 - web/src/app/services/provider.service.ts | 27 - .../app/services/rbac-audit-login.service.ts | 26 - .../services/rbac-audit-operations.service.ts | 26 - web/src/app/services/rbac-group.service.ts | 49 - .../services/rbac-object-candidate.service.ts | 17 - web/src/app/services/rbac-policy.service.ts | 53 - web/src/app/services/rbac-role.service.ts | 51 - web/src/app/services/rbac-user.service.ts | 55 - .../app/services/service-component.service.ts | 52 - web/src/app/services/service.service.ts | 92 - web/src/app/services/stats.service.ts | 27 - web/src/app/services/task.service.ts | 39 - .../add-component/add-button.component.ts | 91 - .../add-component/add-cluster.component.ts | 59 - .../add-component/add-form.component.ts | 83 - .../shared/add-component/add-service-model.ts | 50 - .../app/shared/add-component/add.service.ts | 254 - .../app/shared/add-component/adding.module.ts | 59 - .../add-component/base-form.directive.ts | 40 - .../add-component/controls.component.ts | 39 - .../shared/add-component/host.component.ts | 198 - .../add-component/host2cluster.component.scss | 22 - .../add-component/host2cluster.component.ts | 162 - web/src/app/shared/add-component/index.ts | 19 - .../add-component/interfaces/relation-list.ts | 5 - web/src/app/shared/add-component/naming.ts | 97 - .../add-component/provider.component.ts | 81 - .../add-component/rbac-form.directive.ts | 73 - .../shared/add-component/service.component.ts | 153 - .../action-list/action-list.component.html | 26 - .../action-list/action-list.component.scss | 7 - .../action-list/action-list.component.spec.ts | 41 - .../action-list/action-list.component.ts | 43 - .../menu-item/menu-item.component.scss | 4 - .../menu-item/menu-item.component.spec.ts | 39 - .../menu-item/menu-item.component.ts | 49 - .../components/actions/actions.component.scss | 24 - .../actions/actions.component.spec.ts | 62 - .../components/actions/actions.component.ts | 109 - .../actions/actions.directive.spec.ts | 93 - .../components/actions/actions.directive.ts | 64 - .../actions/actions.service.spec.ts | 30 - .../components/actions/actions.service.ts | 57 - .../master/action-master-config.component.ts | 36 - .../actions/master/master.component.html | 69 - .../actions/master/master.component.spec.ts | 225 - .../actions/master/master.component.ts | 89 - .../actions/master/master.service.ts | 63 - .../components/button-spinner.component.ts | 56 - .../components/crumbs/crumbs.component.scss | 14 - .../components/crumbs/crumbs.component.ts | 48 - .../app/shared/components/dialog.component.ts | 158 - .../components/import/import.component.scss | 24 - .../components/import/import.component.ts | 144 - web/src/app/shared/components/index.ts | 22 - .../components/issue-info.component.spec.ts | 82 - .../shared/components/issue-info.component.ts | 84 - .../components/list/base-list.directive.ts | 287 - .../components/list/list-service-token.ts | 22 - .../shared/components/list/list.service.ts | 141 - .../components/list/multi-sort.directive.ts | 83 - .../shared/components/main-info.component.ts | 30 - .../components/status-info.component.ts | 81 - .../components/status/status.service.ts | 76 - .../app/shared/components/tooltip/index.ts | 13 - .../components/tooltip/tooltip.component.scss | 24 - .../components/tooltip/tooltip.component.ts | 156 - .../components/tooltip/tooltip.directive.ts | 54 - .../components/tooltip/tooltip.module.ts | 15 - .../components/tooltip/tooltip.service.ts | 83 - .../upgrades/master/master.component.html | 70 - .../upgrades/master/master.component.scss | 18 - .../upgrades/master/master.component.spec.ts | 299 - .../upgrades/master/master.component.ts | 76 - .../upgrades/master/master.service.ts | 63 - .../master/upgrade-master-config.component.ts | 36 - .../components/upgrades/upgrade.component.ts | 101 - .../components/upgrades/upgrade.directive.ts | 342 - .../attribute-provider.component.scss | 19 - .../attribute-provider.component.ts | 90 - .../attributes/attribute.service.ts | 187 - .../attributes/attributes.module.ts | 41 - .../group-keys-wrapper.component.scss | 11 - .../group-keys-wrapper.component.ts | 140 - .../attributes/config-field.directive.ts | 10 - .../configuration/configuration.module.ts | 90 - .../configuration/field/field.component.html | 70 - .../configuration/field/field.component.scss | 64 - .../configuration/field/field.component.ts | 168 - .../configuration/fields/fields.component.ts | 110 - .../group-fields/group-fields.component.html | 25 - .../group-fields/group-fields.component.ts | 93 - .../configuration/main/config.component.html | 21 - .../configuration/main/config.component.scss | 33 - .../main/config.component.spec.ts | 182 - .../configuration/main/config.component.ts | 255 - .../configuration/main/main.service.spec.ts | 37 - .../shared/configuration/main/main.service.ts | 162 - .../scheme/item.component.spec.ts | 49 - .../configuration/scheme/item.component.ts | 92 - .../configuration/scheme/root.component.html | 27 - .../configuration/scheme/root.component.scss | 32 - .../scheme/root.component.spec.ts | 66 - .../configuration/scheme/root.component.ts | 111 - .../scheme/scheme.component.spec.ts | 67 - .../configuration/scheme/scheme.component.ts | 74 - .../scheme/scheme.service.spec.ts | 56 - .../configuration/scheme/scheme.service.ts | 88 - .../configuration/services/config.service.ts | 60 - .../services/field.service.spec.ts | 439 - .../configuration/services/field.service.ts | 427 - .../configuration/tests/configuration.ts | 140 - .../tools/color-option.directive.ts | 28 - .../filter-list/filter-list.component.scss | 0 .../filter-list/filter-list.component.ts | 45 - .../tools/filter/filter.component.html | 48 - .../tools/filter/filter.component.scss | 51 - .../tools/filter/filter.component.ts | 208 - .../configuration/tools/history.component.ts | 68 - .../configuration/tools/search.component.ts | 41 - .../server-filter.component.scss | 0 .../server-filter/server-filter.component.ts | 159 - .../configuration/tools/tools.component.ts | 75 - web/src/app/shared/configuration/types.ts | 193 - .../configuration/yspec/yspec.service.spec.ts | 368 - .../configuration/yspec/yspec.service.ts | 175 - web/src/app/shared/details/details.module.ts | 103 - .../concern-menu-item.component.ts | 64 - .../concern-menu-item.pipe.ts | 16 - .../label-menu-item.component.spec.ts | 25 - .../label-menu-item.component.ts | 18 - .../log-menu-item.component.spec.ts | 31 - .../log-menu-item/log-menu-item.component.ts | 46 - .../status-menu-item.component.ts | 53 - .../left-menu/left-menu.component.scss | 3 - .../left-menu/left-menu.component.spec.ts | 25 - .../details/left-menu/left-menu.component.ts | 71 - .../app/shared/details/subtitle.component.ts | 41 - .../app/shared/directives/base.directive.ts | 34 - .../directives/dynamic/dynamic.directive.ts | 34 - .../directives/dynamic/dynamic.module.ts | 14 - .../shared/directives/for-test.directive.ts | 25 - .../app/shared/directives/hover.directive.ts | 31 - web/src/app/shared/directives/index.ts | 19 - .../directives/infinity-scroll.directive.ts | 43 - .../shared/directives/m-textarea.directive.ts | 61 - .../directives/scroll.directive.spec.ts | 19 - .../app/shared/directives/scroll.directive.ts | 34 - .../directives/socketListener.directive.ts | 44 - .../adcm-input-rbac-permission.component.html | 60 - .../adcm-input-rbac-permission.component.scss | 84 - .../adcm-input-rbac-permission.component.ts | 71 - .../adcm-input-rbac-permission.module.ts | 44 - .../shared/form-elements/boolean.component.ts | 43 - .../form-elements/bundle.component.spec.ts | 116 - .../shared/form-elements/bundles.component.ts | 145 - .../button-uploader.component.ts | 55 - .../confirm-equal-validator.directive.ts | 33 - .../form-elements/dropdown.component.ts | 53 - .../form-elements/error-info.component.ts | 34 - .../shared/form-elements/field.directive.ts | 49 - .../form-elements/form-elements.module.ts | 78 - .../shared/form-elements/input.component.ts | 47 - .../shared/form-elements/json.component.ts | 43 - .../form-elements/map-list.template.html | 20 - .../shared/form-elements/map.component.scss | 27 - .../app/shared/form-elements/map.component.ts | 123 - .../password/password.component.html | 35 - .../password/password.component.scss | 11 - .../password/password.component.ts | 180 - .../secret-file/secret-file.component.html | 0 .../secret-file/secret-file.component.scss | 0 .../secret-file/secret-file.component.ts | 14 - .../secret-map/secret-map.component.html | 20 - .../secret-map/secret-map.component.scss | 0 .../secret-map/secret-map.component.ts | 101 - .../secret-text/secret-text.component.html | 14 - .../secret-text/secret-text.component.ts | 75 - .../form-elements/text-box.component.ts | 27 - .../form-elements/textarea.component.ts | 27 - .../form-elements/variant.component.spec.ts | 42 - .../shared/form-elements/variant.component.ts | 45 - .../dependencies.component.spec.ts | 66 - .../dependencies.component.ts | 37 - .../holder.directive.spec.ts | 70 - .../host-components-map/holder.directive.ts | 37 - .../host-components-map.module.ts | 31 - .../much-2-many/much-2-many.component.html | 19 - .../much-2-many/much-2-many.component.scss | 99 - .../much-2-many/much-2-many.component.ts | 109 - .../service-host.component.html | 31 - .../service-host.component.scss | 53 - .../service-host.component.spec.ts | 253 - .../services2hosts/service-host.component.ts | 288 - .../host-components-map/take.service.spec.ts | 159 - .../host-components-map/take.service.ts | 346 - .../shared/host-components-map/test/index.ts | 62 - .../app/shared/host-components-map/types.ts | 168 - web/src/app/shared/material.module.ts | 74 - .../app/shared/pipes/break-row.pipe.spec.ts | 19 - web/src/app/shared/pipes/break-row.pipe.ts | 20 - .../false-as-empty-array.module.ts | 18 - .../false-as-empty-array.pipe.ts | 12 - web/src/app/shared/pipes/index.ts | 13 - web/src/app/shared/pipes/tag-esc.pipe.ts | 21 - ...reset-login-attempts-button.component.html | 9 - ...reset-login-attempts-button.component.scss | 7 - .../reset-login-attempts-button.component.ts | 62 - web/src/app/shared/shared.module.ts | 182 - web/src/app/shared/stuff.module.ts | 113 - web/src/app/shared/translate/intializer.ts | 28 - .../shared/validators/custom-validators.ts | 27 - .../store/navigation/navigation-effects.ts | 123 - .../app/store/navigation/navigation.store.ts | 67 - web/src/app/styles/_fonts.scss | 73 - web/src/app/styles/_grid.scss | 156 - web/src/app/styles/_normalize.scss | 447 - web/src/app/styles/details.scss | 75 - web/src/app/styles/lib.theme.scss | 126 - web/src/app/styles/status-tree.scss | 18 - web/src/app/styles/style.scss | 396 - web/src/app/templates/details.html | 29 - web/src/app/templates/status-tree.html | 17 - web/src/app/ws-logs/log.component.html | 37 - web/src/app/ws-logs/log.component.scss | 21 - web/src/app/ws-logs/log.component.ts | 101 - web/src/assets/.gitkeep | 0 web/src/assets/adcm-logo.png | Bin 9214 -> 0 bytes web/src/assets/favicon.ico | Bin 15406 -> 0 bytes web/src/assets/fonts/UbuntuMono-Bold.eot | Bin 182522 -> 0 bytes web/src/assets/fonts/UbuntuMono-Bold.ttf | Bin 182336 -> 0 bytes web/src/assets/fonts/UbuntuMono-Bold.woff | Bin 102452 -> 0 bytes .../assets/fonts/UbuntuMono-BoldItalic.eot | Bin 208930 -> 0 bytes .../assets/fonts/UbuntuMono-BoldItalic.ttf | Bin 208716 -> 0 bytes .../assets/fonts/UbuntuMono-BoldItalic.woff | Bin 123756 -> 0 bytes web/src/assets/fonts/UbuntuMono-Italic.eot | Bin 201366 -> 0 bytes web/src/assets/fonts/UbuntuMono-Italic.ttf | Bin 201172 -> 0 bytes web/src/assets/fonts/UbuntuMono-Italic.woff | Bin 109468 -> 0 bytes web/src/assets/fonts/UbuntuMono-Regular.eot | Bin 196910 -> 0 bytes web/src/assets/fonts/UbuntuMono-Regular.ttf | Bin 196728 -> 0 bytes web/src/assets/fonts/UbuntuMono-Regular.woff | Bin 106580 -> 0 bytes .../fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 | Bin 82512 -> 0 bytes web/src/assets/google_icons.svg | 50 - web/src/assets/i18n/static/en.json | 6 - web/src/assets/ico_32x32.png | Bin 874 -> 0 bytes web/src/assets/logo_.png | Bin 1686 -> 0 bytes web/src/assets/scss/_grid.scss | 156 - web/src/assets/scss/_mixins.scss | 42 - web/src/assets/scss/_normalize.scss | 447 - web/src/environments/environment.prod.ts | 19 - web/src/environments/environment.ts | 23 - web/src/index.html | 13 - web/src/main.ts | 23 - web/src/polyfills.ts | 77 - web/src/stories/Introduction.stories.mdx | 230 - web/src/stories/assets/code-brackets.svg | 1 - web/src/stories/assets/colors.svg | 1 - web/src/stories/assets/comments.svg | 1 - web/src/stories/assets/direction.svg | 1 - web/src/stories/assets/flow.svg | 1 - web/src/stories/assets/glasses.jpg | Bin 10064 -> 0 bytes web/src/stories/assets/plugin.svg | 1 - web/src/stories/assets/repo.svg | 1 - web/src/stories/assets/stackalt.svg | 1 - web/src/stories/bell.stories.ts | 50 - .../concern/concern-list-popup.stories.ts | 58 - .../stories/concern/concern-list.stories.ts | 54 - web/src/stories/concern/concern.stories.mdx | 7 - web/src/stories/concern/concern.stories.ts | 56 - web/src/stories/concern/mock.ts | 132 - .../status-tree/status-tree.stories.ts | 212 - web/src/styles.scss | 453 - web/src/test.ts | 43 - web/src/tsconfig.app.json | 21 - web/src/tsconfig.spec.json | 19 - web/src/uml/host.wsd | 92 - web/storybook.sh | 5 - web/tsconfig.base.json | 48 - web/tsconfig.json | 17 - web/tslint.json | 155 - web/yarn.lock | 16075 ---- 907 files changed, 1991 insertions(+), 130183 deletions(-) delete mode 100644 spec/_static/css/theme_custom.css delete mode 100644 spec/conf.py delete mode 100644 spec/index.rst delete mode 100644 spec/objects.rst delete mode 100644 spec/system/components.rst delete mode 100644 spec/system/index.rst delete mode 100644 spec/ui/actions.rst delete mode 100644 spec/ui/elements.rst delete mode 100644 spec/ui/img/cluster_services_template.png delete mode 100644 spec/ui/img/cluster_template.png delete mode 100644 spec/ui/img/common_template.png delete mode 100644 spec/ui/img/form_dialog_create_cluster.png delete mode 100644 spec/ui/img/form_login_full.png delete mode 100644 spec/ui/img/form_login_short.png delete mode 100644 spec/ui/img/template_table_view_big.png delete mode 100644 spec/ui/index.rst delete mode 100644 spec/usecase/action/index.rst delete mode 100644 spec/usecase/action/locks/hostprovider.rst delete mode 100644 spec/usecase/action/onhost.rst delete mode 100644 spec/usecase/action/onhost/cluster_on_host.rst delete mode 100644 spec/usecase/action/onhost/component_on_host.rst delete mode 100644 spec/usecase/action/onhost/on_host_list.rst delete mode 100644 spec/usecase/action/onhost/service_on_host.rst delete mode 100644 spec/usecase/action/onhost/target.rst delete mode 100644 spec/usecase/glossary.rst delete mode 100644 spec/usecase/index.rst delete mode 100644 web/.browserslistrc delete mode 100644 web/.editorconfig delete mode 100644 web/.eslintrc.js delete mode 100644 web/.gitignore delete mode 100644 web/.storybook/main.js delete mode 100644 web/.storybook/preview.js delete mode 100644 web/.storybook/tsconfig.json delete mode 100644 web/.storybook/typings.d.ts delete mode 100644 web/README.md delete mode 100644 web/angular.json delete mode 100755 web/build.sh delete mode 100755 web/build_static.sh delete mode 100644 web/documentation.json delete mode 100644 web/e2e/app.e2e-spec.ts delete mode 100644 web/e2e/app.po.ts delete mode 100644 web/e2e/login/login.e2e-spec.ts delete mode 100644 web/e2e/login/login.po.ts delete mode 100644 web/e2e/start/start.e2e-spec.ts delete mode 100644 web/e2e/start/start.po.ts delete mode 100644 web/e2e/tsconfig.e2e.json delete mode 100644 web/export/src/uml/host.png delete mode 100644 web/karma.conf.js delete mode 100755 web/ng_test.sh delete mode 100644 web/package.json delete mode 100644 web/protractor.conf.js delete mode 100644 web/proxy.conf.json delete mode 100644 web/src/_mixins.scss delete mode 100644 web/src/adcm-theme.scss delete mode 100644 web/src/adcm2.scss delete mode 100644 web/src/app/abstract-directives/adwp-base-list.directive.ts delete mode 100644 web/src/app/abstract-directives/adwp-list.directive.ts delete mode 100644 web/src/app/abstract-directives/base-detail.abstract.directive.ts delete mode 100644 web/src/app/abstract-directives/concern-list.directive.ts delete mode 100644 web/src/app/abstract-directives/detail.abstract.directive.ts delete mode 100644 web/src/app/abstract-directives/list.directive.ts delete mode 100644 web/src/app/abstract-directives/menu-item.abstract.directive.ts delete mode 100644 web/src/app/abstract-directives/popover-content.directive.ts delete mode 100644 web/src/app/abstract-directives/rbac-entity-list.directive.ts delete mode 100644 web/src/app/abstract-directives/rbac-options.directive.ts delete mode 100644 web/src/app/abstract-directives/status.abstract.directive.ts delete mode 100644 web/src/app/abstract/deletable-entity.abstract.service.ts delete mode 100644 web/src/app/abstract/entity-service.ts delete mode 100644 web/src/app/abstract/entity.abstract.service.ts delete mode 100644 web/src/app/abstract/having-status-tree.abstract.service.ts delete mode 100644 web/src/app/admin/admin.module.ts delete mode 100644 web/src/app/admin/audit-login/audit-login.component.html delete mode 100644 web/src/app/admin/audit-login/audit-login.component.scss delete mode 100644 web/src/app/admin/audit-login/audit-login.component.ts delete mode 100644 web/src/app/admin/audit-operations/audit-operations.component.html delete mode 100644 web/src/app/admin/audit-operations/audit-operations.component.scss delete mode 100644 web/src/app/admin/audit-operations/audit-operations.component.ts delete mode 100644 web/src/app/admin/groups/groups.component.html delete mode 100644 web/src/app/admin/groups/groups.component.scss delete mode 100644 web/src/app/admin/groups/groups.component.ts delete mode 100644 web/src/app/admin/intro.component.ts delete mode 100644 web/src/app/admin/pattern.component.ts delete mode 100644 web/src/app/admin/policies/policies.component.html delete mode 100644 web/src/app/admin/policies/policies.component.scss delete mode 100644 web/src/app/admin/policies/policies.component.ts delete mode 100644 web/src/app/admin/roles/roles.component.html delete mode 100644 web/src/app/admin/roles/roles.component.scss delete mode 100644 web/src/app/admin/roles/roles.component.ts delete mode 100644 web/src/app/admin/settings.component.ts delete mode 100644 web/src/app/admin/users/users.component.html delete mode 100644 web/src/app/admin/users/users.component.scss delete mode 100644 web/src/app/admin/users/users.component.ts delete mode 100644 web/src/app/adwp/index.ts delete mode 100644 web/src/app/adwp/lib/api/api-config.service.ts delete mode 100644 web/src/app/adwp/lib/api/api-config.ts delete mode 100644 web/src/app/adwp/lib/api/api.module.ts delete mode 100644 web/src/app/adwp/lib/auth/auth-config.service.ts delete mode 100644 web/src/app/adwp/lib/auth/auth-config.ts delete mode 100644 web/src/app/adwp/lib/auth/auth.module.ts delete mode 100644 web/src/app/adwp/lib/cdk/classes/assert.ts delete mode 100644 web/src/app/adwp/lib/cdk/classes/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/components/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/components/portal-host/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/components/portal-host/portal-host.component.ts delete mode 100644 web/src/app/adwp/lib/cdk/components/portal-host/portal-host.module.ts delete mode 100644 web/src/app/adwp/lib/cdk/components/portal-host/portal-host.style.scss delete mode 100644 web/src/app/adwp/lib/cdk/components/portal-host/portal-host.template.html delete mode 100644 web/src/app/adwp/lib/cdk/components/portal-host/portal.service.ts delete mode 100644 web/src/app/adwp/lib/cdk/constants/empty.ts delete mode 100644 web/src/app/adwp/lib/cdk/constants/identify.ts delete mode 100644 web/src/app/adwp/lib/cdk/constants/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/constants/matcher.ts delete mode 100644 web/src/app/adwp/lib/cdk/constants/polling-time.ts delete mode 100644 web/src/app/adwp/lib/cdk/constants/stringify.ts delete mode 100644 web/src/app/adwp/lib/cdk/constants/svg-node-filter.ts delete mode 100644 web/src/app/adwp/lib/cdk/decorators/default-prop.ts delete mode 100644 web/src/app/adwp/lib/cdk/decorators/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/decorators/pure.ts delete mode 100644 web/src/app/adwp/lib/cdk/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/interfaces/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/interfaces/portal-host.ts delete mode 100644 web/src/app/adwp/lib/cdk/observables/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/observables/typed-from-event.ts delete mode 100644 web/src/app/adwp/lib/cdk/observables/zone-free.ts delete mode 100644 web/src/app/adwp/lib/cdk/pipes/filter/filter.module.ts delete mode 100644 web/src/app/adwp/lib/cdk/pipes/filter/filter.pipe.ts delete mode 100644 web/src/app/adwp/lib/cdk/pipes/filter/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/pipes/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/pipes/mapper/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/pipes/mapper/mapper.module.ts delete mode 100644 web/src/app/adwp/lib/cdk/pipes/mapper/mapper.pipe.ts delete mode 100644 web/src/app/adwp/lib/cdk/services/destroy.service.ts delete mode 100644 web/src/app/adwp/lib/cdk/services/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/services/parents-scroll.service.ts delete mode 100644 web/src/app/adwp/lib/cdk/types/event-with.ts delete mode 100644 web/src/app/adwp/lib/cdk/types/handler.ts delete mode 100644 web/src/app/adwp/lib/cdk/types/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/types/mapper.ts delete mode 100644 web/src/app/adwp/lib/cdk/types/matcher.ts delete mode 100644 web/src/app/adwp/lib/cdk/types/overscroll-mode.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/array/concat-by.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/array/difference.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/array/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/dom/get-closest-element.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/dom/get-screen-width.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/dom/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/focus/get-closest-keyboard-focusable.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/focus/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/focus/is-native-keyboard-focusable.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/focus/is-native-mouse-focusable.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/focus/set-native-focused.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/format/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/format/px.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/math/in-range.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/math/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/miscellaneous/fallback-value.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/miscellaneous/index.ts delete mode 100644 web/src/app/adwp/lib/cdk/utils/miscellaneous/is-present.ts delete mode 100644 web/src/app/adwp/lib/core/abstract/abstract-dropdown.ts delete mode 100644 web/src/app/adwp/lib/core/abstract/index.ts delete mode 100644 web/src/app/adwp/lib/core/animations/animations.ts delete mode 100644 web/src/app/adwp/lib/core/animations/index.ts delete mode 100644 web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.component.ts delete mode 100644 web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.module.ts delete mode 100644 web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.style.scss delete mode 100644 web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.template.html delete mode 100644 web/src/app/adwp/lib/core/components/dropdown-box/index.ts delete mode 100644 web/src/app/adwp/lib/core/components/index.ts delete mode 100644 web/src/app/adwp/lib/core/components/select/index.ts delete mode 100644 web/src/app/adwp/lib/core/components/select/select.component.html delete mode 100644 web/src/app/adwp/lib/core/components/select/select.component.scss delete mode 100644 web/src/app/adwp/lib/core/components/select/select.component.ts delete mode 100644 web/src/app/adwp/lib/core/components/select/select.module.ts delete mode 100644 web/src/app/adwp/lib/core/components/selection-list/selection-list-actions.component.html delete mode 100644 web/src/app/adwp/lib/core/components/selection-list/selection-list-actions.component.ts delete mode 100644 web/src/app/adwp/lib/core/components/selection-list/selection-list.component.css delete mode 100644 web/src/app/adwp/lib/core/components/selection-list/selection-list.component.html delete mode 100644 web/src/app/adwp/lib/core/components/selection-list/selection-list.component.ts delete mode 100644 web/src/app/adwp/lib/core/components/selection-list/selection-list.module.ts delete mode 100644 web/src/app/adwp/lib/core/constants/absolute-box-sizes.ts delete mode 100644 web/src/app/adwp/lib/core/constants/index.ts delete mode 100644 web/src/app/adwp/lib/core/directives/click-outside/click-outside.directive.ts delete mode 100644 web/src/app/adwp/lib/core/directives/click-outside/click-outside.module.ts delete mode 100644 web/src/app/adwp/lib/core/directives/click-outside/index.ts delete mode 100644 web/src/app/adwp/lib/core/directives/dropdown/dropdown.directive.ts delete mode 100644 web/src/app/adwp/lib/core/directives/dropdown/dropdown.module.ts delete mode 100644 web/src/app/adwp/lib/core/directives/dropdown/index.ts delete mode 100644 web/src/app/adwp/lib/core/directives/index.ts delete mode 100644 web/src/app/adwp/lib/core/enums/dropdown-animation.ts delete mode 100644 web/src/app/adwp/lib/core/enums/index.ts delete mode 100644 web/src/app/adwp/lib/core/index.ts delete mode 100644 web/src/app/adwp/lib/core/interfaces/animation-options.ts delete mode 100644 web/src/app/adwp/lib/core/interfaces/dropdown-directive.ts delete mode 100644 web/src/app/adwp/lib/core/interfaces/index.ts delete mode 100644 web/src/app/adwp/lib/core/tokens/animation-options.ts delete mode 100644 web/src/app/adwp/lib/core/tokens/animations-duration.ts delete mode 100644 web/src/app/adwp/lib/core/tokens/dropdown-directive.ts delete mode 100644 web/src/app/adwp/lib/core/tokens/index.ts delete mode 100644 web/src/app/adwp/lib/core/types/direction.ts delete mode 100644 web/src/app/adwp/lib/core/types/dropdown-width.ts delete mode 100644 web/src/app/adwp/lib/core/types/index.ts delete mode 100644 web/src/app/adwp/lib/core/utils/dom/check-fixed-position.ts delete mode 100644 web/src/app/adwp/lib/core/utils/dom/index.ts delete mode 100644 web/src/app/adwp/lib/core/utils/index.ts delete mode 100644 web/src/app/adwp/lib/dialog/ComponentData.ts delete mode 100644 web/src/app/adwp/lib/dialog/dialog.component.html delete mode 100644 web/src/app/adwp/lib/dialog/dialog.component.scss delete mode 100644 web/src/app/adwp/lib/dialog/dialog.component.spec.ts delete mode 100644 web/src/app/adwp/lib/dialog/dialog.component.ts delete mode 100644 web/src/app/adwp/lib/dialog/dialog.module.ts delete mode 100644 web/src/app/adwp/lib/footer/footer.module.ts delete mode 100644 web/src/app/adwp/lib/footer/footer/footer.component.html delete mode 100644 web/src/app/adwp/lib/footer/footer/footer.component.scss delete mode 100644 web/src/app/adwp/lib/footer/footer/footer.component.ts delete mode 100644 web/src/app/adwp/lib/form-element/controls/controls.component.html delete mode 100644 web/src/app/adwp/lib/form-element/controls/controls.component.scss delete mode 100644 web/src/app/adwp/lib/form-element/controls/controls.component.spec.ts delete mode 100644 web/src/app/adwp/lib/form-element/controls/controls.component.ts delete mode 100644 web/src/app/adwp/lib/form-element/field.directive.spec.ts delete mode 100644 web/src/app/adwp/lib/form-element/field.directive.ts delete mode 100644 web/src/app/adwp/lib/form-element/form-element.module.ts delete mode 100644 web/src/app/adwp/lib/form-element/input-select/input-select.component.html delete mode 100644 web/src/app/adwp/lib/form-element/input-select/input-select.component.scss delete mode 100644 web/src/app/adwp/lib/form-element/input-select/input-select.component.ts delete mode 100644 web/src/app/adwp/lib/form-element/input/input.component.html delete mode 100644 web/src/app/adwp/lib/form-element/input/input.component.scss delete mode 100644 web/src/app/adwp/lib/form-element/input/input.component.spec.ts delete mode 100644 web/src/app/adwp/lib/form-element/input/input.component.ts delete mode 100644 web/src/app/adwp/lib/header/header.module.ts delete mode 100644 web/src/app/adwp/lib/header/top-menu/top-menu.component.html delete mode 100644 web/src/app/adwp/lib/header/top-menu/top-menu.component.scss delete mode 100644 web/src/app/adwp/lib/header/top-menu/top-menu.component.ts delete mode 100644 web/src/app/adwp/lib/helpers/cookie.ts delete mode 100644 web/src/app/adwp/lib/helpers/event-helper.ts delete mode 100644 web/src/app/adwp/lib/helpers/guid.ts delete mode 100644 web/src/app/adwp/lib/http-interceptors/django-interceptor.ts delete mode 100644 web/src/app/adwp/lib/list-storage/list-storage.module.ts delete mode 100644 web/src/app/adwp/lib/list/cell/component-cell.component.ts delete mode 100644 web/src/app/adwp/lib/list/cell/link-cell.component.ts delete mode 100644 web/src/app/adwp/lib/list/component-holder.directive.ts delete mode 100644 web/src/app/adwp/lib/list/hover.directive.ts delete mode 100644 web/src/app/adwp/lib/list/list-config.service.ts delete mode 100644 web/src/app/adwp/lib/list/list-config.ts delete mode 100644 web/src/app/adwp/lib/list/list.module.ts delete mode 100644 web/src/app/adwp/lib/list/list/list.component.html delete mode 100644 web/src/app/adwp/lib/list/list/list.component.scss delete mode 100644 web/src/app/adwp/lib/list/list/list.component.spec.ts delete mode 100644 web/src/app/adwp/lib/list/list/list.component.ts delete mode 100644 web/src/app/adwp/lib/list/paginator/paginator.component.html delete mode 100644 web/src/app/adwp/lib/list/paginator/paginator.component.scss delete mode 100644 web/src/app/adwp/lib/list/paginator/paginator.component.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/as-string.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/calc-dynamic-cell.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/calc-link-cell.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/is-all-checked.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/is-indeterminate-checked.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/is-main-checkbox-disabled.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/list-checkbox-disabled.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/list-value.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/pages.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/time.pipe.spec.ts delete mode 100644 web/src/app/adwp/lib/list/pipes/time.pipe.ts delete mode 100644 web/src/app/adwp/lib/list/row/component-row.component.ts delete mode 100644 web/src/app/adwp/lib/list/table/table.component.html delete mode 100644 web/src/app/adwp/lib/list/table/table.component.scss delete mode 100644 web/src/app/adwp/lib/list/table/table.component.spec.ts delete mode 100644 web/src/app/adwp/lib/list/table/table.component.ts delete mode 100644 web/src/app/adwp/lib/loading/loading.component.ts delete mode 100644 web/src/app/adwp/lib/loading/loading.module.ts delete mode 100644 web/src/app/adwp/lib/login-form/login-form.component.html delete mode 100644 web/src/app/adwp/lib/login-form/login-form.component.scss delete mode 100644 web/src/app/adwp/lib/login-form/login-form.component.ts delete mode 100644 web/src/app/adwp/lib/login-form/login-form.module.ts delete mode 100644 web/src/app/adwp/lib/miscellaneous/miscellaneous.module.ts delete mode 100644 web/src/app/adwp/lib/models/api-options.ts delete mode 100644 web/src/app/adwp/lib/models/api-params.ts delete mode 100644 web/src/app/adwp/lib/models/auth-credentials.ts delete mode 100644 web/src/app/adwp/lib/models/base.directive.ts delete mode 100644 web/src/app/adwp/lib/models/config-options.ts delete mode 100644 web/src/app/adwp/lib/models/django-http-error-response.ts delete mode 100644 web/src/app/adwp/lib/models/django-http-error.ts delete mode 100644 web/src/app/adwp/lib/models/entity.ts delete mode 100644 web/src/app/adwp/lib/models/field-options.ts delete mode 100644 web/src/app/adwp/lib/models/list.ts delete mode 100644 web/src/app/adwp/lib/models/login-credentials.ts delete mode 100644 web/src/app/adwp/lib/models/menu-item.ts delete mode 100644 web/src/app/adwp/lib/models/root.ts delete mode 100644 web/src/app/adwp/lib/models/version-info.ts delete mode 100644 web/src/app/adwp/lib/notification/notification.module.ts delete mode 100644 web/src/app/adwp/lib/services/api.service.ts delete mode 100644 web/src/app/adwp/lib/services/app.service.ts delete mode 100644 web/src/app/adwp/lib/services/auth.service.ts delete mode 100644 web/src/app/adwp/lib/services/config.service.ts delete mode 100644 web/src/app/adwp/lib/services/index.ts delete mode 100644 web/src/app/adwp/lib/services/list-storage.service.ts delete mode 100644 web/src/app/adwp/lib/services/notification.service.ts delete mode 100644 web/src/app/adwp/lib/services/socket-config.service.ts delete mode 100644 web/src/app/adwp/lib/services/socket.service.ts delete mode 100644 web/src/app/adwp/lib/socket/socket-config.ts delete mode 100644 web/src/app/adwp/lib/socket/socket.module.ts delete mode 100644 web/src/app/adwp/lib/store/api/api.effects.ts delete mode 100644 web/src/app/adwp/lib/store/api/api.reducer.ts delete mode 100644 web/src/app/adwp/lib/store/auth/auth.actions.ts delete mode 100644 web/src/app/adwp/lib/store/auth/auth.effects.ts delete mode 100644 web/src/app/adwp/lib/store/auth/auth.reducers.ts delete mode 100644 web/src/app/adwp/lib/store/auth/auth.selectors.ts delete mode 100644 web/src/app/adwp/lib/store/factory.ts delete mode 100644 web/src/app/adwp/lib/store/socket/socket.actions.ts delete mode 100644 web/src/app/adwp/lib/store/socket/socket.reducers.ts delete mode 100644 web/src/app/adwp/lib/store/socket/socket.selectors.ts delete mode 100644 web/src/app/adwp/lib/store/state.ts delete mode 100644 web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.html delete mode 100644 web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.scss delete mode 100644 web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.spec.ts delete mode 100644 web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.ts delete mode 100644 web/src/app/adwp/lib/toolbar/toolbar.component.html delete mode 100644 web/src/app/adwp/lib/toolbar/toolbar.component.scss delete mode 100644 web/src/app/adwp/lib/toolbar/toolbar.component.ts delete mode 100644 web/src/app/adwp/lib/toolbar/toolbar.module.ts delete mode 100644 web/src/app/adwp/lib/ui-widgets.module.ts delete mode 100644 web/src/app/adwp/test.ts delete mode 100644 web/src/app/app-routing.module.ts delete mode 100644 web/src/app/app.component.ts delete mode 100644 web/src/app/app.module.ts delete mode 100644 web/src/app/components/actions-button/actions-button.component.html delete mode 100644 web/src/app/components/actions-button/actions-button.component.scss delete mode 100644 web/src/app/components/actions-button/actions-button.component.spec.ts delete mode 100644 web/src/app/components/actions-button/actions-button.component.ts delete mode 100644 web/src/app/components/bell/bell.component.scss delete mode 100644 web/src/app/components/bell/bell.component.ts delete mode 100644 web/src/app/components/bundle/bundle-details/bundle-details.component.ts delete mode 100644 web/src/app/components/cluster/cluster-details/cluster-details.component.ts delete mode 100644 web/src/app/components/cluster/cluster-status/cluster-status.component.ts delete mode 100644 web/src/app/components/cluster/hcmap/hcmap.component.ts delete mode 100644 web/src/app/components/cluster/host/cluster-host.component.ts delete mode 100644 web/src/app/components/cluster/services/services.component.ts delete mode 100644 web/src/app/components/columns/cluster-column/cluster-column.component.ts delete mode 100644 web/src/app/components/columns/download-button-column/download-button-column.component.html delete mode 100644 web/src/app/components/columns/download-button-column/download-button-column.component.scss delete mode 100644 web/src/app/components/columns/download-button-column/download-button-column.component.ts delete mode 100644 web/src/app/components/columns/edition-column/edition-column.component.scss delete mode 100644 web/src/app/components/columns/edition-column/edition-column.component.ts delete mode 100644 web/src/app/components/columns/history-column/history-column.component.html delete mode 100644 web/src/app/components/columns/history-column/history-column.component.scss delete mode 100644 web/src/app/components/columns/history-column/history-column.component.ts delete mode 100644 web/src/app/components/columns/job-name/job-name.component.scss delete mode 100644 web/src/app/components/columns/job-name/job-name.component.ts delete mode 100644 web/src/app/components/columns/job-status-column/job-status-column.component.html delete mode 100644 web/src/app/components/columns/job-status-column/job-status-column.component.scss delete mode 100644 web/src/app/components/columns/job-status-column/job-status-column.component.ts delete mode 100644 web/src/app/components/columns/name-edit-column/name-edit-column-field.component.ts delete mode 100644 web/src/app/components/columns/name-edit-column/name-edit-column.component.html delete mode 100644 web/src/app/components/columns/name-edit-column/name-edit-column.component.scss delete mode 100644 web/src/app/components/columns/name-edit-column/name-edit-column.component.ts delete mode 100644 web/src/app/components/columns/signature-column/signature-column.component.html delete mode 100644 web/src/app/components/columns/signature-column/signature-column.component.scss delete mode 100644 web/src/app/components/columns/signature-column/signature-column.component.ts delete mode 100644 web/src/app/components/columns/state-column/state-column.component.html delete mode 100644 web/src/app/components/columns/state-column/state-column.component.scss delete mode 100644 web/src/app/components/columns/state-column/state-column.component.spec.ts delete mode 100644 web/src/app/components/columns/state-column/state-column.component.ts delete mode 100644 web/src/app/components/columns/status-column/status-column.component.html delete mode 100644 web/src/app/components/columns/status-column/status-column.component.scss delete mode 100644 web/src/app/components/columns/status-column/status-column.component.spec.ts delete mode 100644 web/src/app/components/columns/status-column/status-column.component.ts delete mode 100644 web/src/app/components/columns/task-name/task-name.component.scss delete mode 100644 web/src/app/components/columns/task-name/task-name.component.ts delete mode 100644 web/src/app/components/columns/task-objects/task-objects.component.html delete mode 100644 web/src/app/components/columns/task-objects/task-objects.component.scss delete mode 100644 web/src/app/components/columns/task-objects/task-objects.component.ts delete mode 100644 web/src/app/components/columns/task-status-column/task-status-column.component.html delete mode 100644 web/src/app/components/columns/task-status-column/task-status-column.component.scss delete mode 100644 web/src/app/components/columns/task-status-column/task-status-column.component.ts delete mode 100644 web/src/app/components/columns/wrapper-column/wrapper-column.component.html delete mode 100644 web/src/app/components/columns/wrapper-column/wrapper-column.component.scss delete mode 100644 web/src/app/components/columns/wrapper-column/wrapper-column.component.ts delete mode 100644 web/src/app/components/concern/concern-item/concern-item.component.html delete mode 100644 web/src/app/components/concern/concern-item/concern-item.component.scss delete mode 100644 web/src/app/components/concern/concern-item/concern-item.component.ts delete mode 100644 web/src/app/components/concern/concern-list-ref/concern-list-ref.component.scss delete mode 100644 web/src/app/components/concern/concern-list-ref/concern-list-ref.component.ts delete mode 100644 web/src/app/components/concern/concern-list/concern-list.component.scss delete mode 100644 web/src/app/components/concern/concern-list/concern-list.component.ts delete mode 100644 web/src/app/components/concern/concern.component.html delete mode 100644 web/src/app/components/concern/concern.component.scss delete mode 100644 web/src/app/components/concern/concern.component.ts delete mode 100644 web/src/app/components/host/host-details/host-details.component.ts delete mode 100644 web/src/app/components/host/host-list/host-list.component.scss delete mode 100644 web/src/app/components/host/host-list/host-list.component.ts delete mode 100644 web/src/app/components/host/host-status/host-status.component.ts delete mode 100644 web/src/app/components/hostprovider/group-config-details/group-config-details.component.ts delete mode 100644 web/src/app/components/hostprovider/hostprovider.component.ts delete mode 100644 web/src/app/components/hostprovider/provider-details/provider-details.component.ts delete mode 100644 web/src/app/components/job/job-details/job-details.component.ts delete mode 100644 web/src/app/components/job/jobs/jobs.component.scss delete mode 100644 web/src/app/components/job/jobs/jobs.component.ts delete mode 100644 web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.html delete mode 100644 web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.scss delete mode 100644 web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.spec.ts delete mode 100644 web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.ts delete mode 100644 web/src/app/components/navigation/navigation.component.spec.ts delete mode 100644 web/src/app/components/navigation/navigation.component.ts delete mode 100644 web/src/app/components/notifications/notifications.component.scss delete mode 100644 web/src/app/components/notifications/notifications.component.spec.ts delete mode 100644 web/src/app/components/notifications/notifications.component.ts delete mode 100644 web/src/app/components/popover/popover.component.scss delete mode 100644 web/src/app/components/popover/popover.component.ts delete mode 100644 web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.html delete mode 100644 web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.scss delete mode 100644 web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.ts delete mode 100644 web/src/app/components/rbac/group-form/options/rbac-groups-as-options.directive.ts delete mode 100644 web/src/app/components/rbac/group-form/options/rbac-groups-as-options.module.ts delete mode 100644 web/src/app/components/rbac/group-form/rbac-group-form.component.html delete mode 100644 web/src/app/components/rbac/group-form/rbac-group-form.component.ts delete mode 100644 web/src/app/components/rbac/group-form/rbac-group-form.module.ts delete mode 100644 web/src/app/components/rbac/permission-form/rbac-permission-form.component.html delete mode 100644 web/src/app/components/rbac/permission-form/rbac-permission-form.component.scss delete mode 100644 web/src/app/components/rbac/permission-form/rbac-permission-form.component.ts delete mode 100644 web/src/app/components/rbac/permission-form/rbac-permission-form.module.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.html delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.scss delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/validators/user-or-group-required.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.html delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.scss delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.html delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.scss delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.html delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.scss delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.html delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.scss delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/get-clusters-from-services.pipe.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.html delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.scss delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/directives/parametrized-by.directive.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/pipes/parametrized.pipe.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.html delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.scss delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form.component.html delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form.component.ts delete mode 100644 web/src/app/components/rbac/policy-form/rbac-policy-form.module.ts delete mode 100644 web/src/app/components/rbac/policy-form/validators/object-validator.ts delete mode 100644 web/src/app/components/rbac/policy-form/validators/provider-or-host.ts delete mode 100644 web/src/app/components/rbac/role-form/options/rbac-roles-as-options.directive.ts delete mode 100644 web/src/app/components/rbac/role-form/options/rbac-roles-as-options.module.ts delete mode 100644 web/src/app/components/rbac/role-form/rbac-role-form.component.html delete mode 100644 web/src/app/components/rbac/role-form/rbac-role-form.component.scss delete mode 100644 web/src/app/components/rbac/role-form/rbac-role-form.component.ts delete mode 100644 web/src/app/components/rbac/role-form/rbac-role-form.module.ts delete mode 100644 web/src/app/components/rbac/user-form/options/rbac-users-as-options.directive.ts delete mode 100644 web/src/app/components/rbac/user-form/options/rbac-users-as-options.module.ts delete mode 100644 web/src/app/components/rbac/user-form/rbac-user-form.component.html delete mode 100644 web/src/app/components/rbac/user-form/rbac-user-form.component.scss delete mode 100644 web/src/app/components/rbac/user-form/rbac-user-form.component.ts delete mode 100644 web/src/app/components/rbac/user-form/rbac-user-form.module.ts delete mode 100644 web/src/app/components/service-component/service-component-details/service-component-details.component.ts delete mode 100644 web/src/app/components/service-component/service-component-status/service-component-status.component.ts delete mode 100644 web/src/app/components/service-component/service-components.component.ts delete mode 100644 web/src/app/components/service/service-details/service-details.component.ts delete mode 100644 web/src/app/components/service/service-status/service-status.component.ts delete mode 100644 web/src/app/components/snack-bar/snack-bar.component.ts delete mode 100644 web/src/app/components/status-tree/status-tree.component.html delete mode 100644 web/src/app/components/status-tree/status-tree.component.scss delete mode 100644 web/src/app/components/status-tree/status-tree.component.ts delete mode 100644 web/src/app/config-groups/components/config-group-add/config-group-add.component.ts delete mode 100644 web/src/app/config-groups/components/config-group-host-add/config-group-host-add.component.ts delete mode 100644 web/src/app/config-groups/components/index.ts delete mode 100644 web/src/app/config-groups/config-group.module.ts delete mode 100644 web/src/app/config-groups/index.ts delete mode 100644 web/src/app/config-groups/loader.ts delete mode 100644 web/src/app/config-groups/model/config-group.model.ts delete mode 100644 web/src/app/config-groups/model/index.ts delete mode 100644 web/src/app/config-groups/pages/group-list/group-list.component.ts delete mode 100644 web/src/app/config-groups/pages/host-list/host-list.component.ts delete mode 100644 web/src/app/config-groups/pages/index.ts delete mode 100644 web/src/app/config-groups/service/config-group-add.service.ts delete mode 100644 web/src/app/config-groups/service/config-group-host-add.service.ts delete mode 100644 web/src/app/config-groups/service/config-group-host-list.service.ts delete mode 100644 web/src/app/config-groups/service/config-group-list.service.ts delete mode 100644 web/src/app/config-groups/service/config-group.service.ts delete mode 100644 web/src/app/config-groups/service/index.ts delete mode 100644 web/src/app/core/animations/index.ts delete mode 100644 web/src/app/core/api/api.effects.ts delete mode 100644 web/src/app/core/api/api.reducer.ts delete mode 100644 web/src/app/core/api/api.service.ts delete mode 100644 web/src/app/core/api/index.ts delete mode 100644 web/src/app/core/auth/auth.guard.ts delete mode 100644 web/src/app/core/auth/auth.service.ts delete mode 100644 web/src/app/core/auth/auth.store.ts delete mode 100644 web/src/app/core/core.module.ts delete mode 100644 web/src/app/core/http-interseptors/auth-interseptor.ts delete mode 100644 web/src/app/core/http-interseptors/caching-interseptor.ts delete mode 100644 web/src/app/core/http-interseptors/request-cache.service.ts delete mode 100644 web/src/app/core/services/app/app.service.spec.ts delete mode 100644 web/src/app/core/services/app/app.service.ts delete mode 100644 web/src/app/core/services/channel.service.spec.ts delete mode 100644 web/src/app/core/services/channel.service.ts delete mode 100644 web/src/app/core/services/cluster.service.ts delete mode 100644 web/src/app/core/services/config.service.ts delete mode 100644 web/src/app/core/services/dom.service.spec.ts delete mode 100644 web/src/app/core/services/dom.service.ts delete mode 100644 web/src/app/core/services/fully-rendered.service.ts delete mode 100644 web/src/app/core/services/index.ts delete mode 100644 web/src/app/core/services/preloader.service.ts delete mode 100644 web/src/app/core/services/router-history.service.ts delete mode 100644 web/src/app/core/services/stack.service.ts delete mode 100644 web/src/app/core/store/index.ts delete mode 100644 web/src/app/core/store/issue.ts delete mode 100644 web/src/app/core/store/profile/index.ts delete mode 100644 web/src/app/core/store/profile/profile.service.ts delete mode 100644 web/src/app/core/store/router/route-serializer.ts delete mode 100644 web/src/app/core/store/router/router.actions.ts delete mode 100644 web/src/app/core/store/router/router.effects.ts delete mode 100644 web/src/app/core/store/sockets/socket.effect.ts delete mode 100644 web/src/app/core/store/sockets/socket.reducer.ts delete mode 100644 web/src/app/core/store/sockets/socket.service.ts delete mode 100644 web/src/app/core/types/actions.ts delete mode 100644 web/src/app/core/types/api.ts delete mode 100644 web/src/app/core/types/context-manager.ts delete mode 100644 web/src/app/core/types/func.spec.ts delete mode 100644 web/src/app/core/types/func.ts delete mode 100644 web/src/app/core/types/host-component.ts delete mode 100644 web/src/app/core/types/import-export.ts delete mode 100644 web/src/app/core/types/index.ts delete mode 100644 web/src/app/core/types/stack.ts delete mode 100644 web/src/app/core/types/task-job.ts delete mode 100644 web/src/app/core/types/utils.ts delete mode 100644 web/src/app/directives/popover.directive.ts delete mode 100644 web/src/app/entry/bundle/bundle-list.component.ts delete mode 100644 web/src/app/entry/bundle/bundle.module.ts delete mode 100644 web/src/app/entry/cluster/cluster.component.scss delete mode 100644 web/src/app/entry/cluster/cluster.component.ts delete mode 100644 web/src/app/entry/cluster/cluster.module.ts delete mode 100644 web/src/app/entry/entry.module.ts delete mode 100644 web/src/app/entry/job/job-info.component.ts delete mode 100644 web/src/app/entry/job/job-routing.module.ts delete mode 100644 web/src/app/entry/job/job.component.ts delete mode 100644 web/src/app/entry/job/job.module.ts delete mode 100644 web/src/app/entry/job/log/check.component.ts delete mode 100644 web/src/app/entry/job/log/log.component.spec.ts delete mode 100644 web/src/app/entry/job/log/log.component.ts delete mode 100644 web/src/app/entry/job/log/text.component.ts delete mode 100644 web/src/app/entry/task/hover.directive.spec.ts delete mode 100644 web/src/app/entry/task/hover.directive.ts delete mode 100644 web/src/app/entry/task/task.module.ts delete mode 100644 web/src/app/entry/task/tasks.component.html delete mode 100644 web/src/app/entry/task/tasks.component.scss delete mode 100644 web/src/app/entry/task/tasks.component.ts delete mode 100644 web/src/app/factories/details.factory.ts delete mode 100644 web/src/app/factories/list.factory.ts delete mode 100644 web/src/app/helpers/date-helper.ts delete mode 100644 web/src/app/helpers/issue-helper.ts delete mode 100644 web/src/app/helpers/objects-helper.ts delete mode 100644 web/src/app/main/login/login.component.html delete mode 100644 web/src/app/main/login/login.component.scss delete mode 100644 web/src/app/main/login/login.component.ts delete mode 100644 web/src/app/main/main.module.ts delete mode 100644 web/src/app/main/profile/profile.component.ts delete mode 100644 web/src/app/main/progress.component.ts delete mode 100644 web/src/app/main/server-status.component.ts delete mode 100644 web/src/app/main/support/support.component.html delete mode 100644 web/src/app/main/support/support.component.scss delete mode 100644 web/src/app/main/support/support.component.ts delete mode 100644 web/src/app/main/top/top.component.html delete mode 100644 web/src/app/main/top/top.component.scss delete mode 100644 web/src/app/main/top/top.component.ts delete mode 100644 web/src/app/models/action.ts delete mode 100644 web/src/app/models/bundle.ts delete mode 100644 web/src/app/models/cluster-service.ts delete mode 100644 web/src/app/models/cluster.ts delete mode 100644 web/src/app/models/component.ts delete mode 100644 web/src/app/models/concern/concern-reason.ts delete mode 100644 web/src/app/models/concern/concern.ts delete mode 100644 web/src/app/models/details.ts delete mode 100644 web/src/app/models/entity-names.ts delete mode 100644 web/src/app/models/entity.ts delete mode 100644 web/src/app/models/eventable-service.ts delete mode 100644 web/src/app/models/host.ts delete mode 100644 web/src/app/models/issue.ts delete mode 100644 web/src/app/models/list-result.ts delete mode 100644 web/src/app/models/rbac/rbac-audit-login.model.ts delete mode 100644 web/src/app/models/rbac/rbac-audit-operations.model.ts delete mode 100644 web/src/app/models/rbac/rbac-group.model.ts delete mode 100644 web/src/app/models/rbac/rbac-object-candidate.ts delete mode 100644 web/src/app/models/rbac/rbac-permission.model.ts delete mode 100644 web/src/app/models/rbac/rbac-policy.model.ts delete mode 100644 web/src/app/models/rbac/rbac-role.model.ts delete mode 100644 web/src/app/models/rbac/rbac-user.model.ts delete mode 100644 web/src/app/models/service-component.ts delete mode 100644 web/src/app/models/status-tree.ts delete mode 100644 web/src/app/models/universal-adcm-event-data.ts delete mode 100644 web/src/app/pipes/bell-task-link.pipe.ts delete mode 100644 web/src/app/pipes/entity-status-to-status-tree.pipe.ts delete mode 100644 web/src/app/pipes/has-selected.pipe.ts delete mode 100644 web/src/app/pipes/is-array.pipe.ts delete mode 100644 web/src/app/pipes/issue-message-placeholder.pipe.spec.ts delete mode 100644 web/src/app/pipes/issue-message-placeholder.pipe.ts delete mode 100644 web/src/app/pipes/issue-path.pipe.ts delete mode 100644 web/src/app/pipes/keys.pipe.ts delete mode 100644 web/src/app/pipes/nav-item.pipe.ts delete mode 100644 web/src/app/pipes/object-link-column.pipe.ts delete mode 100644 web/src/app/pipes/pick-keys.pipe.ts delete mode 100644 web/src/app/pipes/sort-objects.pipe.ts delete mode 100644 web/src/app/pipes/status-tree-link.pipe.ts delete mode 100644 web/src/app/pipes/to-data-source.pipe.ts delete mode 100644 web/src/app/pipes/translate-object-keys.pipe.ts delete mode 100644 web/src/app/services/bundle.service.ts delete mode 100644 web/src/app/services/cluster-entity.service.ts delete mode 100644 web/src/app/services/concern.service.ts delete mode 100644 web/src/app/services/host.service.ts delete mode 100644 web/src/app/services/issue-message.service.spec.ts delete mode 100644 web/src/app/services/job.service.ts delete mode 100644 web/src/app/services/provider.service.ts delete mode 100644 web/src/app/services/rbac-audit-login.service.ts delete mode 100644 web/src/app/services/rbac-audit-operations.service.ts delete mode 100644 web/src/app/services/rbac-group.service.ts delete mode 100644 web/src/app/services/rbac-object-candidate.service.ts delete mode 100644 web/src/app/services/rbac-policy.service.ts delete mode 100644 web/src/app/services/rbac-role.service.ts delete mode 100644 web/src/app/services/rbac-user.service.ts delete mode 100644 web/src/app/services/service-component.service.ts delete mode 100644 web/src/app/services/service.service.ts delete mode 100644 web/src/app/services/stats.service.ts delete mode 100644 web/src/app/services/task.service.ts delete mode 100644 web/src/app/shared/add-component/add-button.component.ts delete mode 100644 web/src/app/shared/add-component/add-cluster.component.ts delete mode 100644 web/src/app/shared/add-component/add-form.component.ts delete mode 100644 web/src/app/shared/add-component/add-service-model.ts delete mode 100644 web/src/app/shared/add-component/add.service.ts delete mode 100644 web/src/app/shared/add-component/adding.module.ts delete mode 100644 web/src/app/shared/add-component/base-form.directive.ts delete mode 100644 web/src/app/shared/add-component/controls.component.ts delete mode 100644 web/src/app/shared/add-component/host.component.ts delete mode 100644 web/src/app/shared/add-component/host2cluster.component.scss delete mode 100644 web/src/app/shared/add-component/host2cluster.component.ts delete mode 100644 web/src/app/shared/add-component/index.ts delete mode 100644 web/src/app/shared/add-component/interfaces/relation-list.ts delete mode 100644 web/src/app/shared/add-component/naming.ts delete mode 100644 web/src/app/shared/add-component/provider.component.ts delete mode 100644 web/src/app/shared/add-component/rbac-form.directive.ts delete mode 100644 web/src/app/shared/add-component/service.component.ts delete mode 100644 web/src/app/shared/components/actions/action-list/action-list.component.html delete mode 100644 web/src/app/shared/components/actions/action-list/action-list.component.scss delete mode 100644 web/src/app/shared/components/actions/action-list/action-list.component.spec.ts delete mode 100644 web/src/app/shared/components/actions/action-list/action-list.component.ts delete mode 100644 web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.scss delete mode 100644 web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.spec.ts delete mode 100644 web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.ts delete mode 100644 web/src/app/shared/components/actions/actions.component.scss delete mode 100644 web/src/app/shared/components/actions/actions.component.spec.ts delete mode 100644 web/src/app/shared/components/actions/actions.component.ts delete mode 100644 web/src/app/shared/components/actions/actions.directive.spec.ts delete mode 100644 web/src/app/shared/components/actions/actions.directive.ts delete mode 100644 web/src/app/shared/components/actions/actions.service.spec.ts delete mode 100644 web/src/app/shared/components/actions/actions.service.ts delete mode 100644 web/src/app/shared/components/actions/master/action-master-config.component.ts delete mode 100644 web/src/app/shared/components/actions/master/master.component.html delete mode 100644 web/src/app/shared/components/actions/master/master.component.spec.ts delete mode 100644 web/src/app/shared/components/actions/master/master.component.ts delete mode 100644 web/src/app/shared/components/actions/master/master.service.ts delete mode 100644 web/src/app/shared/components/button-spinner.component.ts delete mode 100644 web/src/app/shared/components/crumbs/crumbs.component.scss delete mode 100644 web/src/app/shared/components/crumbs/crumbs.component.ts delete mode 100644 web/src/app/shared/components/dialog.component.ts delete mode 100644 web/src/app/shared/components/import/import.component.scss delete mode 100644 web/src/app/shared/components/import/import.component.ts delete mode 100644 web/src/app/shared/components/index.ts delete mode 100644 web/src/app/shared/components/issue-info.component.spec.ts delete mode 100644 web/src/app/shared/components/issue-info.component.ts delete mode 100644 web/src/app/shared/components/list/base-list.directive.ts delete mode 100644 web/src/app/shared/components/list/list-service-token.ts delete mode 100644 web/src/app/shared/components/list/list.service.ts delete mode 100644 web/src/app/shared/components/list/multi-sort.directive.ts delete mode 100644 web/src/app/shared/components/main-info.component.ts delete mode 100644 web/src/app/shared/components/status-info.component.ts delete mode 100644 web/src/app/shared/components/status/status.service.ts delete mode 100644 web/src/app/shared/components/tooltip/index.ts delete mode 100644 web/src/app/shared/components/tooltip/tooltip.component.scss delete mode 100644 web/src/app/shared/components/tooltip/tooltip.component.ts delete mode 100644 web/src/app/shared/components/tooltip/tooltip.directive.ts delete mode 100644 web/src/app/shared/components/tooltip/tooltip.module.ts delete mode 100644 web/src/app/shared/components/tooltip/tooltip.service.ts delete mode 100644 web/src/app/shared/components/upgrades/master/master.component.html delete mode 100644 web/src/app/shared/components/upgrades/master/master.component.scss delete mode 100644 web/src/app/shared/components/upgrades/master/master.component.spec.ts delete mode 100644 web/src/app/shared/components/upgrades/master/master.component.ts delete mode 100644 web/src/app/shared/components/upgrades/master/master.service.ts delete mode 100644 web/src/app/shared/components/upgrades/master/upgrade-master-config.component.ts delete mode 100644 web/src/app/shared/components/upgrades/upgrade.component.ts delete mode 100644 web/src/app/shared/components/upgrades/upgrade.directive.ts delete mode 100644 web/src/app/shared/configuration/attributes/attribute-provider.component.scss delete mode 100644 web/src/app/shared/configuration/attributes/attribute-provider.component.ts delete mode 100644 web/src/app/shared/configuration/attributes/attribute.service.ts delete mode 100644 web/src/app/shared/configuration/attributes/attributes.module.ts delete mode 100644 web/src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.scss delete mode 100644 web/src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.ts delete mode 100644 web/src/app/shared/configuration/attributes/config-field.directive.ts delete mode 100644 web/src/app/shared/configuration/configuration.module.ts delete mode 100644 web/src/app/shared/configuration/field/field.component.html delete mode 100644 web/src/app/shared/configuration/field/field.component.scss delete mode 100644 web/src/app/shared/configuration/field/field.component.ts delete mode 100644 web/src/app/shared/configuration/fields/fields.component.ts delete mode 100644 web/src/app/shared/configuration/group-fields/group-fields.component.html delete mode 100644 web/src/app/shared/configuration/group-fields/group-fields.component.ts delete mode 100644 web/src/app/shared/configuration/main/config.component.html delete mode 100644 web/src/app/shared/configuration/main/config.component.scss delete mode 100644 web/src/app/shared/configuration/main/config.component.spec.ts delete mode 100644 web/src/app/shared/configuration/main/config.component.ts delete mode 100644 web/src/app/shared/configuration/main/main.service.spec.ts delete mode 100644 web/src/app/shared/configuration/main/main.service.ts delete mode 100644 web/src/app/shared/configuration/scheme/item.component.spec.ts delete mode 100644 web/src/app/shared/configuration/scheme/item.component.ts delete mode 100644 web/src/app/shared/configuration/scheme/root.component.html delete mode 100644 web/src/app/shared/configuration/scheme/root.component.scss delete mode 100644 web/src/app/shared/configuration/scheme/root.component.spec.ts delete mode 100644 web/src/app/shared/configuration/scheme/root.component.ts delete mode 100644 web/src/app/shared/configuration/scheme/scheme.component.spec.ts delete mode 100644 web/src/app/shared/configuration/scheme/scheme.component.ts delete mode 100644 web/src/app/shared/configuration/scheme/scheme.service.spec.ts delete mode 100644 web/src/app/shared/configuration/scheme/scheme.service.ts delete mode 100644 web/src/app/shared/configuration/services/config.service.ts delete mode 100644 web/src/app/shared/configuration/services/field.service.spec.ts delete mode 100644 web/src/app/shared/configuration/services/field.service.ts delete mode 100644 web/src/app/shared/configuration/tests/configuration.ts delete mode 100644 web/src/app/shared/configuration/tools/color-option.directive.ts delete mode 100644 web/src/app/shared/configuration/tools/filter/filter-list/filter-list.component.scss delete mode 100644 web/src/app/shared/configuration/tools/filter/filter-list/filter-list.component.ts delete mode 100644 web/src/app/shared/configuration/tools/filter/filter.component.html delete mode 100644 web/src/app/shared/configuration/tools/filter/filter.component.scss delete mode 100644 web/src/app/shared/configuration/tools/filter/filter.component.ts delete mode 100644 web/src/app/shared/configuration/tools/history.component.ts delete mode 100644 web/src/app/shared/configuration/tools/search.component.ts delete mode 100644 web/src/app/shared/configuration/tools/server-filter/server-filter.component.scss delete mode 100644 web/src/app/shared/configuration/tools/server-filter/server-filter.component.ts delete mode 100644 web/src/app/shared/configuration/tools/tools.component.ts delete mode 100644 web/src/app/shared/configuration/types.ts delete mode 100644 web/src/app/shared/configuration/yspec/yspec.service.spec.ts delete mode 100644 web/src/app/shared/configuration/yspec/yspec.service.ts delete mode 100644 web/src/app/shared/details/details.module.ts delete mode 100644 web/src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.component.ts delete mode 100644 web/src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.pipe.ts delete mode 100644 web/src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.spec.ts delete mode 100644 web/src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.ts delete mode 100644 web/src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.spec.ts delete mode 100644 web/src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.ts delete mode 100644 web/src/app/shared/details/left-menu-items/status-menu-item/status-menu-item.component.ts delete mode 100644 web/src/app/shared/details/left-menu/left-menu.component.scss delete mode 100644 web/src/app/shared/details/left-menu/left-menu.component.spec.ts delete mode 100644 web/src/app/shared/details/left-menu/left-menu.component.ts delete mode 100644 web/src/app/shared/details/subtitle.component.ts delete mode 100644 web/src/app/shared/directives/base.directive.ts delete mode 100644 web/src/app/shared/directives/dynamic/dynamic.directive.ts delete mode 100644 web/src/app/shared/directives/dynamic/dynamic.module.ts delete mode 100644 web/src/app/shared/directives/for-test.directive.ts delete mode 100644 web/src/app/shared/directives/hover.directive.ts delete mode 100644 web/src/app/shared/directives/index.ts delete mode 100644 web/src/app/shared/directives/infinity-scroll.directive.ts delete mode 100644 web/src/app/shared/directives/m-textarea.directive.ts delete mode 100644 web/src/app/shared/directives/scroll.directive.spec.ts delete mode 100644 web/src/app/shared/directives/scroll.directive.ts delete mode 100644 web/src/app/shared/directives/socketListener.directive.ts delete mode 100644 web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.html delete mode 100644 web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.scss delete mode 100644 web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.ts delete mode 100644 web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.module.ts delete mode 100644 web/src/app/shared/form-elements/boolean.component.ts delete mode 100644 web/src/app/shared/form-elements/bundle.component.spec.ts delete mode 100644 web/src/app/shared/form-elements/bundles.component.ts delete mode 100644 web/src/app/shared/form-elements/button-uploader.component.ts delete mode 100644 web/src/app/shared/form-elements/confirm-equal-validator.directive.ts delete mode 100644 web/src/app/shared/form-elements/dropdown.component.ts delete mode 100644 web/src/app/shared/form-elements/error-info.component.ts delete mode 100644 web/src/app/shared/form-elements/field.directive.ts delete mode 100644 web/src/app/shared/form-elements/form-elements.module.ts delete mode 100644 web/src/app/shared/form-elements/input.component.ts delete mode 100644 web/src/app/shared/form-elements/json.component.ts delete mode 100644 web/src/app/shared/form-elements/map-list.template.html delete mode 100644 web/src/app/shared/form-elements/map.component.scss delete mode 100644 web/src/app/shared/form-elements/map.component.ts delete mode 100644 web/src/app/shared/form-elements/password/password.component.html delete mode 100644 web/src/app/shared/form-elements/password/password.component.scss delete mode 100644 web/src/app/shared/form-elements/password/password.component.ts delete mode 100644 web/src/app/shared/form-elements/secret-file/secret-file.component.html delete mode 100644 web/src/app/shared/form-elements/secret-file/secret-file.component.scss delete mode 100644 web/src/app/shared/form-elements/secret-file/secret-file.component.ts delete mode 100644 web/src/app/shared/form-elements/secret-map/secret-map.component.html delete mode 100644 web/src/app/shared/form-elements/secret-map/secret-map.component.scss delete mode 100644 web/src/app/shared/form-elements/secret-map/secret-map.component.ts delete mode 100644 web/src/app/shared/form-elements/secret-text/secret-text.component.html delete mode 100644 web/src/app/shared/form-elements/secret-text/secret-text.component.ts delete mode 100644 web/src/app/shared/form-elements/text-box.component.ts delete mode 100644 web/src/app/shared/form-elements/textarea.component.ts delete mode 100644 web/src/app/shared/form-elements/variant.component.spec.ts delete mode 100644 web/src/app/shared/form-elements/variant.component.ts delete mode 100644 web/src/app/shared/host-components-map/dependencies.component.spec.ts delete mode 100644 web/src/app/shared/host-components-map/dependencies.component.ts delete mode 100644 web/src/app/shared/host-components-map/holder.directive.spec.ts delete mode 100644 web/src/app/shared/host-components-map/holder.directive.ts delete mode 100644 web/src/app/shared/host-components-map/host-components-map.module.ts delete mode 100644 web/src/app/shared/host-components-map/much-2-many/much-2-many.component.html delete mode 100644 web/src/app/shared/host-components-map/much-2-many/much-2-many.component.scss delete mode 100644 web/src/app/shared/host-components-map/much-2-many/much-2-many.component.ts delete mode 100644 web/src/app/shared/host-components-map/services2hosts/service-host.component.html delete mode 100644 web/src/app/shared/host-components-map/services2hosts/service-host.component.scss delete mode 100644 web/src/app/shared/host-components-map/services2hosts/service-host.component.spec.ts delete mode 100644 web/src/app/shared/host-components-map/services2hosts/service-host.component.ts delete mode 100644 web/src/app/shared/host-components-map/take.service.spec.ts delete mode 100644 web/src/app/shared/host-components-map/take.service.ts delete mode 100644 web/src/app/shared/host-components-map/test/index.ts delete mode 100644 web/src/app/shared/host-components-map/types.ts delete mode 100644 web/src/app/shared/material.module.ts delete mode 100644 web/src/app/shared/pipes/break-row.pipe.spec.ts delete mode 100644 web/src/app/shared/pipes/break-row.pipe.ts delete mode 100644 web/src/app/shared/pipes/false-as-empty-array/false-as-empty-array.module.ts delete mode 100644 web/src/app/shared/pipes/false-as-empty-array/false-as-empty-array.pipe.ts delete mode 100644 web/src/app/shared/pipes/index.ts delete mode 100644 web/src/app/shared/pipes/tag-esc.pipe.ts delete mode 100644 web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.html delete mode 100644 web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.scss delete mode 100644 web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.ts delete mode 100644 web/src/app/shared/shared.module.ts delete mode 100644 web/src/app/shared/stuff.module.ts delete mode 100644 web/src/app/shared/translate/intializer.ts delete mode 100644 web/src/app/shared/validators/custom-validators.ts delete mode 100644 web/src/app/store/navigation/navigation-effects.ts delete mode 100644 web/src/app/store/navigation/navigation.store.ts delete mode 100644 web/src/app/styles/_fonts.scss delete mode 100644 web/src/app/styles/_grid.scss delete mode 100644 web/src/app/styles/_normalize.scss delete mode 100644 web/src/app/styles/details.scss delete mode 100644 web/src/app/styles/lib.theme.scss delete mode 100644 web/src/app/styles/status-tree.scss delete mode 100644 web/src/app/styles/style.scss delete mode 100644 web/src/app/templates/details.html delete mode 100644 web/src/app/templates/status-tree.html delete mode 100644 web/src/app/ws-logs/log.component.html delete mode 100644 web/src/app/ws-logs/log.component.scss delete mode 100644 web/src/app/ws-logs/log.component.ts delete mode 100644 web/src/assets/.gitkeep delete mode 100755 web/src/assets/adcm-logo.png delete mode 100644 web/src/assets/favicon.ico delete mode 100644 web/src/assets/fonts/UbuntuMono-Bold.eot delete mode 100644 web/src/assets/fonts/UbuntuMono-Bold.ttf delete mode 100644 web/src/assets/fonts/UbuntuMono-Bold.woff delete mode 100644 web/src/assets/fonts/UbuntuMono-BoldItalic.eot delete mode 100644 web/src/assets/fonts/UbuntuMono-BoldItalic.ttf delete mode 100644 web/src/assets/fonts/UbuntuMono-BoldItalic.woff delete mode 100644 web/src/assets/fonts/UbuntuMono-Italic.eot delete mode 100644 web/src/assets/fonts/UbuntuMono-Italic.ttf delete mode 100644 web/src/assets/fonts/UbuntuMono-Italic.woff delete mode 100644 web/src/assets/fonts/UbuntuMono-Regular.eot delete mode 100644 web/src/assets/fonts/UbuntuMono-Regular.ttf delete mode 100644 web/src/assets/fonts/UbuntuMono-Regular.woff delete mode 100644 web/src/assets/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 delete mode 100644 web/src/assets/google_icons.svg delete mode 100644 web/src/assets/i18n/static/en.json delete mode 100755 web/src/assets/ico_32x32.png delete mode 100644 web/src/assets/logo_.png delete mode 100644 web/src/assets/scss/_grid.scss delete mode 100644 web/src/assets/scss/_mixins.scss delete mode 100644 web/src/assets/scss/_normalize.scss delete mode 100644 web/src/environments/environment.prod.ts delete mode 100644 web/src/environments/environment.ts delete mode 100644 web/src/index.html delete mode 100644 web/src/main.ts delete mode 100644 web/src/polyfills.ts delete mode 100644 web/src/stories/Introduction.stories.mdx delete mode 100644 web/src/stories/assets/code-brackets.svg delete mode 100644 web/src/stories/assets/colors.svg delete mode 100644 web/src/stories/assets/comments.svg delete mode 100644 web/src/stories/assets/direction.svg delete mode 100644 web/src/stories/assets/flow.svg delete mode 100644 web/src/stories/assets/glasses.jpg delete mode 100644 web/src/stories/assets/plugin.svg delete mode 100644 web/src/stories/assets/repo.svg delete mode 100644 web/src/stories/assets/stackalt.svg delete mode 100644 web/src/stories/bell.stories.ts delete mode 100644 web/src/stories/concern/concern-list-popup.stories.ts delete mode 100644 web/src/stories/concern/concern-list.stories.ts delete mode 100644 web/src/stories/concern/concern.stories.mdx delete mode 100644 web/src/stories/concern/concern.stories.ts delete mode 100644 web/src/stories/concern/mock.ts delete mode 100644 web/src/stories/status-tree/status-tree.stories.ts delete mode 100644 web/src/styles.scss delete mode 100644 web/src/test.ts delete mode 100644 web/src/tsconfig.app.json delete mode 100644 web/src/tsconfig.spec.json delete mode 100644 web/src/uml/host.wsd delete mode 100755 web/storybook.sh delete mode 100644 web/tsconfig.base.json delete mode 100644 web/tsconfig.json delete mode 100644 web/tslint.json delete mode 100644 web/yarn.lock diff --git a/.dependabot/config.yml b/.dependabot/config.yml index ff1fef9635..1922044c61 100644 --- a/.dependabot/config.yml +++ b/.dependabot/config.yml @@ -1,15 +1,5 @@ version: 1 update_configs: - - package_manager: "javascript" - directory: "/web" - update_schedule: "daily" - target_branch: "develop" - version_requirement_updates: "auto" - allowed_updates: - - match: - update_type: "all" - dependency_type: "all" - - package_manager: "python" directory: "/" update_schedule: "daily" diff --git a/.dockerignore b/.dockerignore index 7c0c3f8ac9..865a330891 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,5 +3,4 @@ **/tests/ data venv -web adcm-web \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ac990d6df4..b92251ede6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,4 +2,3 @@ /tests/functional/ @arenadata/python-web-qa /tests/ui_tests/ @arenadata/python-web-qa /tests/api/ @arenadata/python-web-qa -/web/ @arenadata/angular diff --git a/CODEOWNERS b/CODEOWNERS index 7527340f2e..7071142002 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,7 +4,6 @@ /os/ @aas @d.skrynnik @aer /python/ @aas @d.skrynnik @a.starovoitov @aer /spec/ @aas @d.skrynnik @aer -/web/ @v.remizov @d.bardin @k.fedorenko .dockerignore @aas @v.remizov @d.skrynnik @aer .gitignore @aas @d.skrynnik @v.remizov @d.bardin @k.fedorenko @aer .gitlab-ci.yaml @aas @v.remizov @d.skrynnik @aer diff --git a/Makefile b/Makefile index ee6c3a1652..f439b28759 100644 --- a/Makefile +++ b/Makefile @@ -10,28 +10,15 @@ ADCM_VERSION = "2.0.0" help: @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -describe_old: - @echo '{"version": "$(shell date '+%Y.%m.%d.%H')","commit_id": "$(shell git log --pretty=format:'%h' -n 1)"}' > config.json - cp config.json web/src/assets/config.json - buildss: @docker run -i --rm -v $(CURDIR)/go:/code -w /code golang sh -c "make" -buildjs_old: - @docker run -i --rm -v $(CURDIR)/wwwroot:/wwwroot -v $(CURDIR)/web:/code -w /code node:16-alpine ./build.sh - buildjs: @docker run -i --rm -v $(CURDIR)/wwwroot:/wwwroot -v $(CURDIR)/adcm-web/app:/code -e ADCM_VERSION=$(ADCM_VERSION) -w /code node:18.16-alpine ./build.sh -build_base_old: - @docker build . -t $(APP_IMAGE):$(APP_TAG)_old - build_base: @docker build . -t $(APP_IMAGE):$(APP_TAG) --build-arg ADCM_VERSION=$(ADCM_VERSION) -# build ADCM_v1 -build_old: describe_old buildss buildjs_old build_base_old - # build ADCM_v2 build: buildss buildjs build_base @@ -46,10 +33,6 @@ unittests_postgresql: poetry run python/manage.py test python -v 2 --parallel docker stop postgres -ng_tests: - docker pull hub.adsw.io/library/functest:3.8.6.slim.buster_node16-x64 - docker run -i --rm -v $(CURDIR)/:/adcm -w /adcm/web hub.adsw.io/library/functest:3.8.6.slim.buster_node16-x64 ./ng_test.sh - pretty: poetry install --no-root --with lint poetry run ruff format license_checker.py python diff --git a/README.md b/README.md index 2bec6ed8e3..9d84136252 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Re-run them when needed/applicable. * go - golang part of application. There is a status server here now. * test * spec - specification in form of Sphinx RST -* web - UI source +* adcm-web - UI source # Build logic @@ -82,26 +82,6 @@ pre-commit install After this you will see invocation of black and pylint on every commit. -## Link ADWP_UI packages - -If you need to debug packages from ADWP_UI, you should do: - -In ADWP_UI repository: -```sh -delete dist folder -yarn run watch:widgets -cd dist/widgets -yarn link -``` - -In ADCM repository: -```sh -cd web -sudo rm -rf ./node_modules OR rmdir -force ./node_modules(WIN) -yarn link "@adwp-ui/widgets" -yarn install -``` - ## Running ADCM using SQLite 1. Start container: diff --git a/adcm-web/app/yarn.lock b/adcm-web/app/yarn.lock index dd545331db..6a984d0df5 100644 --- a/adcm-web/app/yarn.lock +++ b/adcm-web/app/yarn.lock @@ -2,20 +2,20 @@ # Manual changes might be lost - proceed with caution! __metadata: - version: 6 - cacheKey: 8 + version: 8 + cacheKey: 10 "@aashutoshrathi/word-wrap@npm:^1.2.3": version: 1.2.6 resolution: "@aashutoshrathi/word-wrap@npm:1.2.6" - checksum: ada901b9e7c680d190f1d012c84217ce0063d8f5c5a7725bb91ec3c5ed99bb7572680eb2d2938a531ccbaec39a95422fcd8a6b4a13110c7d98dd75402f66a0cd + checksum: 6eebd12a5cd03cee38fcb915ef9f4ea557df6a06f642dfc7fe8eb4839eb5c9ca55a382f3604d52c14200b0c214c12af5e1f23d2a6d8e23ef2d016b105a9d6c0a languageName: node linkType: hard "@adobe/css-tools@npm:^4.0.1": version: 4.2.0 resolution: "@adobe/css-tools@npm:4.2.0" - checksum: dc5cc92ba3d562e7ffddb79d6d222c7e00b65f255fd2725b3d71490ff268844be322f917415d8c4ab39eca646343b632058db8bd5b1d646193fcc94d1d3e420b + checksum: d6d2b48963bef725a0043b7d39c5fb12d6e42b52b8bebd746e80e1732f5160529f00fb184c0d3eb9446765727ccc8997ea8f121c54c7d33d1eb577d0feb54b6c languageName: node linkType: hard @@ -25,7 +25,7 @@ __metadata: dependencies: "@jridgewell/gen-mapping": "npm:^0.3.0" "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079 + checksum: e15fecbf3b54c988c8b4fdea8ef514ab482537e8a080b2978cc4b47ccca7140577ca7b65ad3322dcce65bc73ee6e5b90cbfe0bbd8c766dad04d5c62ec9634c42 languageName: node linkType: hard @@ -33,10 +33,10 @@ __metadata: version: 1.4.126 resolution: "@aw-web-design/x-default-browser@npm:1.4.126" dependencies: - default-browser-id: 3.0.0 + default-browser-id: "npm:3.0.0" bin: x-default-browser: bin/x-default-browser.js - checksum: f63b68a0ff41c8fe478b1b4822e169cac0d26c61b123c0400d5e16a8a5987732b85795aff16d6b21936f9c955f0d32bffbfc166890d3446f74a72a7a2c9633ea + checksum: f7111a6f00953f32d344a05c9a1bc1f22124dfc2696b2b7906ca856a9f845a282f272f603c997ebbb8a2d6b865664f46fda3bec1c480f040e21b815ff8ed3607 languageName: node linkType: hard @@ -45,7 +45,7 @@ __metadata: resolution: "@babel/code-frame@npm:7.22.5" dependencies: "@babel/highlight": "npm:^7.22.5" - checksum: cfe804f518f53faaf9a1d3e0f9f74127ab9a004912c3a16fda07fb6a633393ecb9918a053cb71804204c1b7ec3d49e1699604715e2cfb0c9f7bc4933d324ebb6 + checksum: b1ac7de75859699a9118c5247f489cc943d8d041339323904cd8140592993762f50abc14bc49b6703cb8a94b1aa90d6df2599625825e7ae470c9283b4a6170aa languageName: node linkType: hard @@ -53,23 +53,23 @@ __metadata: version: 7.23.5 resolution: "@babel/code-frame@npm:7.23.5" dependencies: - "@babel/highlight": ^7.23.4 - chalk: ^2.4.2 - checksum: d90981fdf56a2824a9b14d19a4c0e8db93633fd488c772624b4e83e0ceac6039a27cd298a247c3214faa952bf803ba23696172ae7e7235f3b97f43ba278c569a + "@babel/highlight": "npm:^7.23.4" + chalk: "npm:^2.4.2" + checksum: 44e58529c9d93083288dc9e649c553c5ba997475a7b0758cc3ddc4d77b8a7d985dbe78cc39c9bbc61f26d50af6da1ddf0a3427eae8cc222a9370619b671ed8f5 languageName: node linkType: hard "@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.21.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9": version: 7.22.9 resolution: "@babel/compat-data@npm:7.22.9" - checksum: bed77d9044ce948b4327b30dd0de0779fa9f3a7ed1f2d31638714ed00229fa71fc4d1617ae0eb1fad419338d3658d0e9a5a083297451e09e73e078d0347ff808 + checksum: 6797f59857917e57e1765811e4f48371f2bc6063274be012e380e83cbc1a4f7931d616c235df56404134aa4bb4775ee61f7b382688314e1b625a4d51caabd734 languageName: node linkType: hard "@babel/compat-data@npm:^7.23.3, @babel/compat-data@npm:^7.23.5": version: 7.23.5 resolution: "@babel/compat-data@npm:7.23.5" - checksum: 06ce244cda5763295a0ea924728c09bae57d35713b675175227278896946f922a63edf803c322f855a3878323d48d0255a2a3023409d2a123483c8a69ebb4744 + checksum: 088f14f646ecbddd5ef89f120a60a1b3389a50a9705d44603dca77662707d0175a5e0e0da3943c3298f1907a4ab871468656fbbf74bb7842cd8b0686b2c19736 languageName: node linkType: hard @@ -92,7 +92,7 @@ __metadata: gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.2" semver: "npm:^6.3.0" - checksum: f28118447355af2a90bd340e2e60699f94c8020517eba9b71bf8ebff62fa9e00d63f076e033f9dfb97548053ad62ada45fafb0d96584b1a90e8aef5a3b8241b1 + checksum: a71076dc27964e0754ad99f139f82876d3ed35489c1182aae9052813d36c92f4bd9ddab0e490d28ce8b1f33eea87885081adaedd1305bfc5ce6595c030a7bb0b languageName: node linkType: hard @@ -115,7 +115,7 @@ __metadata: gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.2" semver: "npm:^6.3.1" - checksum: 7bf069aeceb417902c4efdaefab1f7b94adb7dea694a9aed1bda2edf4135348a080820529b1a300c6f8605740a00ca00c19b2d5e74b5dd489d99d8c11d5e56d1 + checksum: 0c209a850651e23acd5662fecbd928a4805294579e13b28d1dc7adfb9e3ad31c500e2c5c3db2c8ea18c1f3613b0aed3e24652089652efc8401d824b88962bcf9 languageName: node linkType: hard @@ -123,22 +123,22 @@ __metadata: version: 7.23.7 resolution: "@babel/core@npm:7.23.7" dependencies: - "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.23.5 - "@babel/generator": ^7.23.6 - "@babel/helper-compilation-targets": ^7.23.6 - "@babel/helper-module-transforms": ^7.23.3 - "@babel/helpers": ^7.23.7 - "@babel/parser": ^7.23.6 - "@babel/template": ^7.22.15 - "@babel/traverse": ^7.23.7 - "@babel/types": ^7.23.6 - convert-source-map: ^2.0.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.2.3 - semver: ^6.3.1 - checksum: 32d5bf73372a47429afaae9adb0af39e47bcea6a831c4b5dcbb4791380cda6949cb8cb1a2fea8b60bb1ebe189209c80e333903df1fa8e9dcb04798c0ce5bf59e + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.6" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helpers": "npm:^7.23.7" + "@babel/parser": "npm:^7.23.6" + "@babel/template": "npm:^7.22.15" + "@babel/traverse": "npm:^7.23.7" + "@babel/types": "npm:^7.23.6" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 956841695ea801c8b4196d01072e6c1062335960715a6fcfd4009831003b526b00627c78b373ed49b1658c3622c71142f7ff04235fe839cac4a1a25ed51b90aa languageName: node linkType: hard @@ -150,7 +150,7 @@ __metadata: "@jridgewell/gen-mapping": "npm:^0.3.2" "@jridgewell/trace-mapping": "npm:^0.3.17" jsesc: "npm:^2.5.1" - checksum: 7c9d2c58b8d5ac5e047421a6ab03ec2ff5d9a5ff2c2212130a0055e063ac349e0b19d435537d6886c999771aef394832e4f54cd9fc810100a7f23d982f6af06b + checksum: 1ee43f99512c51d594c8992f4c4cd07d2843eb58cf3c22d1f605906b9c0ed89640bdcea2c8d583e75a8032a49bb4d950d2055007ecb75af404ebc2db8a513b94 languageName: node linkType: hard @@ -158,11 +158,11 @@ __metadata: version: 7.23.6 resolution: "@babel/generator@npm:7.23.6" dependencies: - "@babel/types": ^7.23.6 - "@jridgewell/gen-mapping": ^0.3.2 - "@jridgewell/trace-mapping": ^0.3.17 - jsesc: ^2.5.1 - checksum: 1a1a1c4eac210f174cd108d479464d053930a812798e09fee069377de39a893422df5b5b146199ead7239ae6d3a04697b45fc9ac6e38e0f6b76374390f91fc6c + "@babel/types": "npm:^7.23.6" + "@jridgewell/gen-mapping": "npm:^0.3.2" + "@jridgewell/trace-mapping": "npm:^0.3.17" + jsesc: "npm:^2.5.1" + checksum: 864090d5122c0aa3074471fd7b79d8a880c1468480cbd28925020a3dcc7eb6e98bedcdb38983df299c12b44b166e30915b8085a7bc126e68fa7e2aadc7bd1ac5 languageName: node linkType: hard @@ -179,7 +179,7 @@ __metadata: version: 7.22.15 resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.15" dependencies: - "@babel/types": ^7.22.15 + "@babel/types": "npm:^7.22.15" checksum: 639c697a1c729f9fafa2dd4c9af2e18568190299b5907bd4c2d0bc818fcbd1e83ffeecc2af24327a7faa7ac4c34edd9d7940510a5e66296c19bad17001cf5c7a languageName: node linkType: hard @@ -204,7 +204,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: ea0006c6a93759025f4a35a25228ae260538c9f15023e8aac2a6d45ca68aef4cf86cfc429b19af9a402cbdd54d5de74ad3fbcf6baa7e48184dc079f1a791e178 + checksum: 779510e4c2036fa9880c0ed7b77ce84e5926093e216dffa0044f31a146f0daae363c00d1cdda2250788edc8d6457b9bce6245c51d9f4161bb51e053c12c4b478 languageName: node linkType: hard @@ -212,12 +212,12 @@ __metadata: version: 7.23.6 resolution: "@babel/helper-compilation-targets@npm:7.23.6" dependencies: - "@babel/compat-data": ^7.23.5 - "@babel/helper-validator-option": ^7.23.5 - browserslist: ^4.22.2 - lru-cache: ^5.1.1 - semver: ^6.3.1 - checksum: c630b98d4527ac8fe2c58d9a06e785dfb2b73ec71b7c4f2ddf90f814b5f75b547f3c015f110a010fd31f76e3864daaf09f3adcd2f6acdbfb18a8de3a48717590 + "@babel/compat-data": "npm:^7.23.5" + "@babel/helper-validator-option": "npm:^7.23.5" + browserslist: "npm:^4.22.2" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 05595cd73087ddcd81b82d2f3297aac0c0422858dfdded43d304786cf680ec33e846e2317e6992d2c964ee61d93945cbf1fa8ec80b55aee5bfb159227fb02cb9 languageName: node linkType: hard @@ -236,7 +236,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 6c2436d1a5a3f1ff24628d78fa8c6d3120c40285aa3eda7815b1adbf8c5951e0dd73d368cf845825888fa3dc2f207dadce53309825598d7c67953e5ed9dd51d2 + checksum: 7e4ed99b88f844b762013862d7453b531b792da13a0afa3ef1a2d483c4f52f688b38e6d07e9b32c2304d17be752b2deba00b48530113cad979060dbc3bf20594 languageName: node linkType: hard @@ -244,18 +244,18 @@ __metadata: version: 7.23.7 resolution: "@babel/helper-create-class-features-plugin@npm:7.23.7" dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-function-name": ^7.23.0 - "@babel/helper-member-expression-to-functions": ^7.23.0 - "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.20 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - semver: ^6.3.1 + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-member-expression-to-functions": "npm:^7.23.0" + "@babel/helper-optimise-call-expression": "npm:^7.22.5" + "@babel/helper-replace-supers": "npm:^7.22.20" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 33e60714b856c3816a7965d4c76278cc8f430644a2dfc4eeafad2f7167c4fbd2becdb74cbfeb04b02efd6bbd07176ef53c6683262b588e65d378438e9c55c26b + checksum: c8b3ef58fca399a25f00d703b0fb2ac1d86642d9e3bd7af04df77857641ed08aaca042ffb271ef93771f9272481fd1cf102a9bddfcee407fb126c927deeef6a7 languageName: node linkType: hard @@ -268,7 +268,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 87cb48a7ee898ab205374274364c3adc70b87b08c7bd07f51019ae4562c0170d7148e654d591f825dee14b5fe11666a0e7966872dfdbfa0d1b94b861ecf0e4e1 + checksum: 6f3475a7661bc34527201c07eeeec3077c8adab0ed74bff728dc479da6c74bb393b6121ddf590ef1671f3f508fab3c7792a5ada65672665d84db4556daebd210 languageName: node linkType: hard @@ -276,12 +276,12 @@ __metadata: version: 7.22.15 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - regexpu-core: ^5.3.1 - semver: ^6.3.1 + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + regexpu-core: "npm:^5.3.1" + semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 0243b8d4854f1dc8861b1029a46d3f6393ad72f366a5a08e36a4648aa682044f06da4c6e87a456260e1e1b33c999f898ba591a0760842c1387bcc93fbf2151a6 + checksum: 886b675e82f1327b4f7a2c69a68eefdb5dbb0b9d4762c2d4f42a694960a9ccf61e1a3bcad601efd92c110033eb1a944fcd1e5cac188aa6b2e2076b541e210e20 languageName: node linkType: hard @@ -297,7 +297,7 @@ __metadata: semver: "npm:^6.1.2" peerDependencies: "@babel/core": ^7.4.0-0 - checksum: 8e3fe75513302e34f6d92bd67b53890e8545e6c5bca8fe757b9979f09d68d7e259f6daea90dc9e01e332c4f8781bda31c5fe551c82a277f9bc0bec007aed497c + checksum: a32b09f9d3827145347fca5105a33bc1a52ff8eb3d63e8eb4acc515f9b54a371862cc6ae376c275cdfa97ff9828975dde88fd6105a8d01107364200b52dfc9ad languageName: node linkType: hard @@ -305,14 +305,14 @@ __metadata: version: 0.4.4 resolution: "@babel/helper-define-polyfill-provider@npm:0.4.4" dependencies: - "@babel/helper-compilation-targets": ^7.22.6 - "@babel/helper-plugin-utils": ^7.22.5 - debug: ^4.1.1 - lodash.debounce: ^4.0.8 - resolve: ^1.14.2 + "@babel/helper-compilation-targets": "npm:^7.22.6" + "@babel/helper-plugin-utils": "npm:^7.22.5" + debug: "npm:^4.1.1" + lodash.debounce: "npm:^4.0.8" + resolve: "npm:^1.14.2" peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 2453cdd79f18a4cb8653d8a7e06b2eb0d8e31bae0d35070fc5abadbddca246a36d82b758064b421cca49b48d0e696d331d54520ba8582c1d61fb706d6d831817 + checksum: 16c312e40ecf2ead81f3ab7275387079071012d2363022c04cf16d56fe0d781185f3a517b928f4556c716ae45e0567b817b636d5cd2fee8fb2ce2b18a04c5bcd languageName: node linkType: hard @@ -336,7 +336,7 @@ __metadata: dependencies: "@babel/template": "npm:^7.22.5" "@babel/types": "npm:^7.22.5" - checksum: 6b1f6ce1b1f4e513bf2c8385a557ea0dd7fa37971b9002ad19268ca4384bbe90c09681fe4c076013f33deabc63a53b341ed91e792de741b4b35e01c00238177a + checksum: 6d02e304a45fe2a64d69dfa5b4fdfd6d68e08deb32b0a528e7b99403d664e9207e6b856787a8ff3f420e77d15987ac1de4eb869906e6ed764b67b07c804d20ba languageName: node linkType: hard @@ -344,9 +344,9 @@ __metadata: version: 7.23.0 resolution: "@babel/helper-function-name@npm:7.23.0" dependencies: - "@babel/template": ^7.22.15 - "@babel/types": ^7.23.0 - checksum: e44542257b2d4634a1f979244eb2a4ad8e6d75eb6761b4cfceb56b562f7db150d134bc538c8e6adca3783e3bc31be949071527aa8e3aab7867d1ad2d84a26e10 + "@babel/template": "npm:^7.22.15" + "@babel/types": "npm:^7.23.0" + checksum: 7b2ae024cd7a09f19817daf99e0153b3bf2bc4ab344e197e8d13623d5e36117ed0b110914bc248faa64e8ccd3e97971ec7b41cc6fd6163a2b980220c58dcdf6d languageName: node linkType: hard @@ -363,8 +363,8 @@ __metadata: version: 7.23.0 resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" dependencies: - "@babel/types": ^7.23.0 - checksum: 494659361370c979ada711ca685e2efe9460683c36db1b283b446122596602c901e291e09f2f980ecedfe6e0f2bd5386cb59768285446530df10c14df1024e75 + "@babel/types": "npm:^7.23.0" + checksum: 325feb6e200478c8cd6e10433fabe993a7d3315cc1a2a457e45514a5f95a73dff4c69bea04cc2daea0ffe72d8ed85d504b3f00b2e0767b7d4f5ae25fec9b35b2 languageName: node linkType: hard @@ -373,7 +373,7 @@ __metadata: resolution: "@babel/helper-member-expression-to-functions@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: 4bd5791529c280c00743e8bdc669ef0d4cd1620d6e3d35e0d42b862f8262bc2364973e5968007f960780344c539a4b9cf92ab41f5b4f94560a9620f536de2a39 + checksum: bb51f195c17d8d98ca5fda630fed436643d27f094f3c936f670b43cb05865f192900f455ffb730c8d4310702b2211996a90354fd55ae8659b096bc6c75d36ec5 languageName: node linkType: hard @@ -381,8 +381,8 @@ __metadata: version: 7.22.15 resolution: "@babel/helper-module-imports@npm:7.22.15" dependencies: - "@babel/types": ^7.22.15 - checksum: ecd7e457df0a46f889228f943ef9b4a47d485d82e030676767e6a2fdcbdaa63594d8124d4b55fd160b41c201025aec01fc27580352b1c87a37c9c6f33d116702 + "@babel/types": "npm:^7.22.15" + checksum: 5ecf9345a73b80c28677cfbe674b9f567bb0d079e37dcba9055e36cb337db24ae71992a58e1affa9d14a60d3c69907d30fe1f80aea105184501750a58d15c81c languageName: node linkType: hard @@ -391,7 +391,7 @@ __metadata: resolution: "@babel/helper-module-imports@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: 9ac2b0404fa38b80bdf2653fbeaf8e8a43ccb41bd505f9741d820ed95d3c4e037c62a1bcdcb6c9527d7798d2e595924c4d025daed73283badc180ada2c9c49ad + checksum: d8296447c0cdc3c02417ba32864da3374e53bd2763a6c404aae118987c222c47238d9d1f4fd2a88250a85e0a68eff38d878c491b00c56d9bd20e809f91eb41b4 languageName: node linkType: hard @@ -406,7 +406,7 @@ __metadata: "@babel/helper-validator-identifier": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: 2751f77660518cf4ff027514d6f4794f04598c6393be7b04b8e46c6e21606e11c19f3f57ab6129a9c21bacdf8b3ffe3af87bb401d972f34af2d0ffde02ac3001 + checksum: 80244f45e3f665305f8cf9412ee2efe44d1d30c201f869ceb0e87f9cddbbff06ebfed1dbe122a40875404867b747e7df73c0825c93765c108bcf2e86d2ef8b9b languageName: node linkType: hard @@ -414,14 +414,14 @@ __metadata: version: 7.23.3 resolution: "@babel/helper-module-transforms@npm:7.23.3" dependencies: - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-module-imports": ^7.22.15 - "@babel/helper-simple-access": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/helper-validator-identifier": ^7.22.20 + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-module-imports": "npm:^7.22.15" + "@babel/helper-simple-access": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/helper-validator-identifier": "npm:^7.22.20" peerDependencies: "@babel/core": ^7.0.0 - checksum: 5d0895cfba0e16ae16f3aa92fee108517023ad89a855289c4eb1d46f7aef4519adf8e6f971e1d55ac20c5461610e17213f1144097a8f932e768a9132e2278d71 + checksum: 583fa580f8e50e6f45c4f46aa76a8e49c2528deb84e25f634d66461b9a0e2420e13979b0a607b67aef67eaf8db8668eb9edc038b4514b16e3879fe09e8fd294b languageName: node linkType: hard @@ -437,7 +437,7 @@ __metadata: "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.16.7, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.18.9, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.21.5, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": version: 7.22.5 resolution: "@babel/helper-plugin-utils@npm:7.22.5" - checksum: c0fc7227076b6041acd2f0e818145d2e8c41968cc52fb5ca70eed48e21b8fe6dd88a0a91cbddf4951e33647336eb5ae184747ca706817ca3bef5e9e905151ff5 + checksum: ab220db218089a2aadd0582f5833fd17fa300245999f5f8784b10f5a75267c4e808592284a29438a0da365e702f05acb369f99e1c915c02f9f9210ec60eab8ea languageName: node linkType: hard @@ -458,9 +458,9 @@ __metadata: version: 7.22.20 resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-wrap-function": ^7.22.20 + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-wrap-function": "npm:^7.22.20" peerDependencies: "@babel/core": ^7.0.0 checksum: 2fe6300a6f1b58211dffa0aed1b45d4958506d096543663dba83bd9251fe8d670fa909143a65b45e72acb49e7e20fbdb73eae315d9ddaced467948c3329986e7 @@ -471,12 +471,12 @@ __metadata: version: 7.22.20 resolution: "@babel/helper-replace-supers@npm:7.22.20" dependencies: - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-member-expression-to-functions": ^7.22.15 - "@babel/helper-optimise-call-expression": ^7.22.5 + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-member-expression-to-functions": "npm:^7.22.15" + "@babel/helper-optimise-call-expression": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: a0008332e24daedea2e9498733e3c39b389d6d4512637e000f96f62b797e702ee24a407ccbcd7a236a551590a38f31282829a8ef35c50a3c0457d88218cae639 + checksum: 617666f57b0f94a2f430ee66b67c8f6fa94d4c22400f622947580d8f3638ea34b71280af59599ed4afbb54ae6e2bdd4f9083fe0e341184a4bb0bd26ef58d3017 languageName: node linkType: hard @@ -489,7 +489,7 @@ __metadata: "@babel/helper-optimise-call-expression": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: d41471f56ff2616459d35a5df1900d5f0756ae78b1027040365325ef332d66e08e3be02a9489756d870887585ff222403a228546e93dd7019e19e59c0c0fe586 + checksum: b5a740a95f12250b67afe30574ad60fa44175db92441658c6c3e8f473fcb8f8eaffd24fdad436cdfa1beee21b470d1190d64a0bb97b444525ca952e6cc081dc9 languageName: node linkType: hard @@ -498,7 +498,7 @@ __metadata: resolution: "@babel/helper-simple-access@npm:7.22.5" dependencies: "@babel/types": "npm:^7.22.5" - checksum: fe9686714caf7d70aedb46c3cce090f8b915b206e09225f1e4dbc416786c2fdbbee40b38b23c268b7ccef749dd2db35f255338fb4f2444429874d900dede5ad2 + checksum: 7d5430eecf880937c27d1aed14245003bd1c7383ae07d652b3932f450f60bfcf8f2c1270c593ab063add185108d26198c69d1aca0e6fb7c6fdada4bcf72ab5b7 languageName: node linkType: hard @@ -523,28 +523,28 @@ __metadata: "@babel/helper-string-parser@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-string-parser@npm:7.22.5" - checksum: 836851ca5ec813077bbb303acc992d75a360267aa3b5de7134d220411c852a6f17de7c0d0b8c8dcc0f567f67874c00f4528672b2a4f1bc978a3ada64c8c78467 + checksum: 7f275a7f1a9504da06afc33441e219796352a4a3d0288a961bc14d1e30e06833a71621b33c3e60ee3ac1ff3c502d55e392bcbc0665f6f9d2629809696fab7cdd languageName: node linkType: hard "@babel/helper-string-parser@npm:^7.23.4": version: 7.23.4 resolution: "@babel/helper-string-parser@npm:7.23.4" - checksum: c0641144cf1a7e7dc93f3d5f16d5327465b6cf5d036b48be61ecba41e1eece161b48f46b7f960951b67f8c3533ce506b16dece576baef4d8b3b49f8c65410f90 + checksum: c352082474a2ee1d2b812bd116a56b2e8b38065df9678a32a535f151ec6f58e54633cc778778374f10544b930703cca6ddf998803888a636afa27e2658068a9c languageName: node linkType: hard "@babel/helper-validator-identifier@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-validator-identifier@npm:7.22.20" - checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc + checksum: df882d2675101df2d507b95b195ca2f86a3ef28cb711c84f37e79ca23178e13b9f0d8b522774211f51e40168bf5142be4c1c9776a150cddb61a0d5bf3e95750b languageName: node linkType: hard "@babel/helper-validator-identifier@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-validator-identifier@npm:7.22.5" - checksum: 7f0f30113474a28298c12161763b49de5018732290ca4de13cdaefd4fd0d635a6fe3f6686c37a02905fb1e64f21a5ee2b55140cf7b070e729f1bd66866506aea + checksum: 12cb7d4535b3f8d109a446f7bef08d20eebe94fd97b534cd415c936ab342e9634edc5c99961af976bd78bcae6e6ec4b2ab8483d0da2ac5926fbe9f7dd9ab28ab languageName: node linkType: hard @@ -566,10 +566,10 @@ __metadata: version: 7.22.20 resolution: "@babel/helper-wrap-function@npm:7.22.20" dependencies: - "@babel/helper-function-name": ^7.22.5 - "@babel/template": ^7.22.15 - "@babel/types": ^7.22.19 - checksum: 221ed9b5572612aeb571e4ce6a256f2dee85b3c9536f1dd5e611b0255e5f59a3d0ec392d8d46d4152149156a8109f92f20379b1d6d36abb613176e0e33f05fca + "@babel/helper-function-name": "npm:^7.22.5" + "@babel/template": "npm:^7.22.15" + "@babel/types": "npm:^7.22.19" + checksum: b22e4666dec3d401bdf8ebd01d448bb3733617dae5aa6fbd1b684a22a35653cca832edd876529fd139577713b44fb89b4f5e52b7315ab218620f78b8a8ae23de languageName: node linkType: hard @@ -580,7 +580,7 @@ __metadata: "@babel/helper-function-name": "npm:^7.22.5" "@babel/template": "npm:^7.22.5" "@babel/types": "npm:^7.22.5" - checksum: 037317dc06dac6593e388738ae1d3e43193bc1d31698f067c0ef3d4dc6f074dbed860ed42aa137b48a67aa7cb87336826c4bdc13189260481bcf67eb7256c789 + checksum: 5ac86fe27b92d5fd866b4021644bbbae34b76af4c0a568ed854e10c25481c2cd56a81919aac5df270e8ebef788d62074195236adbf3a4039ecd93e0e8e83a3f5 languageName: node linkType: hard @@ -591,7 +591,7 @@ __metadata: "@babel/template": "npm:^7.22.5" "@babel/traverse": "npm:^7.22.6" "@babel/types": "npm:^7.22.5" - checksum: 5c1f33241fe7bf7709868c2105134a0a86dca26a0fbd508af10a89312b1f77ca38ebae43e50be3b208613c5eacca1559618af4ca236f0abc55d294800faeff30 + checksum: c7c5876476321c979f2c15086e526e3424121829a3abd52a79a5a886008b251e1fcb5ea6e498eca3204e5f1d2455804bf9eb87b7478a535449805acc9dbce190 languageName: node linkType: hard @@ -599,10 +599,10 @@ __metadata: version: 7.23.8 resolution: "@babel/helpers@npm:7.23.8" dependencies: - "@babel/template": ^7.22.15 - "@babel/traverse": ^7.23.7 - "@babel/types": ^7.23.6 - checksum: 8b522d527921f8df45a983dc7b8e790c021250addf81ba7900ba016e165442a527348f6f877aa55e1debb3eef9e860a334b4e8d834e6c9b438ed61a63d9a7ad4 + "@babel/template": "npm:^7.22.15" + "@babel/traverse": "npm:^7.23.7" + "@babel/types": "npm:^7.23.6" + checksum: 4c392351910102403b6a7c922319077b179c276e422a4e45b243b45610f813a05a043b6b116cbf5eb4b437fb51b9a2dfc2b7c65f38a0de7fde1f97d08a675313 languageName: node linkType: hard @@ -613,7 +613,7 @@ __metadata: "@babel/helper-validator-identifier": "npm:^7.22.5" chalk: "npm:^2.0.0" js-tokens: "npm:^4.0.0" - checksum: f61ae6de6ee0ea8d9b5bcf2a532faec5ab0a1dc0f7c640e5047fc61630a0edb88b18d8c92eb06566d30da7a27db841aca11820ecd3ebe9ce514c9350fbed39c4 + checksum: ff59305c0184648c9cb042638e9d2d184c12df2a112c71359268a982e7ab65cd5236f392ee8eb722a3bf5b5bd155954fdc7b5aacb6b2b1cd5e38dafcbe63cc57 languageName: node linkType: hard @@ -621,10 +621,10 @@ __metadata: version: 7.23.4 resolution: "@babel/highlight@npm:7.23.4" dependencies: - "@babel/helper-validator-identifier": ^7.22.20 - chalk: ^2.4.2 - js-tokens: ^4.0.0 - checksum: 643acecdc235f87d925979a979b539a5d7d1f31ae7db8d89047269082694122d11aa85351304c9c978ceeb6d250591ccadb06c366f358ccee08bb9c122476b89 + "@babel/helper-validator-identifier": "npm:^7.22.20" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + checksum: 62fef9b5bcea7131df4626d009029b1ae85332042f4648a4ce6e740c3fd23112603c740c45575caec62f260c96b11054d3be5987f4981a5479793579c3aac71f languageName: node linkType: hard @@ -633,7 +633,7 @@ __metadata: resolution: "@babel/parser@npm:7.22.7" bin: parser: ./bin/babel-parser.js - checksum: 02209ddbd445831ee8bf966fdf7c29d189ed4b14343a68eb2479d940e7e3846340d7cc6bd654a5f3d87d19dc84f49f50a58cf9363bee249dc5409ff3ba3dab54 + checksum: f420f89ea8e5803a44f76a57630002ca5721fbde719c10ac4eaebf1d01fad102447cd90a7721c97b1176bde33ec9bc2b68fe8c7d541668dc6610727ba79c8862 languageName: node linkType: hard @@ -642,7 +642,7 @@ __metadata: resolution: "@babel/parser@npm:7.23.6" bin: parser: ./bin/babel-parser.js - checksum: 140801c43731a6c41fd193f5c02bc71fd647a0360ca616b23d2db8be4b9739b9f951a03fc7c2db4f9b9214f4b27c1074db0f18bc3fa653783082d5af7c8860d5 + checksum: 6be3a63d3c9d07b035b5a79c022327cb7e16cbd530140ecb731f19a650c794c315a72c699a22413ebeafaff14aa8f53435111898d59e01a393d741b85629fa7d languageName: node linkType: hard @@ -661,7 +661,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0 checksum: ddbaf2c396b7780f15e80ee01d6dd790db076985f3dfeb6527d1a8d4cacf370e49250396a3aa005b2c40233cac214a106232f83703d5e8491848bde273938232 @@ -685,9 +685,9 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/plugin-transform-optional-chaining": ^7.23.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/plugin-transform-optional-chaining": "npm:^7.23.3" peerDependencies: "@babel/core": ^7.13.0 checksum: 434b9d710ae856fa1a456678cc304fbc93915af86d581ee316e077af746a709a741ea39d7e1d4f5b98861b629cc7e87f002d3138f5e836775632466d4c74aef2 @@ -698,11 +698,11 @@ __metadata: version: 7.23.7 resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.23.7" dependencies: - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: f88e400b548202a6f8c5dfd25bc4949a13ea1ccb64a170d7dea4deaa655a0fcb001d3fd61c35e1ad9c09a3d5f0d43f783400425471fe6d660ccaf33dabea9aba + checksum: 3b0c9554cd0048e6e7341d7b92f29d400dbc6a5a4fc2f86dbed881d32e02ece9b55bc520387bae2eac22a5ab38a0b205c29b52b181294d99b4dd75e27309b548 languageName: node linkType: hard @@ -828,7 +828,7 @@ __metadata: "@babel/plugin-transform-parameters": "npm:^7.20.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1329db17009964bc644484c660eab717cb3ca63ac0ab0f67c651a028d1bc2ead51dc4064caea283e46994f1b7221670a35cbc0b4beb6273f55e915494b5aa0b2 + checksum: cb0f8f2ff98d7bb64ee91c28b20e8ab15d9bc7043f0932cbb9e51e1bbfb623b12f206a1171e070299c9cf21948c320b710d6d72a42f68a5bfd2702354113a1c5 languageName: node linkType: hard @@ -853,7 +853,7 @@ __metadata: "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 11c5449e01b18bb8881e8e005a577fa7be2fe5688e2382c8822d51f8f7005342a301a46af7b273b1f5645f9a7b894c428eee8526342038a275ef6ba4c8d8d746 + checksum: 522cd133aff5c94c0ef36ff83c64f03deee183815da68b65b6950e81972ace3b514e032df07ea76d0f9ec8cc7a49578092907adfa17fccb4612117557c04a882 languageName: node linkType: hard @@ -874,7 +874,7 @@ __metadata: resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d97745d098b835d55033ff3a7fb2b895b9c5295b08a5759e4f20df325aa385a3e0bc9bd5ad8f2ec554a44d4e6525acfc257b8c5848a1345cb40f26a30e277e91 + checksum: fab70f399aa869275690ec6c7cedb4ef361d4e8b6f55c3d7b04bfee61d52fb93c87cec2c65d73cddbaca89fb8ef5ec0921fce675c9169d9d51f18305ab34e78a languageName: node linkType: hard @@ -888,7 +888,7 @@ __metadata: "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1b880543bc5f525b360b53d97dd30807302bb82615cd42bf931968f59003cac75629563d6b104868db50abd22235b3271fdf679fea5db59a267181a99cc0c265 + checksum: f803b5e1de0cb7c53f0d7f70bfbf57f2b3a20d95c19f8f2710719c4938149b490ee14d2d0c2f8316080823f0943c6cb8668fa8c139420e7bc7f80a66bfd50fff languageName: node linkType: hard @@ -974,7 +974,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-syntax-flow@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: c6e6f355d6ace5f4a9e7bb19f1fed2398aeb9b62c4c671a189d81b124f9f5bb77c4225b6e85e19339268c60a021c1e49104e450375de5e6bb70612190d9678af @@ -996,7 +996,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-syntax-import-assertions@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 883e6b35b2da205138caab832d54505271a3fee3fc1e8dc0894502434fc2b5d517cbe93bbfbfef8068a0fb6ec48ebc9eef3f605200a489065ba43d8cddc1c9a7 @@ -1007,7 +1007,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-syntax-import-attributes@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 9aed7661ffb920ca75df9f494757466ca92744e43072e0848d87fa4aa61a3f2ee5a22198ac1959856c036434b5614a8f46f1fb70298835dbe28220cdd1d4c11e @@ -1051,7 +1051,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-syntax-jsx@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 89037694314a74e7f0e7a9c8d3793af5bf6b23d80950c29b360db1c66859d67f60711ea437e70ad6b5b4b29affe17eababda841b6c01107c2b638e0493bafb4e @@ -1161,7 +1161,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-syntax-typescript@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: abfad3a19290d258b028e285a1f34c9b8a0cbe46ef79eafed4ed7ffce11b5d0720b5e536c82f91cbd8442cde35a3dd8e861fa70366d87ff06fdc0d4756e30876 @@ -1195,7 +1195,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-arrow-functions@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 1e99118176e5366c2636064d09477016ab5272b2a92e78b8edb571d20bc3eaa881789a905b20042942c3c2d04efc530726cf703f937226db5ebc495f5d067e66 @@ -1206,10 +1206,10 @@ __metadata: version: 7.23.7 resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.7" dependencies: - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-remap-async-to-generator": ^7.22.20 - "@babel/plugin-syntax-async-generators": ^7.8.4 + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-remap-async-to-generator": "npm:^7.22.20" + "@babel/plugin-syntax-async-generators": "npm:^7.8.4" peerDependencies: "@babel/core": ^7.0.0-0 checksum: b1f66b23423933c27336b1161ac92efef46683321caea97e2255a666f992979376f47a5559f64188d3831fa66a4b24c2a7a40838cc0e9737e90eebe20e8e6372 @@ -1233,9 +1233,9 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-async-to-generator@npm:7.23.3" dependencies: - "@babel/helper-module-imports": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-remap-async-to-generator": ^7.22.20 + "@babel/helper-module-imports": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-remap-async-to-generator": "npm:^7.22.20" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 2e9d9795d4b3b3d8090332104e37061c677f29a1ce65bcbda4099a32d243e5d9520270a44bbabf0fb1fb40d463bd937685b1a1042e646979086c546d55319c3c @@ -1257,7 +1257,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: e63b16d94ee5f4d917e669da3db5ea53d1e7e79141a2ec873c1e644678cdafe98daa556d0d359963c827863d6b3665d23d4938a94a4c5053a1619c4ebd01d020 @@ -1271,7 +1271,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 26987002cfe6e24544e60fa35f07052b6557f590c1a1cc5cf35d6dc341d7fea163c1222a2d70d5d2692f0b9860d942fd3ba979848b2995d4debffa387b9b19ae + checksum: ecfff46f51daed83a0c7dc5de237b9e09028f40f21d4f3552d2ed0d341e81d3194ffcd0a873dd83ec8d33ffb822666c14dc2d99ae010362e4c1a546416cdd4cf languageName: node linkType: hard @@ -1279,10 +1279,10 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-block-scoping@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: fc4b2100dd9f2c47d694b4b35ae8153214ccb4e24ef545c259a9db17211b18b6a430f22799b56db8f6844deaeaa201af45a03331d0c80cc28b0c4e3c814570e4 + checksum: bbb965a3acdfb03559806d149efbd194ac9c983b260581a60efcb15eb9fbe20e3054667970800146d867446db1c1398f8e4ee87f4454233e49b8f8ce947bd99b languageName: node linkType: hard @@ -1302,8 +1302,8 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-class-properties@npm:7.23.3" dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-class-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 9c6f8366f667897541d360246de176dd29efc7a13d80a5b48361882f7173d9173be4646c3b7d9b003ccc0e01e25df122330308f33db921fa553aa17ad544b3fc @@ -1314,9 +1314,9 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-class-static-block@npm:7.23.4" dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-class-static-block": ^7.14.5 + "@babel/helper-create-class-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.12.0 checksum: c8bfaba19a674fc2eb54edad71e958647360474e3163e8226f1acd63e4e2dbec32a171a0af596c1dc5359aee402cc120fea7abd1fb0e0354b6527f0fc9e8aa1e @@ -1338,7 +1338,7 @@ __metadata: globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8380e855c01033dbc7460d9acfbc1fc37c880350fa798c2de8c594ef818ade0e4c96173ec72f05f2a4549d8d37135e18cb62548352d51557b45a0fb4388d2f3f + checksum: 9b2f653d12ade0302f8b01a0f647cdbe5e5874984bf85f65e445fb5f660abe0347dd7e45bebc376aa4e096e607f62af73fc44a7e67765cfbe387b632ec8867f9 languageName: node linkType: hard @@ -1346,17 +1346,17 @@ __metadata: version: 7.23.8 resolution: "@babel/plugin-transform-classes@npm:7.23.8" dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-compilation-targets": ^7.23.6 - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-function-name": ^7.23.0 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.20 - "@babel/helper-split-export-declaration": ^7.22.6 - globals: ^11.1.0 + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-replace-supers": "npm:^7.22.20" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7dee6cebe52131d2d16944f36e1fdb9d4b24f44d0e7e450f93a44435d001f17cc0789a4cb6b15ec67c8e484581b8a730b5c3ec374470f29ff0133086955b8c58 + checksum: 4bb4b19e7a39871c4414fb44fc5f2cc47c78f993b74c43238dfb99c9dac2d15cb99b43f8a3d42747580e1807d2b8f5e13ce7e95e593fd839bd176aa090bf9a23 languageName: node linkType: hard @@ -1368,7 +1368,7 @@ __metadata: "@babel/template": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c2a77a0f94ec71efbc569109ec14ea2aa925b333289272ced8b33c6108bdbb02caf01830ffc7e49486b62dec51911924d13f3a76f1149f40daace1898009e131 + checksum: a3efa8de19e4c52f01a99301d864819a7997a7845044d9cef5b67b0fb1e5e3e610ecc23053a8b5cf8fe40fcad93c15a586eaeffd22b89eeaa038339c37919661 languageName: node linkType: hard @@ -1376,11 +1376,11 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-computed-properties@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/template": ^7.22.15 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/template": "npm:^7.22.15" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 80452661dc25a0956f89fe98cb562e8637a9556fb6c00d312c57653ce7df8798f58d138603c7e1aad96614ee9ccd10c47e50ab9ded6b6eded5adeb230d2a982e + checksum: e75593e02c5ea473c17839e3c9d597ce3697bf039b66afe9a4d06d086a87fb3d95850b4174476897afc351dc1b46a9ec3165ee6e8fbad3732c0d65f676f855ad languageName: node linkType: hard @@ -1391,7 +1391,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 76f6ea2aee1fcfa1c3791eb7a5b89703c6472650b993e8666fff0f1d6e9d737a84134edf89f63c92297f3e75064c1263219463b02dd9bc7434b6e5b9935e3f20 + checksum: b568c51bc80d9c941a5285b010d694345a1ae50b45bf5eb6c591b3a31303ac920150fc8c1cc810692d139dd3c60285f5bdc250dae58b5a227597f76bffbd9b61 languageName: node linkType: hard @@ -1399,10 +1399,10 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-destructuring@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9e015099877272501162419bfe781689aec5c462cd2aec752ee22288f209eec65969ff11b8fdadca2eaddea71d705d3bba5b9c60752fcc1be67874fcec687105 + checksum: 5abd93718af5a61f8f6a97d2ccac9139499752dd5b2c533d7556fb02947ae01b2f51d4c4f5e64df569e8783d3743270018eb1fa979c43edec7dd1377acf107ed languageName: node linkType: hard @@ -1422,8 +1422,8 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-dotall-regex@npm:7.23.3" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: a2dbbf7f1ea16a97948c37df925cb364337668c41a3948b8d91453f140507bd8a3429030c7ce66d09c299987b27746c19a2dd18b6f17dcb474854b14fd9159a3 @@ -1445,7 +1445,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-duplicate-keys@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: c2a21c34dc0839590cd945192cbc46fde541a27e140c48fe1808315934664cdbf18db64889e23c4eeb6bad9d3e049482efdca91d29de5734ffc887c4fbabaa16 @@ -1456,8 +1456,8 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-dynamic-import@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-dynamic-import": ^7.8.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 57a722604c430d9f3dacff22001a5f31250e34785d4969527a2ae9160fa86858d0892c5b9ff7a06a04076f8c76c9e6862e0541aadca9c057849961343aab0845 @@ -1480,8 +1480,8 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.23.3" dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 00d05ab14ad0f299160fcf9d8f55a1cc1b740e012ab0b5ce30207d2365f091665115557af7d989cd6260d075a252d9e4283de5f2b247dfbbe0e42ae586e6bf66 @@ -1492,8 +1492,8 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-export-namespace-from@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 9f770a81bfd03b48d6ba155d452946fd56d6ffe5b7d871e9ec2a0b15e0f424273b632f3ed61838b90015b25bbda988896b7a46c7d964fbf8f6feb5820b309f93 @@ -1504,11 +1504,11 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-flow-strip-types@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-flow": ^7.23.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-flow": "npm:^7.23.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: de38cc5cf948bc19405ea041292181527a36f59f08d787a590415fac36e9b0c7992f0d3e2fd3b9402089bafdaa1a893291a0edf15beebfd29bdedbbe582fee9b + checksum: 84af4b1f6d79f1a66a2440c5cfe3ba0e2bb9355402da477add13de1867088efb8d7b2be15d67ac955f1d2a745d4a561423bbb473fe6e4622b157989598ec323f languageName: node linkType: hard @@ -1519,7 +1519,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d7b8d4db010bce7273674caa95c4e6abd909362866ce297e86a2ecaa9ae636e05d525415811db9b3c942155df7f3651d19b91dd6c41f142f7308a97c7cb06023 + checksum: 07ab9ce49a15a03840937dbbddbf2235e0e6b9af3c1427746fab6aaa667acd92327620f937134922167193ac7aca871d20326b59e7a8b1efd52f22f876348928 languageName: node linkType: hard @@ -1527,11 +1527,11 @@ __metadata: version: 7.23.6 resolution: "@babel/plugin-transform-for-of@npm:7.23.6" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 228c060aa61f6aa89dc447170075f8214863b94f830624e74ade99c1a09316897c12d76e848460b0b506593e58dbc42739af6dc4cb0fe9b84dffe4a596050a36 + checksum: b84ef1f26a2db316237ae6d10fa7c22c70ac808ed0b8e095a8ecf9101551636cbb026bee9fb95a0a7944f3b8278ff9636a9088cb4a4ac5b84830a13829242735 languageName: node linkType: hard @@ -1552,9 +1552,9 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-function-name@npm:7.23.3" dependencies: - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-function-name": ^7.23.0 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-compilation-targets": "npm:^7.22.15" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 355c6dbe07c919575ad42b2f7e020f320866d72f8b79181a16f8e0cd424a2c761d979f03f47d583d9471b55dcd68a8a9d829b58e1eebcd572145b934b48975a6 @@ -1565,8 +1565,8 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-json-strings@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-json-strings": ^7.8.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-json-strings": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 checksum: f9019820233cf8955d8ba346df709a0683c120fe86a24ed1c9f003f2db51197b979efc88f010d558a12e1491210fc195a43cd1c7fee5e23b92da38f793a875de @@ -1588,7 +1588,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-literals@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 519a544cd58586b9001c4c9b18da25a62f17d23c48600ff7a685d75ca9eb18d2c5e8f5476f067f0a8f1fea2a31107eff950b9864833061e6076dcc4bdc3e71ed @@ -1599,8 +1599,8 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 2ae1dc9b4ff3bf61a990ff3accdecb2afe3a0ca649b3e74c010078d1cdf29ea490f50ac0a905306a2bcf9ac177889a39ac79bdcc3a0fdf220b3b75fac18d39b5 @@ -1622,7 +1622,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-member-expression-literals@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 95cec13c36d447c5aa6b8e4c778b897eeba66dcb675edef01e0d2afcec9e8cb9726baf4f81b4bbae7a782595aed72e6a0d44ffb773272c3ca180fada99bf92db @@ -1637,7 +1637,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7da4c4ebbbcf7d182abb59b2046b22d86eee340caf8a22a39ef6a727da2d8acfec1f714fcdcd5054110b280e4934f735e80a6848d192b6834c5d4459a014f04d + checksum: 5453f829205f6c918cc74d66946c9bf9544869f961d72a9934b4370049bf72a9b0ac089b64389be5172b217858c5353ec3479a18ab14cebb23329d708f6fc1ab languageName: node linkType: hard @@ -1645,11 +1645,11 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-modules-amd@npm:7.23.3" dependencies: - "@babel/helper-module-transforms": ^7.23.3 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d163737b6a3d67ea579c9aa3b83d4df4b5c34d9dcdf25f415f027c0aa8cded7bac2750d2de5464081f67a042ad9e1c03930c2fab42acd79f9e57c00cf969ddff + checksum: 48c87dee2c7dae8ed40d16901f32c9e58be4ef87bf2c3985b51dd2e78e82081f3bad0a39ee5cf6e8909e13e954e2b4bedef0a8141922f281ed833ddb59ed9be2 languageName: node linkType: hard @@ -1662,7 +1662,7 @@ __metadata: "@babel/helper-simple-access": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2067aca8f6454d54ffcce69b02c457cfa61428e11372f6a1d99ff4fcfbb55c396ed2ca6ca886bf06c852e38c1a205b8095921b2364fd0243f3e66bc1dda61caa + checksum: bf8bcc7a0f28f1fb2bfad3e65a50e6aee54998917caf89c68fc871d1831808a74ae7563b8a37485da03a583a9bd1211c30b667bb366c3161a22c6105962ab5f8 languageName: node linkType: hard @@ -1670,12 +1670,12 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-modules-commonjs@npm:7.23.3" dependencies: - "@babel/helper-module-transforms": ^7.23.3 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-simple-access": ^7.22.5 + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-simple-access": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 720a231ceade4ae4d2632478db4e7fecf21987d444942b72d523487ac8d715ca97de6c8f415c71e939595e1a4776403e7dc24ed68fe9125ad4acf57753c9bff7 + checksum: a3bc082d0dfe8327a29263a6d721cea608d440bc8141ba3ec6ba80ad73d84e4f9bbe903c27e9291c29878feec9b5dee2bd0563822f93dc951f5d7fc36bdfe85b languageName: node linkType: hard @@ -1689,7 +1689,7 @@ __metadata: "@babel/helper-validator-identifier": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 04f4178589543396b3c24330a67a59c5e69af5e96119c9adda730c0f20122deaff54671ebbc72ad2df6495a5db8a758bd96942de95fba7ad427de9c80b1b38c8 + checksum: bc9fc6fe6dfe1aeee379abf771a857fdcfea8a548d40ecdafc8e522e71713ae230450d2c48f03e1e3c2d056c0f30286845c1f1fc8c5fd827bddaeb0d860a312c languageName: node linkType: hard @@ -1697,13 +1697,13 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-modules-systemjs@npm:7.23.3" dependencies: - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-module-transforms": ^7.23.3 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.20 + "@babel/helper-hoist-variables": "npm:^7.22.5" + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-validator-identifier": "npm:^7.22.20" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 0d2fdd993c785aecac9e0850cd5ed7f7d448f0fbb42992a950cc0590167144df25d82af5aac9a5c99ef913d2286782afa44e577af30c10901c5ee8984910fa1f + checksum: 051112de7585fff4ffd67865066401f01f90745d41f26b0edbeec0981342c10517ce1a6b4d7051b583a3e513088eece6a3f57b1663f1dd9418071cd05f14fef9 languageName: node linkType: hard @@ -1715,7 +1715,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 46622834c54c551b231963b867adbc80854881b3e516ff29984a8da989bd81665bd70e8cba6710345248e97166689310f544aee1a5773e262845a8f1b3e5b8b4 + checksum: b955d066c68b60c1179bfb0b744e2fad32dbe86d0673bd94637439cfe425d1e3ff579bd47a417233609aac1624f4fe69915bee73e6deb2af6188fda8aaa5db63 languageName: node linkType: hard @@ -1723,11 +1723,11 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-modules-umd@npm:7.23.3" dependencies: - "@babel/helper-module-transforms": ^7.23.3 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 586a7a2241e8b4e753a37af9466a9ffa8a67b4ba9aa756ad7500712c05d8fa9a8c1ed4f7bd25fae2a8265e6cf8fe781ec85a8ee885dd34cf50d8955ee65f12dc + checksum: e3f3af83562d687899555c7826b3faf0ab93ee7976898995b1d20cbe7f4451c55e05b0e17bfb3e549937cbe7573daf5400b752912a241b0a8a64d2457c7626e5 languageName: node linkType: hard @@ -1758,7 +1758,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-new-target@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: e5053389316fce73ad5201b7777437164f333e24787fbcda4ae489cd2580dbbbdfb5694a7237bad91fabb46b591d771975d69beb1c740b82cb4761625379f00b @@ -1769,8 +1769,8 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 checksum: a27d73ea134d3d9560a6b2e26ab60012fba15f1db95865aa0153c18f5ec82cfef6a7b3d8df74e3c2fca81534fa5efeb6cacaf7b08bdb7d123e3dafdd079886a3 @@ -1781,8 +1781,8 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-numeric-separator@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-numeric-separator": ^7.10.4 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 6ba0e5db3c620a3ec81f9e94507c821f483c15f196868df13fa454cbac719a5449baf73840f5b6eb7d77311b24a2cf8e45db53700d41727f693d46f7caf3eec3 @@ -1793,14 +1793,14 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-object-rest-spread@npm:7.23.4" dependencies: - "@babel/compat-data": ^7.23.3 - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-transform-parameters": ^7.23.3 + "@babel/compat-data": "npm:^7.23.3" + "@babel/helper-compilation-targets": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" + "@babel/plugin-transform-parameters": "npm:^7.23.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 73fec495e327ca3959c1c03d07a621be09df00036c69fff0455af9a008291677ee9d368eec48adacdc6feac703269a649747568b4af4c4e9f134aa71cc5b378d + checksum: 656f09c4ec629856e807d5b386559166ae417ff75943abce19656b2c6de5101dfd0aaf23f9074e854339370b4e09f57518d3202457046ee5b567ded531005479 languageName: node linkType: hard @@ -1820,8 +1820,8 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-object-super@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.20 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-replace-supers": "npm:^7.22.20" peerDependencies: "@babel/core": ^7.0.0-0 checksum: e495497186f621fa79026e183b4f1fbb172fd9df812cbd2d7f02c05b08adbe58012b1a6eb6dd58d11a30343f6ec80d0f4074f9b501d70aa1c94df76d59164c53 @@ -1832,8 +1832,8 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 checksum: d50b5ee142cdb088d8b5de1ccf7cea85b18b85d85b52f86618f6e45226372f01ad4cdb29abd4fd35ea99a71fefb37009e0107db7a787dcc21d4d402f97470faf @@ -1849,7 +1849,7 @@ __metadata: "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9713f7920ed04090c149fc5ec024dd1638e8b97aa4ae3753b93072d84103b8de380afb96d6cf03e53b285420db4f705f3ac13149c6fd54f322b61dc19e33c54f + checksum: 9b9e2ab090def43bb4bf811f9b08e0c520249d121de39a743bd1375361cb7b3e0c9bf84ab12511a842aa7f073ffbba19b954ddd8e99f2fc9fa8e7cfe48f5aec2 languageName: node linkType: hard @@ -1857,12 +1857,12 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-optional-chaining@npm:7.23.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e7a4c08038288057b7a08d68c4d55396ada9278095509ca51ed8dfb72a7f13f26bdd7c5185de21079fe0a9d60d22c227cb32e300d266c1bda40f70eee9f4bc1e + checksum: 0ef24e889d6151428953fc443af5f71f4dae73f373dc1b7f5dd3f6a61d511296eb77e9b870e8c2c02a933e3455ae24c1fa91738c826b72a4ff87e0337db527e8 languageName: node linkType: hard @@ -1873,7 +1873,7 @@ __metadata: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b44f89cf97daf23903776ba27c2ab13b439d80d8c8a95be5c476ab65023b1e0c0e94c28d3745f3b60a58edc4e590fa0cd4287a0293e51401ca7d29a2ddb13b8e + checksum: 86bec14b1a42a3c7059fe7dcbbedcae91e778a6b61e59922560d689fea10a165d89e53c2d9f383ad361b642ce444e183880a88dea39d87c09f2046a534b64304 languageName: node linkType: hard @@ -1881,10 +1881,10 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-parameters@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: a735b3e85316d17ec102e3d3d1b6993b429bdb3b494651c9d754e3b7d270462ee1f1a126ccd5e3d871af5e683727e9ef98c9d34d4a42204fffaabff91052ed16 + checksum: a8c36c3fc25f9daa46c4f6db47ea809c395dc4abc7f01c4b1391f6e5b0cd62b83b6016728b02a6a8ac21aca56207c9ec66daefc0336e9340976978de7e6e28df languageName: node linkType: hard @@ -1904,8 +1904,8 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-private-methods@npm:7.23.3" dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-class-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: cedc1285c49b5a6d9a3d0e5e413b756ac40b3ac2f8f68bdfc3ae268bc8d27b00abd8bb0861c72756ff5dd8bf1eb77211b7feb5baf4fdae2ebbaabe49b9adc1d0 @@ -1916,13 +1916,13 @@ __metadata: version: 7.23.4 resolution: "@babel/plugin-transform-private-property-in-object@npm:7.23.4" dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-create-class-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: fb7adfe94ea97542f250a70de32bddbc3e0b802381c92be947fec83ebffda57e68533c4d0697152719a3496fdd3ebf3798d451c024cd4ac848fc15ac26b70aa7 + checksum: 02eef2ee98fa86ee5052ed9bf0742d6d22b510b5df2fcce0b0f5615d6001f7786c6b31505e7f1c2f446406d8fb33603a5316d957cfa5b8365cbf78ddcc24fa42 languageName: node linkType: hard @@ -1941,7 +1941,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-property-literals@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 16b048c8e87f25095f6d53634ab7912992f78e6997a6ff549edc3cf519db4fca01c7b4e0798530d7f6a05228ceee479251245cdd850a5531c6e6f404104d6cc9 @@ -2003,7 +2003,7 @@ __metadata: "@babel/types": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c8f93f29f32cf79683ca2b8958fd62f38155674846ef27a7d4b6fbeb8713c37257418391731b58ff8024ec37b888bed5960e615a3f552e28245d2082e7f2a2df + checksum: 6be5db99b170c937c71fbe68dc64804bb041729d2f95b376ab5e7bc51c34a790f28753b14384160e87cabacf5e1b1aa3379a1a430a60b1fd6b031ba58955f5a6 languageName: node linkType: hard @@ -2035,8 +2035,8 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-regenerator@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - regenerator-transform: ^0.15.2 + "@babel/helper-plugin-utils": "npm:^7.22.5" + regenerator-transform: "npm:^0.15.2" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 7fdacc7b40008883871b519c9e5cdea493f75495118ccc56ac104b874983569a24edd024f0f5894ba1875c54ee2b442f295d6241c3280e61c725d0dd3317c8e6 @@ -2058,7 +2058,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-reserved-words@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 298c4440ddc136784ff920127cea137168e068404e635dc946ddb5d7b2a27b66f1dd4c4acb01f7184478ff7d5c3e7177a127279479926519042948fb7fa0fa48 @@ -2080,7 +2080,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-shorthand-properties@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 5d677a03676f9fff969b0246c423d64d77502e90a832665dc872a5a5e05e5708161ce1effd56bb3c0f2c20a1112fca874be57c8a759d8b08152755519281f326 @@ -2095,7 +2095,7 @@ __metadata: "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 5587f0deb60b3dfc9b274e269031cc45ec75facccf1933ea2ea71ced9fd3ce98ed91bb36d6cd26817c14474b90ed998c5078415f0eab531caf301496ce24c95c + checksum: f9fd247b3fa8953416c8808c124c3a5db5cd697abbf791aae0143a0587fff6b386045f94c62bcd1b6783a1fd275629cc194f25f6c0aafc9f05f12a56fd5f94bf languageName: node linkType: hard @@ -2103,11 +2103,11 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-spread@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8fd5cac201e77a0b4825745f4e07a25f923842f282f006b3a79223c00f61075c8868d12eafec86b2642cd0b32077cdd32314e27bcb75ee5e6a68c0144140dcf2 + checksum: c6372d2f788fd71d85aba12fbe08ee509e053ed27457e6674a4f9cae41ff885e2eb88aafea8fadd0ccf990601fc69ec596fa00959e05af68a15461a8d97a548d languageName: node linkType: hard @@ -2126,7 +2126,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-sticky-regex@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 53e55eb2575b7abfdb4af7e503a2bf7ef5faf8bf6b92d2cd2de0700bdd19e934e5517b23e6dfed94ba50ae516b62f3f916773ef7d9bc81f01503f585051e2949 @@ -2148,7 +2148,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-template-literals@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: b16c5cb0b8796be0118e9c144d15bdc0d20a7f3f59009c6303a6e9a8b74c146eceb3f05186f5b97afcba7cfa87e34c1585a22186e3d5b22f2fd3d27d959d92b2 @@ -2170,7 +2170,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-typeof-symbol@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 0af7184379d43afac7614fc89b1bdecce4e174d52f4efaeee8ec1a4f2c764356c6dba3525c0685231f1cbf435b6dd4ee9e738d7417f3b10ce8bbe869c32f4384 @@ -2187,7 +2187,7 @@ __metadata: "@babel/plugin-syntax-typescript": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6d1317a54d093b302599a4bee8ba9865d0de8b7b6ac1a0746c4316231d632f75b7f086e6e78acb9ac95ba12ba3b9da462dc9ca69370abb4603c4cc987f62e67e + checksum: 7f216a154a507b3a84af29a0f9f2909eb1a418740ebba2b8dd09dac61049b43ca6a35620e28b72ab2c56292e3950355cb2b625bc8ea41e60c8dd770562b1650c languageName: node linkType: hard @@ -2195,13 +2195,13 @@ __metadata: version: 7.23.6 resolution: "@babel/plugin-transform-typescript@npm:7.23.6" dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.23.6 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-typescript": ^7.23.3 + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-create-class-features-plugin": "npm:^7.23.6" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-typescript": "npm:^7.23.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 0462241843d14dff9f1a4c49ab182a6f01a5f7679957c786b08165dac3e8d49184011f05ca204183d164c54b9d3496d1b3005f904fa8708e394e6f15bf5548e6 + checksum: a816811129f3fcb0af1aeb52b84285be390ed8a0eedab17d31fa8e6847c4ca39b4b176d44831f20a8561b3f586974053570ad7bdfa51f89566276e6b191786d2 languageName: node linkType: hard @@ -2220,7 +2220,7 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-unicode-escapes@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 561c429183a54b9e4751519a3dfba6014431e9cdc1484fad03bdaf96582dfc72c76a4f8661df2aeeae7c34efd0fa4d02d3b83a2f63763ecf71ecc925f9cc1f60 @@ -2231,8 +2231,8 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.23.3" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 2298461a194758086d17c23c26c7de37aa533af910f9ebf31ebd0893d4aa317468043d23f73edc782ec21151d3c46cf0ff8098a83b725c49a59de28a1d4d6225 @@ -2255,8 +2255,8 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-unicode-regex@npm:7.23.3" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 checksum: c5f835d17483ba899787f92e313dfa5b0055e3deab332f1d254078a2bba27ede47574b6599fcf34d3763f0c048ae0779dc21d2d8db09295edb4057478dc80a9a @@ -2267,8 +2267,8 @@ __metadata: version: 7.23.3 resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.23.3" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0 checksum: 79d0b4c951955ca68235c87b91ab2b393c96285f8aeaa34d6db416d2ddac90000c9bd6e8c4d82b60a2b484da69930507245035f28ba63c6cae341cf3ba68fdef @@ -2357,7 +2357,7 @@ __metadata: semver: "npm:^6.3.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 86e167f3a351c89f8cd1409262481ece6ddc085b76147e801530ce29d60b1cfda8b264b1efd1ae27b8181b073a923c7161f21e2ebc0a41d652d717b10cf1c829 + checksum: 8ecd96e5869b354fa24930054255d14a0bdc306515809b4dd758de01400d41bbf0323de19ce41cf6f54cbaa62a103343e999a0644ea16e368e99903780d0fb67 languageName: node linkType: hard @@ -2365,89 +2365,89 @@ __metadata: version: 7.23.8 resolution: "@babel/preset-env@npm:7.23.8" dependencies: - "@babel/compat-data": ^7.23.5 - "@babel/helper-compilation-targets": ^7.23.6 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.23.5 - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.23.3 - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.23.3 - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.23.7 - "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 - "@babel/plugin-syntax-async-generators": ^7.8.4 - "@babel/plugin-syntax-class-properties": ^7.12.13 - "@babel/plugin-syntax-class-static-block": ^7.14.5 - "@babel/plugin-syntax-dynamic-import": ^7.8.3 - "@babel/plugin-syntax-export-namespace-from": ^7.8.3 - "@babel/plugin-syntax-import-assertions": ^7.23.3 - "@babel/plugin-syntax-import-attributes": ^7.23.3 - "@babel/plugin-syntax-import-meta": ^7.10.4 - "@babel/plugin-syntax-json-strings": ^7.8.3 - "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - "@babel/plugin-syntax-numeric-separator": ^7.10.4 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - "@babel/plugin-syntax-private-property-in-object": ^7.14.5 - "@babel/plugin-syntax-top-level-await": ^7.14.5 - "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 - "@babel/plugin-transform-arrow-functions": ^7.23.3 - "@babel/plugin-transform-async-generator-functions": ^7.23.7 - "@babel/plugin-transform-async-to-generator": ^7.23.3 - "@babel/plugin-transform-block-scoped-functions": ^7.23.3 - "@babel/plugin-transform-block-scoping": ^7.23.4 - "@babel/plugin-transform-class-properties": ^7.23.3 - "@babel/plugin-transform-class-static-block": ^7.23.4 - "@babel/plugin-transform-classes": ^7.23.8 - "@babel/plugin-transform-computed-properties": ^7.23.3 - "@babel/plugin-transform-destructuring": ^7.23.3 - "@babel/plugin-transform-dotall-regex": ^7.23.3 - "@babel/plugin-transform-duplicate-keys": ^7.23.3 - "@babel/plugin-transform-dynamic-import": ^7.23.4 - "@babel/plugin-transform-exponentiation-operator": ^7.23.3 - "@babel/plugin-transform-export-namespace-from": ^7.23.4 - "@babel/plugin-transform-for-of": ^7.23.6 - "@babel/plugin-transform-function-name": ^7.23.3 - "@babel/plugin-transform-json-strings": ^7.23.4 - "@babel/plugin-transform-literals": ^7.23.3 - "@babel/plugin-transform-logical-assignment-operators": ^7.23.4 - "@babel/plugin-transform-member-expression-literals": ^7.23.3 - "@babel/plugin-transform-modules-amd": ^7.23.3 - "@babel/plugin-transform-modules-commonjs": ^7.23.3 - "@babel/plugin-transform-modules-systemjs": ^7.23.3 - "@babel/plugin-transform-modules-umd": ^7.23.3 - "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.5 - "@babel/plugin-transform-new-target": ^7.23.3 - "@babel/plugin-transform-nullish-coalescing-operator": ^7.23.4 - "@babel/plugin-transform-numeric-separator": ^7.23.4 - "@babel/plugin-transform-object-rest-spread": ^7.23.4 - "@babel/plugin-transform-object-super": ^7.23.3 - "@babel/plugin-transform-optional-catch-binding": ^7.23.4 - "@babel/plugin-transform-optional-chaining": ^7.23.4 - "@babel/plugin-transform-parameters": ^7.23.3 - "@babel/plugin-transform-private-methods": ^7.23.3 - "@babel/plugin-transform-private-property-in-object": ^7.23.4 - "@babel/plugin-transform-property-literals": ^7.23.3 - "@babel/plugin-transform-regenerator": ^7.23.3 - "@babel/plugin-transform-reserved-words": ^7.23.3 - "@babel/plugin-transform-shorthand-properties": ^7.23.3 - "@babel/plugin-transform-spread": ^7.23.3 - "@babel/plugin-transform-sticky-regex": ^7.23.3 - "@babel/plugin-transform-template-literals": ^7.23.3 - "@babel/plugin-transform-typeof-symbol": ^7.23.3 - "@babel/plugin-transform-unicode-escapes": ^7.23.3 - "@babel/plugin-transform-unicode-property-regex": ^7.23.3 - "@babel/plugin-transform-unicode-regex": ^7.23.3 - "@babel/plugin-transform-unicode-sets-regex": ^7.23.3 - "@babel/preset-modules": 0.1.6-no-external-plugins - babel-plugin-polyfill-corejs2: ^0.4.7 - babel-plugin-polyfill-corejs3: ^0.8.7 - babel-plugin-polyfill-regenerator: ^0.5.4 - core-js-compat: ^3.31.0 - semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b850f99fc4aed4ba22c7d9207bd2bbc7a729b49ea6f2c2c36e819fe209e309b96fba336096e555b46f791b39f7cdd5ac41246b556283d435a99106eb825a209f + "@babel/compat-data": "npm:^7.23.5" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-validator-option": "npm:^7.23.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.23.3" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.23.3" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.23.7" + "@babel/plugin-proposal-private-property-in-object": "npm:7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators": "npm:^7.8.4" + "@babel/plugin-syntax-class-properties": "npm:^7.12.13" + "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" + "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" + "@babel/plugin-syntax-import-assertions": "npm:^7.23.3" + "@babel/plugin-syntax-import-attributes": "npm:^7.23.3" + "@babel/plugin-syntax-import-meta": "npm:^7.10.4" + "@babel/plugin-syntax-json-strings": "npm:^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" + "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" + "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" + "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" + "@babel/plugin-transform-arrow-functions": "npm:^7.23.3" + "@babel/plugin-transform-async-generator-functions": "npm:^7.23.7" + "@babel/plugin-transform-async-to-generator": "npm:^7.23.3" + "@babel/plugin-transform-block-scoped-functions": "npm:^7.23.3" + "@babel/plugin-transform-block-scoping": "npm:^7.23.4" + "@babel/plugin-transform-class-properties": "npm:^7.23.3" + "@babel/plugin-transform-class-static-block": "npm:^7.23.4" + "@babel/plugin-transform-classes": "npm:^7.23.8" + "@babel/plugin-transform-computed-properties": "npm:^7.23.3" + "@babel/plugin-transform-destructuring": "npm:^7.23.3" + "@babel/plugin-transform-dotall-regex": "npm:^7.23.3" + "@babel/plugin-transform-duplicate-keys": "npm:^7.23.3" + "@babel/plugin-transform-dynamic-import": "npm:^7.23.4" + "@babel/plugin-transform-exponentiation-operator": "npm:^7.23.3" + "@babel/plugin-transform-export-namespace-from": "npm:^7.23.4" + "@babel/plugin-transform-for-of": "npm:^7.23.6" + "@babel/plugin-transform-function-name": "npm:^7.23.3" + "@babel/plugin-transform-json-strings": "npm:^7.23.4" + "@babel/plugin-transform-literals": "npm:^7.23.3" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.23.4" + "@babel/plugin-transform-member-expression-literals": "npm:^7.23.3" + "@babel/plugin-transform-modules-amd": "npm:^7.23.3" + "@babel/plugin-transform-modules-commonjs": "npm:^7.23.3" + "@babel/plugin-transform-modules-systemjs": "npm:^7.23.3" + "@babel/plugin-transform-modules-umd": "npm:^7.23.3" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.22.5" + "@babel/plugin-transform-new-target": "npm:^7.23.3" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.23.4" + "@babel/plugin-transform-numeric-separator": "npm:^7.23.4" + "@babel/plugin-transform-object-rest-spread": "npm:^7.23.4" + "@babel/plugin-transform-object-super": "npm:^7.23.3" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.23.4" + "@babel/plugin-transform-optional-chaining": "npm:^7.23.4" + "@babel/plugin-transform-parameters": "npm:^7.23.3" + "@babel/plugin-transform-private-methods": "npm:^7.23.3" + "@babel/plugin-transform-private-property-in-object": "npm:^7.23.4" + "@babel/plugin-transform-property-literals": "npm:^7.23.3" + "@babel/plugin-transform-regenerator": "npm:^7.23.3" + "@babel/plugin-transform-reserved-words": "npm:^7.23.3" + "@babel/plugin-transform-shorthand-properties": "npm:^7.23.3" + "@babel/plugin-transform-spread": "npm:^7.23.3" + "@babel/plugin-transform-sticky-regex": "npm:^7.23.3" + "@babel/plugin-transform-template-literals": "npm:^7.23.3" + "@babel/plugin-transform-typeof-symbol": "npm:^7.23.3" + "@babel/plugin-transform-unicode-escapes": "npm:^7.23.3" + "@babel/plugin-transform-unicode-property-regex": "npm:^7.23.3" + "@babel/plugin-transform-unicode-regex": "npm:^7.23.3" + "@babel/plugin-transform-unicode-sets-regex": "npm:^7.23.3" + "@babel/preset-modules": "npm:0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2: "npm:^0.4.7" + babel-plugin-polyfill-corejs3: "npm:^0.8.7" + babel-plugin-polyfill-regenerator: "npm:^0.5.4" + core-js-compat: "npm:^3.31.0" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 74493faa8b3e4bdd07ab3fbde80d7b13cc05321877f997698177c0bb082669c9b6a87397bd79ca6656df3c80c05e514ffed6d81510e2d8719a6e9647c038b7b9 languageName: node linkType: hard @@ -2455,9 +2455,9 @@ __metadata: version: 7.23.3 resolution: "@babel/preset-flow@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.15 - "@babel/plugin-transform-flow-strip-types": ^7.23.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-validator-option": "npm:^7.22.15" + "@babel/plugin-transform-flow-strip-types": "npm:^7.23.3" peerDependencies: "@babel/core": ^7.0.0-0 checksum: 60b5dde79621ae89943af459c4dc5b6030795f595a20ca438c8100f8d82c9ebc986881719030521ff5925799518ac5aa7f3fe62af8c33ab96be3681a71f88d03 @@ -2468,12 +2468,12 @@ __metadata: version: 0.1.6-no-external-plugins resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" dependencies: - "@babel/helper-plugin-utils": ^7.0.0 - "@babel/types": ^7.4.4 - esutils: ^2.0.2 + "@babel/helper-plugin-utils": "npm:^7.0.0" + "@babel/types": "npm:^7.4.4" + esutils: "npm:^2.0.2" peerDependencies: "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 - checksum: 4855e799bc50f2449fb5210f78ea9e8fd46cf4f242243f1e2ed838e2bd702e25e73e822e7f8447722a5f4baa5e67a8f7a0e403f3e7ce04540ff743a9c411c375 + checksum: 039aba98a697b920d6440c622aaa6104bb6076d65356b29dad4b3e6627ec0354da44f9621bafbeefd052cd4ac4d7f88c9a2ab094efcb50963cb352781d0c6428 languageName: node linkType: hard @@ -2488,7 +2488,7 @@ __metadata: esutils: "npm:^2.0.2" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8430e0e9e9d520b53e22e8c4c6a5a080a12b63af6eabe559c2310b187bd62ae113f3da82ba33e9d1d0f3230930ca702843aae9dd226dec51f7d7114dc1f51c10 + checksum: 41583c17748890ad4950ae90ae38bd3f9d56268adc6c3d755839000a72963bda0db448296e4e74069a63567ae5f71f42d4a6dd1672386124bf0897f77c411870 languageName: node linkType: hard @@ -2504,7 +2504,7 @@ __metadata: "@babel/plugin-transform-react-pure-annotations": "npm:^7.18.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 540d9cf0a0cc0bb07e6879994e6fb7152f87dafbac880b56b65e2f528134c7ba33e0cd140b58700c77b2ebf4c81fa6468fed0ba391462d75efc7f8c1699bb4c3 + checksum: 318d501226eb92c099575b2fbc1b4785545502e1543f6e6601c09413e2f381299fdb41acb0034892f5812ca61b3f8fe95ce231f2c1805942b28893c2408dc20f languageName: node linkType: hard @@ -2519,7 +2519,7 @@ __metadata: "@babel/plugin-transform-typescript": "npm:^7.21.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e7b35c435139eec1d6bd9f57e8f3eb79bfc2da2c57a34ad9e9ea848ba4ecd72791cf4102df456604ab07c7f4518525b0764754b6dd5898036608b351e0792448 + checksum: 94df6bad70fcc632490959486378ee9939e4a8f71a05ef27e9c9116fa7832243c9d40f7b0257f5c62e4eea7a516f26cf52d5d8ed8c85d8aa304343faa8c51b4d languageName: node linkType: hard @@ -2527,14 +2527,14 @@ __metadata: version: 7.23.3 resolution: "@babel/preset-typescript@npm:7.23.3" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.15 - "@babel/plugin-syntax-jsx": ^7.23.3 - "@babel/plugin-transform-modules-commonjs": ^7.23.3 - "@babel/plugin-transform-typescript": ^7.23.3 + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-validator-option": "npm:^7.22.15" + "@babel/plugin-syntax-jsx": "npm:^7.23.3" + "@babel/plugin-transform-modules-commonjs": "npm:^7.23.3" + "@babel/plugin-transform-typescript": "npm:^7.23.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 105a2d39bbc464da0f7e1ad7f535c77c5f62d6b410219355b20e552e7d29933567a5c55339b5d0aec1a5c7a0a7dfdf1b54aae601a4fe15a157d54dcbfcb3e854 + checksum: c4add0f3fcbb3f4a305c48db9ccb32694f1308ed9971ccbc1a8a3c76d5a13726addb3c667958092287d7aa080186c5c83dbfefa55eacf94657e6cde39e172848 languageName: node linkType: hard @@ -2542,11 +2542,11 @@ __metadata: version: 7.23.7 resolution: "@babel/register@npm:7.23.7" dependencies: - clone-deep: ^4.0.1 - find-cache-dir: ^2.0.0 - make-dir: ^2.1.0 - pirates: ^4.0.6 - source-map-support: ^0.5.16 + clone-deep: "npm:^4.0.1" + find-cache-dir: "npm:^2.0.0" + make-dir: "npm:^2.1.0" + pirates: "npm:^4.0.6" + source-map-support: "npm:^0.5.16" peerDependencies: "@babel/core": ^7.0.0-0 checksum: c72a6d4856ef04f13490370d805854d2d98a77786bfaec7d85e2c585e1217011c4f3df18197a890e14520906c9111bef95551ba1a9b59c88df4dfc2dfe2c8d1b @@ -2556,7 +2556,7 @@ __metadata: "@babel/regjsgen@npm:^0.8.0": version: 0.8.0 resolution: "@babel/regjsgen@npm:0.8.0" - checksum: 89c338fee774770e5a487382170711014d49a68eb281e74f2b5eac88f38300a4ad545516a7786a8dd5702e9cf009c94c2f582d200f077ac5decd74c56b973730 + checksum: c57fb730b17332b7572574b74364a77d70faa302a281a62819476fa3b09822974fd75af77aea603ad77378395be64e81f89f0e800bf86cbbf21652d49ce12ee8 languageName: node linkType: hard @@ -2565,7 +2565,7 @@ __metadata: resolution: "@babel/runtime@npm:7.22.6" dependencies: regenerator-runtime: "npm:^0.13.11" - checksum: e585338287c4514a713babf4fdb8fc2a67adcebab3e7723a739fc62c79cfda875b314c90fd25f827afb150d781af97bc16c85bfdbfa2889f06053879a1ddb597 + checksum: 1d2f56797f548b009910bddf3dc04f980a9701193233145dc923f3ea87c8f88121a3c3ef1d449e9cb52a370d7d025a2243c748882d5546ff079ddf5ffe29f240 languageName: node linkType: hard @@ -2573,8 +2573,8 @@ __metadata: version: 7.23.8 resolution: "@babel/runtime@npm:7.23.8" dependencies: - regenerator-runtime: ^0.14.0 - checksum: 0bd5543c26811153822a9f382fd39886f66825ff2a397a19008011376533747cd05c33a91f6248c0b8b0edf0448d7c167ebfba34786088f1b7eb11c65be7dfc3 + regenerator-runtime: "npm:^0.14.0" + checksum: ec8f1967a36164da6cac868533ffdff97badd76d23d7d820cc84f0818864accef972f22f9c6a710185db1e3810e353fc18c3da721e5bb3ee8bc61bdbabce03ff languageName: node linkType: hard @@ -2585,7 +2585,7 @@ __metadata: "@babel/code-frame": "npm:^7.22.5" "@babel/parser": "npm:^7.22.5" "@babel/types": "npm:^7.22.5" - checksum: c5746410164039aca61829cdb42e9a55410f43cace6f51ca443313f3d0bdfa9a5a330d0b0df73dc17ef885c72104234ae05efede37c1cc8a72dc9f93425977a3 + checksum: 460634b1c5d61c779270968bd2f0817c19e3a5f20b469330dcab0a324dd29409b15ad1baa8530a21e09a9eb6c7db626500f437690c7be72987e40baa75357799 languageName: node linkType: hard @@ -2593,10 +2593,10 @@ __metadata: version: 7.22.15 resolution: "@babel/template@npm:7.22.15" dependencies: - "@babel/code-frame": ^7.22.13 - "@babel/parser": ^7.22.15 - "@babel/types": ^7.22.15 - checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd + "@babel/code-frame": "npm:^7.22.13" + "@babel/parser": "npm:^7.22.15" + "@babel/types": "npm:^7.22.15" + checksum: 21e768e4eed4d1da2ce5d30aa51db0f4d6d8700bc1821fec6292587df7bba2fe1a96451230de8c64b989740731888ebf1141138bfffb14cacccf4d05c66ad93f languageName: node linkType: hard @@ -2604,17 +2604,17 @@ __metadata: version: 7.23.7 resolution: "@babel/traverse@npm:7.23.7" dependencies: - "@babel/code-frame": ^7.23.5 - "@babel/generator": ^7.23.6 - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-function-name": ^7.23.0 - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/parser": ^7.23.6 - "@babel/types": ^7.23.6 - debug: ^4.3.1 - globals: ^11.1.0 - checksum: d4a7afb922361f710efc97b1e25ec343fab8b2a4ddc81ca84f9a153f22d4482112cba8f263774be8d297918b6c4767c7a98988ab4e53ac73686c986711dd002e + "@babel/code-frame": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.6" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-hoist-variables": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/parser": "npm:^7.23.6" + "@babel/types": "npm:^7.23.6" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 3215e59429963c8dac85c26933372cdd322952aa9930e4bc5ef2d0e4bd7a1510d1ecf8f8fd860ace5d4d9fe496d23805a1ea019a86410aee4111de5f63ee84f9 languageName: node linkType: hard @@ -2632,7 +2632,7 @@ __metadata: "@babel/types": "npm:^7.22.5" debug: "npm:^4.1.0" globals: "npm:^11.1.0" - checksum: a381369bc3eedfd13ed5fef7b884657f1c29024ea7388198149f0edc34bd69ce3966e9f40188d15f56490a5e12ba250ccc485f2882b53d41b054fccefb233e33 + checksum: a2c2157c854a10f64bd8e2ac30e76723a4ee948572158962d102ba4d694abdb47c9cb7f0ede7d662ce083cd1940b631a6ad9ec55e86f4bbe1a1960cbf692078a languageName: node linkType: hard @@ -2643,7 +2643,7 @@ __metadata: "@babel/helper-string-parser": "npm:^7.22.5" "@babel/helper-validator-identifier": "npm:^7.22.5" to-fast-properties: "npm:^2.0.0" - checksum: c13a9c1dc7d2d1a241a2f8363540cb9af1d66e978e8984b400a20c4f38ba38ca29f06e26a0f2d49a70bad9e57615dac09c35accfddf1bb90d23cd3e0a0bab892 + checksum: 7f7edffe7e13dbd26a182677575ca7451bc234ce43b93dc49d27325306748628019e7753e6b5619ae462ea0d7e5ce2c0cc24092d53b592642ea89542037748b5 languageName: node linkType: hard @@ -2651,24 +2651,24 @@ __metadata: version: 7.23.6 resolution: "@babel/types@npm:7.23.6" dependencies: - "@babel/helper-string-parser": ^7.23.4 - "@babel/helper-validator-identifier": ^7.22.20 - to-fast-properties: ^2.0.0 - checksum: 68187dbec0d637f79bc96263ac95ec8b06d424396678e7e225492be866414ce28ebc918a75354d4c28659be6efe30020b4f0f6df81cc418a2d30645b690a8de0 + "@babel/helper-string-parser": "npm:^7.23.4" + "@babel/helper-validator-identifier": "npm:^7.22.20" + to-fast-properties: "npm:^2.0.0" + checksum: 07e70bb94d30b0231396b5e9a7726e6d9227a0a62e0a6830c0bd3232f33b024092e3d5a7d1b096a65bbf2bb43a9ab4c721bf618e115bfbb87b454fa060f88cbf languageName: node linkType: hard "@base2/pretty-print-object@npm:1.0.1": version: 1.0.1 resolution: "@base2/pretty-print-object@npm:1.0.1" - checksum: 1e8a5af578037a9d47d72f815983f9e4efb038e5f03e7635fc893194c5daa723215d71af33267893a9b618656c8eaea7be931b1c063c9b066a40994be0d23545 + checksum: c1b78a521ac712baa076589f3bc81318d07c34a5747e9177b6af37043592252587d98f9b7b59ec174968c6bea31a99fe4d7884121173a449b75fe602b7eb2839 languageName: node linkType: hard "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" - checksum: 850f9305536d0f2bd13e9e0881cb5f02e4f93fad1189f7b2d4bebf694e3206924eadee1068130d43c11b750efcc9405f88a8e42ef098b6d75239c0f047de1a27 + checksum: 1a1f0e356a3bb30b5f1ced6f79c413e6ebacf130421f15fac5fcd8be5ddf98aedb4404d7f5624e3285b700e041f9ef938321f3ca4d359d5b716f96afa120d88d languageName: node linkType: hard @@ -2682,14 +2682,14 @@ __metadata: "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" - checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425 + checksum: 9d226461c1e91e95f067be2bdc5e6f99cfe55a721f45afb44122e23e4b8602eeac4ff7325af6b5a369f36396ee1514d3809af3f57769066d80d83790d8e53339 languageName: node linkType: hard "@discoveryjs/json-ext@npm:^0.5.3": version: 0.5.7 resolution: "@discoveryjs/json-ext@npm:0.5.7" - checksum: 2176d301cc258ea5c2324402997cf8134ebb212469c0d397591636cea8d3c02f2b3cf9fd58dcb748c7a0dade77ebdc1b10284fa63e608c033a1db52fddc69918 + checksum: b95682a852448e8ef50d6f8e3b7ba288aab3fd98a2bafbe46881a3db0c6e7248a2debe9e1ee0d4137c521e4743ca5bbcb1c0765c9d7b3e0ef53231506fec42b4 languageName: node linkType: hard @@ -2698,7 +2698,7 @@ __metadata: resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.0.1" peerDependencies: react: ">=16.8.0" - checksum: 700b6e5bbb37a9231f203bb3af11295eed01d73b2293abece0bc2a2237015e944d7b5114d4887ad9a79776504aa51ed2a8b0ddbc117c54495dd01a6b22f93786 + checksum: 7d7ead9ba3f615510f550aea67815281ec5a5487de55aafc250f820317afc1fd419bd9e9e27602a0206ec5c152f13dc6130bccad312c1036706c584c65d66ef7 languageName: node linkType: hard @@ -3017,14 +3017,14 @@ __metadata: eslint-visitor-keys: "npm:^3.3.0" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: cdfe3ae42b4f572cbfb46d20edafe6f36fc5fb52bf2d90875c58aefe226892b9677fef60820e2832caf864a326fe4fc225714c46e8389ccca04d5f9288aabd22 + checksum: 8d70bcdcd8cd279049183aca747d6c2ed7092a5cf0cf5916faac1ef37ffa74f0c245c2a3a3d3b9979d9dfdd4ca59257b4c5621db699d637b847a2c5e02f491c2 languageName: node linkType: hard "@eslint-community/regexpp@npm:^4.4.0": version: 4.5.1 resolution: "@eslint-community/regexpp@npm:4.5.1" - checksum: 6d901166d64998d591fab4db1c2f872981ccd5f6fe066a1ad0a93d4e11855ecae6bfb76660869a469563e8882d4307228cebd41142adb409d182f2966771e57e + checksum: e31e456d44e9bf98d59c8ac445549098e1a6d9c4e22053cad58e86a9f78a1e64104ef7f7f46255c442e0c878fe0e566ffba287787d070196c83510ef30d1d197 languageName: node linkType: hard @@ -3041,28 +3041,28 @@ __metadata: js-yaml: "npm:^4.1.0" minimatch: "npm:^3.1.2" strip-json-comments: "npm:^3.1.1" - checksum: d5ed0adbe23f6571d8c9bb0ca6edf7618dc6aed4046aa56df7139f65ae7b578874e0d9c796df784c25bda648ceb754b6320277d828c8b004876d7443b8dc018c + checksum: 923adf0fbadbe1548b2cbf6d020cc135fcd3bafee073b937a4c2e15b971cff607d987cc82e076d19d86d660dc0b992f688e0f5cf5eabfb5045c8ecdc3e50bd63 languageName: node linkType: hard "@eslint/js@npm:8.38.0": version: 8.38.0 resolution: "@eslint/js@npm:8.38.0" - checksum: 1f28987aa8c9cd93e23384e16c7220863b39b5dc4b66e46d7cdbccce868040f455a98d24cd8b567a884f26545a0555b761f7328d4a00c051e7ef689cbea5fce1 + checksum: 54a71a7ee3f535a095f919e25806f5e5d0b254ad85abf67bb51328545d16d93a0680560b6abce861478b7aef0f4d5174fc213b6472b78469a9b1937e3dd6d36e languageName: node linkType: hard "@fal-works/esbuild-plugin-global-externals@npm:^2.1.2": version: 2.1.2 resolution: "@fal-works/esbuild-plugin-global-externals@npm:2.1.2" - checksum: c59715902b9062aa7ff38973f298b509499fd146dbf564dc338b3f9e896da5bffb4ca676c27587fde79b3586003e24d65960acb62f009bca43dca34c76f8cbf7 + checksum: fd68714cccfbd33a8ec31d11ac7c6373100a5e1b8e31941a45c723c802feccb0a00dde946f55cc91d58bff77d405adc2064b22f0faf5ee165968965e5da758a1 languageName: node linkType: hard "@floating-ui/core@npm:^1.2.6, @floating-ui/core@npm:^1.3.1": version: 1.3.1 resolution: "@floating-ui/core@npm:1.3.1" - checksum: fe3b40fcaec95b0825c01a98330ae75b60c61c395ca012055a32f9c22ab97fde8ce1bd14fce3d242beb9dbe4564c90ce4a7a767851911d4215b9ec7721440e5b + checksum: b0aeb508315fcc35afa288fc2030c2ac42d5d1518c9609f9fa0e1ef79520f68784bb39bf46dbc783803530686bf5ffb78d221626dfa2b5e1466000977e0ea7e7 languageName: node linkType: hard @@ -3071,7 +3071,7 @@ __metadata: resolution: "@floating-ui/dom@npm:1.2.9" dependencies: "@floating-ui/core": "npm:^1.2.6" - checksum: 16ae5e05a41c2ca16d51579d12729ca9d346241319f68ce5678f5fbeb9c4f9a16176c95089bbd7a0eb37c6ed90e5fd55a310ffc9948af7c841d5b8bfa0afe1b8 + checksum: c85c67b678d68bfb02458f1a997b8f02f3d6ea87d94dab00c1b930a58928fe4ed5c629a0448a0c6d63ed3aaa79cca1935db5067e42f2488c186e703add267744 languageName: node linkType: hard @@ -3080,7 +3080,7 @@ __metadata: resolution: "@floating-ui/dom@npm:1.4.4" dependencies: "@floating-ui/core": "npm:^1.3.1" - checksum: e8e43c786e24f8f111a72d7d17c3a9563cab8eddf2a2b3dacc2785370a97313a8dda0f3470b2b2ef2d3b9d6f1fd706ccf786d9441e54e283ed47c90aa0c0b1e1 + checksum: 1caccbf0bae402e2aa4c7811c87cd329b30e99f6bbe4914f7d2371284f20ab66a3b0da3c24d388c97ccdbbcb38c106a45df96b3c9b7e9a132bdd12427f19fac6 languageName: node linkType: hard @@ -3092,7 +3092,7 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 00fef2cf69ac2b15952e47505fd9e23f6cc5c20a26adc707862932826d1682f3c30f83c9887abfc93574fdca2d34dd2fc00271527318b1db403549cd6bc9eb00 + checksum: c453e252ef71e5386d1ed9fd3bca392d01547cb505daadf38b481544e1819ea00c5f6c4a637c86833d4f2d37377eebfa3c0bc36ffe0b74af2001664121c0d5d4 languageName: node linkType: hard @@ -3106,7 +3106,7 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 0d8300f5706ca7cf69c1b4c26822287fd545b23d9f89c03fca1c04d3899edd188f374567ed98e1ccebd80869b50cd7c4908e9d4be91d25dd5800b787961faf83 + checksum: e08b028d99d05e1af792ffafbab4d4a28feef4db63b88edb84a4eb524a9d32fb2e7c9aeb6d8fd2a4f2d7093ef9b9e4b213698ef04afcdbe43d928f88e58348eb languageName: node linkType: hard @@ -3117,21 +3117,21 @@ __metadata: "@humanwhocodes/object-schema": "npm:^1.2.1" debug: "npm:^4.1.1" minimatch: "npm:^3.0.5" - checksum: 1b1302e2403d0e35bc43e66d67a2b36b0ad1119efc704b5faff68c41f791a052355b010fb2d27ef022670f550de24cd6d08d5ecf0821c16326b7dcd0ee5d5d8a + checksum: f93086ae6a340e739a6bb23d4575b69f52acc4e4e3d62968eaaf77a77db4ba69d6d3e50c0028ba19b634ef6b241553a9d9a13d91b797b3ea33d5d711bb3362fb languageName: node linkType: hard "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 0fd22007db8034a2cdf2c764b140d37d9020bbfce8a49d3ec5c05290e77d4b0263b1b972b752df8c89e5eaa94073408f2b7d977aed131faf6cf396ebb5d7fb61 + checksum: e993950e346331e5a32eefb27948ecdee2a2c4ab3f072b8f566cd213ef485dd50a3ca497050608db91006f5479e43f91a439aef68d2a313bd3ded06909c7c5b3 languageName: node linkType: hard "@humanwhocodes/object-schema@npm:^1.2.1": version: 1.2.1 resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 + checksum: b48a8f87fcd5fdc4ac60a31a8bf710d19cc64556050575e6a35a4a48a8543cf8cde1598a65640ff2cdfbfd165b38f9db4fa3782bea7848eb585cc3db824002e6 languageName: node linkType: hard @@ -3145,7 +3145,7 @@ __metadata: strip-ansi-cjs: "npm:strip-ansi@^6.0.1" wrap-ansi: "npm:^8.1.0" wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 4a473b9b32a7d4d3cfb7a614226e555091ff0c5a29a1734c28c72a182c2f6699b26fc6b5c2131dfd841e86b185aea714c72201d7c98c2fba5f17709333a67aeb + checksum: e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 languageName: node linkType: hard @@ -3158,14 +3158,14 @@ __metadata: get-package-type: "npm:^0.1.0" js-yaml: "npm:^3.13.1" resolve-from: "npm:^5.0.0" - checksum: d578da5e2e804d5c93228450a1380e1a3c691de4953acc162f387b717258512a3e07b83510a936d9fab03eac90817473917e24f5d16297af3867f59328d58568 + checksum: b000a5acd8d4fe6e34e25c399c8bdbb5d3a202b4e10416e17bfc25e12bab90bb56d33db6089ae30569b52686f4b35ff28ef26e88e21e69821d2b85884bd055b8 languageName: node linkType: hard "@istanbuljs/schema@npm:^0.1.2": version: 0.1.3 resolution: "@istanbuljs/schema@npm:0.1.3" - checksum: 5282759d961d61350f33d9118d16bcaed914ebf8061a52f4fa474b2cb08720c9c81d165e13b82f2e5a8a212cc5af482f0c6fc1ac27b9e067e5394c9a6ed186c9 + checksum: a9b1e49acdf5efc2f5b2359f2df7f90c5c725f2656f16099e8b2cd3a000619ecca9fc48cf693ba789cf0fd989f6e0df6a22bc05574be4223ecdbb7997d04384b languageName: node linkType: hard @@ -3179,7 +3179,7 @@ __metadata: jest-message-util: "npm:^29.6.1" jest-util: "npm:^29.6.1" slash: "npm:^3.0.0" - checksum: d0ab23a00947bfb4bff8c0a7e5a7afd16519de16dde3fe7e77b9f13e794c6df7043ecf7fcdde66ac0d2b5fb3262e9cab3d92eaf61f89a12d3b8e3602e06a9902 + checksum: b5a771563c4aad3a0f6e514eeee4254541eb4e7692f0c72eafc0195ba80b74d421f4537aaa262fe6ebfe17c23bd7069c0b74edea9e8c439f18efc5e4a9940c78 languageName: node linkType: hard @@ -3220,7 +3220,7 @@ __metadata: peerDependenciesMeta: node-notifier: optional: true - checksum: 736dcc90c6c58dd9e1d2da122103b851187719ce3b3d4167689c63e68252632cd817712955b52ddaa648eba9c6f98f86cd58677325f0db4185f76899c64d7dac + checksum: 6ec315394432e193c2e87ae8839577b0be5925be9a662987c089bb577ffb486f24e62f5a7f0341dacaf743ed2bab2c7dd7a1ccb406562fcb4c936f35448ee793 languageName: node linkType: hard @@ -3232,7 +3232,7 @@ __metadata: "@jest/types": "npm:^29.6.1" "@types/node": "npm:*" jest-mock: "npm:^29.6.1" - checksum: fb671f91f27e7aa1ba04983ef87a83f0794a597aba0a57d08cbb1fcb484c2aedc2201e99f85fafe27aec9be78af6f2d1d7e6ea88267938992a1d0f9d4615f5b2 + checksum: 4443dff5137d602bf79dcebd14bf274191dd3c3b49a0e586819f7710decf276b70ac502f1a8f3c73d8b6aeb22059dcda3dac5bbc3b6fe5824d2750bc255354cf languageName: node linkType: hard @@ -3241,7 +3241,7 @@ __metadata: resolution: "@jest/expect-utils@npm:29.6.1" dependencies: jest-get-type: "npm:^29.4.3" - checksum: 037ee017eca62f7b45e1465fb5c6f9e92d5709a9ac716b8bff0bd294240a54de734e8f968fb69309cc4aef6c83b9552d5a821f3b18371af394bf04783859d706 + checksum: b8506c067b90e7c7bb2b3db8b1323d0c514471e2cf52c27f955fbae0052c82b045a3e12c8dd6e7d155d4cf278e80d88c39ba48e5675f142f81e3a7ab9f5a230c languageName: node linkType: hard @@ -3251,7 +3251,7 @@ __metadata: dependencies: expect: "npm:^29.6.1" jest-snapshot: "npm:^29.6.1" - checksum: 5c56977b3cc8489744d97d9dc2dcb196c1dfecc83a058a7ef0fd4f63d68cf120a23d27669272d1e1b184fb4337b85e4ac1fc7f886e3988fdf243d42d73973eac + checksum: 126e06ae31d454a87ba99ca7ab221b6e2d083b0eafefc2e807c46d0d1ba22ac1ff7706d560076cb08992fc3f2f09dc5fe4416338e5ebb229dedc258de345ae2c languageName: node linkType: hard @@ -3265,7 +3265,7 @@ __metadata: jest-message-util: "npm:^29.6.1" jest-mock: "npm:^29.6.1" jest-util: "npm:^29.6.1" - checksum: 86991276944b7d6c2ada3703a272517f5f8f2f4e2af1fe26065f6db1dac4dc6299729a88c46bcb781dcc1b20504c1d4bbd8119fd8a0838ac81a9a4b5d2c8e429 + checksum: 093665ee5dc6e5ff4d512e44ed85fd17fffea89d57141dc17cb50e83b89a6c26cbfb8091b50d83c8b38344fee83f988d047d10b87ad59ba461c94cf3fc498ad6 languageName: node linkType: hard @@ -3314,7 +3314,7 @@ __metadata: peerDependenciesMeta: node-notifier: optional: true - checksum: b7dae415f3f6342b4db2671261bbee29af20a829f42135316c3dd548b9ef85290c9bb64a0e3aec4a55486596be1257ac8216a0f8d9794acd43f8b8fb686fc7e3 + checksum: 2990ccfdcc031b426dad550e009636a62410fe8fe3c728a2efb89142fcc41fd6ae270ddc16a21809ee1a4e6ef4286101a0a1c7463c2129c091adccb3e31e4cda languageName: node linkType: hard @@ -3346,7 +3346,7 @@ __metadata: "@jest/types": "npm:^29.6.1" "@types/istanbul-lib-coverage": "npm:^2.0.0" collect-v8-coverage: "npm:^1.0.0" - checksum: 9397a3a3410c5df564e79297b1be4fe33807a6157a017a1f74b54a6ef14de1530f12b922299e822e66a82c53269da16661772bffde3d883a78c5eefd2cd6d1cc + checksum: acb05b0e95490506261921d30b145b5f4f68898d54cb188e5ecb5a060008c79aad03297d18a244dcf7af4f1ef7b90f80a997afe5e7ab571c82714ff1ca3cb78a languageName: node linkType: hard @@ -3358,7 +3358,7 @@ __metadata: graceful-fs: "npm:^4.2.9" jest-haste-map: "npm:^29.6.1" slash: "npm:^3.0.0" - checksum: f3437178b5dca0401ed2e990d8b69161442351856d56f5725e009a487f5232b51039f8829673884b9bea61c861120d08a53a36432f4a4b8aab38915a68f7000d + checksum: 97588815a4605720b973989b2d85f5fb90d00eee96a5e678e4e4e45baf20d6c1c8d2dfb212867cf964ee8b51857d6bcba319bd82de0f4c2305ce747d9ffac2c3 languageName: node linkType: hard @@ -3381,7 +3381,7 @@ __metadata: pirates: "npm:^4.0.4" slash: "npm:^3.0.0" write-file-atomic: "npm:^4.0.2" - checksum: 1635cd66e4b3dbba0689ecefabc6137301756c9c12d1d23e25124dd0dd9b4a6a38653d51e825e90f74faa022152ac1eaf200591fb50417aa7e1f7d1d1c2bc11d + checksum: f39d32a28904d091c185ecb51b8894efc9b1fb40dde8bb449d8203bee735df4351625a0c68022433727b63f2f58d172bd3d6dc5a16e3f073ffc3a8e9ec7a5760 languageName: node linkType: hard @@ -3394,7 +3394,7 @@ __metadata: "@types/node": "npm:*" "@types/yargs": "npm:^16.0.0" chalk: "npm:^4.0.0" - checksum: d1f43cc946d87543ddd79d49547aab2399481d34025d5c5f2025d3d99c573e1d9832fa83cef25e9d9b07a8583500229d15bbb07b8e233d127d911d133e2f14b1 + checksum: d3ca1655673539c54665f3e9135dc70887feb6b667b956e712c38f42e513ae007d3593b8075aecea8f2db7119f911773010f17f93be070b1725fbc6225539b6e languageName: node linkType: hard @@ -3408,7 +3408,7 @@ __metadata: "@types/node": "npm:*" "@types/yargs": "npm:^17.0.8" chalk: "npm:^4.0.0" - checksum: 89fc1ccf71a84fe0da643e0675b1cfe6a6f19ea72e935b2ab1dbdb56ec547e94433fb59b3536d3832a6e156c077865b7176fe9dae707dab9c3d2f9405ba6233c + checksum: f6264fb0fc60efcb95adf3c4b30be6433aae75769b4f90d09de35fb19c65f7184d6c227a75f5b9e0054368d4fbf5cc4b397f9756d9a59eee25f3247d2e020f93 languageName: node linkType: hard @@ -3416,17 +3416,17 @@ __metadata: version: 0.3.0 resolution: "@joshwooding/vite-plugin-react-docgen-typescript@npm:0.3.0" dependencies: - glob: ^7.2.0 - glob-promise: ^4.2.0 - magic-string: ^0.27.0 - react-docgen-typescript: ^2.2.2 + glob: "npm:^7.2.0" + glob-promise: "npm:^4.2.0" + magic-string: "npm:^0.27.0" + react-docgen-typescript: "npm:^2.2.2" peerDependencies: typescript: ">= 4.3.x" vite: ^3.0.0 || ^4.0.0 || ^5.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 3fe2dc68dcb43920cc08bc5cc2937953bed1080e9c453dc3f513156b9a862fe6af0cda94b70272a4844a27964070129f8d0d31056211b1486a8fd9f6e1c20559 + checksum: 9237499394b1f5f1320c9a489dbf5db2ba4b1d68081bf767a08895b70d0d0830adb9f0f1e2c5c94202e5bee63fe031ea2b91870a6bc806ed5e370be6b06df2e8 languageName: node linkType: hard @@ -3437,14 +3437,14 @@ __metadata: "@jridgewell/set-array": "npm:^1.0.1" "@jridgewell/sourcemap-codec": "npm:^1.4.10" "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 4a74944bd31f22354fc01c3da32e83c19e519e3bbadafa114f6da4522ea77dd0c2842607e923a591d60a76699d819a2fbb6f3552e277efdb9b58b081390b60ab + checksum: 072ace159c39ab85944bdabe017c3de15c5e046a4a4a772045b00ff05e2ebdcfa3840b88ae27e897d473eb4d4845b37be3c78e28910c779f5aeeeae2fb7f0cc2 languageName: node linkType: hard "@jridgewell/resolve-uri@npm:3.1.0": version: 3.1.0 resolution: "@jridgewell/resolve-uri@npm:3.1.0" - checksum: b5ceaaf9a110fcb2780d1d8f8d4a0bfd216702f31c988d8042e5f8fbe353c55d9b0f55a1733afdc64806f8e79c485d2464680ac48a0d9fcadb9548ee6b81d267 + checksum: 320ceb37af56953757b28e5b90c34556157676d41e3d0a3ff88769274d62373582bb0f0276a4f2d29c3f4fdd55b82b8be5731f52d391ad2ecae9b321ee1c742d languageName: node linkType: hard @@ -3458,14 +3458,14 @@ __metadata: "@jridgewell/sourcemap-codec@npm:1.4.14": version: 1.4.14 resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" - checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 + checksum: 26e768fae6045481a983e48aa23d8fcd23af5da70ebd74b0649000e815e7fbb01ea2bc088c9176b3fffeb9bec02184e58f46125ef3320b30eaa1f4094cfefa38 languageName: node linkType: hard "@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13, @jridgewell/sourcemap-codec@npm:^1.4.15": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" - checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 + checksum: 89960ac087781b961ad918978975bcdf2051cd1741880469783c42de64239703eab9db5230d776d8e6a09d73bb5e4cb964e07d93ee6e2e7aea5a7d726e865c09 languageName: node linkType: hard @@ -3475,14 +3475,14 @@ __metadata: dependencies: "@jridgewell/resolve-uri": "npm:3.1.0" "@jridgewell/sourcemap-codec": "npm:1.4.14" - checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02 + checksum: f4fabdddf82398a797bcdbb51c574cd69b383db041a6cae1a6a91478681d6aab340c01af655cfd8c6e01cde97f63436a1445f08297cdd33587621cf05ffa0d55 languageName: node linkType: hard "@juggle/resize-observer@npm:^3.3.1": version: 3.4.0 resolution: "@juggle/resize-observer@npm:3.4.0" - checksum: 2505028c05cc2e17639fcad06218b1c4b60f932a4ebb4b41ab546ef8c157031ae377e3f560903801f6d01706dbefd4943b6c4704bf19ed86dfa1c62f1473a570 + checksum: 73d1d00ee9132fb6f0aea0531940a6b93603e935590bd450fc6285a328d906102eeeb95dea77b2edac0e779031a9708aa8c82502bd298ee4dd26e7dff48f397a languageName: node linkType: hard @@ -3494,7 +3494,7 @@ __metadata: "@types/react": "npm:>=16" peerDependencies: react: ">=16" - checksum: f45fe779556e6cd9a787f711274480e0638b63c460f192ebdcd77cc07ffa61e23c98cb46dd46e577093e1cb4997a232a848d1fb0ba850ae204422cf603add524 + checksum: bce1cb1dde0a9a2b786cd9167b9e2bc0e3be52c195a4a79aaf1677470566d1fd2979d01baca2380c76aa4a1a27cd89f051484e595fdc4144a428d6af39bb667a languageName: node linkType: hard @@ -3505,7 +3505,7 @@ __metadata: gunzip-maybe: "npm:^1.4.2" pump: "npm:^3.0.0" tar-fs: "npm:^2.1.1" - checksum: 7fa8ac40b4e85738a4ee6bf891bc27fce2445b65b4477e0ec86aed0fa62ab18bdf5d193ce04553ad9bfa639e1eef33b8b30da4ef3e7218f12bf95f24c8786e5b + checksum: 39697cef2b92f6e08e3590467cc6da88cd6757b2a27cb9208879c2316ed71d6be4608892ee0a86eb0343140da1a5df498f93a32c2aaf8f1fbd90f883f08b5f63 languageName: node linkType: hard @@ -3515,7 +3515,7 @@ __metadata: dependencies: "@nodelib/fs.stat": "npm:2.0.5" run-parallel: "npm:^1.1.9" - checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 + checksum: 6ab2a9b8a1d67b067922c36f259e3b3dfd6b97b219c540877a4944549a4d49ea5ceba5663905ab5289682f1f3c15ff441d02f0447f620a42e1cb5e1937174d4b languageName: node linkType: hard @@ -3532,7 +3532,7 @@ __metadata: dependencies: "@nodelib/fs.scandir": "npm:2.1.5" fastq: "npm:^1.6.0" - checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 + checksum: 40033e33e96e97d77fba5a238e4bba4487b8284678906a9f616b5579ddaf868a18874c0054a75402c9fbaaa033a25ceae093af58c9c30278e35c23c9479e79b0 languageName: node linkType: hard @@ -3541,14 +3541,14 @@ __metadata: resolution: "@npmcli/fs@npm:3.1.0" dependencies: semver: "npm:^7.3.5" - checksum: a50a6818de5fc557d0b0e6f50ec780a7a02ab8ad07e5ac8b16bf519e0ad60a144ac64f97d05c443c3367235d337182e1d012bbac0eb8dbae8dc7b40b193efd0e + checksum: f3a7ab3a31de65e42aeb6ed03ed035ef123d2de7af4deb9d4a003d27acc8618b57d9fb9d259fe6c28ca538032a028f37337264388ba27d26d37fff7dde22476e languageName: node linkType: hard "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f + checksum: 115e8ceeec6bc69dff2048b35c0ab4f8bbee12d8bb6c1f4af758604586d802b6e669dcb02dda61d078de42c2b4ddce41b3d9e726d7daa6b4b850f4adbf7333ff languageName: node linkType: hard @@ -3556,7 +3556,7 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/number@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 + "@babel/runtime": "npm:^7.13.10" checksum: 621ea8b7d4195d1a65a9c0aee918e8335e7f198088eec91577512c89c2ba3a3bab4a767cfb872a2b9c3092a78ff41cad9a924845a939f6bb87fe9356241ea0ea languageName: node linkType: hard @@ -3565,7 +3565,7 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/primitive@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 + "@babel/runtime": "npm:^7.13.10" checksum: 2b93e161d3fdabe9a64919def7fa3ceaecf2848341e9211520c401181c9eaebb8451c630b066fad2256e5c639c95edc41de0ba59c40eff37e799918d019822d1 languageName: node linkType: hard @@ -3574,8 +3574,8 @@ __metadata: version: 1.0.3 resolution: "@radix-ui/react-arrow@npm:1.0.3" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-primitive": 1.0.3 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-primitive": "npm:1.0.3" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3594,11 +3594,11 @@ __metadata: version: 1.0.3 resolution: "@radix-ui/react-collection@npm:1.0.3" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-compose-refs": 1.0.1 - "@radix-ui/react-context": 1.0.1 - "@radix-ui/react-primitive": 1.0.3 - "@radix-ui/react-slot": 1.0.2 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-compose-refs": "npm:1.0.1" + "@radix-ui/react-context": "npm:1.0.1" + "@radix-ui/react-primitive": "npm:1.0.3" + "@radix-ui/react-slot": "npm:1.0.2" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3609,7 +3609,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: acfbc9b0b2c553d343c22f02c9f098bc5cfa99e6e48df91c0d671855013f8b877ade9c657b7420a7aa523b5aceadea32a60dd72c23b1291f415684fb45d00cff + checksum: 2ac740ab746f411942dc95100f1eb60b9a3670960a805e266533fa1bc7dec31a6dabddd746ab788ebd5a9c22b468e38922f39d30447925515f8e44f0a3b2e56c languageName: node linkType: hard @@ -3617,7 +3617,7 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-compose-refs@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 + "@babel/runtime": "npm:^7.13.10" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -3632,14 +3632,14 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-context@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 + "@babel/runtime": "npm:^7.13.10" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 60e9b81d364f40c91a6213ec953f7c64fcd9d75721205a494a5815b3e5ae0719193429b62ee6c7002cd6aaf70f8c0e2f08bdbaba9ffcc233044d32b56d2127d1 + checksum: a02187a3bae3a0f1be5fab5ad19c1ef06ceff1028d957e4d9994f0186f594a9c3d93ee34bacb86d1fa8eb274493362944398e1c17054d12cb3b75384f9ae564b languageName: node linkType: hard @@ -3647,7 +3647,7 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-direction@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 + "@babel/runtime": "npm:^7.13.10" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -3662,12 +3662,12 @@ __metadata: version: 1.0.4 resolution: "@radix-ui/react-dismissable-layer@npm:1.0.4" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/primitive": 1.0.1 - "@radix-ui/react-compose-refs": 1.0.1 - "@radix-ui/react-primitive": 1.0.3 - "@radix-ui/react-use-callback-ref": 1.0.1 - "@radix-ui/react-use-escape-keydown": 1.0.3 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/primitive": "npm:1.0.1" + "@radix-ui/react-compose-refs": "npm:1.0.1" + "@radix-ui/react-primitive": "npm:1.0.3" + "@radix-ui/react-use-callback-ref": "npm:1.0.1" + "@radix-ui/react-use-escape-keydown": "npm:1.0.3" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3678,7 +3678,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: ea86004ed56a10609dd84eef39dc1e57b400d687a35be41bb4aaa06dc7ad6dbd0a8da281e08c8c077fdbd523122e4d860cb7438a60c664f024f77c8b41299ec6 + checksum: bcc14f0704fdc19430a2b922106a278e64401decffd6e47f427aa5de2d63367ba3e848b012c464a6b39a6e057060e41ad16964385941735a329e319cea46711a languageName: node linkType: hard @@ -3686,7 +3686,7 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-focus-guards@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 + "@babel/runtime": "npm:^7.13.10" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -3701,10 +3701,10 @@ __metadata: version: 1.0.3 resolution: "@radix-ui/react-focus-scope@npm:1.0.3" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-compose-refs": 1.0.1 - "@radix-ui/react-primitive": 1.0.3 - "@radix-ui/react-use-callback-ref": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-compose-refs": "npm:1.0.1" + "@radix-ui/react-primitive": "npm:1.0.3" + "@radix-ui/react-use-callback-ref": "npm:1.0.1" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3715,7 +3715,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: e5b1a089071fbe77aca11124a4ad9623fc2bcaf4c019759b0cd044bf0878ecc924131ee09c6a22d38a3f094684ef68ed18fa65c8d891918412e0afc685a464e0 + checksum: d62631cc06a2f37d483d106f3732ffc00831498fc2306df51c675d7cdb9727169512a1ca43ce06d1bfd578e8d8d67a80858c7531579bacaf6079d3aaf0ca8663 languageName: node linkType: hard @@ -3723,8 +3723,8 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-id@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-use-layout-effect": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-use-layout-effect": "npm:1.0.1" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -3739,17 +3739,17 @@ __metadata: version: 1.1.2 resolution: "@radix-ui/react-popper@npm:1.1.2" dependencies: - "@babel/runtime": ^7.13.10 - "@floating-ui/react-dom": ^2.0.0 - "@radix-ui/react-arrow": 1.0.3 - "@radix-ui/react-compose-refs": 1.0.1 - "@radix-ui/react-context": 1.0.1 - "@radix-ui/react-primitive": 1.0.3 - "@radix-ui/react-use-callback-ref": 1.0.1 - "@radix-ui/react-use-layout-effect": 1.0.1 - "@radix-ui/react-use-rect": 1.0.1 - "@radix-ui/react-use-size": 1.0.1 - "@radix-ui/rect": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@floating-ui/react-dom": "npm:^2.0.0" + "@radix-ui/react-arrow": "npm:1.0.3" + "@radix-ui/react-compose-refs": "npm:1.0.1" + "@radix-ui/react-context": "npm:1.0.1" + "@radix-ui/react-primitive": "npm:1.0.3" + "@radix-ui/react-use-callback-ref": "npm:1.0.1" + "@radix-ui/react-use-layout-effect": "npm:1.0.1" + "@radix-ui/react-use-rect": "npm:1.0.1" + "@radix-ui/react-use-size": "npm:1.0.1" + "@radix-ui/rect": "npm:1.0.1" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3760,7 +3760,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 4929daa0d1cccada3cff50de0e00c0d186ffea97a5f28545c77fa85ff9bc5c105a54dddac400c2e2dcac631f0f7ea88e59f2e5ad0f80bb2cb7b62cc7cd30400f + checksum: be32677e846ef93e8cbf219550e55b99583cb927b572a9ee466b0c242156d42ddc70f43135e22acffe48bba4cd3fe28888cc3f929947e078d8732bee958df4c4 languageName: node linkType: hard @@ -3768,8 +3768,8 @@ __metadata: version: 1.0.3 resolution: "@radix-ui/react-portal@npm:1.0.3" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-primitive": 1.0.3 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-primitive": "npm:1.0.3" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3788,8 +3788,8 @@ __metadata: version: 1.0.3 resolution: "@radix-ui/react-primitive@npm:1.0.3" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-slot": 1.0.2 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-slot": "npm:1.0.2" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3800,7 +3800,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 9402bc22923c8e5c479051974a721c301535c36521c0237b83e5fa213d013174e77f3ad7905e6d60ef07e14f88ec7f4ea69891dc7a2b39047f8d3640e8f8d713 + checksum: bedb934ac07c710dc5550a7bfc7065d47e099d958cde1d37e4b1947ae5451f1b7e6f8ff5965e242578bf2c619065e6038c3a3aa779e5eafa7da3e3dbc685799f languageName: node linkType: hard @@ -3808,16 +3808,16 @@ __metadata: version: 1.0.4 resolution: "@radix-ui/react-roving-focus@npm:1.0.4" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/primitive": 1.0.1 - "@radix-ui/react-collection": 1.0.3 - "@radix-ui/react-compose-refs": 1.0.1 - "@radix-ui/react-context": 1.0.1 - "@radix-ui/react-direction": 1.0.1 - "@radix-ui/react-id": 1.0.1 - "@radix-ui/react-primitive": 1.0.3 - "@radix-ui/react-use-callback-ref": 1.0.1 - "@radix-ui/react-use-controllable-state": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/primitive": "npm:1.0.1" + "@radix-ui/react-collection": "npm:1.0.3" + "@radix-ui/react-compose-refs": "npm:1.0.1" + "@radix-ui/react-context": "npm:1.0.1" + "@radix-ui/react-direction": "npm:1.0.1" + "@radix-ui/react-id": "npm:1.0.1" + "@radix-ui/react-primitive": "npm:1.0.3" + "@radix-ui/react-use-callback-ref": "npm:1.0.1" + "@radix-ui/react-use-controllable-state": "npm:1.0.1" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3828,7 +3828,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 69b1c82c2d9db3ba71549a848f2704200dab1b2cd22d050c1e081a78b9a567dbfdc7fd0403ee010c19b79652de69924d8ca2076cd031d6552901e4213493ffc7 + checksum: a23ffb1e3e29a8209b94ce3857bf559dcf2175c4f316169dc47d018e8e94cd018dc914331a1d1762f32448e2594b7c8945efaa7059056f9940ce92cc35cc7026 languageName: node linkType: hard @@ -3836,28 +3836,28 @@ __metadata: version: 1.2.2 resolution: "@radix-ui/react-select@npm:1.2.2" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/number": 1.0.1 - "@radix-ui/primitive": 1.0.1 - "@radix-ui/react-collection": 1.0.3 - "@radix-ui/react-compose-refs": 1.0.1 - "@radix-ui/react-context": 1.0.1 - "@radix-ui/react-direction": 1.0.1 - "@radix-ui/react-dismissable-layer": 1.0.4 - "@radix-ui/react-focus-guards": 1.0.1 - "@radix-ui/react-focus-scope": 1.0.3 - "@radix-ui/react-id": 1.0.1 - "@radix-ui/react-popper": 1.1.2 - "@radix-ui/react-portal": 1.0.3 - "@radix-ui/react-primitive": 1.0.3 - "@radix-ui/react-slot": 1.0.2 - "@radix-ui/react-use-callback-ref": 1.0.1 - "@radix-ui/react-use-controllable-state": 1.0.1 - "@radix-ui/react-use-layout-effect": 1.0.1 - "@radix-ui/react-use-previous": 1.0.1 - "@radix-ui/react-visually-hidden": 1.0.3 - aria-hidden: ^1.1.1 - react-remove-scroll: 2.5.5 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/number": "npm:1.0.1" + "@radix-ui/primitive": "npm:1.0.1" + "@radix-ui/react-collection": "npm:1.0.3" + "@radix-ui/react-compose-refs": "npm:1.0.1" + "@radix-ui/react-context": "npm:1.0.1" + "@radix-ui/react-direction": "npm:1.0.1" + "@radix-ui/react-dismissable-layer": "npm:1.0.4" + "@radix-ui/react-focus-guards": "npm:1.0.1" + "@radix-ui/react-focus-scope": "npm:1.0.3" + "@radix-ui/react-id": "npm:1.0.1" + "@radix-ui/react-popper": "npm:1.1.2" + "@radix-ui/react-portal": "npm:1.0.3" + "@radix-ui/react-primitive": "npm:1.0.3" + "@radix-ui/react-slot": "npm:1.0.2" + "@radix-ui/react-use-callback-ref": "npm:1.0.1" + "@radix-ui/react-use-controllable-state": "npm:1.0.1" + "@radix-ui/react-use-layout-effect": "npm:1.0.1" + "@radix-ui/react-use-previous": "npm:1.0.1" + "@radix-ui/react-visually-hidden": "npm:1.0.3" + aria-hidden: "npm:^1.1.1" + react-remove-scroll: "npm:2.5.5" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3868,7 +3868,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: af7b63cc9e2c6006ec08163392d244941e9e03534e7add1b7c5a86059d0eb8a0398d4f3e80d43ff22126874a02b985e44f1722d1de9218922f7aa653d09412e3 + checksum: 4d7b6d9d988f78764783a4b2fd6523457ff735436829e122dae824bdea4f2835ad0150dfc060517d6c29d953ef61ee12d7ce10cf160593e56967e528bf6f8ee5 languageName: node linkType: hard @@ -3876,8 +3876,8 @@ __metadata: version: 1.0.3 resolution: "@radix-ui/react-separator@npm:1.0.3" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-primitive": 1.0.3 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-primitive": "npm:1.0.3" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3888,7 +3888,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 42f8c95e404de2ce9387040d78049808a48d423cd4c3bad8cca92c4b0bcbdcb3566b5b52a920d4e939a74b51188697f20a012221f0e630fc7f56de64096c15d2 + checksum: b5ea8f1996c86d3f9df73c72926f3d1a400a2eb46a482a345d486651c503895af2ccf9d7723f97a4e612f7c1317eb622078ddf014b13e2b26070d8cf0ad0da1d languageName: node linkType: hard @@ -3896,15 +3896,15 @@ __metadata: version: 1.0.2 resolution: "@radix-ui/react-slot@npm:1.0.2" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-compose-refs": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-compose-refs": "npm:1.0.1" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: "@types/react": optional: true - checksum: edf5edf435ff594bea7e198bf16d46caf81b6fb559493acad4fa8c308218896136acb16f9b7238c788fd13e94a904f2fd0b6d834e530e4cae94522cdb8f77ce9 + checksum: 734866561e991438fbcf22af06e56b272ed6ee8f7b536489ee3bf2f736f8b53bf6bc14ebde94834aa0aceda854d018a0ce20bb171defffbaed1f566006cbb887 languageName: node linkType: hard @@ -3912,14 +3912,14 @@ __metadata: version: 1.0.4 resolution: "@radix-ui/react-toggle-group@npm:1.0.4" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/primitive": 1.0.1 - "@radix-ui/react-context": 1.0.1 - "@radix-ui/react-direction": 1.0.1 - "@radix-ui/react-primitive": 1.0.3 - "@radix-ui/react-roving-focus": 1.0.4 - "@radix-ui/react-toggle": 1.0.3 - "@radix-ui/react-use-controllable-state": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/primitive": "npm:1.0.1" + "@radix-ui/react-context": "npm:1.0.1" + "@radix-ui/react-direction": "npm:1.0.1" + "@radix-ui/react-primitive": "npm:1.0.3" + "@radix-ui/react-roving-focus": "npm:1.0.4" + "@radix-ui/react-toggle": "npm:1.0.3" + "@radix-ui/react-use-controllable-state": "npm:1.0.1" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3930,7 +3930,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: b6c11fbbc3ca857ff68c0fa31f293c0d0111bcc8aa0cde2566214c090907530bfcb3b862f81585c2b02d8989b5c7971acff4d5c07c429870d80bd5602e30d376 + checksum: 96ea35f0e959399f239ff3b75dcad72d5880c66966114c80293ab1450801c87353c0cb2a7a4a5e9825f43c9bd3d881f312a9c14bdacfa70f4050d406bec98c2b languageName: node linkType: hard @@ -3938,10 +3938,10 @@ __metadata: version: 1.0.3 resolution: "@radix-ui/react-toggle@npm:1.0.3" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/primitive": 1.0.1 - "@radix-ui/react-primitive": 1.0.3 - "@radix-ui/react-use-controllable-state": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/primitive": "npm:1.0.1" + "@radix-ui/react-primitive": "npm:1.0.3" + "@radix-ui/react-use-controllable-state": "npm:1.0.1" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3960,14 +3960,14 @@ __metadata: version: 1.0.4 resolution: "@radix-ui/react-toolbar@npm:1.0.4" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/primitive": 1.0.1 - "@radix-ui/react-context": 1.0.1 - "@radix-ui/react-direction": 1.0.1 - "@radix-ui/react-primitive": 1.0.3 - "@radix-ui/react-roving-focus": 1.0.4 - "@radix-ui/react-separator": 1.0.3 - "@radix-ui/react-toggle-group": 1.0.4 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/primitive": "npm:1.0.1" + "@radix-ui/react-context": "npm:1.0.1" + "@radix-ui/react-direction": "npm:1.0.1" + "@radix-ui/react-primitive": "npm:1.0.3" + "@radix-ui/react-roving-focus": "npm:1.0.4" + "@radix-ui/react-separator": "npm:1.0.3" + "@radix-ui/react-toggle-group": "npm:1.0.4" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -3978,7 +3978,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 7ebee1f8add6510108979433c5b38627e2de9d48ef2172ca15274b9edbbc106ff43bcd47ff733b03ed2215b92e7af364ff82c79e5a1728374847e2b1e315552c + checksum: 57f75b6617d4e2bb8f7782d6065e70fd0db44038588b3e8e5f8cd1101dc2c94744bd52b9c011c7b722cb5f9ca96d21fc78ee7caac07722894453019fd5ade3b0 languageName: node linkType: hard @@ -3986,7 +3986,7 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-use-callback-ref@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 + "@babel/runtime": "npm:^7.13.10" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -4001,8 +4001,8 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-use-controllable-state@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-use-callback-ref": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-use-callback-ref": "npm:1.0.1" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -4017,8 +4017,8 @@ __metadata: version: 1.0.3 resolution: "@radix-ui/react-use-escape-keydown@npm:1.0.3" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-use-callback-ref": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-use-callback-ref": "npm:1.0.1" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -4033,7 +4033,7 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-use-layout-effect@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 + "@babel/runtime": "npm:^7.13.10" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -4048,7 +4048,7 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-use-previous@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 + "@babel/runtime": "npm:^7.13.10" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -4063,8 +4063,8 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-use-rect@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/rect": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/rect": "npm:1.0.1" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -4079,8 +4079,8 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/react-use-size@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-use-layout-effect": 1.0.1 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-use-layout-effect": "npm:1.0.1" peerDependencies: "@types/react": "*" react: ^16.8 || ^17.0 || ^18.0 @@ -4095,8 +4095,8 @@ __metadata: version: 1.0.3 resolution: "@radix-ui/react-visually-hidden@npm:1.0.3" dependencies: - "@babel/runtime": ^7.13.10 - "@radix-ui/react-primitive": 1.0.3 + "@babel/runtime": "npm:^7.13.10" + "@radix-ui/react-primitive": "npm:1.0.3" peerDependencies: "@types/react": "*" "@types/react-dom": "*" @@ -4115,8 +4115,8 @@ __metadata: version: 1.0.1 resolution: "@radix-ui/rect@npm:1.0.1" dependencies: - "@babel/runtime": ^7.13.10 - checksum: aeec13b234a946052512d05239067d2d63422f9ec70bf2fe7acfd6b9196693fc33fbaf43c2667c167f777d90a095c6604eb487e0bce79e230b6df0f6cacd6a55 + "@babel/runtime": "npm:^7.13.10" + checksum: e25492cb8a683246161d781f0f3205f79507280a60f50eb763f06e8b6fa211b940b784aa581131ed76695bd5df5d1033a6246b43a6996cf8959a326fe4d3eb00 languageName: node linkType: hard @@ -4136,14 +4136,14 @@ __metadata: optional: true react-redux: optional: true - checksum: 54672c5593d05208af577e948a338f23128d3aa01ef056ab0d40bcfa14400cf6566be99e11715388f12c1d7655cdf7c5c6b63cb92eb0fecf996c454a46a3914c + checksum: ac24173de599b830232da5e040ea2b898c34cc803cb219e537ce15c5b914c85dfdb97f8f7015ea4e8cc9110430e2a081766b0dcbc1e71f99639b8bec136d3499 languageName: node linkType: hard "@remix-run/router@npm:1.6.2": version: 1.6.2 resolution: "@remix-run/router@npm:1.6.2" - checksum: 5969d313bff6ba5c75917910090cebafda84b9d3b4b453fae6b3d60fea9f938078578ffca769c532ab7ce252cd4a207b78d1024d7c727ab80dd572e62fd3b3f2 + checksum: c261c3b52f08d7fcacce9c66d68dba3b6f0c8263ea15f69f9f1c89734685cdfe4f383c879324acade68cb331d48e3deca9ec00734abe08d9694e529096907f40 languageName: node linkType: hard @@ -4153,7 +4153,7 @@ __metadata: dependencies: estree-walker: "npm:^2.0.1" picomatch: "npm:^2.2.2" - checksum: 6bc41f22b1a0f1efec3043899e4d3b6b1497b3dea4d94292d8f83b4cf07a1073ecbaedd562a22d11913ff7659f459677b01b09e9598a98936e746780ecc93a12 + checksum: 503a6f0a449e11a2873ac66cfdfb9a3a0b77ffa84c5cad631f5e4bc1063c850710e8d5cd5dab52477c0d66cda2ec719865726dbe753318cd640bab3fff7ca476 languageName: node linkType: hard @@ -4169,14 +4169,14 @@ __metadata: peerDependenciesMeta: rollup: optional: true - checksum: edea15e543bebc7dcac3b0ac8bc7b8e8e6dbd46e2864dbe5dd28072de1fbd5b0e10d545a610c0edaa178e8a7ac432e2a2a52e547ece1308471412caba47db8ce + checksum: 7aebf04d5d25d7d2e9514cc8f81a49b11f093b29eae2862da29022532b66e3de4681f537cc785fdcf438bcdefa3af4453470e7951ca91d6ebea2f41d6aea42d3 languageName: node linkType: hard "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" - checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1 + checksum: 297f95ff77c82c54de8c9907f186076e715ff2621c5222ba50b8d40a170661c0c5242c763cba2a4791f0f91cb1d8ffa53ea1d7294570cf8cd4694c0e383e484d languageName: node linkType: hard @@ -4185,7 +4185,7 @@ __metadata: resolution: "@sinonjs/commons@npm:3.0.0" dependencies: type-detect: "npm:4.0.8" - checksum: b4b5b73d4df4560fb8c0c7b38c7ad4aeabedd362f3373859d804c988c725889cde33550e4bcc7cd316a30f5152a2d1d43db71b6d0c38f5feef71fd8d016763f8 + checksum: 086720ae0bc370829322df32612205141cdd44e592a8a9ca97197571f8f970352ea39d3bda75b347c43789013ddab36b34b59e40380a49bdae1c2df3aa85fe4f languageName: node linkType: hard @@ -4194,7 +4194,7 @@ __metadata: resolution: "@sinonjs/fake-timers@npm:10.3.0" dependencies: "@sinonjs/commons": "npm:^3.0.0" - checksum: 614d30cb4d5201550c940945d44c9e0b6d64a888ff2cd5b357f95ad6721070d6b8839cd10e15b76bf5e14af0bcc1d8f9ec00d49a46318f1f669a4bec1d7f3148 + checksum: 78155c7bd866a85df85e22028e046b8d46cf3e840f72260954f5e3ed5bd97d66c595524305a6841ffb3f681a08f6e5cef572a2cce5442a8a232dc29fb409b83e languageName: node linkType: hard @@ -4202,13 +4202,13 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-actions@npm:7.6.7" dependencies: - "@storybook/core-events": 7.6.7 - "@storybook/global": ^5.0.0 - "@types/uuid": ^9.0.1 - dequal: ^2.0.2 - polished: ^4.2.2 - uuid: ^9.0.0 - checksum: 0a68abbb89e2aa569dd0d1bb7793bd571e6095e108e19028a7f23afdbf4625d008c96e0b0c95c4a77fce97380f50765ef922152fe02134e5a9a96a66ca4237a7 + "@storybook/core-events": "npm:7.6.7" + "@storybook/global": "npm:^5.0.0" + "@types/uuid": "npm:^9.0.1" + dequal: "npm:^2.0.2" + polished: "npm:^4.2.2" + uuid: "npm:^9.0.0" + checksum: 894096f4cb2f8d45c8bf5fe3d75b49ce8e9a6dbb6e7a6d5c6c388400e50822d7c72c89e25920f3006f017cac490e2ca6cd82ab65e2f244a40f0b82078e238522 languageName: node linkType: hard @@ -4216,10 +4216,10 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-backgrounds@npm:7.6.7" dependencies: - "@storybook/global": ^5.0.0 - memoizerific: ^1.11.3 - ts-dedent: ^2.0.0 - checksum: 0598707fef857c1bb9402875dcd08362b090b524ca02cb9a2d475150ae489b17c4cfa6b0f76759a1c41c8a00502b7e362ca3352ed1263a4c5295f5380ad0ba8a + "@storybook/global": "npm:^5.0.0" + memoizerific: "npm:^1.11.3" + ts-dedent: "npm:^2.0.0" + checksum: 5cb9da3c9621004622fd7b142256d41535aaf0c32d4059462e92d6c52143350c768e2ebfd962b0f9919d24fa102a35d1e9d86489e006b761725127674eba7352 languageName: node linkType: hard @@ -4227,10 +4227,10 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-controls@npm:7.6.7" dependencies: - "@storybook/blocks": 7.6.7 - lodash: ^4.17.21 - ts-dedent: ^2.0.0 - checksum: b98166568f3479e628618f77d64baaf361e74f4388a2c15dd1fd2c353c497873890365d15af411af1f66b83b63627050939ad1a058125faa9f6f67714626308e + "@storybook/blocks": "npm:7.6.7" + lodash: "npm:^4.17.21" + ts-dedent: "npm:^2.0.0" + checksum: ad69e1012c49f69cf490e4e44ee507a1dbe3751a51a7e30b6221110422e4f72b460c3d4e0be6c69bf4523b7e2c0bd0a1723b6743506f36ff445583cdd8dd41f6 languageName: node linkType: hard @@ -4238,29 +4238,29 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-docs@npm:7.6.7" dependencies: - "@jest/transform": ^29.3.1 - "@mdx-js/react": ^2.1.5 - "@storybook/blocks": 7.6.7 - "@storybook/client-logger": 7.6.7 - "@storybook/components": 7.6.7 - "@storybook/csf-plugin": 7.6.7 - "@storybook/csf-tools": 7.6.7 - "@storybook/global": ^5.0.0 - "@storybook/mdx2-csf": ^1.0.0 - "@storybook/node-logger": 7.6.7 - "@storybook/postinstall": 7.6.7 - "@storybook/preview-api": 7.6.7 - "@storybook/react-dom-shim": 7.6.7 - "@storybook/theming": 7.6.7 - "@storybook/types": 7.6.7 - fs-extra: ^11.1.0 - remark-external-links: ^8.0.0 - remark-slug: ^6.0.0 - ts-dedent: ^2.0.0 + "@jest/transform": "npm:^29.3.1" + "@mdx-js/react": "npm:^2.1.5" + "@storybook/blocks": "npm:7.6.7" + "@storybook/client-logger": "npm:7.6.7" + "@storybook/components": "npm:7.6.7" + "@storybook/csf-plugin": "npm:7.6.7" + "@storybook/csf-tools": "npm:7.6.7" + "@storybook/global": "npm:^5.0.0" + "@storybook/mdx2-csf": "npm:^1.0.0" + "@storybook/node-logger": "npm:7.6.7" + "@storybook/postinstall": "npm:7.6.7" + "@storybook/preview-api": "npm:7.6.7" + "@storybook/react-dom-shim": "npm:7.6.7" + "@storybook/theming": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + fs-extra: "npm:^11.1.0" + remark-external-links: "npm:^8.0.0" + remark-slug: "npm:^6.0.0" + ts-dedent: "npm:^2.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 967669f44014c194dab94ad572cbf6d89dce86376ccf43867ae1801609598cb70faca49b7df8426227bfe6348887688285fae5f6cebb12e58048e74dec6ba0ce + checksum: 8b6e3f9218a1b290de5f5d5aaca9901afbc76aee980215ede8e2025113d51dc44687ceaecd9d53e993eb6001ae40b84ae31407be2a7d3d6c5250f990fa59f6f6 languageName: node linkType: hard @@ -4268,20 +4268,20 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-essentials@npm:7.6.7" dependencies: - "@storybook/addon-actions": 7.6.7 - "@storybook/addon-backgrounds": 7.6.7 - "@storybook/addon-controls": 7.6.7 - "@storybook/addon-docs": 7.6.7 - "@storybook/addon-highlight": 7.6.7 - "@storybook/addon-measure": 7.6.7 - "@storybook/addon-outline": 7.6.7 - "@storybook/addon-toolbars": 7.6.7 - "@storybook/addon-viewport": 7.6.7 - "@storybook/core-common": 7.6.7 - "@storybook/manager-api": 7.6.7 - "@storybook/node-logger": 7.6.7 - "@storybook/preview-api": 7.6.7 - ts-dedent: ^2.0.0 + "@storybook/addon-actions": "npm:7.6.7" + "@storybook/addon-backgrounds": "npm:7.6.7" + "@storybook/addon-controls": "npm:7.6.7" + "@storybook/addon-docs": "npm:7.6.7" + "@storybook/addon-highlight": "npm:7.6.7" + "@storybook/addon-measure": "npm:7.6.7" + "@storybook/addon-outline": "npm:7.6.7" + "@storybook/addon-toolbars": "npm:7.6.7" + "@storybook/addon-viewport": "npm:7.6.7" + "@storybook/core-common": "npm:7.6.7" + "@storybook/manager-api": "npm:7.6.7" + "@storybook/node-logger": "npm:7.6.7" + "@storybook/preview-api": "npm:7.6.7" + ts-dedent: "npm:^2.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4293,8 +4293,8 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-highlight@npm:7.6.7" dependencies: - "@storybook/global": ^5.0.0 - checksum: a148e54c2a489ae452f77b2870359fe7800655735dd18046d3d081fd78b5caebacec016fbda649e24c0fcc779639a38641c18ba2efedf37f05e401232689168c + "@storybook/global": "npm:^5.0.0" + checksum: 2f4bf8e822a04ada97242eb469f525fb1742871b5977ff106883e5afbd3fc4e6ae12fec15e64f0f884ed5348ca2ac76ab86368f922b5ab25570ef1f7068e1e02 languageName: node linkType: hard @@ -4302,12 +4302,12 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-interactions@npm:7.6.7" dependencies: - "@storybook/global": ^5.0.0 - "@storybook/types": 7.6.7 - jest-mock: ^27.0.6 - polished: ^4.2.2 - ts-dedent: ^2.2.0 - checksum: f0e148c02602a5608c85295b39435ae9d672f657a23fdabb22d6882bb444bfd04aaf19aa8c015c6e8a59de48a498c1bb8c51b83c7b3172842ded18d5ff0e8cf4 + "@storybook/global": "npm:^5.0.0" + "@storybook/types": "npm:7.6.7" + jest-mock: "npm:^27.0.6" + polished: "npm:^4.2.2" + ts-dedent: "npm:^2.2.0" + checksum: c9243bf838d9d9d2ef87e45ac96c7f909e09d9c5831fcfb07df3f5218ddc998c0d932f08490e3d8e46716291ad5db9bf0f63397d8c0adb79d4f88b682ab4e01b languageName: node linkType: hard @@ -4315,15 +4315,15 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-links@npm:7.6.7" dependencies: - "@storybook/csf": ^0.1.2 - "@storybook/global": ^5.0.0 - ts-dedent: ^2.0.0 + "@storybook/csf": "npm:^0.1.2" + "@storybook/global": "npm:^5.0.0" + ts-dedent: "npm:^2.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: react: optional: true - checksum: a0ea89f2ffd09c2a5de66381d1a5b955b78a92d93f65885285af39c69e17ab35f0b6099742b7cb36816e14b307f59f88c85023499ab56d028d3e68fea6033c6c + checksum: 0cb9a33cd8e8ba2605ab2598df7cb14e56b482731053f451ce5201dcf93fca3be522df1a784d978553892b23621018231d19fce0ba89197612c498948201e716 languageName: node linkType: hard @@ -4331,9 +4331,9 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-measure@npm:7.6.7" dependencies: - "@storybook/global": ^5.0.0 - tiny-invariant: ^1.3.1 - checksum: 1c89eff8d5663cd1caf6f6ebe6a9bf0335dc4787948a7ec76c6bc440dd40a8fbc217ddcd0596f3823131a5264573c091683b6bb7859bdf7dac647d503b0870f5 + "@storybook/global": "npm:^5.0.0" + tiny-invariant: "npm:^1.3.1" + checksum: 77baed9e39af58e0d004d5ae7c2d7e39a3914b8cba9cc4ca3207a9a530ae5a3f9f6753979ead3908588cfa3a69b3143889132b77bbcd3869b5814f1cc781f07b languageName: node linkType: hard @@ -4341,16 +4341,16 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-outline@npm:7.6.7" dependencies: - "@storybook/global": ^5.0.0 - ts-dedent: ^2.0.0 - checksum: e4f39d4310d17defef60110e1927a4be1278ba1fbfdc5ca85563b41be29df1a685ec38aa591db830c3baf9234fd1a935ba49202491429e2f1142a7cbe88af88e + "@storybook/global": "npm:^5.0.0" + ts-dedent: "npm:^2.0.0" + checksum: cc06660969fd735adea20cfe2ffa2d5752e6bda3709a0ea645d5fa46da445e9763cabb6c0358b38848892a9d3bd4a17404a7074cdc24a34e3b038c52c5506e8a languageName: node linkType: hard "@storybook/addon-toolbars@npm:7.6.7": version: 7.6.7 resolution: "@storybook/addon-toolbars@npm:7.6.7" - checksum: beedf517f457e37e1e29144cefcbc0519bfd6588f0ac16831191453943842fec8ae96bbc4febeb70facde21bb7491db124235acd2b5e54addee5d766a71a33bd + checksum: 15fa295c46e8cbd43d4fb8190dce93c935cbcc3c104a1fd6fc4f7e93c409f6446425780baafab82adce8f7c1d11772c0f32c4e93391860b3773dadbf42bebb64 languageName: node linkType: hard @@ -4358,8 +4358,8 @@ __metadata: version: 7.6.7 resolution: "@storybook/addon-viewport@npm:7.6.7" dependencies: - memoizerific: ^1.11.3 - checksum: 724e83509ead4edb8720bb4fa803bb0ba0b76309be741d4a2322c63f5bc20964066e42c1dab0820251f60a8c67be42ea3aa285ebe8ffee32b9b938d097a3c9f4 + memoizerific: "npm:^1.11.3" + checksum: 2286ee1d3c2fe73bff1a5e8bda263b9c3dedd7e6478f3c194026be5778d734859b4f55e92a11f91a675493c6279fe7dffae90b5013d53deff064711d154cf036 languageName: node linkType: hard @@ -4367,33 +4367,33 @@ __metadata: version: 7.6.7 resolution: "@storybook/blocks@npm:7.6.7" dependencies: - "@storybook/channels": 7.6.7 - "@storybook/client-logger": 7.6.7 - "@storybook/components": 7.6.7 - "@storybook/core-events": 7.6.7 - "@storybook/csf": ^0.1.2 - "@storybook/docs-tools": 7.6.7 - "@storybook/global": ^5.0.0 - "@storybook/manager-api": 7.6.7 - "@storybook/preview-api": 7.6.7 - "@storybook/theming": 7.6.7 - "@storybook/types": 7.6.7 - "@types/lodash": ^4.14.167 - color-convert: ^2.0.1 - dequal: ^2.0.2 - lodash: ^4.17.21 - markdown-to-jsx: ^7.1.8 - memoizerific: ^1.11.3 - polished: ^4.2.2 - react-colorful: ^5.1.2 - telejson: ^7.2.0 - tocbot: ^4.20.1 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 + "@storybook/channels": "npm:7.6.7" + "@storybook/client-logger": "npm:7.6.7" + "@storybook/components": "npm:7.6.7" + "@storybook/core-events": "npm:7.6.7" + "@storybook/csf": "npm:^0.1.2" + "@storybook/docs-tools": "npm:7.6.7" + "@storybook/global": "npm:^5.0.0" + "@storybook/manager-api": "npm:7.6.7" + "@storybook/preview-api": "npm:7.6.7" + "@storybook/theming": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + "@types/lodash": "npm:^4.14.167" + color-convert: "npm:^2.0.1" + dequal: "npm:^2.0.2" + lodash: "npm:^4.17.21" + markdown-to-jsx: "npm:^7.1.8" + memoizerific: "npm:^1.11.3" + polished: "npm:^4.2.2" + react-colorful: "npm:^5.1.2" + telejson: "npm:^7.2.0" + tocbot: "npm:^4.20.1" + ts-dedent: "npm:^2.0.0" + util-deprecate: "npm:^1.0.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 6f5815cb8a7aae4ca9b104f1c5e5ec6b4949c90a373d904b44c5aebfec0b885606ef1ab2e44ecbbc544c3d6eed869f0feaa284d7336aeebb1f440d6797dc649f + checksum: 1c73d3da0f738c4efc2dc0aa1d7c8691eaafac8ae7d5da2be9d15551664b30894c0c96f3a5cca2fa3c3200d4e0ef725cd7ae9db7347045cbbaf62cd6ebc790c3 languageName: node linkType: hard @@ -4401,23 +4401,23 @@ __metadata: version: 7.6.7 resolution: "@storybook/builder-manager@npm:7.6.7" dependencies: - "@fal-works/esbuild-plugin-global-externals": ^2.1.2 - "@storybook/core-common": 7.6.7 - "@storybook/manager": 7.6.7 - "@storybook/node-logger": 7.6.7 - "@types/ejs": ^3.1.1 - "@types/find-cache-dir": ^3.2.1 - "@yarnpkg/esbuild-plugin-pnp": ^3.0.0-rc.10 - browser-assert: ^1.2.1 - ejs: ^3.1.8 - esbuild: ^0.18.0 - esbuild-plugin-alias: ^0.2.1 - express: ^4.17.3 - find-cache-dir: ^3.0.0 - fs-extra: ^11.1.0 - process: ^0.11.10 - util: ^0.12.4 - checksum: dd4d64038cb8bcc06092cf239d95d7f8c8a7420243ce26db0b362f44182a138d9e1d5fee15bd12865df6d3b89d2fad1a167d5ebed2dba4357bd5c1d16be66874 + "@fal-works/esbuild-plugin-global-externals": "npm:^2.1.2" + "@storybook/core-common": "npm:7.6.7" + "@storybook/manager": "npm:7.6.7" + "@storybook/node-logger": "npm:7.6.7" + "@types/ejs": "npm:^3.1.1" + "@types/find-cache-dir": "npm:^3.2.1" + "@yarnpkg/esbuild-plugin-pnp": "npm:^3.0.0-rc.10" + browser-assert: "npm:^1.2.1" + ejs: "npm:^3.1.8" + esbuild: "npm:^0.18.0" + esbuild-plugin-alias: "npm:^0.2.1" + express: "npm:^4.17.3" + find-cache-dir: "npm:^3.0.0" + fs-extra: "npm:^11.1.0" + process: "npm:^0.11.10" + util: "npm:^0.12.4" + checksum: a6930ad250c78a78a6c54f14801ef54561297678d7070eb5b4cb21d4dd42d254608636836ddb5af91fc5a65c3a441bba1d40b51baa763fa281ae7e529dfcc7f7 languageName: node linkType: hard @@ -4425,22 +4425,22 @@ __metadata: version: 7.6.7 resolution: "@storybook/builder-vite@npm:7.6.7" dependencies: - "@storybook/channels": 7.6.7 - "@storybook/client-logger": 7.6.7 - "@storybook/core-common": 7.6.7 - "@storybook/csf-plugin": 7.6.7 - "@storybook/node-logger": 7.6.7 - "@storybook/preview": 7.6.7 - "@storybook/preview-api": 7.6.7 - "@storybook/types": 7.6.7 - "@types/find-cache-dir": ^3.2.1 - browser-assert: ^1.2.1 - es-module-lexer: ^0.9.3 - express: ^4.17.3 - find-cache-dir: ^3.0.0 - fs-extra: ^11.1.0 - magic-string: ^0.30.0 - rollup: ^2.25.0 || ^3.3.0 + "@storybook/channels": "npm:7.6.7" + "@storybook/client-logger": "npm:7.6.7" + "@storybook/core-common": "npm:7.6.7" + "@storybook/csf-plugin": "npm:7.6.7" + "@storybook/node-logger": "npm:7.6.7" + "@storybook/preview": "npm:7.6.7" + "@storybook/preview-api": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + "@types/find-cache-dir": "npm:^3.2.1" + browser-assert: "npm:^1.2.1" + es-module-lexer: "npm:^0.9.3" + express: "npm:^4.17.3" + find-cache-dir: "npm:^3.0.0" + fs-extra: "npm:^11.1.0" + magic-string: "npm:^0.30.0" + rollup: "npm:^2.25.0 || ^3.3.0" peerDependencies: "@preact/preset-vite": "*" typescript: ">= 4.3.x" @@ -4453,7 +4453,7 @@ __metadata: optional: true vite-plugin-glimmerx: optional: true - checksum: 48fa0f0d4a6ec0f97c7e8ea4f6d45861722efda6ca6d8d0585afada32ea0cd44bf25fbb061538685378df6332b16adb59793704868c2110f1a38cb30b7f1a9ea + checksum: 44eb27b26c51dc11a49fed1e76c87466ae82d259fa3d7362305d9ccfc13c6051aafe424e23471438a0f7b4bbbf10e64a0e6f55a04b34f1a813c120344a9d8135 languageName: node linkType: hard @@ -4461,13 +4461,13 @@ __metadata: version: 7.6.7 resolution: "@storybook/channels@npm:7.6.7" dependencies: - "@storybook/client-logger": 7.6.7 - "@storybook/core-events": 7.6.7 - "@storybook/global": ^5.0.0 - qs: ^6.10.0 - telejson: ^7.2.0 - tiny-invariant: ^1.3.1 - checksum: cc90ae81bfe7225f3d8de5c0d871870ccc126ae065b83ee9450993877b70d708d3ee198a556d8c3da0fb58ebe68b576a20907e2916308a8ac7a6d7c68eda59ac + "@storybook/client-logger": "npm:7.6.7" + "@storybook/core-events": "npm:7.6.7" + "@storybook/global": "npm:^5.0.0" + qs: "npm:^6.10.0" + telejson: "npm:^7.2.0" + tiny-invariant: "npm:^1.3.1" + checksum: c5db4e7c6d7b8663809a49e21c79a4fb0f189b321007783b2517141cc130348d7c2866d868627929e5a06df814163738e3f0fe46eddc3c9ff66f61ab69d777eb languageName: node linkType: hard @@ -4475,51 +4475,51 @@ __metadata: version: 7.6.7 resolution: "@storybook/cli@npm:7.6.7" dependencies: - "@babel/core": ^7.23.2 - "@babel/preset-env": ^7.23.2 - "@babel/types": ^7.23.0 - "@ndelangen/get-tarball": ^3.0.7 - "@storybook/codemod": 7.6.7 - "@storybook/core-common": 7.6.7 - "@storybook/core-events": 7.6.7 - "@storybook/core-server": 7.6.7 - "@storybook/csf-tools": 7.6.7 - "@storybook/node-logger": 7.6.7 - "@storybook/telemetry": 7.6.7 - "@storybook/types": 7.6.7 - "@types/semver": ^7.3.4 - "@yarnpkg/fslib": 2.10.3 - "@yarnpkg/libzip": 2.3.0 - chalk: ^4.1.0 - commander: ^6.2.1 - cross-spawn: ^7.0.3 - detect-indent: ^6.1.0 - envinfo: ^7.7.3 - execa: ^5.0.0 - express: ^4.17.3 - find-up: ^5.0.0 - fs-extra: ^11.1.0 - get-npm-tarball-url: ^2.0.3 - get-port: ^5.1.1 - giget: ^1.0.0 - globby: ^11.0.2 - jscodeshift: ^0.15.1 - leven: ^3.1.0 - ora: ^5.4.1 - prettier: ^2.8.0 - prompts: ^2.4.0 - puppeteer-core: ^2.1.1 - read-pkg-up: ^7.0.1 - semver: ^7.3.7 - simple-update-notifier: ^2.0.0 - strip-json-comments: ^3.0.1 - tempy: ^1.0.1 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 + "@babel/core": "npm:^7.23.2" + "@babel/preset-env": "npm:^7.23.2" + "@babel/types": "npm:^7.23.0" + "@ndelangen/get-tarball": "npm:^3.0.7" + "@storybook/codemod": "npm:7.6.7" + "@storybook/core-common": "npm:7.6.7" + "@storybook/core-events": "npm:7.6.7" + "@storybook/core-server": "npm:7.6.7" + "@storybook/csf-tools": "npm:7.6.7" + "@storybook/node-logger": "npm:7.6.7" + "@storybook/telemetry": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + "@types/semver": "npm:^7.3.4" + "@yarnpkg/fslib": "npm:2.10.3" + "@yarnpkg/libzip": "npm:2.3.0" + chalk: "npm:^4.1.0" + commander: "npm:^6.2.1" + cross-spawn: "npm:^7.0.3" + detect-indent: "npm:^6.1.0" + envinfo: "npm:^7.7.3" + execa: "npm:^5.0.0" + express: "npm:^4.17.3" + find-up: "npm:^5.0.0" + fs-extra: "npm:^11.1.0" + get-npm-tarball-url: "npm:^2.0.3" + get-port: "npm:^5.1.1" + giget: "npm:^1.0.0" + globby: "npm:^11.0.2" + jscodeshift: "npm:^0.15.1" + leven: "npm:^3.1.0" + ora: "npm:^5.4.1" + prettier: "npm:^2.8.0" + prompts: "npm:^2.4.0" + puppeteer-core: "npm:^2.1.1" + read-pkg-up: "npm:^7.0.1" + semver: "npm:^7.3.7" + simple-update-notifier: "npm:^2.0.0" + strip-json-comments: "npm:^3.0.1" + tempy: "npm:^1.0.1" + ts-dedent: "npm:^2.0.0" + util-deprecate: "npm:^1.0.2" bin: getstorybook: ./bin/index.js sb: ./bin/index.js - checksum: bb0d1babdf7c2c607bbaf0890ac102dd230c3576decf39d32c6ec551cc6fc841e552964d13efb40b526cb6fd05e02fda5307e888992f928805fe828107c07b88 + checksum: a237cea898f936324c13341ba0fb48ec7aebd66336bce361f3cc7049f2c5b6e4415fc9e38a786d752271bf0cd26fc44d389a5e0335b1ae1947a5b0e8314e49cb languageName: node linkType: hard @@ -4527,8 +4527,8 @@ __metadata: version: 7.6.7 resolution: "@storybook/client-logger@npm:7.6.7" dependencies: - "@storybook/global": ^5.0.0 - checksum: 4f4934fa4e022fa4ae0b802653d8ac8bd353d7514b1afb36b387029d274bbf40ad7a6fd1a2858220d415e7f535d643d701b7cdb752d71565269d44fdb482ed45 + "@storybook/global": "npm:^5.0.0" + checksum: b594e8300271826b578a7e4290445f36c1028b4b39fb9232c98366af7e651f4180d55b5c8adc09e5bd9bad49a2dbb7bf35b8f29e2e5e62e3b9d4f26aa0d63b03 languageName: node linkType: hard @@ -4536,21 +4536,21 @@ __metadata: version: 7.6.7 resolution: "@storybook/codemod@npm:7.6.7" dependencies: - "@babel/core": ^7.23.2 - "@babel/preset-env": ^7.23.2 - "@babel/types": ^7.23.0 - "@storybook/csf": ^0.1.2 - "@storybook/csf-tools": 7.6.7 - "@storybook/node-logger": 7.6.7 - "@storybook/types": 7.6.7 - "@types/cross-spawn": ^6.0.2 - cross-spawn: ^7.0.3 - globby: ^11.0.2 - jscodeshift: ^0.15.1 - lodash: ^4.17.21 - prettier: ^2.8.0 - recast: ^0.23.1 - checksum: e850371a8df11a414fc3d06c87ff81d439ed2e8f87d76846b44ead6500fd97c51d000f7b12c3a137d05f64f0e21c10aaa397e44303269b7834b17f8da3c33f59 + "@babel/core": "npm:^7.23.2" + "@babel/preset-env": "npm:^7.23.2" + "@babel/types": "npm:^7.23.0" + "@storybook/csf": "npm:^0.1.2" + "@storybook/csf-tools": "npm:7.6.7" + "@storybook/node-logger": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + "@types/cross-spawn": "npm:^6.0.2" + cross-spawn: "npm:^7.0.3" + globby: "npm:^11.0.2" + jscodeshift: "npm:^0.15.1" + lodash: "npm:^4.17.21" + prettier: "npm:^2.8.0" + recast: "npm:^0.23.1" + checksum: 060cbef7e7203fa1cb056ff5f6e3951175106ac27a1e969821c7ff01da86cdf200d566f59f46c4437fbd2cf8325c4353177beed7633392ce19b09f897b2a930e languageName: node linkType: hard @@ -4558,20 +4558,20 @@ __metadata: version: 7.6.7 resolution: "@storybook/components@npm:7.6.7" dependencies: - "@radix-ui/react-select": ^1.2.2 - "@radix-ui/react-toolbar": ^1.0.4 - "@storybook/client-logger": 7.6.7 - "@storybook/csf": ^0.1.2 - "@storybook/global": ^5.0.0 - "@storybook/theming": 7.6.7 - "@storybook/types": 7.6.7 - memoizerific: ^1.11.3 - use-resize-observer: ^9.1.0 - util-deprecate: ^1.0.2 + "@radix-ui/react-select": "npm:^1.2.2" + "@radix-ui/react-toolbar": "npm:^1.0.4" + "@storybook/client-logger": "npm:7.6.7" + "@storybook/csf": "npm:^0.1.2" + "@storybook/global": "npm:^5.0.0" + "@storybook/theming": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + memoizerific: "npm:^1.11.3" + use-resize-observer: "npm:^9.1.0" + util-deprecate: "npm:^1.0.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: cbc7c12148a463b7efbac2c8568b7b8669d0a7a05c46cdddd735d0505619468a3842ac1893b5ba8cf4fd61c715fd7a1df09065406fc0634a7d61e9c8e6ebd6cd + checksum: f11d2ddd749c64f7e4b85ae3a48da7780e2c1d184fbd155a56337e29872303ec6b0c184e3c64d763a0e89867bdc55efc52ab298430bac89d7d3ab8f7cec239b3 languageName: node linkType: hard @@ -4579,9 +4579,9 @@ __metadata: version: 7.6.7 resolution: "@storybook/core-client@npm:7.6.7" dependencies: - "@storybook/client-logger": 7.6.7 - "@storybook/preview-api": 7.6.7 - checksum: 234af026a2447e91602a55522b616c0ead2dd996a845d4db393b400acf5a7054785b14a714fdb3919f8720083ee9d24a5d5dd8eda92090ce0f54c654d4f27155 + "@storybook/client-logger": "npm:7.6.7" + "@storybook/preview-api": "npm:7.6.7" + checksum: 2933872953c519691744a458718c91093de8429dc362f57e2d79106d83f97a68d1d072190f688c07fe8d70965132532114fa17f99822438ec9c638c83bef590b languageName: node linkType: hard @@ -4589,30 +4589,30 @@ __metadata: version: 7.6.7 resolution: "@storybook/core-common@npm:7.6.7" dependencies: - "@storybook/core-events": 7.6.7 - "@storybook/node-logger": 7.6.7 - "@storybook/types": 7.6.7 - "@types/find-cache-dir": ^3.2.1 - "@types/node": ^18.0.0 - "@types/node-fetch": ^2.6.4 - "@types/pretty-hrtime": ^1.0.0 - chalk: ^4.1.0 - esbuild: ^0.18.0 - esbuild-register: ^3.5.0 - file-system-cache: 2.3.0 - find-cache-dir: ^3.0.0 - find-up: ^5.0.0 - fs-extra: ^11.1.0 - glob: ^10.0.0 - handlebars: ^4.7.7 - lazy-universal-dotenv: ^4.0.0 - node-fetch: ^2.0.0 - picomatch: ^2.3.0 - pkg-dir: ^5.0.0 - pretty-hrtime: ^1.0.3 - resolve-from: ^5.0.0 - ts-dedent: ^2.0.0 - checksum: 5e9a03114aa964ff997e1185d4f1b45bff5db941afde57ff6e8f411e08371bd3c197bd69b4f4d71a4f81970182c90ca3ee0cdce713ad992dae29c550cbff2340 + "@storybook/core-events": "npm:7.6.7" + "@storybook/node-logger": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + "@types/find-cache-dir": "npm:^3.2.1" + "@types/node": "npm:^18.0.0" + "@types/node-fetch": "npm:^2.6.4" + "@types/pretty-hrtime": "npm:^1.0.0" + chalk: "npm:^4.1.0" + esbuild: "npm:^0.18.0" + esbuild-register: "npm:^3.5.0" + file-system-cache: "npm:2.3.0" + find-cache-dir: "npm:^3.0.0" + find-up: "npm:^5.0.0" + fs-extra: "npm:^11.1.0" + glob: "npm:^10.0.0" + handlebars: "npm:^4.7.7" + lazy-universal-dotenv: "npm:^4.0.0" + node-fetch: "npm:^2.0.0" + picomatch: "npm:^2.3.0" + pkg-dir: "npm:^5.0.0" + pretty-hrtime: "npm:^1.0.3" + resolve-from: "npm:^5.0.0" + ts-dedent: "npm:^2.0.0" + checksum: b8a1c74cfb4be213f7495e36789113b5c90af578291128a070aa0a0970f8462defe271aff029b3cab093e528080c87d37a9a1b1b218079fe1dc7536e7c2d43c7 languageName: node linkType: hard @@ -4620,8 +4620,8 @@ __metadata: version: 7.6.7 resolution: "@storybook/core-events@npm:7.6.7" dependencies: - ts-dedent: ^2.0.0 - checksum: b355f2cdfa8a805d035e7f05909cdb670cf1ced653d3cf2281976dbc7591faaeca066ba8c3b68f1b19097301b5908b3d37381ff00364ce509bce38c5f9c2465c + ts-dedent: "npm:^2.0.0" + checksum: 8768dab5ed9e6a3f7973acb9ea7ef4e15a04d5826979d6b3cb57bdffb707709470254dfb1e8d03931ef5101ffe7c88056a099106657fa3ad32a4e10c4e737105 languageName: node linkType: hard @@ -4629,48 +4629,48 @@ __metadata: version: 7.6.7 resolution: "@storybook/core-server@npm:7.6.7" dependencies: - "@aw-web-design/x-default-browser": 1.4.126 - "@discoveryjs/json-ext": ^0.5.3 - "@storybook/builder-manager": 7.6.7 - "@storybook/channels": 7.6.7 - "@storybook/core-common": 7.6.7 - "@storybook/core-events": 7.6.7 - "@storybook/csf": ^0.1.2 - "@storybook/csf-tools": 7.6.7 - "@storybook/docs-mdx": ^0.1.0 - "@storybook/global": ^5.0.0 - "@storybook/manager": 7.6.7 - "@storybook/node-logger": 7.6.7 - "@storybook/preview-api": 7.6.7 - "@storybook/telemetry": 7.6.7 - "@storybook/types": 7.6.7 - "@types/detect-port": ^1.3.0 - "@types/node": ^18.0.0 - "@types/pretty-hrtime": ^1.0.0 - "@types/semver": ^7.3.4 - better-opn: ^3.0.2 - chalk: ^4.1.0 - cli-table3: ^0.6.1 - compression: ^1.7.4 - detect-port: ^1.3.0 - express: ^4.17.3 - fs-extra: ^11.1.0 - globby: ^11.0.2 - ip: ^2.0.0 - lodash: ^4.17.21 - open: ^8.4.0 - pretty-hrtime: ^1.0.3 - prompts: ^2.4.0 - read-pkg-up: ^7.0.1 - semver: ^7.3.7 - telejson: ^7.2.0 - tiny-invariant: ^1.3.1 - ts-dedent: ^2.0.0 - util: ^0.12.4 - util-deprecate: ^1.0.2 - watchpack: ^2.2.0 - ws: ^8.2.3 - checksum: 8759f1911868875eeee9b5b810395733037c84ae47885becd4e351f4d1c51821f5501b11f0ac651996fe31fd16d11e33c8bff29670d05c244d408f021b7ceaa9 + "@aw-web-design/x-default-browser": "npm:1.4.126" + "@discoveryjs/json-ext": "npm:^0.5.3" + "@storybook/builder-manager": "npm:7.6.7" + "@storybook/channels": "npm:7.6.7" + "@storybook/core-common": "npm:7.6.7" + "@storybook/core-events": "npm:7.6.7" + "@storybook/csf": "npm:^0.1.2" + "@storybook/csf-tools": "npm:7.6.7" + "@storybook/docs-mdx": "npm:^0.1.0" + "@storybook/global": "npm:^5.0.0" + "@storybook/manager": "npm:7.6.7" + "@storybook/node-logger": "npm:7.6.7" + "@storybook/preview-api": "npm:7.6.7" + "@storybook/telemetry": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + "@types/detect-port": "npm:^1.3.0" + "@types/node": "npm:^18.0.0" + "@types/pretty-hrtime": "npm:^1.0.0" + "@types/semver": "npm:^7.3.4" + better-opn: "npm:^3.0.2" + chalk: "npm:^4.1.0" + cli-table3: "npm:^0.6.1" + compression: "npm:^1.7.4" + detect-port: "npm:^1.3.0" + express: "npm:^4.17.3" + fs-extra: "npm:^11.1.0" + globby: "npm:^11.0.2" + ip: "npm:^2.0.0" + lodash: "npm:^4.17.21" + open: "npm:^8.4.0" + pretty-hrtime: "npm:^1.0.3" + prompts: "npm:^2.4.0" + read-pkg-up: "npm:^7.0.1" + semver: "npm:^7.3.7" + telejson: "npm:^7.2.0" + tiny-invariant: "npm:^1.3.1" + ts-dedent: "npm:^2.0.0" + util: "npm:^0.12.4" + util-deprecate: "npm:^1.0.2" + watchpack: "npm:^2.2.0" + ws: "npm:^8.2.3" + checksum: fa539338823c92a377f7d0ec18c6c22ee825456dcc41b70db7fa1a244d7f3c7eb8e57bd8d81c27752b6a13adfd78bae51b28fcc8e2a0d0c0f884e344f923d7f9 languageName: node linkType: hard @@ -4678,8 +4678,8 @@ __metadata: version: 7.6.7 resolution: "@storybook/csf-plugin@npm:7.6.7" dependencies: - "@storybook/csf-tools": 7.6.7 - unplugin: ^1.3.1 + "@storybook/csf-tools": "npm:7.6.7" + unplugin: "npm:^1.3.1" checksum: 1e9bba748b383a0a3d0e5bb1f36a6fc6eda192deefe5e0c056c8f743362a7dc7ade9d90723ce79189da9c9d4f9081db6173bc1c21978757090420995abd1b061 languageName: node linkType: hard @@ -4688,16 +4688,16 @@ __metadata: version: 7.6.7 resolution: "@storybook/csf-tools@npm:7.6.7" dependencies: - "@babel/generator": ^7.23.0 - "@babel/parser": ^7.23.0 - "@babel/traverse": ^7.23.2 - "@babel/types": ^7.23.0 - "@storybook/csf": ^0.1.2 - "@storybook/types": 7.6.7 - fs-extra: ^11.1.0 - recast: ^0.23.1 - ts-dedent: ^2.0.0 - checksum: bf78f5bcf9885840caf6c03ef3bc431b1325d4b3074b1d94185a9d26563aa87731ed947b05553ec44867ac9637d43db7431e8e68ecc041d81f948f7812bdeafb + "@babel/generator": "npm:^7.23.0" + "@babel/parser": "npm:^7.23.0" + "@babel/traverse": "npm:^7.23.2" + "@babel/types": "npm:^7.23.0" + "@storybook/csf": "npm:^0.1.2" + "@storybook/types": "npm:7.6.7" + fs-extra: "npm:^11.1.0" + recast: "npm:^0.23.1" + ts-dedent: "npm:^2.0.0" + checksum: 4a69830865256fa8b86180665b5f4997c3237d961a0c73c20a03d7f548abff5dd0215ca452d9c0d84354160352dfcdca8677e6d2ca25693d0220edfae36eb5c0 languageName: node linkType: hard @@ -4706,7 +4706,7 @@ __metadata: resolution: "@storybook/csf@npm:0.0.1" dependencies: lodash: "npm:^4.17.15" - checksum: fb57fa028b08a51edf44e1a2bf4be40a4607f5c6ccb58aae8924f476a42b9bbd61a0ad521cfc82196f23e6a912caae0a615e70a755e6800b284c91c509fd2de6 + checksum: f6bb019bccd8abc14e45a85258158b7bd8cc525887ac8dc9151ed8c4908be3b5f5523da8a7a9b96ff11b13b6c1744e1a0e070560d63d836b950f595f9a5719d4 languageName: node linkType: hard @@ -4714,15 +4714,15 @@ __metadata: version: 0.1.2 resolution: "@storybook/csf@npm:0.1.2" dependencies: - type-fest: ^2.19.0 - checksum: 22038dfd5e46cd9565c3dec615918c0712eb5fc5f56e9ec89cfa75d7b48667b8fcbf7e9d1f46c9f4d440eee074f1d23a84dc56a937add37b28ddf890fdedfb8a + type-fest: "npm:^2.19.0" + checksum: 11168df65e7b6bd0e5d31e7e805c8ba80397fc190cb33424e043b72bbd85d8f826dba082503992d7f606b72484337ab9d091eca947550613e241fbef57780d4c languageName: node linkType: hard "@storybook/docs-mdx@npm:^0.1.0": version: 0.1.0 resolution: "@storybook/docs-mdx@npm:0.1.0" - checksum: a7770842c3947a761bcbe776a9c4fd35163d30c3274fca034169f69ff614242eaa4cacaa2c95fd215827081ef9a43f4774d521a6f43a4d063ea5f4ea14b1d69a + checksum: f830eda81606a8af86d2bbf9ed6e36c70d9e88442990684139629742f2cc5d7ddddba91338fe2fc5e9b98e74af1940a9899fde471a8bfbfec744deaa990592e7 languageName: node linkType: hard @@ -4730,21 +4730,21 @@ __metadata: version: 7.6.7 resolution: "@storybook/docs-tools@npm:7.6.7" dependencies: - "@storybook/core-common": 7.6.7 - "@storybook/preview-api": 7.6.7 - "@storybook/types": 7.6.7 - "@types/doctrine": ^0.0.3 - assert: ^2.1.0 - doctrine: ^3.0.0 - lodash: ^4.17.21 - checksum: a8b9a995ca8031b56bc1ba64b81b3fe491519f0999dfc315d3f73f99eb9e004f9d242f167d4629a7cffe89ef3ac2c72f79632a4030c779f9ac99fb92011c3833 + "@storybook/core-common": "npm:7.6.7" + "@storybook/preview-api": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + "@types/doctrine": "npm:^0.0.3" + assert: "npm:^2.1.0" + doctrine: "npm:^3.0.0" + lodash: "npm:^4.17.21" + checksum: 5cd47ee0f5a751efe4b5d5a75cd237ad3e2e5f7fc621070b501aa40fae0450fdf530a679116a91c7fe287b0413f49c2df588f66afba99b3a28cfcab3225d8b9a languageName: node linkType: hard "@storybook/global@npm:^5.0.0": version: 5.0.0 resolution: "@storybook/global@npm:5.0.0" - checksum: ede0ad35ec411fe31c61150dbd118fef344d1d0e72bf5d3502368e35cf68126f6b7ae4a0ab5e2ffe2f0baa3b4286f03ad069ba3e098e1725449ef08b7e154ba8 + checksum: 0e7b495f4fe7f36447e793926f1c0460ec07fd66f0da68e3150da5878f6043c9eeb9b41614a45c5ec0d48d5d383c59ca8f88b6dc7882a2a784ac9b20375d8edb languageName: node linkType: hard @@ -4752,49 +4752,49 @@ __metadata: version: 7.6.7 resolution: "@storybook/manager-api@npm:7.6.7" dependencies: - "@storybook/channels": 7.6.7 - "@storybook/client-logger": 7.6.7 - "@storybook/core-events": 7.6.7 - "@storybook/csf": ^0.1.2 - "@storybook/global": ^5.0.0 - "@storybook/router": 7.6.7 - "@storybook/theming": 7.6.7 - "@storybook/types": 7.6.7 - dequal: ^2.0.2 - lodash: ^4.17.21 - memoizerific: ^1.11.3 - store2: ^2.14.2 - telejson: ^7.2.0 - ts-dedent: ^2.0.0 - checksum: b40e667d647398d140f142aaf3033579308f23573a8023b4366ca9482dce47bd34c090ba0381f66fc0b19600c24032551ddb418683b907bee0f1c9a86899c2da + "@storybook/channels": "npm:7.6.7" + "@storybook/client-logger": "npm:7.6.7" + "@storybook/core-events": "npm:7.6.7" + "@storybook/csf": "npm:^0.1.2" + "@storybook/global": "npm:^5.0.0" + "@storybook/router": "npm:7.6.7" + "@storybook/theming": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + dequal: "npm:^2.0.2" + lodash: "npm:^4.17.21" + memoizerific: "npm:^1.11.3" + store2: "npm:^2.14.2" + telejson: "npm:^7.2.0" + ts-dedent: "npm:^2.0.0" + checksum: ceda990fb6b139b417ff81ccd6139543bf7e44d5b290430df82b214cc2a3e4e3ecae7a02eba48b6e3c4fe54cffbf876acf32154f70a283f6ca40dd5de5559bd8 languageName: node linkType: hard "@storybook/manager@npm:7.6.7": version: 7.6.7 resolution: "@storybook/manager@npm:7.6.7" - checksum: 1eba0f753f16dfd7358b5e184c16ee356b618304d374d067177cd898dc9b0106cb48563d8040a60d44b1e1ee48f8e1f2ea421a1540aa3f9efc67248262b6a3e6 + checksum: f438f227a1025a872cd4b90a562d5cf2f7391dd594442badd70ff77287661e6dd159aa7effc2140178bc9ba4375dc93e7d1e0b3407b70701fa329ef430612146 languageName: node linkType: hard "@storybook/mdx2-csf@npm:^1.0.0": version: 1.1.0 resolution: "@storybook/mdx2-csf@npm:1.1.0" - checksum: 5ccdb13f4e59b989499f76e54ffaffb96b5710a696346efe19989b3373f375703adf516780894b270fa64a7e765b55274dc18575fc4a84e7fa92b844a4467c5d + checksum: acc368a8c8915e9487aa8e0c59241a39533d83635ddcc37fa4095cc239268a75900ec2bbfff65b573ead6ebcadcb1de0e4d70c9112faf105e0821de0a4803ca2 languageName: node linkType: hard "@storybook/node-logger@npm:7.6.7": version: 7.6.7 resolution: "@storybook/node-logger@npm:7.6.7" - checksum: 85b0c63e37adbfbe30cff165d21d12df42a82648f0af9bd9d4d9ac3eb85be54946afa265cfeebc45712cf42ba4e9da9f5a6fed95eacca10b9cde87bbb79e20dd + checksum: 25acaded5c833f7d8a32e8e6049b3e7ce0691a4613137b3c9ae766586a4220706e34bdba527ee32e3adabc9fdb67f8de4b81b870b0ad9b851fb676e1f6e1915a languageName: node linkType: hard "@storybook/postinstall@npm:7.6.7": version: 7.6.7 resolution: "@storybook/postinstall@npm:7.6.7" - checksum: c3198f5a04c5970cb59d701a56b3fd08eb2074dbf47f39bce4643c1106c83d2e0a6112199b2257a089d28819bed25483112b78f6d11d83f87b36c0043e183133 + checksum: 4506edfc678ce812f8b33f8558c1b7f98abe8accb160e75a55de77c4b0281800f29d57e72a63430b82c8c12710b68e7b564033c25709e1012794b59ca124029f languageName: node linkType: hard @@ -4802,28 +4802,28 @@ __metadata: version: 7.6.7 resolution: "@storybook/preview-api@npm:7.6.7" dependencies: - "@storybook/channels": 7.6.7 - "@storybook/client-logger": 7.6.7 - "@storybook/core-events": 7.6.7 - "@storybook/csf": ^0.1.2 - "@storybook/global": ^5.0.0 - "@storybook/types": 7.6.7 - "@types/qs": ^6.9.5 - dequal: ^2.0.2 - lodash: ^4.17.21 - memoizerific: ^1.11.3 - qs: ^6.10.0 - synchronous-promise: ^2.0.15 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - checksum: 2cea8458320f92eea604ac92c23051decf3208bc4d4546fde96de822b8acad010dd126a30fe211a4090b2b78c83fb33617ca64a0ecedfd3f42526350957f2ff7 + "@storybook/channels": "npm:7.6.7" + "@storybook/client-logger": "npm:7.6.7" + "@storybook/core-events": "npm:7.6.7" + "@storybook/csf": "npm:^0.1.2" + "@storybook/global": "npm:^5.0.0" + "@storybook/types": "npm:7.6.7" + "@types/qs": "npm:^6.9.5" + dequal: "npm:^2.0.2" + lodash: "npm:^4.17.21" + memoizerific: "npm:^1.11.3" + qs: "npm:^6.10.0" + synchronous-promise: "npm:^2.0.15" + ts-dedent: "npm:^2.0.0" + util-deprecate: "npm:^1.0.2" + checksum: 9fffc215436f11fd7ef953d3f7e925ea805ab07aaee7c18d4239b44d2761fd7243a2f270ad2d82bae03183c2688c1bb97f36528fa0606c117bf4b71890759efb languageName: node linkType: hard "@storybook/preview@npm:7.6.7": version: 7.6.7 resolution: "@storybook/preview@npm:7.6.7" - checksum: caf4c9e52ff81a420f2cd14677d137e5af91da05303276712e0d7e96f8458e2cf71ef880a1736f92da083b0ef0ad9e1e75fa1174a6face8bc5797a5444f540b6 + checksum: 4c2a390c2633f11ad82302ebab37fb3e85d51bd9a596193da8a411d7f307461919f23f1f65ca77da5f8880700f70088e8ad1c70e12c075d4f0e390dc6f3f042c languageName: node linkType: hard @@ -4833,7 +4833,7 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: e5518543a87df2d8525ab6d48970398e82739f978317a3a6be8b9c1be116b947c6bca8cd4eddc918488f2d60ff6c12a63966e4e624a3b8b379fcf2846844dd69 + checksum: d878bb9cac096aed7be827141ca4f3d703cf54679cdd3e602ac05450c3ae78f722da2b2d1bf11ddf72812d6f7bc10abc5f93f4671f8762e05f10011ccbf0f1f7 languageName: node linkType: hard @@ -4841,18 +4841,18 @@ __metadata: version: 7.6.7 resolution: "@storybook/react-vite@npm:7.6.7" dependencies: - "@joshwooding/vite-plugin-react-docgen-typescript": 0.3.0 - "@rollup/pluginutils": ^5.0.2 - "@storybook/builder-vite": 7.6.7 - "@storybook/react": 7.6.7 - "@vitejs/plugin-react": ^3.0.1 - magic-string: ^0.30.0 - react-docgen: ^7.0.0 + "@joshwooding/vite-plugin-react-docgen-typescript": "npm:0.3.0" + "@rollup/pluginutils": "npm:^5.0.2" + "@storybook/builder-vite": "npm:7.6.7" + "@storybook/react": "npm:7.6.7" + "@vitejs/plugin-react": "npm:^3.0.1" + magic-string: "npm:^0.30.0" + react-docgen: "npm:^7.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 || ^5.0.0 - checksum: 344a7135234b320da7703a4d86ba2249a7ed2f2daebfbc915bc06a8f2343b6eac2a8e2db6811299ececa89fe589d1ccdfea62a5f513d2a513c3830b98afe5efb + checksum: d02aea07d378511b708bce3253241000208e738775dd51adee2a59468ba94ad40049c4006561dccb469a29b9cd484a220496af3b64aa2a6f82bb0fe42768d4d8 languageName: node linkType: hard @@ -4860,27 +4860,27 @@ __metadata: version: 7.6.7 resolution: "@storybook/react@npm:7.6.7" dependencies: - "@storybook/client-logger": 7.6.7 - "@storybook/core-client": 7.6.7 - "@storybook/docs-tools": 7.6.7 - "@storybook/global": ^5.0.0 - "@storybook/preview-api": 7.6.7 - "@storybook/react-dom-shim": 7.6.7 - "@storybook/types": 7.6.7 - "@types/escodegen": ^0.0.6 - "@types/estree": ^0.0.51 - "@types/node": ^18.0.0 - acorn: ^7.4.1 - acorn-jsx: ^5.3.1 - acorn-walk: ^7.2.0 - escodegen: ^2.1.0 - html-tags: ^3.1.0 - lodash: ^4.17.21 - prop-types: ^15.7.2 - react-element-to-jsx-string: ^15.0.0 - ts-dedent: ^2.0.0 - type-fest: ~2.19 - util-deprecate: ^1.0.2 + "@storybook/client-logger": "npm:7.6.7" + "@storybook/core-client": "npm:7.6.7" + "@storybook/docs-tools": "npm:7.6.7" + "@storybook/global": "npm:^5.0.0" + "@storybook/preview-api": "npm:7.6.7" + "@storybook/react-dom-shim": "npm:7.6.7" + "@storybook/types": "npm:7.6.7" + "@types/escodegen": "npm:^0.0.6" + "@types/estree": "npm:^0.0.51" + "@types/node": "npm:^18.0.0" + acorn: "npm:^7.4.1" + acorn-jsx: "npm:^5.3.1" + acorn-walk: "npm:^7.2.0" + escodegen: "npm:^2.1.0" + html-tags: "npm:^3.1.0" + lodash: "npm:^4.17.21" + prop-types: "npm:^15.7.2" + react-element-to-jsx-string: "npm:^15.0.0" + ts-dedent: "npm:^2.0.0" + type-fest: "npm:~2.19" + util-deprecate: "npm:^1.0.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4888,7 +4888,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 010707cf34f1ac982bdb4d6a364d89a7ebb3c10eb8f40793147c71bed2eeb4320fb2ab2a791073ad748b18a3a20d0ba85345415f3b155c864fb0cfb4f5677ba6 + checksum: c03cb0eefe7686958a29c624bd675d390cab6e20bd9e4f241f0479ad6fd7560498e5adb2ec59f198dba6a6e348e62c7ab074c3e7fcaa643ed633e7f6c0b7c51e languageName: node linkType: hard @@ -4896,10 +4896,10 @@ __metadata: version: 7.6.7 resolution: "@storybook/router@npm:7.6.7" dependencies: - "@storybook/client-logger": 7.6.7 - memoizerific: ^1.11.3 - qs: ^6.10.0 - checksum: b25f03b63b00851b3224d0ed97e4bf495b513d7e8af9aafc9eeab4c72b7561f848ec15f8595519056fc8a71b88fa75614252ce253c4c662d995bcaef6f98da5c + "@storybook/client-logger": "npm:7.6.7" + memoizerific: "npm:^1.11.3" + qs: "npm:^6.10.0" + checksum: b9771ac473f22a49e2599be1937bd77de354c8987eea41f4c9de7c2c0706232edea0f9de3614a215c474ed549038d8cc0a9da0f0208db85507ab1ec40d925f5d languageName: node linkType: hard @@ -4907,15 +4907,15 @@ __metadata: version: 7.6.7 resolution: "@storybook/telemetry@npm:7.6.7" dependencies: - "@storybook/client-logger": 7.6.7 - "@storybook/core-common": 7.6.7 - "@storybook/csf-tools": 7.6.7 - chalk: ^4.1.0 - detect-package-manager: ^2.0.1 - fetch-retry: ^5.0.2 - fs-extra: ^11.1.0 - read-pkg-up: ^7.0.1 - checksum: 6b6786aef18a9133fed870e4030dbbab971d6dfc809ee81c6079f7816d34dd9295c35e796a772011c9dd6006abf7eb9b9c743f5e06e831a1d7e077f91ad81364 + "@storybook/client-logger": "npm:7.6.7" + "@storybook/core-common": "npm:7.6.7" + "@storybook/csf-tools": "npm:7.6.7" + chalk: "npm:^4.1.0" + detect-package-manager: "npm:^2.0.1" + fetch-retry: "npm:^5.0.2" + fs-extra: "npm:^11.1.0" + read-pkg-up: "npm:^7.0.1" + checksum: 82d01b8f6322c230407733300ac368fc53f04ce660102b988a9d6b5694f4a69f447b133ef31097b5251bbf0a7f2b4dd62af46f02c28e9cb4b811b4b4ed1e4093 languageName: node linkType: hard @@ -4923,10 +4923,10 @@ __metadata: version: 0.2.2 resolution: "@storybook/testing-library@npm:0.2.2" dependencies: - "@testing-library/dom": ^9.0.0 - "@testing-library/user-event": ^14.4.0 - ts-dedent: ^2.2.0 - checksum: 8ccdc1fbbb3472264c56b0aaf2f1c5d273f1ae9b230a53adf9cf82bf82c1a555550894f0e8869c206fa07b1fe8423da4d56590377756c58de3ec560b35a96c46 + "@testing-library/dom": "npm:^9.0.0" + "@testing-library/user-event": "npm:^14.4.0" + ts-dedent: "npm:^2.2.0" + checksum: 85a8c39b432009c5ebac40569deef48b54f3b65f91bd1902bc86d4f130433bff2866c8bece9acdbd3f5cc92da5a1401f7405d11457570c96d3a30ba21c976b7b languageName: node linkType: hard @@ -4934,14 +4934,14 @@ __metadata: version: 7.6.7 resolution: "@storybook/theming@npm:7.6.7" dependencies: - "@emotion/use-insertion-effect-with-fallbacks": ^1.0.0 - "@storybook/client-logger": 7.6.7 - "@storybook/global": ^5.0.0 - memoizerific: ^1.11.3 + "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.0.0" + "@storybook/client-logger": "npm:7.6.7" + "@storybook/global": "npm:^5.0.0" + memoizerific: "npm:^1.11.3" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: a8f144e693167b10f170ff56ec38551f6606c7cc04450446838d7cb6ae15f5e1b82d2264cd24c0a75e8949b4cce2fe1d5f17cec88797e43f038a1d7832e8d72d + checksum: a8be120508b8cd6185aebeb666c26383ca2496df1e203d2056a3e7e6ed427e87cdeb310bd5095858f169fdac839d365877f09ae591b886845600f15b3c9b64c5 languageName: node linkType: hard @@ -4949,11 +4949,11 @@ __metadata: version: 7.6.7 resolution: "@storybook/types@npm:7.6.7" dependencies: - "@storybook/channels": 7.6.7 - "@types/babel__core": ^7.0.0 - "@types/express": ^4.7.0 - file-system-cache: 2.3.0 - checksum: 3e3395409e42d0854b93afa12e6c588e6a47d42b9d60f714e71ee43f39356917ec1b5b1ab014155005091463bc4535a5e640dfc3d838da3517c6366e1d22a5a8 + "@storybook/channels": "npm:7.6.7" + "@types/babel__core": "npm:^7.0.0" + "@types/express": "npm:^4.7.0" + file-system-cache: "npm:2.3.0" + checksum: 3ff500fbedafcd0a13dbd7fea58723bc167a1ec46e327d0ab5595c6c30358321fae0cf249bb7372b20e0a0fe1e1b6948cda834c2b7d6385c94e22c579ce7027b languageName: node linkType: hard @@ -5025,7 +5025,7 @@ __metadata: resolution: "@svgr/babel-plugin-transform-svg-component@npm:7.0.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: cf5be9c6b24a4a9c0afefe67214370af1cd562d9a06082a89486ec25298a223766cdf57591c92750764068a0d27377c3ce3a9609d18eaae59f64c94e60f2b25c + checksum: 0cd529df17943386d74d5d739779e377993cd531fb2607582a451dbe602eb28e051cf5260c90d7ce1578deed8be829552ea793f17e3a4e549764e67aeb983452 languageName: node linkType: hard @@ -5055,7 +5055,7 @@ __metadata: "@svgr/babel-preset": "npm:^7.0.0" camelcase: "npm:^6.2.0" cosmiconfig: "npm:^8.1.3" - checksum: 34fa14557baf560c78a6d7ac79401d35feb081d54ab55ee1b43d1649a89b322b4ecc7dba3daca0063af1f639c499cea1c46e34e5b066655ae7dc3553c1a64672 + checksum: 47cd50b74dcf1be2e41ae894da425346d83c5f4caf5f268ac9f215b24936b72afaf6da1774b7963fde2634710cf5dac60c57f722a4ba7a8a4a5794b0bc515cb7 languageName: node linkType: hard @@ -5065,7 +5065,7 @@ __metadata: dependencies: "@babel/types": "npm:^7.21.3" entities: "npm:^4.4.0" - checksum: c2168c36c8d25e876da879815728310cf204579c97a73908ce33b063cccfb9a18b6e53f53c6daf81506a96761d84b6261bf64faf26f16453f27e73cb322a9256 + checksum: 71cf7fc641fef2f20ec5c90a77223a1c85aad7015617236d232b9738660bb4982cb60a62364010151ca1f6ec5927a89d2714a9c5a3248b83dafa056cf64496c4 languageName: node linkType: hard @@ -5093,7 +5093,7 @@ __metadata: dom-accessibility-api: "npm:^0.5.9" lz-string: "npm:^1.5.0" pretty-format: "npm:^27.0.2" - checksum: 790f4da6a8cbe7da8b7769e81e68caea1aed5b5f1973b808895692a945fb854fe8acdc66ffc34b6a57ec49bad9d76ccdd69b632ea8a82ad61d1e97d76cfdf9ec + checksum: 51fab7d30358c25c0a65c967aeda6cdc9ba86b322299cada41414536258c7c2e037bcf7812cd1e1ad01ea7966b0bd7290b57ae83138549f54f78755d6d39b72e languageName: node linkType: hard @@ -5109,7 +5109,7 @@ __metadata: dom-accessibility-api: "npm:^0.5.9" lz-string: "npm:^1.5.0" pretty-format: "npm:^27.0.2" - checksum: 8ee3136451644e39990edea93709c38cf1e8ce5306f3c66273ca00935963faa51ca74e8d92b02eb442ccb842cfa28ca62833e393e075eb269cf9bef6f5600663 + checksum: 80114bcd2164a99ad12eecb3eee263c454ba7710d251f655cd1e81ea3335f2ccc4f1c31f8a3e1cbebdf8c0d233553384ac2bf92adea6468154eac7db7cabac83 languageName: node linkType: hard @@ -5126,7 +5126,7 @@ __metadata: dom-accessibility-api: "npm:^0.5.6" lodash: "npm:^4.17.15" redent: "npm:^3.0.0" - checksum: 94911f901a8031f3e489d04ac057cb5373621230f5d92bed80e514e24b069fb58a3166d1dd86963e55f078a1bd999da595e2ab96ed95f452d477e272937d792a + checksum: 472a14b6295a18af28b5133ecaf4d22a7bb9c50bf05e1f04a076b2e2d7c596e76cdd56a95387ad6d2a4dda0c46bc93d95cbca5b314fabe0fd13362f29118749e languageName: node linkType: hard @@ -5140,7 +5140,7 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 4a54c8f56cc4a39b50803205f84f06280bb76521d6d5d4b3b36651d760c7c7752ef142d857d52aaf4fad4848ed7a8be49afc793a5dda105955d2f8bef24901ac + checksum: 1f2a4f78d107e741b35671e9c7dd992d5c9f49b48ee24112ccfe636179be72f3c62a65b1405901b59eb6cde996176ebc2c99099e04d9f14575641e46688747f0 languageName: node linkType: hard @@ -5149,7 +5149,7 @@ __metadata: resolution: "@testing-library/user-event@npm:14.4.3" peerDependencies: "@testing-library/dom": ">=7.21.4" - checksum: 852c48ea6db1c9471b18276617c84fec4320771e466cd58339a732ca3fd73ad35e5a43ae14f51af51a8d0a150dcf60fcaab049ef367871207bea8f92c4b8195e + checksum: 0c7c1ee6bacd8faf15e00624ff6815f0cdf2529493c3a0d8ec6878bbedfc7bd4c7600b7a4b7a07302737e71400dc560ee17dc5706291505da09905c8ea3f3cd7 languageName: node linkType: hard @@ -5158,7 +5158,7 @@ __metadata: resolution: "@testing-library/user-event@npm:14.5.2" peerDependencies: "@testing-library/dom": ">=7.21.4" - checksum: d76937dffcf0082fbf3bb89eb2b81a31bf5448048dd61c33928c5f10e33a58e035321d39145cefd469bb5a499c68a5b4086b22f1a44e3e7c7e817dc5f6782867 + checksum: 49821459d81c6bc435d97128d6386ca24f1e4b3ba8e46cb5a96fe3643efa6e002d88c1b02b7f2ec58da593e805c59b78d7fdf0db565c1f02ba782f63ee984040 languageName: node linkType: hard @@ -5172,14 +5172,14 @@ __metadata: "@trysound/sax@npm:0.2.0": version: 0.2.0 resolution: "@trysound/sax@npm:0.2.0" - checksum: 11226c39b52b391719a2a92e10183e4260d9651f86edced166da1d95f39a0a1eaa470e44d14ac685ccd6d3df7e2002433782872c0feeb260d61e80f21250e65c + checksum: 7379713eca480ac0d9b6c7b063e06b00a7eac57092354556c81027066eb65b61ea141a69d0cc2e15d32e05b2834d4c9c2184793a5e36bbf5daf05ee5676af18c languageName: node linkType: hard "@types/aria-query@npm:^5.0.1": version: 5.0.1 resolution: "@types/aria-query@npm:5.0.1" - checksum: 69fd7cceb6113ed370591aef04b3fd0742e9a1b06dd045c43531448847b85de181495e4566f98e776b37c422a12fd71866e0a1dfd904c5ec3f84d271682901de + checksum: 0635081bb506576b937899afa8e76e6b8d2faf5662f309d6fdc3fc89c749d63362cd8cb3baa0a6d786fe8664994fbffbb11461fcad62b5394f2663891e722b86 languageName: node linkType: hard @@ -5192,7 +5192,7 @@ __metadata: "@types/babel__generator": "npm:*" "@types/babel__template": "npm:*" "@types/babel__traverse": "npm:*" - checksum: 9fcd9691a33074802d9057ff70b0e3ff3778f52470475b68698a0f6714fbe2ccb36c16b43dc924eb978cd8a81c1f845e5ff4699e7a47606043b539eb8c6331a8 + checksum: e63e5e71be75dd2fe41951c83650ab62006179340a7b280bfa58e9c39118cb2752ca786f952f4a12f75b83b55346f2d5e8df2b91926ef99f2f4a2a69162cab99 languageName: node linkType: hard @@ -5200,12 +5200,12 @@ __metadata: version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" dependencies: - "@babel/parser": ^7.20.7 - "@babel/types": ^7.20.7 - "@types/babel__generator": "*" - "@types/babel__template": "*" - "@types/babel__traverse": "*" - checksum: a3226f7930b635ee7a5e72c8d51a357e799d19cbf9d445710fa39ab13804f79ab1a54b72ea7d8e504659c7dfc50675db974b526142c754398d7413aa4bc30845 + "@babel/parser": "npm:^7.20.7" + "@babel/types": "npm:^7.20.7" + "@types/babel__generator": "npm:*" + "@types/babel__template": "npm:*" + "@types/babel__traverse": "npm:*" + checksum: c32838d280b5ab59d62557f9e331d3831f8e547ee10b4f85cb78753d97d521270cebfc73ce501e9fb27fe71884d1ba75e18658692c2f4117543f0fc4e3e118b3 languageName: node linkType: hard @@ -5214,7 +5214,7 @@ __metadata: resolution: "@types/babel__generator@npm:7.6.4" dependencies: "@babel/types": "npm:^7.0.0" - checksum: 20effbbb5f8a3a0211e95959d06ae70c097fb6191011b73b38fe86deebefad8e09ee014605e0fd3cdaedc73d158be555866810e9166e1f09e4cfd880b874dcb0 + checksum: 34f361a0d54a0d85ea4c4b5122c4025a5738fe6795361c85f07a4f8f9add383de640e8611edeeb8339db8203c2d64bff30be266bdcfe3cf777c19e8d34f9cebc languageName: node linkType: hard @@ -5233,7 +5233,7 @@ __metadata: resolution: "@types/babel__traverse@npm:7.20.1" dependencies: "@babel/types": "npm:^7.20.7" - checksum: 58341e23c649c0eba134a1682d4f20d027fad290d92e5740faa1279978f6ed476fc467ae51ce17a877e2566d805aeac64eae541168994367761ec883a4150221 + checksum: 8f18d1488adf296f50d01e2386797c56a607cde2cfc3c7c55cea34d760aed9386c81ea808a151a0efb11d99e0083c138c5733d3f214471a30abed055bede39d8 languageName: node linkType: hard @@ -5241,8 +5241,8 @@ __metadata: version: 7.20.5 resolution: "@types/babel__traverse@npm:7.20.5" dependencies: - "@babel/types": ^7.20.7 - checksum: 608e0ab4fc31cd47011d98942e6241b34d461608c0c0e153377c5fd822c436c475f1ded76a56bfa76a1adf8d9266b727bbf9bfac90c4cb152c97f30dadc5b7e8 + "@babel/types": "npm:^7.20.7" + checksum: f0352d537448e1e37f27e6bb8c962d7893720a92fde9d8601a68a93dbc14e15c088b4c0c8f71021d0966d09fba802ef3de11fdb6766c33993f8cf24f1277c6a9 languageName: node linkType: hard @@ -5269,7 +5269,7 @@ __metadata: version: 6.0.6 resolution: "@types/cross-spawn@npm:6.0.6" dependencies: - "@types/node": "*" + "@types/node": "npm:*" checksum: b4172927cd1387cf037c3ade785ef46c87537b7bc2803d7f6663b4904d0c5d6f726415d1adb2fee4fecb21746738f11336076449265d46be4ce110cc3a8c8436 languageName: node linkType: hard @@ -5284,35 +5284,35 @@ __metadata: "@types/doctrine@npm:^0.0.3": version: 0.0.3 resolution: "@types/doctrine@npm:0.0.3" - checksum: 7ca9c8ff4d2da437785151c9eef0dd80b8fa12e0ff0fcb988458a78de4b6f0fc92727ba5bbee446e1df615a91f03053c5783b30b7c21ab6ceab6a42557e93e50 + checksum: 398c30efc903a750c71166c7385d763c98605723dfae23f0134d6de4d365a8f0a5585a0fe6f959569ff33646e7f43fa83bacb5f2a4d5929cd0f6163d06e4f6b3 languageName: node linkType: hard "@types/doctrine@npm:^0.0.9": version: 0.0.9 resolution: "@types/doctrine@npm:0.0.9" - checksum: 3909eaca42e7386b2ab866f082b78da3e00718d2fa323597e254feb0556c678b41f2c490729067433630083ac9c806ec6ae1e146754f7f8ba7d3e43ed68d6500 + checksum: 64ef06e6eea2f4f9684d259fedbcb8bf21c954630b96ea2e04875ca42763552b0ba3b01b3dd27ec0f9ea6f8b3b0dba4965d31d5a925cd4c6225fd13a93ae9354 languageName: node linkType: hard "@types/ejs@npm:^3.1.1": version: 3.1.2 resolution: "@types/ejs@npm:3.1.2" - checksum: e4f0745b6ed53a63c08bdfdeb019a7d0e0c400896722b44d6732b4ee6bf6061d2dc965206186b8b0ae2ecd71303c29f1af1feddbca2df0acbd7bd234a74ca518 + checksum: 8be94c952dc06525a5fb229a469db66f2240425ce137a1f5108a6a11f500cac9190691e924e6d18df34c5c2be40ef36b537921d2833262467ee1dfb7a7c919ac languageName: node linkType: hard "@types/emscripten@npm:^1.39.6": version: 1.39.10 resolution: "@types/emscripten@npm:1.39.10" - checksum: 1721da76593f9194e0b7c90a581e2d31c23bd4eb28f93030cd1dc58216cdf1e692c045274f2eedaed29c652c25c9a4dff2e503b11bd1258d07095c009a1956b1 + checksum: 6ed97aa115761e83665897b3d5d259895db60c10d2378c1bf84f94746c3c178715004812f5f42bcfb6e439664144f812318e8175103c76806aa6eaaf126a94f0 languageName: node linkType: hard "@types/escodegen@npm:^0.0.6": version: 0.0.6 resolution: "@types/escodegen@npm:0.0.6" - checksum: 7b25aeedd48dbef68345224082c6bc774845cbfc1d9b2ce91a477130fe7ccabf33da126c1d6d55e5dfd838db429a7c80890628a167e5aa55b6a4620974da38d3 + checksum: 2e91554a47eb98076a3ba6e3548640e50b28a0f5b69134f99dd1e0ce5223c0a1726f23d25aafd40e4c7961d7c3c519782949aa606d58d0e7431c7fb1ec011c4c languageName: node linkType: hard @@ -5322,21 +5322,21 @@ __metadata: dependencies: "@types/estree": "npm:*" "@types/json-schema": "npm:*" - checksum: 2655f409a4ecdd64bb9dd9eb6715e7a2ac30c0e7f902b414e10dbe9d6d497baa5a0f13105e1f7bd5ad7a913338e2ab4bed1faf192a7a0d27d1acd45ba79d3f69 + checksum: 29657ff1e3325be8048646b0f10f20e6fd6668c81e560cdf931b228eae8758e56ba0a51b71e699e86adfea4fdc05f68d23cb078b105d77be81a731f7aa172caa languageName: node linkType: hard "@types/estree@npm:*, @types/estree@npm:^1.0.0": version: 1.0.1 resolution: "@types/estree@npm:1.0.1" - checksum: e9aa175eacb797216fafce4d41e8202c7a75555bc55232dee0f9903d7171f8f19f0ae7d5191bb1a88cb90e65468be508c0df850a9fb81b4433b293a5a749899d + checksum: f252569c002506c61ad913e778aa69415908078c46c78c901ccad77bc66cd34f1e1b9babefb8ff0d27c07a15fb0824755edd7bb3fa7ea828f32ae0fe5faa9962 languageName: node linkType: hard "@types/estree@npm:^0.0.51": version: 0.0.51 resolution: "@types/estree@npm:0.0.51" - checksum: e56a3bcf759fd9185e992e7fdb3c6a5f81e8ff120e871641607581fb3728d16c811702a7d40fa5f869b7f7b4437ab6a87eb8d98ffafeee51e85bbe955932a189 + checksum: b566c7a3fc8a81ca3d9e00a717e90b8f5d567e2476b4f6d76a20ec6da33ec28165b8f989ed8dd0c9df41405199777ec36a4f85f32a347fbc6c3f696a3128b6e7 languageName: node linkType: hard @@ -5348,7 +5348,7 @@ __metadata: "@types/qs": "npm:*" "@types/range-parser": "npm:*" "@types/send": "npm:*" - checksum: cc8995d10c6feda475ec1b3a0e69eb0f35f21ab6b49129ad5c6f279e0bc5de8175bc04ec51304cb79a43eec3ed2f5a1e01472eb6d5f827b8c35c6ca8ad24eb6e + checksum: 9f08212ac163e9b2a1005d84cc43ace52d5057dfaa009c575eb3f3a659949b9c9cecec0cbff863622871c56e1c604bd67857a5e1d353256eaf9adacec59f87bf languageName: node linkType: hard @@ -5360,7 +5360,7 @@ __metadata: "@types/express-serve-static-core": "npm:^4.17.33" "@types/qs": "npm:*" "@types/serve-static": "npm:*" - checksum: 0196dacc275ac3ce89d7364885cb08e7fb61f53ca101f65886dbf1daf9b7eb05c0943e2e4bbd01b0cc5e50f37e0eea7e4cbe97d0304094411ac73e1b7998f4da + checksum: e2959a5fecdc53f8a524891a16e66dfc330ee0519e89c2579893179db686e10cfa6079a68e0fb8fd00eedbcaf3eabfd10916461939f3bc02ef671d848532c37e languageName: node linkType: hard @@ -5405,7 +5405,7 @@ __metadata: dependencies: "@types/react": "npm:*" hoist-non-react-statics: "npm:^3.3.0" - checksum: 2c0778570d9a01d05afabc781b32163f28409bb98f7245c38d5eaf082416fdb73034003f5825eb5e21313044e8d2d9e1f3fe2831e345d3d1b1d20bcd12270719 + checksum: 071e6d75a0ed9aa0e9ca2cc529a8c15bf7ac3e4a37aac279772ea6036fd0bf969b67fb627b65cfce65adeab31fec1e9e95b4dcdefeab075b580c0c7174206f63 languageName: node linkType: hard @@ -5428,7 +5428,7 @@ __metadata: resolution: "@types/istanbul-lib-report@npm:3.0.0" dependencies: "@types/istanbul-lib-coverage": "npm:*" - checksum: 656398b62dc288e1b5226f8880af98087233cdb90100655c989a09f3052b5775bf98ba58a16c5ae642fb66c61aba402e07a9f2bff1d1569e3b306026c59f3f36 + checksum: f121dcac8a6b8184f3cab97286d8d519f1937fa8620ada5dbc43b699d602b8be289e4a4bccbd6ee1aade6869d3c9fb68bf04c6fdca8c5b0c4e7e314c31c7900a languageName: node linkType: hard @@ -5447,7 +5447,7 @@ __metadata: dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: e36bb92e0b9e5ea7d6f8832baa42f087fc1697f6cd30ec309a07ea4c268e06ec460f1f0cfd2581daf5eff5763475190ec1ad8ac6520c49ccfe4f5c0a48bfa676 + checksum: e8b4eda3ba379b21fcd5c2d1d531ec94f636676f1690f06ff3f7b8dc199c2cec711d4c4e122175f05d50040e5dec69f3c13ef88bd825f0b1a1ac1332eb072c12 languageName: node linkType: hard @@ -5457,7 +5457,7 @@ __metadata: dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: 7d205599ea3cccc262bad5cc173d3242d6bf8138c99458509230e4ecef07a52d6ddcde5a1dbd49ace655c0af51d2dbadef3748697292ea4d86da19d9e03e19c0 + checksum: c45d1f2825b31c87b479d6ea0e22d0353c11c547f02c85e504623550527460e4fc572cd566374c4c00fcff2c8a022ef71c4b52545ccb03118b603b3c1e4e884f languageName: node linkType: hard @@ -5468,28 +5468,28 @@ __metadata: "@types/node": "npm:*" "@types/tough-cookie": "npm:*" parse5: "npm:^7.0.0" - checksum: d55402c5256ef451f93a6e3d3881f98339fe73a5ac2030588df056d6835df8367b5a857b48d27528289057e26dcdd3f502edc00cb877c79174cb3a4c7f2198c1 + checksum: 15fbb9a0bfb4a5845cf6e795f2fd12400aacfca53b8c7e5bca4a3e5e8fa8629f676327964d64258aefb127d2d8a2be86dad46359efbfca0e8c9c2b790e7f8a88 languageName: node linkType: hard "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.9": version: 7.0.12 resolution: "@types/json-schema@npm:7.0.12" - checksum: 00239e97234eeb5ceefb0c1875d98ade6e922bfec39dd365ec6bd360b5c2f825e612ac4f6e5f1d13601b8b30f378f15e6faa805a3a732f4a1bbe61915163d293 + checksum: 7a72ba9cb7d2b45d7bb032e063c9eeb1ce4102d62551761e84c91f99f8273ba5aaffd34be835869456ec7c40761b4389009d9e777c0020a7227ca0f5e3238e94 languageName: node linkType: hard "@types/json5@npm:^0.0.29": version: 0.0.29 resolution: "@types/json5@npm:0.0.29" - checksum: e60b153664572116dfea673c5bda7778dbff150498f44f998e34b5886d8afc47f16799280e4b6e241c0472aef1bc36add771c569c68fc5125fc2ae519a3eb9ac + checksum: 4e5aed58cabb2bbf6f725da13421aa50a49abb6bc17bfab6c31b8774b073fa7b50d557c61f961a09a85f6056151190f8ac95f13f5b48136ba5841f7d4484ec56 languageName: node linkType: hard "@types/lodash@npm:^4.14.167": version: 4.14.195 resolution: "@types/lodash@npm:4.14.195" - checksum: 39b75ca635b3fa943d17d3d3aabc750babe4c8212485a4df166fe0516e39288e14b0c60afc6e21913cc0e5a84734633c71e617e2bd14eaa1cf51b8d7799c432e + checksum: d7c0902684508a3d0fdb60fe939a855f9f244fd4bf828eb75388a39d00b44e955dac16faea6c90c0ae4592a57784e45ceb6d51354af8dfd401de38046c685775 languageName: node linkType: hard @@ -5503,7 +5503,7 @@ __metadata: "@types/mime-types@npm:^2.1.0": version: 2.1.1 resolution: "@types/mime-types@npm:2.1.1" - checksum: 106b5d556add46446a579ad25ff15d6b421851790d887edcad558c90c1e64b1defc72bfbaf4b08f208916e21d9cc45cdb951d77be51268b18221544cfe054a3c + checksum: 1b9cfea94517790dfe3f3f4b5cfde96d4acde303f1112643a6fa6a6a5901f358be3613cafcec232ee91c3601684cb806ef3254018da3d0e1075e00684f6029ee languageName: node linkType: hard @@ -5524,7 +5524,7 @@ __metadata: "@types/minimatch@npm:*": version: 5.1.2 resolution: "@types/minimatch@npm:5.1.2" - checksum: 0391a282860c7cb6fe262c12b99564732401bdaa5e395bee9ca323c312c1a0f45efbf34dce974682036e857db59a5c9b1da522f3d6055aeead7097264c8705a8 + checksum: 94db5060d20df2b80d77b74dd384df3115f01889b5b6c40fa2dfa27cfc03a68fb0ff7c1f2a0366070263eb2e9d6bfd8c87111d4bc3ae93c3f291297c1bf56c85 languageName: node linkType: hard @@ -5532,16 +5532,16 @@ __metadata: version: 2.6.11 resolution: "@types/node-fetch@npm:2.6.11" dependencies: - "@types/node": "*" - form-data: ^4.0.0 - checksum: 180e4d44c432839bdf8a25251ef8c47d51e37355ddd78c64695225de8bc5dc2b50b7bb855956d471c026bb84bd7295688a0960085e7158cbbba803053492568b + "@types/node": "npm:*" + form-data: "npm:^4.0.0" + checksum: c416df8f182ec3826278ea42557fda08f169a48a05e60722d9c8edd4e5b2076ae281c6b6601ad406035b7201f885b0257983b61c26b3f9eb0f41192a807b5de5 languageName: node linkType: hard "@types/node@npm:*": version: 20.4.2 resolution: "@types/node@npm:20.4.2" - checksum: 99e544ea7560d51f01f95627fc40394c24a13da8f041121a0da13e4ef0a2aa332932eaf9a5e8d0e30d1c07106e96a183be392cbba62e8cf0bf6a085d5c0f4149 + checksum: d013c11ea228921ae319f7db5f2f65e9d3f58537919bca9e6409f6b380d1ef05625389e7d0dd0e8c4bbb90560a12b9ae6fab98b4722e19611b3de9052a0e2f94 languageName: node linkType: hard @@ -5549,8 +5549,8 @@ __metadata: version: 18.19.8 resolution: "@types/node@npm:18.19.8" dependencies: - undici-types: ~5.26.4 - checksum: fa291495d6157a9d9393b4c3bdbf1ce12a8f661dc9da6a4fa19bcdb19af1c62bb8dbf7fb66ae135f29cd788b618e9845b83e9c47edcf39f0953a8561fdacd9a3 + undici-types: "npm:~5.26.4" + checksum: 3fb90057208d7c3d1750eb9151b7ff2e048c4192ccf9837c9af4e843fbf9c76ead0c5a658187769adcf0b012cd348656c48695dd7a358bd2b3174b1575b1982b languageName: node linkType: hard @@ -5564,7 +5564,7 @@ __metadata: "@types/prettier@npm:^2.1.5": version: 2.7.3 resolution: "@types/prettier@npm:2.7.3" - checksum: 705384209cea6d1433ff6c187c80dcc0b95d99d5c5ce21a46a9a58060c527973506822e428789d842761e0280d25e3359300f017fbe77b9755bc772ab3dc2f83 + checksum: cda84c19acc3bf327545b1ce71114a7d08efbd67b5030b9e8277b347fa57b05178045f70debe1d363ff7efdae62f237260713aafc2d7217e06fc99b048a88497 languageName: node linkType: hard @@ -5610,7 +5610,7 @@ __metadata: resolution: "@types/react-dom@npm:18.0.11" dependencies: "@types/react": "npm:*" - checksum: 579691e4d5ec09688087568037c35edf8cfb1ab3e07f6c60029280733ee7b5c06d66df6fcc90786702c93ac8cb13bc7ff16c79ddfc75d082938fbaa36e1cdbf4 + checksum: e6dd39b2ef65f6e6257f1792c62e997273a06c3e72e05f082185d0b8dfd8972340f9d5452408183b4bf03bd68cbb2fb9da89e063f1ba98c287a38953491febec languageName: node linkType: hard @@ -5619,7 +5619,7 @@ __metadata: resolution: "@types/react-dom@npm:18.2.7" dependencies: "@types/react": "npm:*" - checksum: e02ea908289a7ad26053308248d2b87f6aeafd73d0e2de2a3d435947bcea0422599016ffd1c3e38ff36c42f5e1c87c7417f05b0a157e48649e4a02f21727d54f + checksum: 9b70ef66cbe2d2898ea37eb79ee3697e0e4ad3d950e769a601f79be94097d43b8ef45b98a0b29528203c7d731c81666f637b2b7032deeced99214b4bc0662614 languageName: node linkType: hard @@ -5628,7 +5628,7 @@ __metadata: resolution: "@types/react-syntax-highlighter@npm:15.5.7" dependencies: "@types/react": "npm:*" - checksum: 1918d01baaa9bf485093fb04167d0dc87131be708bd68d32d3f614c0e7dba05de765fc62df139fa1972836b13e27983a2d89552eda5b5a38691a4ec300949648 + checksum: d5dbfd41cb3574cef6005ec112ede51a3c0a1bada281a1c4d967b52e5a044dd8fa130a59de77e23f65b1247e553c0a40ea76d378f29d60b9fd552ec1efc444c8 languageName: node linkType: hard @@ -5639,7 +5639,7 @@ __metadata: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: a6a5e8cc78f486b9020d1ad009aa6c56943c68c7c6376e0f8399e9cbcd950b7b8f5d73f00200f5379f5e58d31d57d8aed24357f301d8e86108cd438ce6c8b3dd + checksum: 9a8e9a6e6d39dba32a449ac986add435ee30d1f5af336efa7b0cb0e8e31eefa2b85ab2ef921284b373e820c47d184c7161f826cc77f1e528cc13642be3596110 languageName: node linkType: hard @@ -5650,7 +5650,7 @@ __metadata: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: e752df961105e5127652460504785897ca6e77259e0da8f233f694f9e8f451cde7fa0709d4456ade0ff600c8ce909cfe29f9b08b9c247fa9b734e126ec53edd7 + checksum: 7a752e6c5e76139f258bc14827d2c574bb76d6e7eb1b240f24f79b269153cb88668c34ba7078d3de99ec1973b7022e1f788e71117bd52a287f382d24bb80be40 languageName: node linkType: hard @@ -5671,7 +5671,7 @@ __metadata: "@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4": version: 7.5.0 resolution: "@types/semver@npm:7.5.0" - checksum: 0a64b9b9c7424d9a467658b18dd70d1d781c2d6f033096a6e05762d20ebbad23c1b69b0083b0484722aabf35640b78ccc3de26368bcae1129c87e9df028a22e2 + checksum: 8fbfbf79e9c14c3c20160a42145a146cba44d9763d0fac78358b394dc36e41bc2590bc4f0129c6fcbbc9b30f12ea1ba821bfe84b29dc80897f315cc7dd251393 languageName: node linkType: hard @@ -5681,7 +5681,7 @@ __metadata: dependencies: "@types/mime": "npm:^1" "@types/node": "npm:*" - checksum: 10b620a5960058ef009afbc17686f680d6486277c62f640845381ec4baa0ea683fdd77c3afea4803daf5fcddd3fb2972c8aa32e078939f1d4e96f83195c89793 + checksum: 6420837887858f7aa82f2c0272f73edb42385bd0978f43095e83590a405d86c8cc6d918c30b2d542f1d8bddc9f3d16c2e8fdfca936940de71b97c45f228d1896 languageName: node linkType: hard @@ -5692,7 +5692,7 @@ __metadata: "@types/http-errors": "npm:*" "@types/mime": "npm:*" "@types/node": "npm:*" - checksum: 15c261dbfc57890f7cc17c04d5b22b418dfa0330c912b46c5d8ae2064da5d6f844ef7f41b63c7f4bbf07675e97ebe6ac804b032635ec742ae45d6f1274259b3e + checksum: d5f8f5aaa765be6417aa3f2ebe36591f4e9d2d8a7480edf7d3db041427420fd565cb921fc021271098dd2afafce2b443fc0d978faa3ae21a2a58ebde7d525e9e languageName: node linkType: hard @@ -5708,14 +5708,14 @@ __metadata: resolution: "@types/testing-library__jest-dom@npm:5.14.8" dependencies: "@types/jest": "npm:*" - checksum: 18f5ba7d0db8ebd91667b544537762ce63f11c4fd02b3d57afa92f9457a384d3ecf9bc7b50b6b445af1b3ea38b69862b4f95130720d4dd23621d598ac074d93a + checksum: 26d768b3de5c71ecef683aa0e968ec2bb7f4626d78718132fa5a9c2064f9237836135e2551aa048c728407760d51d985a9d58a14528f2679a35d18d5ca200f08 languageName: node linkType: hard "@types/tough-cookie@npm:*": version: 4.0.2 resolution: "@types/tough-cookie@npm:4.0.2" - checksum: e055556ffdaa39ad85ede0af192c93f93f986f4bd9e9426efdc2948e3e2632db3a4a584d4937dbf6d7620527419bc99e6182d3daf2b08685e710f2eda5291905 + checksum: 8682b4062959c15c0521361825839e10d374344fa84166ee0b731b815ac7b79a942f6e9192fad6383d69df2251021678c86c46748ff69c61609934a3e27472f2 languageName: node linkType: hard @@ -5743,7 +5743,7 @@ __metadata: "@types/yargs-parser@npm:*": version: 21.0.0 resolution: "@types/yargs-parser@npm:21.0.0" - checksum: b2f4c8d12ac18a567440379909127cf2cec393daffb73f246d0a25df36ea983b93b7e9e824251f959e9f928cbc7c1aab6728d0a0ff15d6145f66cec2be67d9a2 + checksum: c4caec730c1ee09466588389ba4ac83d85a01423c539b9565bb5b5a084bff3f4e47bfb7c06e963c0ef8d4929cf6fca0bc2923a33ef16727cdba60e95c8cdd0d0 languageName: node linkType: hard @@ -5752,7 +5752,7 @@ __metadata: resolution: "@types/yargs@npm:16.0.5" dependencies: "@types/yargs-parser": "npm:*" - checksum: 22697f7cc8aa32dcc10981a87f035e183303a58351c537c81fb450270d5c494b1d918186210e445b0eb2e4a8b34a8bda2a595f346bdb1c9ed2b63d193cb00430 + checksum: 9673a69487768dad14e805777bca262f7a5774d3a0964981105ffc04ff95e754f1109fa2c8210a0fe863f263c580ddf667e1345f22e018036513245b3dc3c71c languageName: node linkType: hard @@ -5761,7 +5761,7 @@ __metadata: resolution: "@types/yargs@npm:17.0.24" dependencies: "@types/yargs-parser": "npm:*" - checksum: 5f3ac4dc4f6e211c1627340160fbe2fd247ceba002190da6cf9155af1798450501d628c9165a183f30a224fc68fa5e700490d740ff4c73e2cdef95bc4e8ba7bf + checksum: 03d9a985cb9331b2194a52d57a66aad88bf46aa32b3968a71cc6f39fb05c74f0709f0dd3aa9c0b29099cfe670343e3b1bd2ac6df2abfab596ede4453a616f63f languageName: node linkType: hard @@ -5785,7 +5785,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 3ea842ef9615e298e28c6687c4dc285577ea0995944410553b3ca514ce9d437534b6e89114e9398c1a370324afe7a4a251c8c49540bb3bf13dcadde9ada3ecc2 + checksum: db712a503aefb1153ea96ba14f0ec0f1dce4d15327230e52ce9bbbf04da7daa3c1baa1da929e6e130ebbee08ff3c354a1919645664f7edffe1ad614dcf4bf0bc languageName: node linkType: hard @@ -5802,7 +5802,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: db61a12a67bc45d814297e7f089768c0849f18162b330279aa15121223ec3b18d80df4c327f4ca0a40a7bddb9150ba1a9379fce00bc0e4a10cc189d04e36f0e3 + checksum: 3f8e14057574282dbbe846696cef90853c301bde2b59001ca4e885340bbf9fd900c3a921d39511d4f1bc3af1f6dc8807dd748294f7e97978e7da83d3bb392ef1 languageName: node linkType: hard @@ -5812,7 +5812,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:5.57.1" "@typescript-eslint/visitor-keys": "npm:5.57.1" - checksum: 4f03d54372f0591fbc5f6e0267a6f1b73e3012e8a319c1893829e0b8e71f882e17a696995dc8b11e700162daf74444fd2d8f55dba314e1a95221a9d3eabcfb2b + checksum: 724302b4fa4de8b19b9d56ce3f827bd4478f34b7c2b09893e044e9dcc7efc064a5446d4da7170d1c84eef2005e43171e90983fc50e20c235a94abf0ce38a7646 languageName: node linkType: hard @@ -5822,7 +5822,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:5.62.0" "@typescript-eslint/visitor-keys": "npm:5.62.0" - checksum: 6062d6b797fe1ce4d275bb0d17204c827494af59b5eaf09d8a78cdd39dadddb31074dded4297aaf5d0f839016d601032857698b0e4516c86a41207de606e9573 + checksum: e827770baa202223bc0387e2fd24f630690809e460435b7dc9af336c77322290a770d62bd5284260fa881c86074d6a9fd6c97b07382520b115f6786b8ed499da languageName: node linkType: hard @@ -5839,21 +5839,21 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 06fab95315fc1ffdaaa011e6ec1ae538826ef3d9b422e2c926dbe9b83e55d9e8bdaa07c43317a4c0a59b40a24c5c48a7c8284e6a18780475a65894b1b949fc23 + checksum: 228b5ee4249c1fbd02746deb6eaddbaa374aae732da85af9c42fce2b07f336d00cbe76f8c85a99cb51bdd94a8db8fba16e2e4b468518094ec3bf0b228271ccca languageName: node linkType: hard "@typescript-eslint/types@npm:5.57.1": version: 5.57.1 resolution: "@typescript-eslint/types@npm:5.57.1" - checksum: 21789eb697904bbb44a18df961d5918e7c5bd90c79df3a8b8b835da81d0c0f42c7eeb2d05f77cafe49a7367ae7f549a0c8281656ea44b6dc56ae1bf19a3a1eae + checksum: 8451a99e5470956528f3f82a58da964555c4e2db9cf2be3fc566c1a951f06f700313bb2ed3f01ffe00d152be4d446ebe762368cfcf6dc0a0f8c6a02dfd768597 languageName: node linkType: hard "@typescript-eslint/types@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/types@npm:5.62.0" - checksum: 48c87117383d1864766486f24de34086155532b070f6264e09d0e6139449270f8a9559cfef3c56d16e3bcfb52d83d42105d61b36743626399c7c2b5e0ac3b670 + checksum: 24e8443177be84823242d6729d56af2c4b47bfc664dd411a1d730506abf2150d6c31bdefbbc6d97c8f91043e3a50e0c698239dcb145b79bb6b0c34469aaf6c45 languageName: node linkType: hard @@ -5871,7 +5871,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: bf96520f6de562838a40c3f009fc61fbee5369621071cd0d1dba4470b2b2f746cf79afe4ffa3fbccb8913295a2fbb3d89681d5178529e8da4987c46ed4e5cbed + checksum: 32d6d2f801994dab3c8f33f3f919d8bc8f11971bd78a71507bc304ab2001be6ce61fce23c61310960be1906c431731ba75c5d7e6c31eff7436047b41b4f3264b languageName: node linkType: hard @@ -5889,7 +5889,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 3624520abb5807ed8f57b1197e61c7b1ed770c56dfcaca66372d584ff50175225798bccb701f7ef129d62c5989070e1ee3a0aa2d84e56d9524dcf011a2bb1a52 + checksum: 06c975eb5f44b43bd19fadc2e1023c50cf87038fe4c0dd989d4331c67b3ff509b17fa60a3251896668ab4d7322bdc56162a9926971218d2e1a1874d2bef9a52e languageName: node linkType: hard @@ -5907,7 +5907,7 @@ __metadata: semver: "npm:^7.3.7" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 12e55144c8087f4e8f0f22e5693f3901b81bb7899dec42c7bfe540ac672a802028b688884bb43bd67bcf3cd3546a7205d207afcd948c731c19f551ea61267205 + checksum: 774688ff8c50f3d1d7f810ed881a59d4f342a2aac3448816df4e192ed8d4c90f2cde2b3a4b60e2095a399274337c623abefa0c36e5c525854e3a9848d36187ee languageName: node linkType: hard @@ -5925,7 +5925,7 @@ __metadata: semver: "npm:^7.3.7" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: ee9398c8c5db6d1da09463ca7bf36ed134361e20131ea354b2da16a5fdb6df9ba70c62a388d19f6eebb421af1786dbbd79ba95ddd6ab287324fc171c3e28d931 + checksum: 15ef13e43998a082b15f85db979f8d3ceb1f9ce4467b8016c267b1738d5e7cdb12aa90faf4b4e6dd6486c236cf9d33c463200465cf25ff997dbc0f12358550a1 languageName: node linkType: hard @@ -5935,7 +5935,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:5.57.1" eslint-visitor-keys: "npm:^3.3.0" - checksum: d187dfac044b7c0f24264a9ba5eebcf6651412d840b4aaba8eacabff7e771babcd67c738525b1f7c9eb8c94b7edfe7658f6de99f5fdc9745e409c538c1374674 + checksum: 46670fd2ef7c623bb376fb54553095de0cf24691365cb0c8209492d14df90d5514cc9dc9786be8c1eb27fad5b12f0ef6fc3ae59811107ca98d6c506179378f70 languageName: node linkType: hard @@ -5945,7 +5945,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:5.62.0" eslint-visitor-keys: "npm:^3.3.0" - checksum: 976b05d103fe8335bef5c93ad3f76d781e3ce50329c0243ee0f00c0fcfb186c81df50e64bfdd34970148113f8ade90887f53e3c4938183afba830b4ba8e30a35 + checksum: dc613ab7569df9bbe0b2ca677635eb91839dfb2ca2c6fa47870a5da4f160db0b436f7ec0764362e756d4164e9445d49d5eb1ff0b87f4c058946ae9d8c92eb388 languageName: node linkType: hard @@ -5959,7 +5959,7 @@ __metadata: react-refresh: "npm:^0.14.0" peerDependencies: vite: ^4.2.0 - checksum: 575298f66517c51348892d49b302490c48e15c9ddb0b2c5f710931804e559dceafca1be1e62cb72d0902cba5f3c98e4b1272970d328e3a62d59ecdf976e68d3d + checksum: 9e7378621cb7e4dacd7277cd83b55382febdd3ff4c8a47793895caa8bfe3ce42c3ebe4e4cc49c29b53846d28c2796cf32c5727a3f9e784f7855f4421a80fcf42 languageName: node linkType: hard @@ -5974,7 +5974,7 @@ __metadata: react-refresh: "npm:^0.14.0" peerDependencies: vite: ^4.1.0-beta.0 - checksum: 450fac79e67cba9e1581c860f78e687b44108ab4117663ef20db279316e03cd8e87f94fef376e27cc5e200bd52813dcc09b70ea570c7c7cc291fcd47eb260fbc + checksum: 54baf15170faed08c5c050ed6ac3b071e743d703f2c26ae685bf362bbaa2d8a733a98af0639f0662d474d95a6d91d008da9de8f3a51cc3e6660c4e642399cf2c languageName: node linkType: hard @@ -5985,7 +5985,7 @@ __metadata: tslib: "npm:^2.4.0" peerDependencies: esbuild: ">=0.10.0" - checksum: 04da15355a99773b441742814ba4d0f3453a83df47aa07e215f167e156f109ab8e971489c8b1a4ddf3c79d568d35213f496ad52e97298228597e1aacc22680aa + checksum: 454f521088c1fa24fda51f83ca4a50ba6e3bd147e5dee8c899e6bf24a7196186532c3abb18480e83395708ffb7238c9cac5b82595c3985ce93593b5afbd0a9f0 languageName: node linkType: hard @@ -5993,9 +5993,9 @@ __metadata: version: 2.10.3 resolution: "@yarnpkg/fslib@npm:2.10.3" dependencies: - "@yarnpkg/libzip": ^2.3.0 - tslib: ^1.13.0 - checksum: 0ca693f61d47bcf165411a121ed9123f512b1b5bfa5e1c6c8f280b4ffdbea9bf2a6db418f99ecfc9624587fdc695b2b64eb0fe7b4028e44095914b25ca99655e + "@yarnpkg/libzip": "npm:^2.3.0" + tslib: "npm:^1.13.0" + checksum: 29b38bd2054e3ec14677c16321a20ed69ac41d9d6f2fee7d9d7bc0a5a737e6d94add79cfa5f6ab867b5a98ab6aa2df3b53cb34f81159907cc308576a7bc08c67 languageName: node linkType: hard @@ -6003,23 +6003,23 @@ __metadata: version: 2.3.0 resolution: "@yarnpkg/libzip@npm:2.3.0" dependencies: - "@types/emscripten": ^1.39.6 - tslib: ^1.13.0 - checksum: 533a4883f69bb013f955d80dc19719881697e6849ea5f0cbe6d87ef1d582b05cbae8a453802f92ad0c852f976296cac3ff7834be79a7e415b65cdf213e448110 + "@types/emscripten": "npm:^1.39.6" + tslib: "npm:^1.13.0" + checksum: 0eb147f39eab2830c29120d17e8bfba5aa15dedb940a7378070c67d4de08e9ba8d34068522e15e6b4db94ecaed4ad520e1e517588a36a348d1aa160bc36156ea languageName: node linkType: hard "abab@npm:^2.0.6": version: 2.0.6 resolution: "abab@npm:2.0.6" - checksum: 6ffc1af4ff315066c62600123990d87551ceb0aafa01e6539da77b0f5987ac7019466780bf480f1787576d4385e3690c81ccc37cfda12819bf510b8ab47e5a3e + checksum: ebe95d7278999e605823fc515a3b05d689bc72e7f825536e73c95ebf621636874c6de1b749b3c4bf866b96ccd4b3a2802efa313d0e45ad51a413c8c73247db20 languageName: node linkType: hard "abbrev@npm:^1.0.0": version: 1.1.1 resolution: "abbrev@npm:1.1.1" - checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 + checksum: 2d882941183c66aa665118bafdab82b7a177e9add5eb2776c33e960a4f3c89cff88a1b38aba13a456de01d0dd9d66a8bea7c903268b21ea91dd1097e1e2e8243 languageName: node linkType: hard @@ -6029,7 +6029,7 @@ __metadata: dependencies: mime-types: "npm:~2.1.34" negotiator: "npm:0.6.3" - checksum: 50c43d32e7b50285ebe84b613ee4a3aa426715a7d131b65b786e2ead0fd76b6b60091b9916d3478a75f11f162628a2139991b6c03ab3f1d9ab7c86075dc8eab4 + checksum: 67eaaa90e2917c58418e7a9b89392002d2b1ccd69bcca4799135d0c632f3b082f23f4ae4ddeedbced5aa59bcc7bdf4699c69ebed4593696c922462b7bc5744d6 languageName: node linkType: hard @@ -6048,21 +6048,21 @@ __metadata: resolution: "acorn-jsx@npm:5.3.2" peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950 + checksum: d4371eaef7995530b5b5ca4183ff6f062ca17901a6d3f673c9ac011b01ede37e7a1f7f61f8f5cfe709e88054757bb8f3277dc4061087cdf4f2a1f90ccbcdb977 languageName: node linkType: hard "acorn-walk@npm:^7.2.0": version: 7.2.0 resolution: "acorn-walk@npm:7.2.0" - checksum: 9252158a79b9d92f1bc0dd6acc0fcfb87a67339e84bcc301bb33d6078936d27e35d606b4d35626d2962cd43c256d6f27717e70cbe15c04fff999ab0b2260b21f + checksum: 4d3e186f729474aed3bc3d0df44692f2010c726582655b20a23347bef650867655521c48ada444cb4fda241ee713dcb792da363ec74c6282fa884fb7144171bb languageName: node linkType: hard "acorn-walk@npm:^8.0.2": version: 8.2.0 resolution: "acorn-walk@npm:8.2.0" - checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 + checksum: e69f7234f2adfeb16db3671429a7c80894105bd7534cb2032acf01bb26e6a847952d11a062d071420b43f8d82e33d2e57f26fe87d9cce0853e8143d8910ff1de languageName: node linkType: hard @@ -6071,7 +6071,7 @@ __metadata: resolution: "acorn@npm:7.4.1" bin: acorn: bin/acorn - checksum: 1860f23c2107c910c6177b7b7be71be350db9e1080d814493fae143ae37605189504152d1ba8743ba3178d0b37269ce1ffc42b101547fdc1827078f82671e407 + checksum: 8be2a40714756d713dfb62544128adce3b7102c6eb94bc312af196c2cc4af76e5b93079bd66b05e9ca31b35a9b0ce12171d16bc55f366cafdb794fdab9d753ec languageName: node linkType: hard @@ -6080,7 +6080,7 @@ __metadata: resolution: "acorn@npm:8.10.0" bin: acorn: bin/acorn - checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d + checksum: 522310c20fdc3c271caed3caf0f06c51d61cb42267279566edd1d58e83dbc12eebdafaab666a0f0be1b7ad04af9c6bc2a6f478690a9e6391c3c8b165ada917dd languageName: node linkType: hard @@ -6089,7 +6089,7 @@ __metadata: resolution: "acorn@npm:8.11.3" bin: acorn: bin/acorn - checksum: 76d8e7d559512566b43ab4aadc374f11f563f0a9e21626dd59cb2888444e9445923ae9f3699972767f18af61df89cd89f5eaaf772d1327b055b45cb829b4a88c + checksum: b688e7e3c64d9bfb17b596e1b35e4da9d50553713b3b3630cf5690f2b023a84eac90c56851e6912b483fe60e8b4ea28b254c07e92f17ef83d72d78745a8352dd languageName: node linkType: hard @@ -6097,93 +6097,93 @@ __metadata: version: 0.0.0-use.local resolution: "adcm-web2@workspace:." dependencies: - "@babel/core": 7.21.8 - "@babel/preset-env": 7.21.5 - "@babel/preset-react": 7.18.6 - "@babel/preset-typescript": 7.21.5 - "@braintree/browser-detection": ^2.0.0 - "@floating-ui/dom": 1.2.9 - "@floating-ui/react": 0.24.2 - "@reduxjs/toolkit": 1.9.5 - "@storybook/addon-essentials": 7.6.7 - "@storybook/addon-interactions": 7.6.7 - "@storybook/addon-links": 7.6.7 - "@storybook/blocks": 7.6.7 - "@storybook/builder-vite": 7.6.7 - "@storybook/react": 7.6.7 - "@storybook/react-vite": 7.6.7 - "@storybook/testing-library": 0.2.2 - "@testing-library/dom": 9.3.0 - "@testing-library/jest-dom": 5.16.5 - "@testing-library/react": 14.0.0 - "@testing-library/user-event": 14.4.3 - "@types/jest": 29.5.2 - "@types/json-schema": ^7.0.12 - "@types/qs": 6.9.7 - "@types/react": 18.0.28 - "@types/react-copy-to-clipboard": 5.0.4 - "@types/react-dom": 18.0.11 - "@types/react-syntax-highlighter": 15.5.7 - "@typescript-eslint/eslint-plugin": 5.57.1 - "@typescript-eslint/parser": 5.57.1 - "@vitejs/plugin-react": 4.0.0 - ajv: ^8.12.0 - axios: 1.4.0 - classnames: 2.3.2 - date-fns: 2.30.0 - eslint: 8.38.0 - eslint-config-prettier: 8.8.0 - eslint-plugin-import: 2.27.5 - eslint-plugin-jsx-a11y: 6.7.1 - eslint-plugin-prettier: 4.2.1 - eslint-plugin-react: 7.32.2 - eslint-plugin-react-hooks: 4.6.0 - eslint-plugin-react-refresh: 0.3.4 - eslint-plugin-spellcheck: 0.0.20 - eslint-plugin-storybook: 0.6.12 - html-react-parser: 4.2.1 - husky: 8.0.3 - identity-obj-proxy: 3.0.0 - jest: 29.5.0 - jest-environment-jsdom: 29.5.0 - js-base64: 3.7.5 - json-schema: 0.4.0 - prettier: 2.8.8 - prop-types: 15.8.1 - qs: 6.11.2 - react: 18.2.0 - react-collapsed: 4.0.2 - react-copy-to-clipboard: 5.1.0 - react-dom: 18.2.0 - react-json-view-compare: ^2.0.2 - react-merge-refs: 2.0.2 - react-redux: 8.1.1 - react-router-dom: 6.11.2 - react-syntax-highlighter: 15.5.0 - redux: 4.2.1 - sass: 1.62.1 - storybook: 7.6.7 - typescript: 5.0.2 - vite: 4.4.1 - vite-plugin-eslint: 1.8.1 - vite-plugin-react-remove-attributes: 1.0.3 - vite-plugin-svg-sprite: 0.3.2 - vite-plugin-svgr: 3.2.0 - vite-tsconfig-paths: 4.2.0 + "@babel/core": "npm:7.21.8" + "@babel/preset-env": "npm:7.21.5" + "@babel/preset-react": "npm:7.18.6" + "@babel/preset-typescript": "npm:7.21.5" + "@braintree/browser-detection": "npm:^2.0.0" + "@floating-ui/dom": "npm:1.2.9" + "@floating-ui/react": "npm:0.24.2" + "@reduxjs/toolkit": "npm:1.9.5" + "@storybook/addon-essentials": "npm:7.6.7" + "@storybook/addon-interactions": "npm:7.6.7" + "@storybook/addon-links": "npm:7.6.7" + "@storybook/blocks": "npm:7.6.7" + "@storybook/builder-vite": "npm:7.6.7" + "@storybook/react": "npm:7.6.7" + "@storybook/react-vite": "npm:7.6.7" + "@storybook/testing-library": "npm:0.2.2" + "@testing-library/dom": "npm:9.3.0" + "@testing-library/jest-dom": "npm:5.16.5" + "@testing-library/react": "npm:14.0.0" + "@testing-library/user-event": "npm:14.4.3" + "@types/jest": "npm:29.5.2" + "@types/json-schema": "npm:^7.0.12" + "@types/qs": "npm:6.9.7" + "@types/react": "npm:18.0.28" + "@types/react-copy-to-clipboard": "npm:5.0.4" + "@types/react-dom": "npm:18.0.11" + "@types/react-syntax-highlighter": "npm:15.5.7" + "@typescript-eslint/eslint-plugin": "npm:5.57.1" + "@typescript-eslint/parser": "npm:5.57.1" + "@vitejs/plugin-react": "npm:4.0.0" + ajv: "npm:^8.12.0" + axios: "npm:1.4.0" + classnames: "npm:2.3.2" + date-fns: "npm:2.30.0" + eslint: "npm:8.38.0" + eslint-config-prettier: "npm:8.8.0" + eslint-plugin-import: "npm:2.27.5" + eslint-plugin-jsx-a11y: "npm:6.7.1" + eslint-plugin-prettier: "npm:4.2.1" + eslint-plugin-react: "npm:7.32.2" + eslint-plugin-react-hooks: "npm:4.6.0" + eslint-plugin-react-refresh: "npm:0.3.4" + eslint-plugin-spellcheck: "npm:0.0.20" + eslint-plugin-storybook: "npm:0.6.12" + html-react-parser: "npm:4.2.1" + husky: "npm:8.0.3" + identity-obj-proxy: "npm:3.0.0" + jest: "npm:29.5.0" + jest-environment-jsdom: "npm:29.5.0" + js-base64: "npm:3.7.5" + json-schema: "npm:0.4.0" + prettier: "npm:2.8.8" + prop-types: "npm:15.8.1" + qs: "npm:6.11.2" + react: "npm:18.2.0" + react-collapsed: "npm:4.0.2" + react-copy-to-clipboard: "npm:5.1.0" + react-dom: "npm:18.2.0" + react-json-view-compare: "npm:^2.0.2" + react-merge-refs: "npm:2.0.2" + react-redux: "npm:8.1.1" + react-router-dom: "npm:6.11.2" + react-syntax-highlighter: "npm:15.5.0" + redux: "npm:4.2.1" + sass: "npm:1.62.1" + storybook: "npm:7.6.7" + typescript: "npm:5.0.2" + vite: "npm:4.4.1" + vite-plugin-eslint: "npm:1.8.1" + vite-plugin-react-remove-attributes: "npm:1.0.3" + vite-plugin-svg-sprite: "npm:0.3.2" + vite-plugin-svgr: "npm:3.2.0" + vite-tsconfig-paths: "npm:4.2.0" languageName: unknown linkType: soft "address@npm:^1.0.1": version: 1.2.2 resolution: "address@npm:1.2.2" - checksum: ace439960c1e3564d8f523aff23a841904bf33a2a7c2e064f7f60a064194075758b9690e65bd9785692a4ef698a998c57eb74d145881a1cecab8ba658ddb1607 + checksum: 57d80a0c6ccadc8769ad3aeb130c1599e8aee86a8d25f671216c40df9b8489d6c3ef879bc2752b40d1458aa768f947c2d91e5b2fedfe63cf702c40afdfda9ba9 languageName: node linkType: hard "agent-base@npm:5": version: 5.1.1 resolution: "agent-base@npm:5.1.1" - checksum: 61ae789f3019f1dc10e8cba6d3ae9826949299a4e54aaa1cfa2fa37c95a108e70e95423b963bb987d7891a703fd9a5c383a506f4901819f3ee56f3147c0aa8ab + checksum: 82954db5dccdccccf52c4b7f548394a696accd259d564bfb325fb02586aaaa9df96f5d50bb19134923fe5ff9c21195e7a88871bf4e086cca9014a549a0ba2a5f languageName: node linkType: hard @@ -6192,7 +6192,7 @@ __metadata: resolution: "agent-base@npm:6.0.2" dependencies: debug: "npm:4" - checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d + checksum: 21fb903e0917e5cb16591b4d0ef6a028a54b83ac30cd1fca58dece3d4e0990512a8723f9f83130d88a41e2af8b1f7be1386fda3ea2d181bb1a62155e75e95e23 languageName: node linkType: hard @@ -6203,7 +6203,7 @@ __metadata: debug: "npm:^4.1.0" depd: "npm:^2.0.0" humanize-ms: "npm:^1.2.1" - checksum: 982453aa44c11a06826c836025e5162c846e1200adb56f2d075400da7d32d87021b3b0a58768d949d824811f5654223d5a8a3dad120921a2439625eb847c6260 + checksum: f791317eb4b42278d094547669b9b745e19e5d783bb42a8695820c94098ef18fc99f9d2777b5871cae76d761e45b0add8e6703e044de5d74d47181038ec7b536 languageName: node linkType: hard @@ -6225,7 +6225,7 @@ __metadata: fast-json-stable-stringify: "npm:^2.0.0" json-schema-traverse: "npm:^0.4.1" uri-js: "npm:^4.2.2" - checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4 + checksum: 48d6ad21138d12eb4d16d878d630079a2bda25a04e745c07846a4ad768319533031e28872a9b3c5790fa1ec41aabdf2abed30a56e5a03ebc2cf92184b8ee306c languageName: node linkType: hard @@ -6237,7 +6237,7 @@ __metadata: json-schema-traverse: "npm:^1.0.0" require-from-string: "npm:^2.0.2" uri-js: "npm:^4.2.2" - checksum: 4dc13714e316e67537c8b31bc063f99a1d9d9a497eb4bbd55191ac0dcd5e4985bbb71570352ad6f1e76684fb6d790928f96ba3b2d4fd6e10024be9612fe3f001 + checksum: b406f3b79b5756ac53bfe2c20852471b08e122bc1ee4cde08ae4d6a800574d9cd78d60c81c69c63ff81e4da7cd0b638fafbb2303ae580d49cf1600b9059efb85 languageName: node linkType: hard @@ -6246,7 +6246,7 @@ __metadata: resolution: "ansi-escapes@npm:4.3.2" dependencies: type-fest: "npm:^0.21.3" - checksum: 93111c42189c0a6bed9cdb4d7f2829548e943827ee8479c74d6e0b22ee127b2a21d3f8b5ca57723b8ef78ce011fbfc2784350eb2bde3ccfccf2f575fa8489815 + checksum: 8661034456193ffeda0c15c8c564a9636b0c04094b7f78bd01517929c17c504090a60f7a75f949f5af91289c264d3e1001d91492c1bd58efc8e100500ce04de2 languageName: node linkType: hard @@ -6292,7 +6292,7 @@ __metadata: resolution: "ansi-styles@npm:4.3.0" dependencies: color-convert: "npm:^2.0.1" - checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 + checksum: b4494dfbfc7e4591b4711a396bd27e540f8153914123dccb4cdbbcb514015ada63a3809f362b9d8d4f6b17a706f1d7bea3c6f974b15fa5ae76b5b502070889ff languageName: node linkType: hard @@ -6306,7 +6306,7 @@ __metadata: "ansi-styles@npm:^6.1.0": version: 6.2.1 resolution: "ansi-styles@npm:6.2.1" - checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 + checksum: 70fdf883b704d17a5dfc9cde206e698c16bcd74e7f196ab821511651aee4f9f76c9514bdfa6ca3a27b5e49138b89cb222a28caf3afe4567570139577f991df32 languageName: node linkType: hard @@ -6330,7 +6330,7 @@ __metadata: "aproba@npm:^1.0.3 || ^2.0.0": version: 2.0.0 resolution: "aproba@npm:2.0.0" - checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 + checksum: c2b9a631298e8d6f3797547e866db642f68493808f5b37cd61da778d5f6ada890d16f668285f7d60bd4fc3b03889bd590ffe62cf81b700e9bb353431238a0a7b languageName: node linkType: hard @@ -6340,7 +6340,7 @@ __metadata: dependencies: delegates: "npm:^1.0.0" readable-stream: "npm:^3.6.0" - checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 + checksum: 390731720e1bf9ed5d0efc635ea7df8cbc4c90308b0645a932f06e8495a0bf1ecc7987d3b97e805f62a17d6c4b634074b25200aa4d149be2a7b17250b9744bc4 languageName: node linkType: hard @@ -6349,14 +6349,14 @@ __metadata: resolution: "argparse@npm:1.0.10" dependencies: sprintf-js: "npm:~1.0.2" - checksum: 7ca6e45583a28de7258e39e13d81e925cfa25d7d4aacbf806a382d3c02fcb13403a07fb8aeef949f10a7cfe4a62da0e2e807b348a5980554cc28ee573ef95945 + checksum: c6a621343a553ff3779390bb5ee9c2263d6643ebcd7843227bdde6cc7adbed796eb5540ca98db19e3fd7b4714e1faa51551f8849b268bb62df27ddb15cbcd91e languageName: node linkType: hard "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" - checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced + checksum: 18640244e641a417ec75a9bd38b0b2b6b95af5199aa241b131d4b2fb206f334d7ecc600bd194861610a5579084978bfcbb02baa399dbe442d56d0ae5e60dbaef languageName: node linkType: hard @@ -6365,7 +6365,7 @@ __metadata: resolution: "aria-hidden@npm:1.2.3" dependencies: tslib: "npm:^2.0.0" - checksum: 7d7d211629eef315e94ed3b064c6823d13617e609d3f9afab1c2ed86399bb8e90405f9bdd358a85506802766f3ecb468af985c67c846045a34b973bcc0289db9 + checksum: cd7f8474f1bef2dadce8fc74ef6d0fa8c9a477ee3c9e49fc3698e5e93a62014140c520266ee28969d63b5ab474144fe48b6182d010feb6a223f7a73928e6660a languageName: node linkType: hard @@ -6374,7 +6374,7 @@ __metadata: resolution: "aria-query@npm:5.1.3" dependencies: deep-equal: "npm:^2.0.5" - checksum: 929ff95f02857b650fb4cbcd2f41072eee2f46159a6605ea03bf63aa572e35ffdff43d69e815ddc462e16e07de8faba3978afc2813650b4448ee18c9895d982b + checksum: e5da608a7c4954bfece2d879342b6c218b6b207e2d9e5af270b5e38ef8418f02d122afdc948b68e32649b849a38377785252059090d66fa8081da95d1609c0d2 languageName: node linkType: hard @@ -6383,7 +6383,7 @@ __metadata: resolution: "aria-query@npm:5.3.0" dependencies: dequal: "npm:^2.0.3" - checksum: 305bd73c76756117b59aba121d08f413c7ff5e80fa1b98e217a3443fcddb9a232ee790e24e432b59ae7625aebcf4c47cb01c2cac872994f0b426f5bdfcd96ba9 + checksum: c3e1ed127cc6886fea4732e97dd6d3c3938e64180803acfb9df8955517c4943760746ffaf4020ce8f7ffaa7556a3b5f85c3769a1f5ca74a1288e02d042f9ae4e languageName: node linkType: hard @@ -6421,7 +6421,7 @@ __metadata: "array-flatten@npm:1.1.1": version: 1.1.1 resolution: "array-flatten@npm:1.1.1" - checksum: a9925bf3512d9dce202112965de90c222cd59a4fbfce68a0951d25d965cf44642931f40aac72309c41f12df19afa010ecadceb07cfff9ccc1621e99d89ab5f3b + checksum: e13c9d247241be82f8b4ec71d035ed7204baa82fae820d4db6948d30d3c4a9f2b3905eb2eec2b937d4aa3565200bd3a1c500480114cff649fa748747d2a50feb languageName: node linkType: hard @@ -6434,7 +6434,7 @@ __metadata: es-abstract: "npm:^1.20.4" get-intrinsic: "npm:^1.1.3" is-string: "npm:^1.0.7" - checksum: f22f8cd8ba8a6448d91eebdc69f04e4e55085d09232b5216ee2d476dab3ef59984e8d1889e662c6a0ed939dcb1b57fd05b2c0209c3370942fc41b752c82a2ca5 + checksum: a7168bd16821ec76b95a8f50f73076577a7cbd6c762452043d2b978c8a5fa4afe4f98a025d6f1d5c971b8d0b440b4ee73f6a57fc45382c858b8e17c275015428 languageName: node linkType: hard @@ -6460,7 +6460,7 @@ __metadata: define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" es-shim-unscopables: "npm:^1.0.0" - checksum: 5a8415949df79bf6e01afd7e8839bbde5a3581300e8ad5d8449dea52639e9e59b26a467665622783697917b43bf39940a6e621877c7dd9b3d1c1f97484b9b88b + checksum: 787bd3e93887b1c12cfed018864cb819a4fe361728d4aadc7b401b0811cf923121881cca369557432529ffa803a463f01e37eaa4b52e4c13bc574c438cd615cb languageName: node linkType: hard @@ -6472,7 +6472,7 @@ __metadata: define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" es-shim-unscopables: "npm:^1.0.0" - checksum: 8c1c43a4995f12cf12523436da28515184c753807b3f0bc2ca6c075f71c470b099e2090cc67dba8e5280958fea401c1d0c59e1db0143272aef6cd1103921a987 + checksum: f1f3d8e0610afce06a8622295b4843507dfc2fbbd2c2b2a8d541d9f42871747393c3099d630a3f8266ca086b97b089687db64cd86b6eb7e270ebc8f767eec9fc languageName: node linkType: hard @@ -6485,7 +6485,7 @@ __metadata: es-abstract: "npm:^1.20.4" es-shim-unscopables: "npm:^1.0.0" get-intrinsic: "npm:^1.1.3" - checksum: 7923324a67e70a2fc0a6e40237405d92395e45ebd76f5cb89c2a5cf1e66b47aca6baacd0cd628ffd88830b90d47fff268071493d09c9ae123645613dac2c2ca3 + checksum: 23e86074d0dda9260aaa137ec45ae5a8196916ee3f256e41665381f120fdb5921bd84ad93eeba8d0234e5cd355093049585167ba2307fde340e5cee15b12415d languageName: node linkType: hard @@ -6497,7 +6497,7 @@ __metadata: is-nan: "npm:^1.2.1" object-is: "npm:^1.0.1" util: "npm:^0.12.0" - checksum: bb91f181a86d10588ee16c5e09c280f9811373974c29974cbe401987ea34e966699d7989a812b0e19377b511ea0bc627f5905647ce569311824848ede382cae8 + checksum: 5bd5e80a0dc5fce9ac812254ad39bcec8c224878705e5021a1a0ae84e2c30b980f90584ef544a5f6b1cd79edb002e80972367731260dac723c7a6f76e0fcd2ea languageName: node linkType: hard @@ -6505,12 +6505,12 @@ __metadata: version: 2.1.0 resolution: "assert@npm:2.1.0" dependencies: - call-bind: ^1.0.2 - is-nan: ^1.3.2 - object-is: ^1.1.5 - object.assign: ^4.1.4 - util: ^0.12.5 - checksum: 1ed1cabba9abe55f4109b3f7292b4e4f3cf2953aad8dc148c0b3c3bd676675c31b1abb32ef563b7d5a19d1715bf90d1e5f09fad2a4ee655199468902da80f7c2 + call-bind: "npm:^1.0.2" + is-nan: "npm:^1.3.2" + object-is: "npm:^1.1.5" + object.assign: "npm:^4.1.4" + util: "npm:^0.12.5" + checksum: 6b9d813c8eef1c0ac13feac5553972e4bd180ae16000d4eb5c0ded2489188737c75a5aacefc97a985008b37502f62fe1bad34da1a7481a54bbfabec3964c8aa7 languageName: node linkType: hard @@ -6524,7 +6524,7 @@ __metadata: "ast-types-flow@npm:^0.0.7": version: 0.0.7 resolution: "ast-types-flow@npm:0.0.7" - checksum: a26dcc2182ffee111cad7c471759b0bda22d3b7ebacf27c348b22c55f16896b18ab0a4d03b85b4020dce7f3e634b8f00b593888f622915096ea1927fa51866c4 + checksum: 663b90e99b56ee2d7f736a6b6fff8b3c5404f28fa1860bb8d83ee5a9bff9e687520d0d6d9db6edff5a34fd4d3c0c11a3beb1cf75e43c9a880cca04371cc99808 languageName: node linkType: hard @@ -6533,7 +6533,7 @@ __metadata: resolution: "ast-types@npm:0.16.1" dependencies: tslib: "npm:^2.0.1" - checksum: 21c186da9fdb1d8087b1b7dabbc4059f91aa5a1e593a9776b4393cc1eaa857e741b2dda678d20e34b16727b78fef3ab59cf8f0c75ed1ba649c78fe194e5c114b + checksum: f569b475eb1c8cb93888cb6e7b7e36dc43fa19a77e4eb132cbff6e3eb1598ca60f850db6e60b070e5a0ee8c1559fca921dac0916e576f2f104e198793b0bdd8d languageName: node linkType: hard @@ -6547,14 +6547,14 @@ __metadata: "async@npm:^3.2.3": version: 3.2.4 resolution: "async@npm:3.2.4" - checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 + checksum: bebb5dc2258c45b83fa1d3be179ae0eb468e1646a62d443c8d60a45e84041b28fccebe1e2d1f234bfc3dcad44e73dcdbf4ba63d98327c9f6556e3dbd47c2ae8b languageName: node linkType: hard "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" - checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be + checksum: 3ce727cbc78f69d6a4722517a58ee926c8c21083633b1d3fdf66fd688f6c127a53a592141bd4866f9b63240a86e9d8e974b13919450bd17fa33c2d22c4558ad8 languageName: node linkType: hard @@ -6563,21 +6563,21 @@ __metadata: resolution: "atob@npm:2.1.2" bin: atob: bin/atob.js - checksum: dfeeeb70090c5ebea7be4b9f787f866686c645d9f39a0d184c817252d0cf08455ed25267d79c03254d3be1f03ac399992a792edcd5ffb9c91e097ab5ef42833a + checksum: 0624406cc0295533b38b60ab2e3b028aa7b8225f37e0cde6be3bc5c13a8015c889b192e874fd7660671179cef055f2e258855f372b0e495bd4096cf0b4785c25 languageName: node linkType: hard "available-typed-arrays@npm:^1.0.5": version: 1.0.5 resolution: "available-typed-arrays@npm:1.0.5" - checksum: 20eb47b3cefd7db027b9bbb993c658abd36d4edd3fe1060e83699a03ee275b0c9b216cc076ff3f2db29073225fb70e7613987af14269ac1fe2a19803ccc97f1a + checksum: 4d4d5e86ea0425696f40717882f66a570647b94ac8d273ddc7549a9b61e5da099e149bf431530ccbd776bd74e02039eb8b5edf426e3e2211ee61af16698a9064 languageName: node linkType: hard "axe-core@npm:^4.6.2": version: 4.7.2 resolution: "axe-core@npm:4.7.2" - checksum: 5d86fa0f45213b0e54cbb5d713ce885c4a8fe3a72b92dd915a47aa396d6fd149c4a87fec53aa978511f6d941402256cfeb26f2db35129e370f25a453c688655a + checksum: 1b94fcbe203296fc7174992a3d70dbcd477d88b933afa045aaffa1704fe63d8da8945e4b38fc576f9c7384abeb353e2d6607ab54d25b5c90b255ef2244bda29a languageName: node linkType: hard @@ -6588,7 +6588,7 @@ __metadata: follow-redirects: "npm:^1.15.0" form-data: "npm:^4.0.0" proxy-from-env: "npm:^1.1.0" - checksum: 7fb6a4313bae7f45e89d62c70a800913c303df653f19eafec88e56cea2e3821066b8409bc68be1930ecca80e861c52aa787659df0ffec6ad4d451c7816b9386b + checksum: b987e4259e5cfc93e95ee306c267a44380bbc045789a91b716e8434a75e22987344605eb4e133482fe285dd3a2e0b7e791ba26999965f04a5ecdde25f56930cb languageName: node linkType: hard @@ -6597,7 +6597,7 @@ __metadata: resolution: "axobject-query@npm:3.2.1" dependencies: dequal: "npm:^2.0.3" - checksum: a94047e702b57c91680e6a952ec4a1aaa2cfd0d80ead76bc8c954202980d8c51968a6ea18b4d8010e8e2cf95676533d8022a8ebba9abc1dfe25686721df26fd2 + checksum: 675af2548ed4ece75ad6d50cc0473cfdec7579eac77ec9861e7088d03ffb171aa697b70d2877423bee2ce16460ef62c698c6442a105612cc015719e8ea06b0bd languageName: node linkType: hard @@ -6623,7 +6623,7 @@ __metadata: slash: "npm:^3.0.0" peerDependencies: "@babel/core": ^7.8.0 - checksum: bc46cfba468edde91f34a8292501d4448a39fab72d80d7d95f4349feb114fa21becb01def007d6166de7933ab9633bf5b5e1b72ba6ffeaa991f7abf014a2f61d + checksum: abdc2d78566825c07a0f067a71615295ba9f55b1102512c4e876f3ac01035ec6a68b649a1d24e0aa1b98d62e1ef11de39e11bb3cc0099bba10a646649b24770f languageName: node linkType: hard @@ -6636,7 +6636,7 @@ __metadata: "@istanbuljs/schema": "npm:^0.1.2" istanbul-lib-instrument: "npm:^5.0.4" test-exclude: "npm:^6.0.0" - checksum: cb4fd95738219f232f0aece1116628cccff16db891713c4ccb501cddbbf9272951a5df81f2f2658dfdf4b3e7b236a9d5cbcf04d5d8c07dd5077297339598061a + checksum: ffd436bb2a77bbe1942a33245d770506ab2262d9c1b3c1f1da7f0592f78ee7445a95bc2efafe619dd9c1b6ee52c10033d6c7d29ddefe6f5383568e60f31dfe8d languageName: node linkType: hard @@ -6648,7 +6648,7 @@ __metadata: "@babel/types": "npm:^7.3.3" "@types/babel__core": "npm:^7.1.14" "@types/babel__traverse": "npm:^7.0.6" - checksum: 099b5254073b6bc985b6d2d045ad26fb8ed30ff8ae6404c4fe8ee7cd0e98a820f69e3dfb871c7c65aae0f4b65af77046244c07bb92d49ef9005c90eedf681539 + checksum: 18066c177da855f478178bd2a48fa1c131d31f15c04af8c732bb4c7eb5c952fde8ac9b11133e5ddd5b74aed92c6a833fbfde51cc5dec1f7169bf865b548da680 languageName: node linkType: hard @@ -6661,7 +6661,7 @@ __metadata: semver: "npm:^6.1.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7db3044993f3dddb3cc3d407bc82e640964a3bfe22de05d90e1f8f7a5cb71460011ab136d3c03c6c1ba428359ebf635688cd6205e28d0469bba221985f5c6179 + checksum: 78584305a614325894b47b88061621b442f3fd7ccf7c61c68e49522e9ec5da300f4e5f09d8738abf7f2e93e578560587bc0af19a3a0fd815cdd0fb16c23442ab languageName: node linkType: hard @@ -6669,12 +6669,12 @@ __metadata: version: 0.4.7 resolution: "babel-plugin-polyfill-corejs2@npm:0.4.7" dependencies: - "@babel/compat-data": ^7.22.6 - "@babel/helper-define-polyfill-provider": ^0.4.4 - semver: ^6.3.1 + "@babel/compat-data": "npm:^7.22.6" + "@babel/helper-define-polyfill-provider": "npm:^0.4.4" + semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: b3c84ce44d00211c919a94f76453fb2065861612f3e44862eb7acf854e325c738a7441ad82690deba2b6fddfa2ad2cf2c46960f46fab2e3b17c6ed4fd2d73b38 + checksum: 3b61cdb275592f61b29d582ee8c738a13d9897c5dd201cddb0610b381f3ae139ebc988ac96f72978fc143c3d50c15d46618df865822e282c8e76c236e7378b63 languageName: node linkType: hard @@ -6686,7 +6686,7 @@ __metadata: core-js-compat: "npm:^3.25.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 470bb8c59f7c0912bd77fe1b5a2e72f349b3f65bbdee1d60d6eb7e1f4a085c6f24b2dd5ab4ac6c2df6444a96b070ef6790eccc9edb6a2668c60d33133bfb62c6 + checksum: cd030ffef418d34093a77264227d293ef6a4b808a1b1adb84b36203ca569504de65cf1185b759657e0baf479c0825c39553d78362445395faf5c4d03085a629f languageName: node linkType: hard @@ -6694,11 +6694,11 @@ __metadata: version: 0.8.7 resolution: "babel-plugin-polyfill-corejs3@npm:0.8.7" dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.4 - core-js-compat: ^3.33.1 + "@babel/helper-define-polyfill-provider": "npm:^0.4.4" + core-js-compat: "npm:^3.33.1" peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 51bc215ab0c062bbb2225d912f69f8a6705d1837c8e01f9651307b5b937804287c1d73ebd8015689efcc02c3c21f37688b9ee6f5997635619b7a9cc4b7d9908d + checksum: defbc6de3d309c9639dd31223b5011707fcc0384037ac5959a1aefe16eb314562e1c1e5cfbce0af14a220d639ef92dfe5baf66664e9e6054656aca2841677622 languageName: node linkType: hard @@ -6717,7 +6717,7 @@ __metadata: version: 0.5.4 resolution: "babel-plugin-polyfill-regenerator@npm:0.5.4" dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.4 + "@babel/helper-define-polyfill-provider": "npm:^0.4.4" peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 checksum: 461b735c6c0eca3c7b4434d14bfa98c2ab80f00e2bdc1c69eb46d1d300092a9786d76bbd3ee55e26d2d1a2380c14592d8d638e271dfd2a2b78a9eacffa3645d1 @@ -6742,7 +6742,7 @@ __metadata: "@babel/plugin-syntax-top-level-await": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0 - checksum: d118c2742498c5492c095bc8541f4076b253e705b5f1ad9a2e7d302d81a84866f0070346662355c8e25fc02caa28dc2da8d69bcd67794a0d60c4d6fab6913cc8 + checksum: 94561959cb12bfa80867c9eeeace7c3d48d61707d33e55b4c3fdbe82fc745913eb2dbfafca62aef297421b38aadcb58550e5943f50fbcebbeefd70ce2bed4b74 languageName: node linkType: hard @@ -6783,7 +6783,7 @@ __metadata: isobject: "npm:^3.0.1" mixin-deep: "npm:^1.2.0" pascalcase: "npm:^0.1.1" - checksum: a4a146b912e27eea8f66d09cb0c9eab666f32ce27859a7dfd50f38cd069a2557b39f16dba1bc2aecb3b44bf096738dd207b7970d99b0318423285ab1b1994edd + checksum: 33b0c5d570840873cf370248e653d43e8d82ce4f03161ad3c58b7da6238583cfc65bf4bbb06b27050d6c2d8f40628777f3933f483c0a7c0274fcef4c51f70a7e languageName: node linkType: hard @@ -6791,22 +6791,22 @@ __metadata: version: 3.0.2 resolution: "better-opn@npm:3.0.2" dependencies: - open: ^8.0.4 - checksum: 1471552fa7f733561e7f49e812be074b421153006ca744de985fb6d38939807959fc5fe9cb819cf09f864782e294704fd3b31711ea14c115baf3330a2f1135de + open: "npm:^8.0.4" + checksum: 24668e5a837d0d2c0edf17ad5ebcfeb00a8a5578a5eb09f7a409e1a60617cdfea40b8ebfc95e5f12d9568157930d033e6805788fcf0780413ac982c95d3745d1 languageName: node linkType: hard "big-integer@npm:^1.6.44": version: 1.6.51 resolution: "big-integer@npm:1.6.51" - checksum: 3d444173d1b2e20747e2c175568bedeebd8315b0637ea95d75fd27830d3b8e8ba36c6af40374f36bdaea7b5de376dcada1b07587cb2a79a928fccdb6e6e3c518 + checksum: c7a12640901906d6f6b6bdb42a4eaba9578397b6d9a0dd090cf001ec813ff2bfcd441e364068ea0416db6175d2615f8ed19cff7d1a795115bf7c92d44993f991 languageName: node linkType: hard "big.js@npm:^5.2.2": version: 5.2.2 resolution: "big.js@npm:5.2.2" - checksum: b89b6e8419b097a8fb4ed2399a1931a68c612bce3cfd5ca8c214b2d017531191070f990598de2fc6f3f993d91c0f08aa82697717f6b3b8732c9731866d233c9e + checksum: c04416aeb084f4aa1c5857722439c327cc0ada9bd99ab80b650e3f30e2e4f1b92a04527ed1e7df8ffcd7c0ea311745a04af12d53e2f091bf09a06f1292003827 languageName: node linkType: hard @@ -6824,14 +6824,14 @@ __metadata: buffer: "npm:^5.5.0" inherits: "npm:^2.0.4" readable-stream: "npm:^3.4.0" - checksum: 9e8521fa7e83aa9427c6f8ccdcba6e8167ef30cc9a22df26effcc5ab682ef91d2cbc23a239f945d099289e4bbcfae7a192e9c28c84c6202e710a0dfec3722662 + checksum: b7904e66ed0bdfc813c06ea6c3e35eafecb104369dbf5356d0f416af90c1546de3b74e5b63506f0629acf5e16a6f87c3798f16233dcff086e9129383aa02ab55 languageName: node linkType: hard "bluebird@npm:^3.5.0": version: 3.7.2 resolution: "bluebird@npm:3.7.2" - checksum: 869417503c722e7dc54ca46715f70e15f4d9c602a423a02c825570862d12935be59ed9c7ba34a9b31f186c017c23cac6b54e35446f8353059c101da73eac22ef + checksum: 007c7bad22c5d799c8dd49c85b47d012a1fe3045be57447721e6afbd1d5be43237af1db62e26cb9b0d9ba812d2e4ca3bac82f6d7e016b6b88de06ee25ceb96e7 languageName: node linkType: hard @@ -6851,7 +6851,7 @@ __metadata: raw-body: "npm:2.5.1" type-is: "npm:~1.6.18" unpipe: "npm:1.0.0" - checksum: f1050dbac3bede6a78f0b87947a8d548ce43f91ccc718a50dd774f3c81f2d8b04693e52acf62659fad23101827dd318da1fb1363444ff9a8482b886a3e4a5266 + checksum: 5f8d128022a2fb8b6e7990d30878a0182f300b70e46b3f9d358a9433ad6275f0de46add6d63206da3637c01c3b38b6111a7480f7e7ac2e9f7b989f6133fe5510 languageName: node linkType: hard @@ -6867,7 +6867,7 @@ __metadata: resolution: "bplist-parser@npm:0.2.0" dependencies: big-integer: "npm:^1.6.44" - checksum: d5339dd16afc51de6c88f88f58a45b72ed6a06aa31f5557d09877575f220b7c1d3fbe375da0b62e6a10d4b8ed80523567e351f24014f5bc886ad523758142cdd + checksum: 15d31c1b0c7e0fb384e96349453879a33609d92d91b55a9ccee04b4be4b0645f1c823253d73326a1a23104521fbc45c2dd97fb05adf61863841b68cbb2ca7a3d languageName: node linkType: hard @@ -6904,7 +6904,7 @@ __metadata: snapdragon-node: "npm:^2.0.1" split-string: "npm:^3.0.2" to-regex: "npm:^3.0.1" - checksum: e30dcb6aaf4a31c8df17d848aa283a65699782f75ad61ae93ec25c9729c66cf58e66f0000a9fec84e4add1135bb7da40f7cb9601b36bebcfa9ca58e8d5c07de0 + checksum: 7c0f0d962570812009b050ee2e6243fd425ea80d3136aace908d0038bde9e7a43e9326fa35538cebf7c753f0482655f08ea11be074c9a140394287980a5c66c9 languageName: node linkType: hard @@ -6913,7 +6913,7 @@ __metadata: resolution: "braces@npm:3.0.2" dependencies: fill-range: "npm:^7.0.1" - checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459 + checksum: 966b1fb48d193b9d155f810e5efd1790962f2c4e0829f8440b8ad236ba009222c501f70185ef732fef17a4c490bb33a03b90dab0631feafbdf447da91e8165b1 languageName: node linkType: hard @@ -6929,7 +6929,7 @@ __metadata: resolution: "browserify-zlib@npm:0.1.4" dependencies: pako: "npm:~0.2.0" - checksum: abee4cb4349e8a21391fd874564f41b113fe691372913980e6fa06a777e4ea2aad4e942af14ab99bce190d5ac8f5328201432f4ef0eae48c6d02208bc212976f + checksum: cd506a1ef9c3280f6537a17ed1352ef7738b66fef0a15a655dc3a43edc34be6ee78c5838427146ae1fcd4801fc06d2ab203614d0f8c4df8b5a091cf0134b9a80 languageName: node linkType: hard @@ -6943,7 +6943,7 @@ __metadata: update-browserslist-db: "npm:^1.0.11" bin: browserslist: cli.js - checksum: 80d3820584e211484ad1b1a5cfdeca1dd00442f47be87e117e1dda34b628c87e18b81ae7986fa5977b3e6a03154f6d13cd763baa6b8bf5dd9dd19f4926603698 + checksum: f015dd3d97e9eadcc13aaaf03b4a78a071874eee1cf756a2361191c0888f238dd0ddf1b92c20d072ecd1834d9a51e5a6361f5efaf966728da6a5daaf95b37eb3 languageName: node linkType: hard @@ -6951,13 +6951,13 @@ __metadata: version: 4.22.2 resolution: "browserslist@npm:4.22.2" dependencies: - caniuse-lite: ^1.0.30001565 - electron-to-chromium: ^1.4.601 - node-releases: ^2.0.14 - update-browserslist-db: ^1.0.13 + caniuse-lite: "npm:^1.0.30001565" + electron-to-chromium: "npm:^1.4.601" + node-releases: "npm:^2.0.14" + update-browserslist-db: "npm:^1.0.13" bin: browserslist: cli.js - checksum: 33ddfcd9145220099a7a1ac533cecfe5b7548ffeb29b313e1b57be6459000a1f8fa67e781cf4abee97268ac594d44134fcc4a6b2b4750ceddc9796e3a22076d9 + checksum: e3590793db7f66ad3a50817e7b7f195ce61e029bd7187200244db664bfbe0ac832f784e4f6b9c958aef8ea4abe001ae7880b7522682df521f4bc0a5b67660b5e languageName: node linkType: hard @@ -6966,7 +6966,7 @@ __metadata: resolution: "bser@npm:2.1.1" dependencies: node-int64: "npm:^0.4.0" - checksum: 9ba4dc58ce86300c862bffc3ae91f00b2a03b01ee07f3564beeeaf82aa243b8b03ba53f123b0b842c190d4399b94697970c8e7cf7b1ea44b61aa28c3526a4449 + checksum: edba1b65bae682450be4117b695997972bd9a3c4dfee029cab5bcb72ae5393a79a8f909b8bc77957eb0deec1c7168670f18f4d5c556f46cdd3bca5f3b3a8d020 languageName: node linkType: hard @@ -6990,7 +6990,7 @@ __metadata: dependencies: base64-js: "npm:^1.3.1" ieee754: "npm:^1.1.13" - checksum: e2cf8429e1c4c7b8cbd30834ac09bd61da46ce35f5c22a78e6c2f04497d6d25541b16881e30a019c6fd3154150650ccee27a308eff3e26229d788bbdeb08ab84 + checksum: 997434d3c6e3b39e0be479a80288875f71cd1c07d75a3855e6f08ef848a3c966023f79534e22e415ff3a5112708ce06127277ab20e527146d55c84566405c7c6 languageName: node linkType: hard @@ -7004,7 +7004,7 @@ __metadata: "bytes@npm:3.1.2": version: 3.1.2 resolution: "bytes@npm:3.1.2" - checksum: e4bcd3948d289c5127591fbedf10c0b639ccbf00243504e4e127374a15c3bc8eed0d28d4aaab08ff6f1cf2abc0cce6ba3085ed32f4f90e82a5683ce0014e1b6e + checksum: a10abf2ba70c784471d6b4f58778c0beeb2b5d405148e66affa91f23a9f13d07603d0a0354667310ae1d6dc141474ffd44e2a074be0f6e2254edb8fc21445388 languageName: node linkType: hard @@ -7024,7 +7024,7 @@ __metadata: ssri: "npm:^10.0.0" tar: "npm:^6.1.11" unique-filename: "npm:^3.0.0" - checksum: 385756781e1e21af089160d89d7462b7ed9883c978e848c7075b90b73cb823680e66092d61513050164588387d2ca87dd6d910e28d64bc13a9ac82cd8580c796 + checksum: 216fb41c739b845c5acbc1f8a01876ccc6293644e701ad0abb7acb87b648a12abc2af5fc4b86df2d82731d0f7d6beebee85e62b1d59211535ed72de4b8b0fce6 languageName: node linkType: hard @@ -7041,7 +7041,7 @@ __metadata: to-object-path: "npm:^0.3.0" union-value: "npm:^1.0.0" unset-value: "npm:^1.0.0" - checksum: 9114b8654fe2366eedc390bad0bcf534e2f01b239a888894e2928cb58cdc1e6ea23a73c6f3450dcfd2058aa73a8a981e723cd1e7c670c047bf11afdc65880107 + checksum: 50dd11af5ce4aaa8a8bff190a870c940db80234cf087cd47dd177be8629c36ad8cd0716e62418ec1e135f2d01b28aafff62cd22d33412c3d18b2109dd9073711 languageName: node linkType: hard @@ -7051,7 +7051,7 @@ __metadata: dependencies: function-bind: "npm:^1.1.1" get-intrinsic: "npm:^1.0.2" - checksum: f8e31de9d19988a4b80f3e704788c4a2d6b6f3d17cfec4f57dc29ced450c53a49270dc66bf0fbd693329ee948dd33e6c90a329519aef17474a4d961e8d6426b0 + checksum: ca787179c1cbe09e1697b56ad499fd05dc0ae6febe5081d728176ade699ea6b1589240cb1ff1fe11fcf9f61538c1af60ad37e8eb2ceb4ef21cd6085dfd3ccedd languageName: node linkType: hard @@ -7079,14 +7079,14 @@ __metadata: "caniuse-lite@npm:^1.0.30001503": version: 1.0.30001515 resolution: "caniuse-lite@npm:1.0.30001515" - checksum: ec5d51785aea6af5cf62ca9d35821d36ab7fa0f85e3e7f752d532025ad59e07131fa3cb3a0a6c486b5ac8620c8c3440e761dc5b38c990d49c17655906f216123 + checksum: fad26250e2038dfc509d7bbc1db0d0b8abc43e41ce03f39438005a8d4fd15ff5a253144bc6b1079e659d2187d3fb609b6ea652a65ef0a954d0c8e40ddc1cc1d7 languageName: node linkType: hard "caniuse-lite@npm:^1.0.30001565": version: 1.0.30001578 resolution: "caniuse-lite@npm:1.0.30001578" - checksum: b0cd4fed07ae1224f564baaed5e096c9c479b3063d023fc629df52caa14e59b7436b33498729161e253a5b8974d644374ff1ce47ccf1885ef3d1541f4067705f + checksum: 3b1c41e70270839c958c3fefa3430d74021e15f019667c53f44894eff7382c03c1464e68c4aced284a212c1f157888b09f5b7fd5cae163efdc916202ec71a59d languageName: node linkType: hard @@ -7099,7 +7099,7 @@ __metadata: has-ansi: "npm:^2.0.0" strip-ansi: "npm:^3.0.0" supports-color: "npm:^2.0.0" - checksum: 9d2ea6b98fc2b7878829eec223abcf404622db6c48396a9b9257f6d0ead2acf18231ae368d6a664a83f272b0679158da12e97b5229f794939e555cc574478acd + checksum: abcf10da02afde04cc615f06c4bdb3ffc70d2bfbf37e0df03bb88b7459a9411dab4d01210745b773abc936031530a20355f1facc4bee1bbf08613d8fdcfb3aeb languageName: node linkType: hard @@ -7110,7 +7110,7 @@ __metadata: ansi-styles: "npm:^3.2.1" escape-string-regexp: "npm:^1.0.5" supports-color: "npm:^5.3.0" - checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 + checksum: 3d1d103433166f6bfe82ac75724951b33769675252d8417317363ef9d54699b7c3b2d46671b772b893a8e50c3ece70c4b933c73c01e81bc60ea4df9b55afa303 languageName: node linkType: hard @@ -7120,7 +7120,7 @@ __metadata: dependencies: ansi-styles: "npm:^4.1.0" supports-color: "npm:^7.1.0" - checksum: 8e3ddf3981c4da405ddbd7d9c8d91944ddf6e33d6837756979f7840a29272a69a5189ecae0ff84006750d6d1e92368d413335eab4db5476db6e6703a1d1e0505 + checksum: 37f90b31fd655fb49c2bd8e2a68aebefddd64522655d001ef417e6f955def0ed9110a867ffc878a533f2dafea5f2032433a37c8a7614969baa7f8a1cd424ddfc languageName: node linkType: hard @@ -7130,14 +7130,14 @@ __metadata: dependencies: ansi-styles: "npm:^4.1.0" supports-color: "npm:^7.1.0" - checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc + checksum: cb3f3e594913d63b1814d7ca7c9bafbf895f75fbf93b92991980610dfd7b48500af4e3a5d4e3a8f337990a96b168d7eb84ee55efdce965e2ee8efc20f8c8f139 languageName: node linkType: hard "char-regex@npm:^1.0.2": version: 1.0.2 resolution: "char-regex@npm:1.0.2" - checksum: b563e4b6039b15213114626621e7a3d12f31008bdce20f9c741d69987f62aeaace7ec30f6018890ad77b2e9b4d95324c9f5acfca58a9441e3b1dcdd1e2525d17 + checksum: 1ec5c2906adb9f84e7f6732a40baef05d7c85401b82ffcbc44b85fbd0f7a2b0c2a96f2eb9cf55cae3235dc12d4023003b88f09bcae8be9ae894f52ed746f4d48 languageName: node linkType: hard @@ -7151,14 +7151,14 @@ __metadata: "character-entities@npm:^1.0.0": version: 1.2.4 resolution: "character-entities@npm:1.2.4" - checksum: e1545716571ead57beac008433c1ff69517cd8ca5b336889321c5b8ff4a99c29b65589a701e9c086cda8a5e346a67295e2684f6c7ea96819fe85cbf49bf8686d + checksum: 7c11641c48d1891aaba7bc800d4500804d91a28f46d64e88c001c38e6ab2e7eae28873a77ae16e6c55d24cac35ddfbb15efe56c3012b86684a3c4e95c70216b7 languageName: node linkType: hard "character-reference-invalid@npm:^1.0.0": version: 1.1.4 resolution: "character-reference-invalid@npm:1.1.4" - checksum: 20274574c70e05e2f81135f3b93285536bc8ff70f37f0809b0d17791a832838f1e49938382899ed4cb444e5bbd4314ca1415231344ba29f4222ce2ccf24fea0b + checksum: 812ebc5e6e8d08fd2fa5245ae78c1e1a4bea4692e93749d256a135c4a442daf931ca18e067cc61ff4a58a419eae52677126a0bc4f05a511290427d60d3057805 languageName: node linkType: hard @@ -7177,7 +7177,7 @@ __metadata: dependenciesMeta: fsevents: optional: true - checksum: b49fcde40176ba007ff361b198a2d35df60d9bb2a5aab228279eb810feae9294a6b4649ab15981304447afe1e6ffbf4788ad5db77235dc770ab777c6e771980c + checksum: 863e3ff78ee7a4a24513d2a416856e84c8e4f5e60efbe03e8ab791af1a183f569b62fc6f6b8044e2804966cb81277ddbbc1dc374fba3265bd609ea8efd62f5b3 languageName: node linkType: hard @@ -7198,14 +7198,14 @@ __metadata: "ci-info@npm:^3.2.0": version: 3.8.0 resolution: "ci-info@npm:3.8.0" - checksum: d0a4d3160497cae54294974a7246202244fff031b0a6ea20dd57b10ec510aa17399c41a1b0982142c105f3255aff2173e5c0dd7302ee1b2f28ba3debda375098 + checksum: b00e9313c1f7042ca8b1297c157c920d6d69f0fbad7b867910235676df228c4b4f4df33d06cacae37f9efba7a160b0a167c6be85492b419ef71d85660e60606b languageName: node linkType: hard "cjs-module-lexer@npm:^1.0.0": version: 1.2.3 resolution: "cjs-module-lexer@npm:1.2.3" - checksum: 5ea3cb867a9bb609b6d476cd86590d105f3cfd6514db38ff71f63992ab40939c2feb68967faa15a6d2b1f90daa6416b79ea2de486e9e2485a6f8b66a21b4fb0a + checksum: f96a5118b0a012627a2b1c13bd2fcb92509778422aaa825c5da72300d6dcadfb47134dd2e9d97dfa31acd674891dd91642742772d19a09a8adc3e56bd2f5928c languageName: node linkType: hard @@ -7217,14 +7217,14 @@ __metadata: define-property: "npm:^0.2.5" isobject: "npm:^3.0.0" static-extend: "npm:^0.1.1" - checksum: be108900801e639e50f96a7e4bfa8867c753a7750a7603879f3981f8b0a89cba657497a2d5f40cd4ea557ff15d535a100818bb486baf6e26fe5d7872e75f1078 + checksum: b236d9deb6594828966e45c5f48abac9a77453ee0dbdb89c635ce876f59755d7952309d554852b6f7d909198256c335a4bd51b09c1d238b36b92152eb2b9d47a languageName: node linkType: hard "classnames@npm:2.3.2": version: 2.3.2 resolution: "classnames@npm:2.3.2" - checksum: 2c62199789618d95545c872787137262e741f9db13328e216b093eea91c85ef2bfb152c1f9e63027204e2559a006a92eb74147d46c800a9f96297ae1d9f96f4e + checksum: ba3151c12e8b6a84c64b340ab4259ad0408947652009314462d828e94631505989c6a7d7e796bec1d309be9295d3111b498ad18a9d533fe3e6f859e51e574cbb languageName: node linkType: hard @@ -7239,7 +7239,7 @@ __metadata: version: 3.1.0 resolution: "cli-cursor@npm:3.1.0" dependencies: - restore-cursor: ^3.1.0 + restore-cursor: "npm:^3.1.0" checksum: 2692784c6cd2fd85cfdbd11f53aea73a463a6d64a77c3e098b2b4697a20443f430c220629e1ca3b195ea5ac4a97a74c2ee411f3807abf6df2b66211fec0c0a29 languageName: node linkType: hard @@ -7247,7 +7247,7 @@ __metadata: "cli-spinners@npm:^2.5.0": version: 2.9.2 resolution: "cli-spinners@npm:2.9.2" - checksum: 1bd588289b28432e4676cb5d40505cfe3e53f2e4e10fbe05c8a710a154d6fe0ce7836844b00d6858f740f2ffe67cdc36e0fce9c7b6a8430e80e6388d5aa4956c + checksum: a0a863f442df35ed7294424f5491fa1756bd8d2e4ff0c8736531d886cec0ece4d85e8663b77a5afaf1d296e3cbbebff92e2e99f52bbea89b667cbe789b994794 languageName: node linkType: hard @@ -7260,7 +7260,7 @@ __metadata: dependenciesMeta: "@colors/colors": optional: true - checksum: 09897f68467973f827c04e7eaadf13b55f8aec49ecd6647cc276386ea660059322e2dd8020a8b6b84d422dbdd619597046fa89cbbbdc95b2cea149a2df7c096c + checksum: 8d82b75be7edc7febb1283dc49582a521536527cba80af62a2e4522a0ee39c252886a1a2f02d05ae9d753204dbcffeb3a40d1358ee10dccd7fe8d935cfad3f85 languageName: node linkType: hard @@ -7271,7 +7271,7 @@ __metadata: string-width: "npm:^4.2.0" strip-ansi: "npm:^6.0.1" wrap-ansi: "npm:^7.0.0" - checksum: 79648b3b0045f2e285b76fb2e24e207c6db44323581e421c3acbd0e86454cba1b37aea976ab50195a49e7384b871e6dfb2247ad7dec53c02454ac6497394cb56 + checksum: eaa5561aeb3135c2cddf7a3b3f562fc4238ff3b3fc666869ef2adf264be0f372136702f16add9299087fb1907c2e4ec5dbfe83bd24bce815c70a80c6c1a2e950 languageName: node linkType: hard @@ -7296,21 +7296,21 @@ __metadata: "clone@npm:^2.1.1": version: 2.1.2 resolution: "clone@npm:2.1.2" - checksum: aaf106e9bc025b21333e2f4c12da539b568db4925c0501a1bf4070836c9e848c892fa22c35548ce0d1132b08bbbfa17a00144fe58fccdab6fa900fec4250f67d + checksum: d9c79efba655f0bf601ab299c57eb54cbaa9860fb011aee9d89ed5ac0d12df1660ab7642fddaabb9a26b7eff0e117d4520512cb70798319ff5d30a111b5310c2 languageName: node linkType: hard "co@npm:^4.6.0": version: 4.6.0 resolution: "co@npm:4.6.0" - checksum: 5210d9223010eb95b29df06a91116f2cf7c8e0748a9013ed853b53f362ea0e822f1e5bb054fb3cefc645239a4cf966af1f6133a3b43f40d591f3b68ed6cf0510 + checksum: a5d9f37091c70398a269e625cedff5622f200ed0aa0cff22ee7b55ed74a123834b58711776eb0f1dc58eb6ebbc1185aa7567b57bd5979a948c6e4f85073e2c05 languageName: node linkType: hard "collect-v8-coverage@npm:^1.0.0": version: 1.0.2 resolution: "collect-v8-coverage@npm:1.0.2" - checksum: c10f41c39ab84629d16f9f6137bc8a63d332244383fc368caf2d2052b5e04c20cd1fd70f66fcf4e2422b84c8226598b776d39d5f2d2a51867cc1ed5d1982b4da + checksum: 30ea7d5c9ee51f2fdba4901d4186c5b7114a088ef98fd53eda3979da77eed96758a2cae81cc6d97e239aaea6065868cf908b24980663f7b7e96aa291b3e12fa4 languageName: node linkType: hard @@ -7329,7 +7329,7 @@ __metadata: resolution: "color-convert@npm:1.9.3" dependencies: color-name: "npm:1.1.3" - checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203 + checksum: ffa319025045f2973919d155f25e7c00d08836b6b33ea2d205418c59bd63a665d713c52d9737a9e0fe467fb194b40fbef1d849bae80d674568ee220a31ef3d10 languageName: node linkType: hard @@ -7338,7 +7338,7 @@ __metadata: resolution: "color-convert@npm:2.0.1" dependencies: color-name: "npm:~1.1.4" - checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 + checksum: fa00c91b4332b294de06b443923246bccebe9fab1b253f7fe1772d37b06a2269b4039a85e309abe1fe11b267b11c08d1d0473fda3badd6167f57313af2887a64 languageName: node linkType: hard @@ -7361,14 +7361,14 @@ __metadata: resolution: "color-support@npm:1.1.3" bin: color-support: bin.js - checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b + checksum: 4bcfe30eea1498fe1cabc852bbda6c9770f230ea0e4faf4611c5858b1b9e4dde3730ac485e65f54ca182f4c50b626c1bea7c8441ceda47367a54a818c248aa7a languageName: node linkType: hard "colorette@npm:^2.0.19": version: 2.0.20 resolution: "colorette@npm:2.0.20" - checksum: 0c016fea2b91b733eb9f4bcdb580018f52c0bc0979443dad930e5037a968237ac53d9beb98e218d2e9235834f8eebce7f8e080422d6194e957454255bde71d3d + checksum: 0b8de48bfa5d10afc160b8eaa2b9938f34a892530b2f7d7897e0458d9535a066e3998b49da9d21161c78225b272df19ae3a64d6df28b4c9734c0e55bbd02406f languageName: node linkType: hard @@ -7377,7 +7377,7 @@ __metadata: resolution: "combined-stream@npm:1.0.8" dependencies: delayed-stream: "npm:~1.0.0" - checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c + checksum: 2e969e637d05d09fa50b02d74c83a1186f6914aae89e6653b62595cc75a221464f884f55f231b8f4df7a49537fba60bdc0427acd2bf324c09a1dbb84837e36e4 languageName: node linkType: hard @@ -7391,28 +7391,28 @@ __metadata: "commander@npm:^6.2.1": version: 6.2.1 resolution: "commander@npm:6.2.1" - checksum: d7090410c0de6bc5c67d3ca41c41760d6d268f3c799e530aafb73b7437d1826bbf0d2a3edac33f8b57cc9887b4a986dce307fa5557e109be40eadb7c43b21742 + checksum: 25b88c2efd0380c84f7844b39cf18510da7bfc5013692d68cdc65f764a1c34e6c8a36ea6d72b6620e3710a930cf8fab2695bdec2bf7107a0f4fa30a3ef3b7d0e languageName: node linkType: hard "commander@npm:^7.2.0": version: 7.2.0 resolution: "commander@npm:7.2.0" - checksum: 53501cbeee61d5157546c0bef0fedb6cdfc763a882136284bed9a07225f09a14b82d2a84e7637edfd1a679fb35ed9502fd58ef1d091e6287f60d790147f68ddc + checksum: 9973af10727ad4b44f26703bf3e9fdc323528660a7590efe3aa9ad5042b4584c0deed84ba443f61c9d6f02dade54a5a5d3c95e306a1e1630f8374ae6db16c06d languageName: node linkType: hard "commondir@npm:^1.0.1": version: 1.0.1 resolution: "commondir@npm:1.0.1" - checksum: 59715f2fc456a73f68826285718503340b9f0dd89bfffc42749906c5cf3d4277ef11ef1cca0350d0e79204f00f1f6d83851ececc9095dc88512a697ac0b9bdcb + checksum: 4620bc4936a4ef12ce7dfcd272bb23a99f2ad68889a4e4ad766c9f8ad21af982511934d6f7050d4a8bde90011b1c15d56e61a1b4576d9913efbf697a20172d6c languageName: node linkType: hard "component-emitter@npm:^1.2.1": version: 1.3.0 resolution: "component-emitter@npm:1.3.0" - checksum: b3c46de38ffd35c57d1c02488355be9f218e582aec72d72d1b8bbec95a3ac1b38c96cd6e03ff015577e68f550fbb361a3bfdbd9bb248be9390b7b3745691be6b + checksum: dfc1ec2e7aa2486346c068f8d764e3eefe2e1ca0b24f57506cd93b2ae3d67829a7ebd7cc16e2bf51368fac2f45f78fcff231718e40b1975647e4a86be65e1d05 languageName: node linkType: hard @@ -7436,14 +7436,14 @@ __metadata: on-headers: "npm:~1.0.2" safe-buffer: "npm:5.1.2" vary: "npm:~1.1.2" - checksum: 35c0f2eb1f28418978615dc1bc02075b34b1568f7f56c62d60f4214d4b7cc00d0f6d282b5f8a954f59872396bd770b6b15ffd8aa94c67d4bce9b8887b906999b + checksum: 469cd097908fe1d3ff146596d4c24216ad25eabb565c5456660bdcb3a14c82ebc45c23ce56e19fc642746cf407093b55ab9aa1ac30b06883b27c6c736e6383c2 languageName: node linkType: hard "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" - checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af + checksum: 9680699c8e2b3af0ae22592cb764acaf973f292a7b71b8a06720233011853a58e256c89216a10cbe889727532fd77f8bcd49a760cedfde271b8e006c20e079f2 languageName: node linkType: hard @@ -7455,14 +7455,14 @@ __metadata: inherits: "npm:^2.0.3" readable-stream: "npm:^2.2.2" typedarray: "npm:^0.0.6" - checksum: 1ef77032cb4459dcd5187bd710d6fc962b067b64ec6a505810de3d2b8cc0605638551b42f8ec91edf6fcd26141b32ef19ad749239b58fae3aba99187adc32285 + checksum: 71db903c84fc073ca35a274074e8d26c4330713d299f8623e993c448c1f6bf8b967806dd1d1a7b0f8add6f15ab1af7435df21fe79b4fe7efd78420c89e054e28 languageName: node linkType: hard "console-control-strings@npm:^1.1.0": version: 1.1.0 resolution: "console-control-strings@npm:1.1.0" - checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed + checksum: 27b5fa302bc8e9ae9e98c03c66d76ca289ad0c61ce2fe20ab288d288bee875d217512d2edb2363fc83165e88f1c405180cf3f5413a46e51b4fe1a004840c6cdb languageName: node linkType: hard @@ -7471,14 +7471,14 @@ __metadata: resolution: "content-disposition@npm:0.5.4" dependencies: safe-buffer: "npm:5.2.1" - checksum: afb9d545e296a5171d7574fcad634b2fdf698875f4006a9dd04a3e1333880c5c0c98d47b560d01216fb6505a54a2ba6a843ee3a02ec86d7e911e8315255f56c3 + checksum: b7f4ce176e324f19324be69b05bf6f6e411160ac94bc523b782248129eb1ef3be006f6cff431aaea5e337fe5d176ce8830b8c2a1b721626ead8933f0cbe78720 languageName: node linkType: hard "content-type@npm:~1.0.4": version: 1.0.5 resolution: "content-type@npm:1.0.5" - checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 + checksum: 585847d98dc7fb8035c02ae2cb76c7a9bd7b25f84c447e5ed55c45c2175e83617c8813871b4ee22f368126af6b2b167df655829007b21aa10302873ea9c62662 languageName: node linkType: hard @@ -7492,7 +7492,7 @@ __metadata: "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" - checksum: 63ae9933be5a2b8d4509daca5124e20c14d023c820258e484e32dc324d34c2754e71297c94a05784064ad27615037ef677e3f0c00469fb55f409d2bb21261035 + checksum: c987be3ec061348cdb3c2bfb924bec86dea1eacad10550a85ca23edb0fe3556c3a61c7399114f3331ccb3499d7fd0285ab24566e5745929412983494c3926e15 languageName: node linkType: hard @@ -7506,14 +7506,14 @@ __metadata: "cookie@npm:0.5.0": version: 0.5.0 resolution: "cookie@npm:0.5.0" - checksum: 1f4bd2ca5765f8c9689a7e8954183f5332139eb72b6ff783d8947032ec1fdf43109852c178e21a953a30c0dd42257828185be01b49d1eb1a67fd054ca588a180 + checksum: aae7911ddc5f444a9025fbd979ad1b5d60191011339bce48e555cb83343d0f98b865ff5c4d71fecdfb8555a5cafdc65632f6fce172f32aaf6936830a883a0380 languageName: node linkType: hard "copy-descriptor@npm:^0.1.0": version: 0.1.1 resolution: "copy-descriptor@npm:0.1.1" - checksum: d4b7b57b14f1d256bb9aa0b479241048afd7f5bcf22035fc7b94e8af757adeae247ea23c1a774fe44869fd5694efba4a969b88d966766c5245fdee59837fe45b + checksum: edf4651bce36166c7fcc60b5c1db2c5dad1d87820f468507331dd154b686ece8775f5d383127d44aeef813462520c866f83908aa2d4291708f898df776816860 languageName: node linkType: hard @@ -7531,7 +7531,7 @@ __metadata: resolution: "core-js-compat@npm:3.31.1" dependencies: browserslist: "npm:^4.21.9" - checksum: 9a16d6992621f4e099169297381a28d5712cdef7df1fa85352a7c285a5885d5d7a117ec2eae9ad715ed88c7cc774787a22cdb8aceababf6775fbc8b0cbeccdb7 + checksum: 200c60f512a2bfacf54a9d88313371f958688a0de7bf5c53c1222cc7860990c4762f5671ea7e77904d8bbb057cdf409f8c2ad40256a0ce9110bc35b70a1cda08 languageName: node linkType: hard @@ -7539,8 +7539,8 @@ __metadata: version: 3.35.0 resolution: "core-js-compat@npm:3.35.0" dependencies: - browserslist: ^4.22.2 - checksum: 64c41ce6870aa9130b9d0cb8f00c05204094f46db7e345d520ec2e38f8b6e1d51e921d4974ceb880948f19c0a79e5639e55be0e56f88ea20e32e9a6274da7f82 + browserslist: "npm:^4.22.2" + checksum: aa21ad2f0c946be7a8ecef92233bc003a38fa27e43a925fcd9b79e32ae49b879e0f5c23459ffc310df38ee547389b8e5e43a6a8be0b2369b9b9ebf3d04ae69b9 languageName: node linkType: hard @@ -7559,7 +7559,7 @@ __metadata: js-yaml: "npm:^4.1.0" parse-json: "npm:^5.0.0" path-type: "npm:^4.0.0" - checksum: 836d5d8efa750f3fb17b03d6ca74cd3154ed025dffd045304b3ef59637f662bde1e5dc88f8830080d180ec60841719cf4ea2ce73fb21ec694b16865c478ff297 + checksum: e0b188f9a672ee7135851bf9d9fc8f0ba00f9769c95fda5af0ebc274804f6aeb713b753e04e706f595e1fbd0fa67c5073840666019068c0296a06057560ab39d languageName: node linkType: hard @@ -7570,7 +7570,7 @@ __metadata: path-key: "npm:^3.1.0" shebang-command: "npm:^2.0.0" which: "npm:^2.0.1" - checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 + checksum: e1a13869d2f57d974de0d9ef7acbf69dc6937db20b918525a01dacb5032129bd552d290d886d981e99f1b624cb03657084cc87bd40f115c07ecf376821c729ce languageName: node linkType: hard @@ -7590,7 +7590,7 @@ __metadata: domhandler: "npm:^4.3.1" domutils: "npm:^2.8.0" nth-check: "npm:^2.0.1" - checksum: d6202736839194dd7f910320032e7cfc40372f025e4bf21ca5bf6eb0a33264f322f50ba9c0adc35dadd342d3d6fae5ca244779a4873afbfa76561e343f2058e0 + checksum: 8f7310c9af30ccaba8f72cb4a54d32232c53bf9ba05d019b693e16bfd7ba5df0affc1f4d74b1ee55923643d23b80a837eedcf60938c53356e479b04049ff9994 languageName: node linkType: hard @@ -7600,14 +7600,14 @@ __metadata: dependencies: mdn-data: "npm:2.0.14" source-map: "npm:^0.6.1" - checksum: 79f9b81803991b6977b7fcb1588799270438274d89066ce08f117f5cdb5e20019b446d766c61506dd772c839df84caa16042d6076f20c97187f5abe3b50e7d1f + checksum: 29710728cc4b136f1e9b23ee1228ec403ec9f3d487bc94a9c5dbec563c1e08c59bc917dd6f82521a35e869ff655c298270f43ca673265005b0cd05b292eb05ab languageName: node linkType: hard "css-what@npm:^6.0.1": version: 6.1.0 resolution: "css-what@npm:6.1.0" - checksum: b975e547e1e90b79625918f84e67db5d33d896e6de846c9b584094e529f0c63e2ab85ee33b9daffd05bff3a146a1916bec664e18bb76dd5f66cbff9fc13b2bbe + checksum: c67a3a2d0d81843af87f8bf0a4d0845b0f952377714abbb2884e48942409d57a2110eabee003609d02ee487b054614bdfcfc59ee265728ff105bd5aa221c1d0e languageName: node linkType: hard @@ -7623,21 +7623,21 @@ __metadata: resolution: "csso@npm:4.2.0" dependencies: css-tree: "npm:^1.1.2" - checksum: 380ba9663da3bcea58dee358a0d8c4468bb6539be3c439dc266ac41c047217f52fd698fb7e4b6b6ccdfb8cf53ef4ceed8cc8ceccb8dfca2aa628319826b5b998 + checksum: 8b6a2dc687f2a8165dde13f67999d5afec63cb07a00ab100fbb41e4e8b28d986cfa0bc466b4f5ba5de7260c2448a64e6ad26ec718dd204d3a7d109982f0bf1aa languageName: node linkType: hard "cssom@npm:^0.5.0": version: 0.5.0 resolution: "cssom@npm:0.5.0" - checksum: 823471aa30091c59e0a305927c30e7768939b6af70405808f8d2ce1ca778cddcb24722717392438329d1691f9a87cb0183b64b8d779b56a961546d54854fde01 + checksum: b502a315b1ce020a692036cc38cb36afa44157219b80deadfa040ab800aa9321fcfbecf02fd2e6ec87db169715e27978b4ab3701f916461e9cf7808899f23b54 languageName: node linkType: hard "cssom@npm:~0.3.6": version: 0.3.8 resolution: "cssom@npm:0.3.8" - checksum: 24beb3087c76c0d52dd458be9ee1fbc80ac771478a9baef35dd258cdeb527c68eb43204dd439692bb2b1ae5272fa5f2946d10946edab0d04f1078f85e06bc7f6 + checksum: 49eacc88077555e419646c0ea84ddc73c97e3a346ad7cb95e22f9413a9722d8964b91d781ce21d378bd5ae058af9a745402383fa4e35e9cdfd19654b63f892a9 languageName: node linkType: hard @@ -7646,21 +7646,21 @@ __metadata: resolution: "cssstyle@npm:2.3.0" dependencies: cssom: "npm:~0.3.6" - checksum: 5f05e6fd2e3df0b44695c2f08b9ef38b011862b274e320665176467c0725e44a53e341bc4959a41176e83b66064ab786262e7380fd1cabeae6efee0d255bb4e3 + checksum: 46f7f05a153446c4018b0454ee1464b50f606cb1803c90d203524834b7438eb52f3b173ba0891c618f380ced34ee12020675dc0052a7f1be755fe4ebc27ee977 languageName: node linkType: hard "csstype@npm:^3.0.2": version: 3.1.2 resolution: "csstype@npm:3.1.2" - checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5 + checksum: 1f39c541e9acd9562996d88bc9fb62d1cb234786ef11ed275567d4b2bd82e1ceacde25debc8de3d3b4871ae02c2933fa02614004c97190711caebad6347debc2 languageName: node linkType: hard "damerau-levenshtein@npm:^1.0.8": version: 1.0.8 resolution: "damerau-levenshtein@npm:1.0.8" - checksum: d240b7757544460ae0586a341a53110ab0a61126570ef2d8c731e3eab3f0cb6e488e2609e6a69b46727635de49be20b071688698744417ff1b6c1d7ccd03e0de + checksum: f4eba1c90170f96be25d95fa3857141b5f81e254f7e4d530da929217b19990ea9a0390fc53d3c1cafac9152fda78e722ea4894f765cf6216be413b5af1fbf821 languageName: node linkType: hard @@ -7680,7 +7680,7 @@ __metadata: resolution: "date-fns@npm:2.30.0" dependencies: "@babel/runtime": "npm:^7.21.0" - checksum: f7be01523282e9bb06c0cd2693d34f245247a29098527d4420628966a2d9aad154bd0e90a6b1cf66d37adcb769cd108cf8a7bd49d76db0fb119af5cdd13644f4 + checksum: 70b3e8ea7aaaaeaa2cd80bd889622a4bcb5d8028b4de9162cbcda359db06e16ff6e9309e54eead5341e71031818497f19aaf9839c87d1aba1e27bb4796e758a9 languageName: node linkType: hard @@ -7689,7 +7689,7 @@ __metadata: resolution: "debug@npm:2.6.9" dependencies: ms: "npm:2.0.0" - checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6 + checksum: e07005f2b40e04f1bd14a3dd20520e9c4f25f60224cb006ce9d6781732c917964e9ec029fc7f1a151083cd929025ad5133814d4dc624a9aaf020effe4914ed14 languageName: node linkType: hard @@ -7701,7 +7701,7 @@ __metadata: peerDependenciesMeta: supports-color: optional: true - checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + checksum: 0073c3bcbd9cb7d71dd5f6b55be8701af42df3e56e911186dfa46fac3a5b9eb7ce7f377dd1d3be6db8977221f8eb333d945216f645cf56f6b688cd484837d255 languageName: node linkType: hard @@ -7710,21 +7710,21 @@ __metadata: resolution: "debug@npm:3.2.7" dependencies: ms: "npm:^2.1.1" - checksum: b3d8c5940799914d30314b7c3304a43305fd0715581a919dacb8b3176d024a782062368405b47491516d2091d6462d4d11f2f4974a405048094f8bfebfa3071c + checksum: d86fd7be2b85462297ea16f1934dc219335e802f629ca9a69b63ed8ed041dda492389bb2ee039217c02e5b54792b1c51aa96ae954cf28634d363a2360c7a1639 languageName: node linkType: hard "decimal.js@npm:^10.4.2": version: 10.4.3 resolution: "decimal.js@npm:10.4.3" - checksum: 796404dcfa9d1dbfdc48870229d57f788b48c21c603c3f6554a1c17c10195fc1024de338b0cf9e1efe0c7c167eeb18f04548979bcc5fdfabebb7cc0ae3287bae + checksum: de663a7bc4d368e3877db95fcd5c87b965569b58d16cdc4258c063d231ca7118748738df17cd638f7e9dd0be8e34cec08d7234b20f1f2a756a52fc5a38b188d0 languageName: node linkType: hard "decode-uri-component@npm:^0.2.0": version: 0.2.2 resolution: "decode-uri-component@npm:0.2.2" - checksum: 95476a7d28f267292ce745eac3524a9079058bbb35767b76e3ee87d42e34cd0275d2eb19d9d08c3e167f97556e8a2872747f5e65cbebcac8b0c98d83e285f139 + checksum: 17a0e5fa400bf9ea84432226e252aa7b5e72793e16bf80b907c99b46a799aeacc139ec20ea57121e50c7bd875a1a4365928f884e92abf02e21a5a13790a0f33e languageName: node linkType: hard @@ -7757,21 +7757,21 @@ __metadata: which-boxed-primitive: "npm:^1.0.2" which-collection: "npm:^1.0.1" which-typed-array: "npm:^1.1.9" - checksum: eb61c35157b6ecb96a5359b507b083fbff8ddb4c86a78a781ee38485f77a667465e45d63ee2ebd8a00e86d94c80e499906900cd82c2debb400237e1662cd5397 + checksum: 883cb8b3cf10d387ce8fb191f7d7b46b48022e00810074c5629053953aa3be5c5890dd40d30d31d27fb140af9a541c06c852ab5d28f76b07095c9d28e3c4b04f languageName: node linkType: hard "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" - checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804 + checksum: ec12d074aef5ae5e81fa470b9317c313142c9e8e2afe3f8efa124db309720db96d1d222b82b84c834e5f87e7a614b44a4684b6683583118b87c833b3be40d4d8 languageName: node linkType: hard "deepmerge@npm:^4.2.2": version: 4.3.1 resolution: "deepmerge@npm:4.3.1" - checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 + checksum: 058d9e1b0ff1a154468bf3837aea436abcfea1ba1d165ddaaf48ca93765fdd01a30d33c36173da8fbbed951dd0a267602bc782fe288b0fc4b7e1e7091afc4529 languageName: node linkType: hard @@ -7789,7 +7789,7 @@ __metadata: version: 1.0.4 resolution: "defaults@npm:1.0.4" dependencies: - clone: ^1.0.2 + clone: "npm:^1.0.2" checksum: 3a88b7a587fc076b84e60affad8b85245c01f60f38fc1d259e7ac1d89eb9ce6abb19e27215de46b98568dd5bc48471730b327637e6f20b0f1bc85cf00440c80a languageName: node linkType: hard @@ -7842,7 +7842,7 @@ __metadata: "defu@npm:^6.1.2": version: 6.1.2 resolution: "defu@npm:6.1.2" - checksum: 2ec0ff8414d5a1ab2b8c7e9a79bbad6d97d23ea7ebf5dcf80c3c7ffd9715c30f84a3cc47b917379ea756b3db0dc4701ce6400e493a1ae1688dffcd0f884233b2 + checksum: 5704aa6ea0b503004ee25b2ce909af8e6dc7c472d2d41e293f5a879534a0a7827a37e6692e0ca0c6e8d3ef6b00651d50089be681c814832cbed98f0f206ef25b languageName: node linkType: hard @@ -7879,14 +7879,14 @@ __metadata: "depd@npm:2.0.0, depd@npm:^2.0.0": version: 2.0.0 resolution: "depd@npm:2.0.0" - checksum: abbe19c768c97ee2eed6282d8ce3031126662252c58d711f646921c9623f9052e3e1906443066beec1095832f534e57c523b7333f8e7e0d93051ab6baef5ab3a + checksum: c0c8ff36079ce5ada64f46cc9d6fd47ebcf38241105b6e0c98f412e8ad91f084bcf906ff644cc3a4bd876ca27a62accb8b0fff72ea6ed1a414b89d8506f4a5ca languageName: node linkType: hard "dequal@npm:^2.0.2, dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" - checksum: 8679b850e1a3d0ebbc46ee780d5df7b478c23f335887464023a631d1b9af051ad4a6595a44220f9ff8ff95a8ddccf019b5ad778a976fd7bbf77383d36f412f90 + checksum: 6ff05a7561f33603df87c45e389c9ac0a95e3c056be3da1a0c4702149e3a7f6fe5ffbb294478687ba51a9e95f3a60e8b6b9005993acd79c292c7d15f71964b6b languageName: node linkType: hard @@ -7943,7 +7943,7 @@ __metadata: "diff-sequences@npm:^29.4.3": version: 29.4.3 resolution: "diff-sequences@npm:29.4.3" - checksum: 28b265e04fdddcf7f9f814effe102cc95a9dec0564a579b5aed140edb24fc345c611ca52d76d725a3cab55d3888b915b5e8a4702e0f6058968a90fa5f41fcde7 + checksum: 2287b259400513332d757f921eeda7c740863a919a00bd1d1b22ab2532b3e763538c404aec0953a813bbe33e660cbc77d0742875d6674d8dc5bc31d74ec88cc1 languageName: node linkType: hard @@ -7961,7 +7961,7 @@ __metadata: resolution: "doctrine@npm:2.1.0" dependencies: esutils: "npm:^2.0.2" - checksum: a45e277f7feaed309fe658ace1ff286c6e2002ac515af0aaf37145b8baa96e49899638c7cd47dccf84c3d32abfc113246625b3ac8f552d1046072adee13b0dc8 + checksum: 555684f77e791b17173ea86e2eea45ef26c22219cb64670669c4f4bebd26dbc95cd90ec1f4159e9349a6bb9eb892ce4dde8cd0139e77bedd8bf4518238618474 languageName: node linkType: hard @@ -7970,14 +7970,14 @@ __metadata: resolution: "doctrine@npm:3.0.0" dependencies: esutils: "npm:^2.0.2" - checksum: fd7673ca77fe26cd5cba38d816bc72d641f500f1f9b25b83e8ce28827fe2da7ad583a8da26ab6af85f834138cf8dae9f69b0cd6ab925f52ddab1754db44d99ce + checksum: b4b28f1df5c563f7d876e7461254a4597b8cabe915abe94d7c5d1633fed263fcf9a85e8d3836591fc2d040108e822b0d32758e5ec1fe31c590dc7e08086e3e48 languageName: node linkType: hard "dom-accessibility-api@npm:^0.5.6, dom-accessibility-api@npm:^0.5.9": version: 0.5.16 resolution: "dom-accessibility-api@npm:0.5.16" - checksum: 005eb283caef57fc1adec4d5df4dd49189b628f2f575af45decb210e04d634459e3f1ee64f18b41e2dcf200c844bc1d9279d80807e686a30d69a4756151ad248 + checksum: 377b4a7f9eae0a5d72e1068c369c99e0e4ca17fdfd5219f3abd32a73a590749a267475a59d7b03a891f9b673c27429133a818c44b2e47e32fec024b34274e2ca languageName: node linkType: hard @@ -7998,7 +7998,7 @@ __metadata: domelementtype: "npm:^2.0.1" domhandler: "npm:^4.2.0" entities: "npm:^2.0.0" - checksum: fbb0b01f87a8a2d18e6e5a388ad0f7ec4a5c05c06d219377da1abc7bb0f674d804f4a8a94e3f71ff15f6cb7dcfc75704a54b261db672b9b3ab03da6b758b0b22 + checksum: 53b217bcfed4a0f90dd47f34f239b1c81fff53ffa39d164d722325817fdb554903b145c2d12c8421ce0df7d31c1b180caf7eacd3c86391dd925f803df8027dcc languageName: node linkType: hard @@ -8009,7 +8009,7 @@ __metadata: domelementtype: "npm:^2.3.0" domhandler: "npm:^5.0.2" entities: "npm:^4.2.0" - checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 + checksum: e3bf9027a64450bca0a72297ecdc1e3abb7a2912268a9f3f5d33a2e29c1e2c3502c6e9f860fc6625940bfe0cfb57a44953262b9e94df76872fdfb8151097eeb3 languageName: node linkType: hard @@ -8032,7 +8032,7 @@ __metadata: resolution: "domexception@npm:4.0.0" dependencies: webidl-conversions: "npm:^7.0.0" - checksum: ddbc1268edf33a8ba02ccc596735ede80375ee0cf124b30d2f05df5b464ba78ef4f49889b6391df4a04954e63d42d5631c7fcf8b1c4f12bc531252977a5f13d5 + checksum: 4ed443227d2871d76c58d852b2e93c68e0443815b2741348f20881bedee8c1ad4f9bfc5d30c7dec433cd026b57da63407c010260b1682fef4c8847e7181ea43f languageName: node linkType: hard @@ -8041,7 +8041,7 @@ __metadata: resolution: "domhandler@npm:5.0.3" dependencies: domelementtype: "npm:^2.3.0" - checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c + checksum: 809b805a50a9c6884a29f38aec0a4e1b4537f40e1c861950ed47d10b049febe6b79ab72adaeeebb3cc8fc1cd33f34e97048a72a9265103426d93efafa78d3e96 languageName: node linkType: hard @@ -8050,7 +8050,7 @@ __metadata: resolution: "domhandler@npm:2.4.2" dependencies: domelementtype: "npm:1" - checksum: 49bd70c9c784f845cd047e1dfb3611bd10891c05719acfc93f01fc726a419ed09fbe0b69f9064392d556a63fffc5a02010856cedae9368f4817146d95a97011f + checksum: d8b0303c53c0eda912e45820ef8f6023f8462a724e8b824324f27923970222a250c7569e067de398c4d9ca3ce0f2b2d2818bc632d6fa72956721d6729479a9b9 languageName: node linkType: hard @@ -8059,7 +8059,7 @@ __metadata: resolution: "domhandler@npm:4.3.1" dependencies: domelementtype: "npm:^2.2.0" - checksum: 4c665ceed016e1911bf7d1dadc09dc888090b64dee7851cccd2fcf5442747ec39c647bb1cb8c8919f8bbdd0f0c625a6bafeeed4b2d656bbecdbae893f43ffaaa + checksum: e0d2af7403997a3ca040a9ace4a233b75ebe321e0ef628b417e46d619d65d47781b2f2038b6c2ef6e56e73e66aec99caf6a12c7e687ecff18ef74af6dfbde5de languageName: node linkType: hard @@ -8069,7 +8069,7 @@ __metadata: dependencies: dom-serializer: "npm:0" domelementtype: "npm:1" - checksum: f60a725b1f73c1ae82f4894b691601ecc6ecb68320d87923ac3633137627c7865725af813ae5d188ad3954283853bcf46779eb50304ec5d5354044569fcefd2b + checksum: 8c1d879fd3bbfc0156c970d12ebdf530f541cbda895d7f631b2444d22bbb9d0e5a3a4c3210cffb17708ad67531d7d40e1bef95e915c53a218d268607b66b63c8 languageName: node linkType: hard @@ -8080,7 +8080,7 @@ __metadata: dom-serializer: "npm:^1.0.1" domelementtype: "npm:^2.2.0" domhandler: "npm:^4.2.0" - checksum: abf7434315283e9aadc2a24bac0e00eab07ae4313b40cc239f89d84d7315ebdfd2fb1b5bf750a96bc1b4403d7237c7b2ebf60459be394d625ead4ca89b934391 + checksum: 1f316a03f00b09a8893d4a25d297d5cbffd02c564509dede28ef72d5ce38d93f6d61f1de88d439f31b14a1d9b42f587ed711b9e8b1b4d3bf6001399832bfc4e0 languageName: node linkType: hard @@ -8091,21 +8091,21 @@ __metadata: dom-serializer: "npm:^2.0.0" domelementtype: "npm:^2.3.0" domhandler: "npm:^5.0.3" - checksum: e5757456ddd173caa411cfc02c2bb64133c65546d2c4081381a3bafc8a57411a41eed70494551aa58030be9e58574fcc489828bebd673863d39924fb4878f416 + checksum: 9a169a6e57ac4c738269a73ab4caf785114ed70e46254139c1bbc8144ac3102aacb28a6149508395ae34aa5d6a40081f4fa5313855dc8319c6d8359866b6dfea languageName: node linkType: hard "dotenv-expand@npm:^10.0.0": version: 10.0.0 resolution: "dotenv-expand@npm:10.0.0" - checksum: 2a38b470efe0abcb1ac8490421a55e1d764dc9440fd220942bce40965074f3fb00b585f4346020cb0f0f219966ee6b4ee5023458b3e2953fe5b3214de1b314ee + checksum: b41eb278bc96b92cbf3037ca5f3d21e8845bf165dc06b6f9a0a03d278c2bd5a01c0cfbb3528ae3a60301ba1a8a9cace30e748c54b460753bc00d4c014b675597 languageName: node linkType: hard "dotenv@npm:^16.0.0": version: 16.3.1 resolution: "dotenv@npm:16.3.1" - checksum: 15d75e7279018f4bafd0ee9706593dd14455ddb71b3bcba9c52574460b7ccaf67d5cf8b2c08a5af1a9da6db36c956a04a1192b101ee102a3e0cf8817bbcf3dfd + checksum: dbb778237ef8750e9e3cd1473d3c8eaa9cc3600e33a75c0e36415d0fa0848197f56c3800f77924c70e7828f0b03896818cd52f785b07b9ad4d88dba73fbba83f languageName: node linkType: hard @@ -8117,14 +8117,14 @@ __metadata: inherits: "npm:^2.0.1" readable-stream: "npm:^2.0.0" stream-shift: "npm:^1.0.0" - checksum: 3c2ed2223d956a5da713dae12ba8295acb61d9acd966ccbba938090d04f4574ca4dca75cca089b5077c2d7e66101f32e6ea9b36a78ca213eff574e7a8b8accf2 + checksum: 7799984d178fb57e11c43f5f172a10f795322ec85ff664c2a98d2c2de6deeb9d7a30b810f83923dcd7ebe0f1786724b8aee2b62ca4577522141f93d6d48fb31c languageName: node linkType: hard "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" - checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed + checksum: 9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 languageName: node linkType: hard @@ -8142,49 +8142,49 @@ __metadata: jake: "npm:^10.8.5" bin: ejs: bin/cli.js - checksum: af6f10eb815885ff8a8cfacc42c6b6cf87daf97a4884f87a30e0c3271fedd85d76a3a297d9c33a70e735b97ee632887f85e32854b9cdd3a2d97edf931519a35f + checksum: 71f56d37540d2c2d71701f0116710c676f75314a3e997ef8b83515d5d4d2b111c5a72725377caeecb928671bacb84a0d38135f345904812e989847057d59f21a languageName: node linkType: hard "electron-to-chromium@npm:^1.4.431": version: 1.4.459 resolution: "electron-to-chromium@npm:1.4.459" - checksum: 2052797a639c131e459c7d8261506b52b277c3e9c0622a1171dcc9b9dc2293c3b2b43260687d320e89a2a82264521135a525c4ed97beba43f5507583d8c0d532 + checksum: 9eeac70b64b31b802d94df9f1f81a31a34ab727023b212a6bee356fda5d781eb233e51e5eaf28b08d308054987dcbb7f58b877a52a1ea04a0f4ad32341225109 languageName: node linkType: hard "electron-to-chromium@npm:^1.4.601": version: 1.4.634 resolution: "electron-to-chromium@npm:1.4.634" - checksum: 5fdaf23ab5162f6cceb115d2151345b9b9258ee4e7635a489c665fd7ccd5b4291ee1eb9017fbab876dadaf9fbea311c3e4c3d7b5b6de75049e76d9960d15583c + checksum: 3245cada8dfb7b169f54e728e7b89ac3d1a3e8579b1972ed5491017537786869756a9b59f525671409f66b93d115bb5b8802001105b0f8528f8f2528360025d6 languageName: node linkType: hard "emittery@npm:^0.13.1": version: 0.13.1 resolution: "emittery@npm:0.13.1" - checksum: 2b089ab6306f38feaabf4f6f02792f9ec85fc054fda79f44f6790e61bbf6bc4e1616afb9b232e0c5ec5289a8a452f79bfa6d905a6fd64e94b49981f0934001c6 + checksum: fbe214171d878b924eedf1757badf58a5dce071cd1fa7f620fa841a0901a80d6da47ff05929d53163105e621ce11a71b9d8acb1148ffe1745e045145f6e69521 languageName: node linkType: hard "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" - checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 + checksum: c72d67a6821be15ec11997877c437491c313d924306b8da5d87d2a2bcc2cec9903cb5b04ee1a088460501d8e5b44f10df82fdc93c444101a7610b80c8b6938e1 languageName: node linkType: hard "emoji-regex@npm:^9.2.2": version: 9.2.2 resolution: "emoji-regex@npm:9.2.2" - checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 + checksum: 915acf859cea7131dac1b2b5c9c8e35c4849e325a1d114c30adb8cd615970f6dca0e27f64f3a4949d7d6ed86ecd79a1c5c63f02e697513cddd7b5835c90948b8 languageName: node linkType: hard "emojis-list@npm:^3.0.0": version: 3.0.0 resolution: "emojis-list@npm:3.0.0" - checksum: ddaaa02542e1e9436c03970eeed445f4ed29a5337dfba0fe0c38dfdd2af5da2429c2a0821304e8a8d1cadf27fdd5b22ff793571fa803ae16852a6975c65e8e70 + checksum: 114f47d6d45612621497d2b1556c8f142c35332a591780a54e863e42d281e72d6c7d7c419f2e419319d4eb7f6ebf1db82d9744905d90f275db20d06a763b5e19 languageName: node linkType: hard @@ -8216,21 +8216,21 @@ __metadata: "entities@npm:^1.1.1": version: 1.1.2 resolution: "entities@npm:1.1.2" - checksum: d537b02799bdd4784ffd714d000597ed168727bddf4885da887c5a491d735739029a00794f1998abbf35f3f6aeda32ef5c15010dca1817d401903a501b6d3e05 + checksum: 4a707022f4e932060f03df2526be55d085a2576fe534421e5b22bc62abb0d1f04241c171f9981e3d7baa4f4160606cad72a2f7eb01b6a25e279e3f31a2be4bf2 languageName: node linkType: hard "entities@npm:^2.0.0": version: 2.2.0 resolution: "entities@npm:2.2.0" - checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 + checksum: 2c765221ee324dbe25e1b8ca5d1bf2a4d39e750548f2e85cbf7ca1d167d709689ddf1796623e66666ae747364c11ed512c03b48c5bbe70968d30f2a4009509b7 languageName: node linkType: hard "entities@npm:^4.2.0, entities@npm:^4.4.0, entities@npm:^4.5.0": version: 4.5.0 resolution: "entities@npm:4.5.0" - checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 + checksum: ede2a35c9bce1aeccd055a1b445d41c75a14a2bb1cd22e242f20cf04d236cdcd7f9c859eb83f76885327bfae0c25bf03303665ee1ce3d47c5927b98b0e3e3d48 languageName: node linkType: hard @@ -8246,14 +8246,14 @@ __metadata: resolution: "envinfo@npm:7.10.0" bin: envinfo: dist/cli.js - checksum: 05e81a5768c42cbd5c580dc3f274db3401facadd53e9bd52e2aa49dfbb5d8b26f6181c25a6652d79618a6994185bd2b1c137673101690b147f758e4e71d42f7d + checksum: d4db29c5a405081759c57c0e74ffa6adab09b7477ca105587252643394f13ab128ad4c8f755b15334b5f1901cef091acc76c71b695ce0f27853ebf147c882075 languageName: node linkType: hard "err-code@npm:^2.0.2": version: 2.0.3 resolution: "err-code@npm:2.0.3" - checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 + checksum: 1d20d825cdcce8d811bfbe86340f4755c02655a7feb2f13f8c880566d9d72a3f6c92c192a6867632e490d6da67b678271f46e01044996a6443e870331100dfdd languageName: node linkType: hard @@ -8262,7 +8262,7 @@ __metadata: resolution: "error-ex@npm:1.3.2" dependencies: is-arrayish: "npm:^0.2.1" - checksum: c1c2b8b65f9c91b0f9d75f0debaa7ec5b35c266c2cac5de412c1a6de86d4cbae04ae44e510378cb14d032d0645a36925d0186f8bb7367bcc629db256b743a001 + checksum: d547740aa29c34e753fb6fed2c5de81802438529c12b3673bd37b6bb1fe49b9b7abdc3c11e6062fe625d8a296b3cf769a80f878865e25e685f787763eede3ffb languageName: node linkType: hard @@ -8305,7 +8305,7 @@ __metadata: typed-array-length: "npm:^1.0.4" unbox-primitive: "npm:^1.0.2" which-typed-array: "npm:^1.1.10" - checksum: 4c5ee900699030a629fc224a3595dcd05f9ff31d607e72bc9042d15e3b1bfde99f408c940b622e96439e755a7b23a3b9e47f3be234015750d32dad38b8f772f4 + checksum: 57fbf1e651308291813b545a5dd70ec6ff8bcd670fbc8dce81f189beeecd173dcad128d4ef2874edd3e566018f5d8ef1e263d34358875f93ff13c96af02c2e35 languageName: node linkType: hard @@ -8322,14 +8322,14 @@ __metadata: is-string: "npm:^1.0.7" isarray: "npm:^2.0.5" stop-iteration-iterator: "npm:^1.0.0" - checksum: 8fa118da42667a01a7c7529f8a8cca514feeff243feec1ce0bb73baaa3514560bd09d2b3438873cf8a5aaec5d52da248131de153b28e2638a061b6e4df13267d + checksum: bc2194befbe55725f9489098626479deee3c801eda7e83ce0dff2eb266a28dc808edb9b623ff01d31ebc1328f09d661333d86b601036692c2e3c1a6942319433 languageName: node linkType: hard "es-module-lexer@npm:^0.9.3": version: 0.9.3 resolution: "es-module-lexer@npm:0.9.3" - checksum: 84bbab23c396281db2c906c766af58b1ae2a1a2599844a504df10b9e8dc77ec800b3211fdaa133ff700f5703d791198807bba25d9667392d27a5e9feda344da8 + checksum: c3e39465d06a6ecd103ccdb746508c88ee4bdd56c15238b0013de38b949a4eca91d5e44d2a9b88d772fe7821547c5fe9200ba0f3353116e208d44bb50c7bc1ea languageName: node linkType: hard @@ -8349,7 +8349,7 @@ __metadata: resolution: "es-shim-unscopables@npm:1.0.0" dependencies: has: "npm:^1.0.3" - checksum: 83e95cadbb6ee44d3644dfad60dcad7929edbc42c85e66c3e99aefd68a3a5c5665f2686885cddb47dfeabfd77bd5ea5a7060f2092a955a729bbd8834f0d86fa1 + checksum: ac2db2c70d253cf83bebcdc974d185239e205ca18af743efd3b656bac00cabfee2358a050b18b63b46972dab5cfa10ef3f2597eb3a8d4d6d9417689793665da6 languageName: node linkType: hard @@ -8360,14 +8360,14 @@ __metadata: is-callable: "npm:^1.1.4" is-date-object: "npm:^1.0.1" is-symbol: "npm:^1.0.2" - checksum: 4ead6671a2c1402619bdd77f3503991232ca15e17e46222b0a41a5d81aebc8740a77822f5b3c965008e631153e9ef0580540007744521e72de8e33599fca2eed + checksum: 74aeeefe2714cf99bb40cab7ce3012d74e1e2c1bd60d0a913b467b269edde6e176ca644b5ba03a5b865fb044a29bca05671cd445c85ca2cdc2de155d7fc8fe9b languageName: node linkType: hard "es6-object-assign@npm:^1.1.0": version: 1.1.0 resolution: "es6-object-assign@npm:1.1.0" - checksum: 8d4fdf63484d78b5c64cacc2c2e1165bc7b6a64b739d2a9db6a4dc8641d99cc9efb433cdd4dc3d3d6b00bfa6ce959694e4665e3255190339945c5f33b692b5d8 + checksum: 396c30376c89e91b5435f177ff83ba0d5ba265e3583cbaaa3bce185df08bf87db58c6d5d84600634280cbf35f8f342569b6ab776d728a12e177e5db82f5b6e2f languageName: node linkType: hard @@ -8382,10 +8382,10 @@ __metadata: version: 3.5.0 resolution: "esbuild-register@npm:3.5.0" dependencies: - debug: ^4.3.4 + debug: "npm:^4.3.4" peerDependencies: esbuild: ">=0.12 <1" - checksum: f4307753c9672a2c901d04a1165031594a854f0a4c6f4c1db08aa393b68a193d38f2df483dc8ca0513e89f7b8998415e7e26fb9830989fb8cdccc5fb5f181c6b + checksum: af6874ce9b5fcdb0974c9d9e9f16530a5b9bd80c699b2ba9d7ace33439c1af1be6948535c775d9a6439e2bf23fb31cfd54ac882cfa38308a3f182039f4b98a01 languageName: node linkType: hard @@ -8393,28 +8393,28 @@ __metadata: version: 0.18.20 resolution: "esbuild@npm:0.18.20" dependencies: - "@esbuild/android-arm": 0.18.20 - "@esbuild/android-arm64": 0.18.20 - "@esbuild/android-x64": 0.18.20 - "@esbuild/darwin-arm64": 0.18.20 - "@esbuild/darwin-x64": 0.18.20 - "@esbuild/freebsd-arm64": 0.18.20 - "@esbuild/freebsd-x64": 0.18.20 - "@esbuild/linux-arm": 0.18.20 - "@esbuild/linux-arm64": 0.18.20 - "@esbuild/linux-ia32": 0.18.20 - "@esbuild/linux-loong64": 0.18.20 - "@esbuild/linux-mips64el": 0.18.20 - "@esbuild/linux-ppc64": 0.18.20 - "@esbuild/linux-riscv64": 0.18.20 - "@esbuild/linux-s390x": 0.18.20 - "@esbuild/linux-x64": 0.18.20 - "@esbuild/netbsd-x64": 0.18.20 - "@esbuild/openbsd-x64": 0.18.20 - "@esbuild/sunos-x64": 0.18.20 - "@esbuild/win32-arm64": 0.18.20 - "@esbuild/win32-ia32": 0.18.20 - "@esbuild/win32-x64": 0.18.20 + "@esbuild/android-arm": "npm:0.18.20" + "@esbuild/android-arm64": "npm:0.18.20" + "@esbuild/android-x64": "npm:0.18.20" + "@esbuild/darwin-arm64": "npm:0.18.20" + "@esbuild/darwin-x64": "npm:0.18.20" + "@esbuild/freebsd-arm64": "npm:0.18.20" + "@esbuild/freebsd-x64": "npm:0.18.20" + "@esbuild/linux-arm": "npm:0.18.20" + "@esbuild/linux-arm64": "npm:0.18.20" + "@esbuild/linux-ia32": "npm:0.18.20" + "@esbuild/linux-loong64": "npm:0.18.20" + "@esbuild/linux-mips64el": "npm:0.18.20" + "@esbuild/linux-ppc64": "npm:0.18.20" + "@esbuild/linux-riscv64": "npm:0.18.20" + "@esbuild/linux-s390x": "npm:0.18.20" + "@esbuild/linux-x64": "npm:0.18.20" + "@esbuild/netbsd-x64": "npm:0.18.20" + "@esbuild/openbsd-x64": "npm:0.18.20" + "@esbuild/sunos-x64": "npm:0.18.20" + "@esbuild/win32-arm64": "npm:0.18.20" + "@esbuild/win32-ia32": "npm:0.18.20" + "@esbuild/win32-x64": "npm:0.18.20" dependenciesMeta: "@esbuild/android-arm": optional: true @@ -8462,7 +8462,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 5d253614e50cdb6ec22095afd0c414f15688e7278a7eb4f3720a6dd1306b0909cf431e7b9437a90d065a31b1c57be60130f63fe3e8d0083b588571f31ee6ec7b + checksum: 1f723ec71c3aa196473bf3298316eedc3f62d523924652dfeb60701b609792f918fc60db84b420d1d8ba9bfa7d69de2fc1d3157ba47c028bdae5d507a26a3c64 languageName: node linkType: hard @@ -8539,14 +8539,14 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 9d5aac77f637bf69f161dbf900f91cdec38c4bd47562b81302a2f790781fc1430f17790ee934058fa18379673c2987b0310fa61e8ccefb37065b8cc79956f099 + checksum: 724411d6dc01ac4ee9a6a7f9f735765f81383c9f2a1cbc35dcccf558cd5bc13f0913ff9a3a3eab0dfe3db20f85991e9f60f59a5d709443ed2179d525722d17e9 languageName: node linkType: hard "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" - checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 + checksum: afa618e73362576b63f6ca83c975456621095a1ed42ff068174e3f5cea48afc422814dda548c96e6ebb5333e7265140c7292abcc81bbd6ccb1757d50d3a4e182 languageName: node linkType: hard @@ -8592,7 +8592,7 @@ __metadata: bin: escodegen: bin/escodegen.js esgenerate: bin/esgenerate.js - checksum: 096696407e161305cd05aebb95134ad176708bc5cb13d0dcc89a5fcbb959b8ed757e7f2591a5f8036f8f4952d4a724de0df14cd419e29212729fa6df5ce16bf6 + checksum: 47719a65b2888b4586e3fa93769068b275961c13089e90d5d01a96a6e8e95871b1c3893576814c8fbf08a4a31a496f37e7b2c937cf231270f4d81de012832c7c languageName: node linkType: hard @@ -8603,7 +8603,7 @@ __metadata: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: 1e94c3882c4d5e41e1dcfa2c368dbccbfe3134f6ac7d40101644d3bfbe3eb2f2ffac757f3145910b5eacf20c0e85e02b91293d3126d770cbf3dc390b3564681c + checksum: 3638144cecada897105ff9442bc85aba71c4f44d7d25b576cb34d50a207f6655f7cc55e729aad1a934a9f15e55c88e7adcbd1067d6582325fc89864c879b52f1 languageName: node linkType: hard @@ -8614,7 +8614,7 @@ __metadata: debug: "npm:^3.2.7" is-core-module: "npm:^2.11.0" resolve: "npm:^1.22.1" - checksum: 3379aacf1d2c6952c1b9666c6fa5982c3023df695430b0d391c0029f6403a7775414873d90f397e98ba6245372b6c8960e16e74d9e4a3b0c0a4582f3bdbe3d6e + checksum: 31c6dfbd3457d1e6170ac2326b7ba9c323ff1ea68e3fcc5309f234bd1cefed050ee9b35e458b5eaed91323ab0d29bb2eddb41a1720ba7ca09bbacb00a0339d64 languageName: node linkType: hard @@ -8626,7 +8626,7 @@ __metadata: peerDependenciesMeta: eslint: optional: true - checksum: 74c6dfea7641ebcfe174be61168541a11a14aa8d72e515f5f09af55cd0d0862686104b0524aa4b8e0ce66418a44aa38a94d2588743db5fd07a6b49ffd16921d2 + checksum: a9a7ed93eb858092e3cdc797357d4ead2b3ea06959b0eada31ab13862d46a59eb064b9cb82302214232e547980ce33618c2992f6821138a4934e65710ed9cc29 languageName: node linkType: hard @@ -8651,7 +8651,7 @@ __metadata: tsconfig-paths: "npm:^3.14.1" peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: f500571a380167e25d72a4d925ef9a7aae8899eada57653e5f3051ec3d3c16d08271fcefe41a30a9a2f4fefc232f066253673ee4ea77b30dba65ae173dade85d + checksum: b8ab9521bd47acdad959309cbb5635069cebd0f1dfd14b5f6ad24f609dfda82c604b029c7366cafce1d359845300957ec246587cd5e4b237a0378118a9d3dfa7 languageName: node linkType: hard @@ -8677,7 +8677,7 @@ __metadata: semver: "npm:^6.3.0" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: f166dd5fe7257c7b891c6692e6a3ede6f237a14043ae3d97581daf318fc5833ddc6b4871aa34ab7656187430170500f6d806895747ea17ecdf8231a666c3c2fd + checksum: b7eb451304dc27c9552649a716be1de3b5d577f39e53f6da6a2dac084b84b349b0224be3020439f99c2b3bf417a13c5591326f1ce6af8d74f1cb5d5d95c4222b languageName: node linkType: hard @@ -8692,7 +8692,7 @@ __metadata: peerDependenciesMeta: eslint-config-prettier: optional: true - checksum: b9e839d2334ad8ec7a5589c5cb0f219bded260839a857d7a486997f9870e95106aa59b8756ff3f37202085ebab658de382b0267cae44c3a7f0eb0bcc03a4f6d6 + checksum: d387f85dd1bfcb6bc6b794845fee6afb9ebb2375653de6bcde6e615892fb97f85121a7c012a4651b181fc09953bdf54c9bc70cab7ad297019d89ae87dd007e28 languageName: node linkType: hard @@ -8701,7 +8701,7 @@ __metadata: resolution: "eslint-plugin-react-hooks@npm:4.6.0" peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 23001801f14c1d16bf0a837ca7970d9dd94e7b560384b41db378b49b6e32dc43d6e2790de1bd737a652a86f81a08d6a91f402525061b47719328f586a57e86c3 + checksum: 3c63134e056a6d98d66e2c475c81f904169db817e89316d14e36269919e31f4876a2588aa0e466ec8ef160465169c627fe823bfdaae7e213946584e4a165a3ac languageName: node linkType: hard @@ -8735,7 +8735,7 @@ __metadata: string.prototype.matchall: "npm:^4.0.8" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: 2232b3b8945aa50b7773919c15cd96892acf35d2f82503667a79e2f55def90f728ed4f0e496f0f157acbe1bd4397c5615b676ae7428fe84488a544ca53feb944 + checksum: 5ca7959c85fa557bcd25c4b9b3f81fbfae974e8fb16172e31a275712cc71da8ecbb9436da2d3130a8b24dd7a4bbe69d37d4392944aecc4821618717ba156caf4 languageName: node linkType: hard @@ -8748,7 +8748,7 @@ __metadata: lodash: "npm:^4.17.15" peerDependencies: eslint: ">=0.8.0" - checksum: 2ab85337774910de86586581f76bf10e40f83be4e0971d2f6f5a31b658ed3bb003528bedd25d70b07e2942e8418cd0009bf6eeab829eb7cbf2108e13afa83f35 + checksum: 073102a28b25f81f9ea0f4334dd0bf9fe23d3585039bae0706b7b1d7848601c3cf8d003f56932d7948745ba5290e748f9f62f93b4fca2fe0cfdb9508dab3e835 languageName: node linkType: hard @@ -8762,7 +8762,7 @@ __metadata: ts-dedent: "npm:^2.2.0" peerDependencies: eslint: ">=6" - checksum: 8e0e160c71216019c291a5a03b797b5359076067d16ea03b3dec63594093d45398f028d15c47eb89f2ddb6e8db18cc7e376b02d921dacc4fb31bbc8da46363c8 + checksum: 12fc268a2834bec5f512608d90c84a86fd664bdcb8a6a2e085b6808370093c83fdaf09112776d395e739c526c5c8d82ab6bf1159180406723ad5ed905f4b43d1 languageName: node linkType: hard @@ -8772,7 +8772,7 @@ __metadata: dependencies: esrecurse: "npm:^4.3.0" estraverse: "npm:^4.1.1" - checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb + checksum: c541ef384c92eb5c999b7d3443d80195fcafb3da335500946f6db76539b87d5826c8f2e1d23bf6afc3154ba8cd7c8e566f8dc00f1eea25fdf3afc8fb9c87b238 languageName: node linkType: hard @@ -8782,14 +8782,14 @@ __metadata: dependencies: esrecurse: "npm:^4.3.0" estraverse: "npm:^5.2.0" - checksum: 64591a2d8b244ade9c690b59ef238a11d5c721a98bcee9e9f445454f442d03d3e04eda88e95a4daec558220a99fa384309d9faae3d459bd40e7a81b4063980ae + checksum: 94d8942840b35bf5e6559bd0f0a8b10610d65b1e44e41295e66ed1fe82f83bc51756e7af607d611b75f435adf821122bd901aa565701596ca1a628db41c0cd87 languageName: node linkType: hard "eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.0, eslint-visitor-keys@npm:^3.4.1": version: 3.4.1 resolution: "eslint-visitor-keys@npm:3.4.1" - checksum: f05121d868202736b97de7d750847a328fcfa8593b031c95ea89425333db59676ac087fa905eba438d0a3c5769632f828187e0c1a0d271832a2153c1d3661c2c + checksum: 92641e7ccde470065aa2931161a6a053690a54aae35ae08f38e376ecfd7c012573c542b37a3baecf921eb951fd57943411392f464c2b8f3399adee4723a1369f languageName: node linkType: hard @@ -8839,7 +8839,7 @@ __metadata: text-table: "npm:^0.2.0" bin: eslint: bin/eslint.js - checksum: 73b6d9b650d0434aa7c07d0a1802f099b086ee70a8d8ba7be730439a26572a5eb71def12125c82942be2ec8ee5be38a6f1b42a13e40d4b67f11a148ec9e263eb + checksum: 203bc814d5d482c952b8e1e2b10b624ba7f228c7c3453cf5b14d52faddfc2aba6600dc1759ca85ff54a36c56608e43ef50255971c50d03e468fec38092b23d18 languageName: node linkType: hard @@ -8850,7 +8850,7 @@ __metadata: acorn: "npm:^8.9.0" acorn-jsx: "npm:^5.3.2" eslint-visitor-keys: "npm:^3.4.1" - checksum: 1287979510efb052a6a97c73067ea5d0a40701b29adde87bbe2d3eb1667e39ca55e8129e20e2517fed3da570150e7ef470585228459a8f3e3755f45007a1c662 + checksum: 870834c0ab188213ba56fae7003ff9fadbad2b9285dae941840c3d425cedbb2221ad3cffaabd217bc36b96eb80d651c2a2d9b0b1f3b9394b2358b27052c942e2 languageName: node linkType: hard @@ -8860,7 +8860,7 @@ __metadata: bin: esparse: ./bin/esparse.js esvalidate: ./bin/esvalidate.js - checksum: b45bc805a613dbea2835278c306b91aff6173c8d034223fa81498c77dcbce3b2931bf6006db816f62eacd9fd4ea975dfd85a5b7f3c6402cfd050d4ca3c13a628 + checksum: f1d3c622ad992421362294f7acf866aa9409fbad4eb2e8fa230bd33944ce371d32279667b242d8b8907ec2b6ad7353a717f3c0e60e748873a34a7905174bc0eb languageName: node linkType: hard @@ -8869,7 +8869,7 @@ __metadata: resolution: "esquery@npm:1.5.0" dependencies: estraverse: "npm:^5.1.0" - checksum: aefb0d2596c230118656cd4ec7532d447333a410a48834d80ea648b1e7b5c9bc9ed8b5e33a89cb04e487b60d622f44cf5713bf4abed7c97343edefdc84a35900 + checksum: e65fcdfc1e0ff5effbf50fb4f31ea20143ae5df92bb2e4953653d8d40aa4bc148e0d06117a592ce4ea53eeab1dafdfded7ea7e22a5be87e82d73757329a1b01d languageName: node linkType: hard @@ -8878,35 +8878,35 @@ __metadata: resolution: "esrecurse@npm:4.3.0" dependencies: estraverse: "npm:^5.2.0" - checksum: ebc17b1a33c51cef46fdc28b958994b1dc43cd2e86237515cbc3b4e5d2be6a811b2315d0a1a4d9d340b6d2308b15322f5c8291059521cc5f4802f65e7ec32837 + checksum: 44ffcd89e714ea6b30143e7f119b104fc4d75e77ee913f34d59076b40ef2d21967f84e019f84e1fd0465b42cdbf725db449f232b5e47f29df29ed76194db8e16 languageName: node linkType: hard "estraverse@npm:^4.1.1": version: 4.3.0 resolution: "estraverse@npm:4.3.0" - checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827 + checksum: 3f67ad02b6dbfaddd9ea459cf2b6ef4ecff9a6082a7af9d22e445b9abc082ad9ca47e1825557b293fcdae477f4714e561123e30bb6a5b2f184fb2bad4a9497eb languageName: node linkType: hard "estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" - checksum: 072780882dc8416ad144f8fe199628d2b3e7bbc9989d9ed43795d2c90309a2047e6bc5979d7e2322a341163d22cfad9e21f4110597fe487519697389497e4e2b + checksum: 37cbe6e9a68014d34dbdc039f90d0baf72436809d02edffcc06ba3c2a12eb298048f877511353b130153e532aac8d68ba78430c0dd2f44806ebc7c014b01585e languageName: node linkType: hard "estree-walker@npm:^2.0.1, estree-walker@npm:^2.0.2": version: 2.0.2 resolution: "estree-walker@npm:2.0.2" - checksum: 6151e6f9828abe2259e57f5fd3761335bb0d2ebd76dc1a01048ccee22fabcfef3c0859300f6d83ff0d1927849368775ec5a6d265dde2f6de5a1be1721cd94efc + checksum: b02109c5d46bc2ed47de4990eef770f7457b1159a229f0999a09224d2b85ffeed2d7679cffcff90aeb4448e94b0168feb5265b209cdec29aad50a3d6e93d21e2 languageName: node linkType: hard "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" - checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 + checksum: b23acd24791db11d8f65be5ea58fd9a6ce2df5120ae2da65c16cfc5331ff59d5ac4ef50af66cd4bde238881503ec839928a0135b99a036a9cdfa22d17fd56cdb languageName: node linkType: hard @@ -8930,14 +8930,14 @@ __metadata: onetime: "npm:^5.1.2" signal-exit: "npm:^3.0.3" strip-final-newline: "npm:^2.0.0" - checksum: fba9022c8c8c15ed862847e94c252b3d946036d7547af310e344a527e59021fd8b6bb0723883ea87044dc4f0201f949046993124a42ccb0855cae5bf8c786343 + checksum: 8ada91f2d70f7dff702c861c2c64f21dfdc1525628f3c0454fd6f02fce65f7b958616cbd2b99ca7fa4d474e461a3d363824e91b3eb881705231abbf387470597 languageName: node linkType: hard "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" - checksum: abc407f07a875c3961e4781dfcb743b58d6c93de9ab263f4f8c9d23bb6da5f9b7764fc773f86b43dd88030444d5ab8abcb611cb680fba8ca075362b77114bba3 + checksum: 387555050c5b3c10e7a9e8df5f43194e95d7737c74532c409910e585d5554eaff34960c166643f5e23d042196529daad059c292dcf1fb61b8ca878d3677f4b87 languageName: node linkType: hard @@ -8952,7 +8952,7 @@ __metadata: regex-not: "npm:^1.0.0" snapdragon: "npm:^0.8.1" to-regex: "npm:^3.0.1" - checksum: 1781d422e7edfa20009e2abda673cadb040a6037f0bd30fcd7357304f4f0c284afd420d7622722ca4a016f39b6d091841ab57b401c1f7e2e5131ac65b9f14fa1 + checksum: aa4acc62084638c761ecdbe178bd3136f01121939f96bbfc3be27c46c66625075f77fe0a446b627c9071b1aaf6d93ccf5bde5ff34b7ef883e4f46067a8e63e41 languageName: node linkType: hard @@ -8966,14 +8966,14 @@ __metadata: jest-matcher-utils: "npm:^29.6.1" jest-message-util: "npm:^29.6.1" jest-util: "npm:^29.6.1" - checksum: 4e712e52c90f6c54e748fd2876be33c43ada6a59088ddf6a1acb08b18b3b97b3a672124684abe32599986d2f2a438d5afad148837ee06ea386d2a4bf0348de78 + checksum: aa737890fe4a2c3145c4004e2817a14f6196775a53bd591f756f617062881eb576ed9c0409f10b076ad969ceb3dc73b88752100a69db9652a06e0a77e297a6fa languageName: node linkType: hard "exponential-backoff@npm:^3.1.1": version: 3.1.1 resolution: "exponential-backoff@npm:3.1.1" - checksum: 3d21519a4f8207c99f7457287291316306255a328770d320b401114ec8481986e4e467e854cb9914dd965e0a1ca810a23ccb559c642c88f4c7f55c55778a9b48 + checksum: 2d9bbb6473de7051f96790d5f9a678f32e60ed0aa70741dc7fdc96fec8d631124ec3374ac144387604f05afff9500f31a1d45bd9eee4cdc2e4f9ad2d9b9d5dbd languageName: node linkType: hard @@ -9012,7 +9012,7 @@ __metadata: type-is: "npm:~1.6.18" utils-merge: "npm:1.0.1" vary: "npm:~1.1.2" - checksum: 3c4b9b076879442f6b968fe53d85d9f1eeacbb4f4c41e5f16cc36d77ce39a2b0d81b3f250514982110d815b2f7173f5561367f9110fcc541f9371948e8c8b037 + checksum: 869ae89ed6ff4bed7b373079dc58e5dddcf2915a2669b36037ff78c99d675ae930e5fe052b35c24f56557d28a023bb1cbe3e2f2fb87eaab96a1cedd7e597809d languageName: node linkType: hard @@ -9038,7 +9038,7 @@ __metadata: "extend@npm:^3.0.0": version: 3.0.2 resolution: "extend@npm:3.0.2" - checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515 + checksum: 59e89e2dc798ec0f54b36d82f32a27d5f6472c53974f61ca098db5d4648430b725387b53449a34df38fd0392045434426b012f302b3cc049a6500ccf82877e4e languageName: node linkType: hard @@ -9054,7 +9054,7 @@ __metadata: regex-not: "npm:^1.0.0" snapdragon: "npm:^0.8.1" to-regex: "npm:^3.0.1" - checksum: a41531b8934735b684cef5e8c5a01d0f298d7d384500ceca38793a9ce098125aab04ee73e2d75d5b2901bc5dddd2b64e1b5e3bf19139ea48bac52af4a92f1d00 + checksum: 6869edd48d40c322e1cda9bf494ed2407c69a19063fd2897184cb62d6d35c14fa7402b01d9dedd65d77ed1ccc74a291235a702c68b4f28a7314da0cdee97c85b languageName: node linkType: hard @@ -9068,7 +9068,7 @@ __metadata: yauzl: "npm:^2.10.0" bin: extract-zip: cli.js - checksum: 011bab660d738614555773d381a6ba4815d98c1cfcdcdf027e154ebcc9fc8c9ef637b3ea5c9b2144013100071ee41722ed041fc9aacc60f6198ef747cac0c073 + checksum: a9a5e2b118cc1d3b780d296f056308a8fda580bb18a26e12d6137321e5d3ef1d09355195ff187e9c7039aab42a253ac1e3996c66d031c44abca5abde6fd51393 languageName: node linkType: hard @@ -9082,7 +9082,7 @@ __metadata: "fast-diff@npm:^1.1.2": version: 1.3.0 resolution: "fast-diff@npm:1.3.0" - checksum: d22d371b994fdc8cce9ff510d7b8dc4da70ac327bcba20df607dd5b9cae9f908f4d1028f5fe467650f058d1e7270235ae0b8230809a262b4df587a3b3aa216c3 + checksum: 9e57415bc69cd6efcc720b3b8fe9fdaf42dcfc06f86f0f45378b1fa512598a8aac48aa3928c8751d58e2f01bb4ba4f07e4f3d9bc0d57586d45f1bd1e872c6cde languageName: node linkType: hard @@ -9095,21 +9095,21 @@ __metadata: glob-parent: "npm:^5.1.2" merge2: "npm:^1.3.0" micromatch: "npm:^4.0.4" - checksum: 20df62be28eb5426fe8e40e0d05601a63b1daceb7c3d87534afcad91bdcf1e4b1743cf2d5247d6e225b120b46df0b9053a032b2691ba34ee121e033acd81f547 + checksum: 4cd74914f13eab48dd1a0d16051aa102c13d30ea8a79c991563ea3111a37ff6d888518964291d52d723e7ad2a946149ce9f13d27ad9a07a1e4e1aefb4717ed29 languageName: node linkType: hard "fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb + checksum: 2c20055c1fa43c922428f16ca8bb29f2807de63e5c851f665f7ac9790176c01c3b40335257736b299764a8d383388dabc73c8083b8e1bc3d99f0a941444ec60e languageName: node linkType: hard "fast-levenshtein@npm:^2.0.6": version: 2.0.6 resolution: "fast-levenshtein@npm:2.0.6" - checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c + checksum: eb7e220ecf2bab5159d157350b81d01f75726a4382f5a9266f42b9150c4523b9795f7f5d9fbbbeaeac09a441b2369f05ee02db48ea938584205530fe5693cfe1 languageName: node linkType: hard @@ -9118,7 +9118,7 @@ __metadata: resolution: "fastq@npm:1.15.0" dependencies: reusify: "npm:^1.0.4" - checksum: 0170e6bfcd5d57a70412440b8ef600da6de3b2a6c5966aeaf0a852d542daff506a0ee92d6de7679d1de82e644bce69d7a574a6c93f0b03964b5337eed75ada1a + checksum: 67c01b1c972e2d5b6fea197a1a39d5d582982aea69ff4c504badac71080d8396d4843b165a9686e907c233048f15a86bbccb0e7f83ba771f6fa24bcde059d0c3 languageName: node linkType: hard @@ -9136,7 +9136,7 @@ __metadata: resolution: "fb-watchman@npm:2.0.2" dependencies: bser: "npm:2.1.1" - checksum: b15a124cef28916fe07b400eb87cbc73ca082c142abf7ca8e8de6af43eca79ca7bd13eb4d4d48240b3bd3136eaac40d16e42d6edf87a8e5d1dd8070626860c78 + checksum: 4f95d336fb805786759e383fd7fff342ceb7680f53efcc0ef82f502eb479ce35b98e8b207b6dfdfeea0eba845862107dc73813775fc6b56b3098c6e90a2dad77 languageName: node linkType: hard @@ -9145,14 +9145,14 @@ __metadata: resolution: "fd-slicer@npm:1.1.0" dependencies: pend: "npm:~1.2.0" - checksum: c8585fd5713f4476eb8261150900d2cb7f6ff2d87f8feb306ccc8a1122efd152f1783bdb2b8dc891395744583436bfd8081d8e63ece0ec8687eeefea394d4ff2 + checksum: db3e34fa483b5873b73f248e818f8a8b59a6427fd8b1436cd439c195fdf11e8659419404826059a642b57d18075c856d06d6a50a1413b714f12f833a9341ead3 languageName: node linkType: hard "fetch-retry@npm:^5.0.2": version: 5.0.6 resolution: "fetch-retry@npm:5.0.6" - checksum: 4ad8bca6ec7a7b1212e636bb422a9ae8bb9dce38df0b441c9eb77a29af99b368029d6248ff69427da67e3d43c53808b121135ea395e7fe4f8f383e0ad65b4f27 + checksum: 9d64b37f9d179fecf486725ada210d169375803b731304a9500754e094a2a6aa81630d946adbb313d7f9d54457ad0d17c3ed5c115034961a719e8a65faa8b77c languageName: node linkType: hard @@ -9161,7 +9161,7 @@ __metadata: resolution: "file-entry-cache@npm:6.0.1" dependencies: flat-cache: "npm:^3.0.4" - checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 + checksum: 099bb9d4ab332cb93c48b14807a6918a1da87c45dce91d4b61fd40e6505d56d0697da060cb901c729c90487067d93c9243f5da3dc9c41f0358483bfdebca736b languageName: node linkType: hard @@ -9171,7 +9171,7 @@ __metadata: dependencies: fs-extra: "npm:11.1.1" ramda: "npm:0.29.0" - checksum: 74afa2870a062500643d41e02d1fbd47a3f30100f9e153dec5233d59f05545f4c8ada6085629d624e043479ac28c0cafc31824f7b49a3f997efab8cc5d05bfee + checksum: 8f0530aaa8bed115ef1b00f69accde8d1311d0eaffc6e37bb0b5057b8be79e6e960823025ea3c980a58147eed0ba690b9906c2229e132f5d96158e9b635a052c languageName: node linkType: hard @@ -9180,7 +9180,7 @@ __metadata: resolution: "filelist@npm:1.0.4" dependencies: minimatch: "npm:^5.0.1" - checksum: a303573b0821e17f2d5e9783688ab6fbfce5d52aaac842790ae85e704a6f5e4e3538660a63183d6453834dedf1e0f19a9dadcebfa3e926c72397694ea11f5160 + checksum: 4b436fa944b1508b95cffdfc8176ae6947b92825483639ef1b9a89b27d82f3f8aa22b21eed471993f92709b431670d4e015b39c087d435a61e1bb04564cf51de languageName: node linkType: hard @@ -9192,7 +9192,7 @@ __metadata: is-number: "npm:^3.0.0" repeat-string: "npm:^1.6.1" to-regex-range: "npm:^2.1.0" - checksum: dbb5102467786ab42bc7a3ec7380ae5d6bfd1b5177b2216de89e4a541193f8ba599a6db84651bd2c58c8921db41b8cc3d699ea83b477342d3ce404020f73c298 + checksum: 68be23b3c40d5a3fd2847ce18e3a5eac25d9f4c05627291e048ba1346ed0e429668b58a3429e61c0db9fa5954c4402fe99322a65d8a0eb06ebed8d3a18fbb09a languageName: node linkType: hard @@ -9201,7 +9201,7 @@ __metadata: resolution: "fill-range@npm:7.0.1" dependencies: to-regex-range: "npm:^5.0.1" - checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917 + checksum: e260f7592fd196b4421504d3597cc76f4a1ca7a9488260d533b611fc3cefd61e9a9be1417cb82d3b01ad9f9c0ff2dbf258e1026d2445e26b0cf5148ff4250429 languageName: node linkType: hard @@ -9216,7 +9216,7 @@ __metadata: parseurl: "npm:~1.3.3" statuses: "npm:2.0.1" unpipe: "npm:~1.0.0" - checksum: 92effbfd32e22a7dff2994acedbd9bcc3aa646a3e919ea6a53238090e87097f8ef07cced90aa2cc421abdf993aefbdd5b00104d55c7c5479a8d00ed105b45716 + checksum: 635718cb203c6d18e6b48dfbb6c54ccb08ea470e4f474ddcef38c47edcf3227feec316f886dd701235997d8af35240cae49856721ce18f539ad038665ebbf163 languageName: node linkType: hard @@ -9238,7 +9238,7 @@ __metadata: commondir: "npm:^1.0.1" make-dir: "npm:^3.0.2" pkg-dir: "npm:^4.1.0" - checksum: 1e61c2e64f5c0b1c535bd85939ae73b0e5773142713273818cc0b393ee3555fb0fd44e1a5b161b8b6c3e03e98c2fcc9c227d784850a13a90a8ab576869576817 + checksum: 3907c2e0b15132704ed67083686cd3e68ab7d9ecc22e50ae9da20678245d488b01fa22c0e34c0544dc6edc4354c766f016c8c186a787be7c17f7cde8c5281e85 languageName: node linkType: hard @@ -9277,7 +9277,7 @@ __metadata: dependencies: flatted: "npm:^3.1.0" rimraf: "npm:^3.0.2" - checksum: 4fdd10ecbcbf7d520f9040dd1340eb5dfe951e6f0ecf2252edeec03ee68d989ec8b9a20f4434270e71bcfd57800dc09b3344fca3966b2eb8f613072c7d9a2365 + checksum: 9fe5d0cb97c988e3b25242e71346965fae22757674db3fca14206850af2efa3ca3b04a3ba0eba8d5e20fd8a3be80a2e14b1c2917e70ffe1acb98a8c3327e4c9f languageName: node linkType: hard @@ -9291,7 +9291,7 @@ __metadata: "flow-parser@npm:0.*": version: 0.212.0 resolution: "flow-parser@npm:0.212.0" - checksum: e9ae67959134a610079b22d6c12b09e8fa2f2a4f6e6e83c31c2603a94b6b687f78c9ad1229cbcc9c8c50d5f040ac582dd5c25aaeda0acd535dad93c41b4701f7 + checksum: 47a52ac9db1fb6e4a2d5bbbcdc64f0ca60151395b1714ebad3bd132b307ca9bdefae320d71f24884ddd5622ae76151ee14022b592c385e4ae239825309e1677e languageName: node linkType: hard @@ -9301,7 +9301,7 @@ __metadata: peerDependenciesMeta: debug: optional: true - checksum: faa66059b66358ba65c234c2f2a37fcec029dc22775f35d9ad6abac56003268baf41e55f9ee645957b32c7d9f62baf1f0b906e68267276f54ec4b4c597c2b190 + checksum: 8be0d39919770054812537d376850ccde0b4762b0501c440bd08724971a078123b55f57704f2984e0664fecc0c86adea85add63295804d9dce401cd9604c91d3 languageName: node linkType: hard @@ -9310,7 +9310,7 @@ __metadata: resolution: "for-each@npm:0.3.3" dependencies: is-callable: "npm:^1.1.3" - checksum: 6c48ff2bc63362319c65e2edca4a8e1e3483a2fabc72fbe7feaf8c73db94fc7861bd53bc02c8a66a0c1dd709da6b04eec42e0abdd6b40ce47305ae92a25e5d28 + checksum: fdac0cde1be35610bd635ae958422e8ce0cc1313e8d32ea6d34cfda7b60850940c1fd07c36456ad76bd9c24aef6ff5e03b02beb58c83af5ef6c968a64eada676 languageName: node linkType: hard @@ -9327,7 +9327,7 @@ __metadata: dependencies: cross-spawn: "npm:^7.0.0" signal-exit: "npm:^4.0.1" - checksum: 139d270bc82dc9e6f8bc045fe2aae4001dc2472157044fdfad376d0a3457f77857fa883c1c8b21b491c6caade9a926a4bed3d3d2e8d3c9202b151a4cbbd0bcd5 + checksum: 087edd44857d258c4f73ad84cb8df980826569656f2550c341b27adf5335354393eec24ea2fabd43a253233fb27cee177ebe46bd0b7ea129c77e87cb1e9936fb languageName: node linkType: hard @@ -9338,21 +9338,21 @@ __metadata: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" mime-types: "npm:^2.1.12" - checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c + checksum: 7264aa760a8cf09482816d8300f1b6e2423de1b02bba612a136857413fdc96d7178298ced106817655facc6b89036c6e12ae31c9eb5bdc16aabf502ae8a5d805 languageName: node linkType: hard "format@npm:^0.2.0": version: 0.2.2 resolution: "format@npm:0.2.2" - checksum: 646a60e1336250d802509cf24fb801e43bd4a70a07510c816fa133aa42cdbc9c21e66e9cc0801bb183c5b031c9d68be62e7fbb6877756e52357850f92aa28799 + checksum: 5f878b8fc1a672c8cbefa4f293bdd977c822862577d70d53456a48b4169ec9b51677c0c995bf62c633b4e5cd673624b7c273f57923b28735a6c0c0a72c382a4a languageName: node linkType: hard "forwarded@npm:0.2.0": version: 0.2.0 resolution: "forwarded@npm:0.2.0" - checksum: fd27e2394d8887ebd16a66ffc889dc983fbbd797d5d3f01087c020283c0f019a7d05ee85669383d8e0d216b116d720fc0cef2f6e9b7eb9f4c90c6e0bc7fd28e6 + checksum: 29ba9fd347117144e97cbb8852baae5e8b2acb7d1b591ef85695ed96f5b933b1804a7fac4a15dd09ca7ac7d0cdc104410e8102aae2dd3faa570a797ba07adb81 languageName: node linkType: hard @@ -9368,7 +9368,7 @@ __metadata: "fresh@npm:0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" - checksum: 13ea8b08f91e669a64e3ba3a20eb79d7ca5379a81f1ff7f4310d54e2320645503cc0c78daedc93dfb6191287295f6479544a649c64d8e41a1c0fb0c221552346 + checksum: 64c88e489b5d08e2f29664eb3c79c705ff9a8eb15d3e597198ef76546d4ade295897a44abb0abd2700e7ef784b2e3cbf1161e4fbf16f59129193fd1030d16da1 languageName: node linkType: hard @@ -9386,7 +9386,7 @@ __metadata: graceful-fs: "npm:^4.2.0" jsonfile: "npm:^6.0.1" universalify: "npm:^2.0.0" - checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd + checksum: c4e9fabf9762a70d1403316b7faa899f3d3303c8afa765b891c2210fdeba368461e04ae1203920b64ef6a7d066a39ab8cef2160b5ce8d1011bb4368688cd9bb7 languageName: node linkType: hard @@ -9395,7 +9395,7 @@ __metadata: resolution: "fs-minipass@npm:2.1.0" dependencies: minipass: "npm:^3.0.0" - checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 + checksum: 03191781e94bc9a54bd376d3146f90fe8e082627c502185dbf7b9b3032f66b0b142c1115f3b2cc5936575fc1b44845ce903dd4c21bec2a8d69f3bd56f9cee9ec languageName: node linkType: hard @@ -9404,14 +9404,14 @@ __metadata: resolution: "fs-minipass@npm:3.0.2" dependencies: minipass: "npm:^5.0.0" - checksum: e9cc0e1f2d01c6f6f62f567aee59530aba65c6c7b2ae88c5027bc34c711ebcfcfaefd0caf254afa6adfe7d1fba16bc2537508a6235196bac7276747d078aef0a + checksum: 1c071b5b8fc5b553ad2bd40f85988bc4d78d80eee766d0082a67dcff9a2536fd4fdd5fa2441661f799fa95000054296e4f900d6e96b2a025d173d325f3adf458 languageName: node linkType: hard "fs.realpath@npm:^1.0.0": version: 1.0.0 resolution: "fs.realpath@npm:1.0.0" - checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 + checksum: e703107c28e362d8d7b910bbcbfd371e640a3bb45ae157a362b5952c0030c0b6d4981140ec319b347bce7adc025dd7813da1ff908a945ac214d64f5402a51b96 languageName: node linkType: hard @@ -9420,14 +9420,14 @@ __metadata: resolution: "fsevents@npm:2.3.2" dependencies: node-gyp: "npm:latest" - checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f + checksum: 6b5b6f5692372446ff81cf9501c76e3e0459a4852b3b5f1fc72c103198c125a6b8c72f5f166bdd76ffb2fca261e7f6ee5565daf80dca6e571e55bcc589cc1256 conditions: os=darwin languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^2.3.2#~builtin, fsevents@patch:fsevents@npm%3A~2.3.2#~builtin": +"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1" dependencies: node-gyp: "npm:latest" conditions: os=darwin @@ -9437,7 +9437,7 @@ __metadata: "function-bind@npm:^1.1.1": version: 1.1.1 resolution: "function-bind@npm:1.1.1" - checksum: b32fbaebb3f8ec4969f033073b43f5c8befbb58f1a79e12f1d7490358150359ebd92f49e72ff0144f65f2c48ea2a605bff2d07965f548f6474fd8efd95bf361a + checksum: d83f2968030678f0b8c3f2183d63dcd969344eb8b55b4eb826a94ccac6de8b87c95bebffda37a6386c74f152284eb02956ff2c496897f35d32bdc2628ac68ac5 languageName: node linkType: hard @@ -9449,14 +9449,14 @@ __metadata: define-properties: "npm:^1.1.3" es-abstract: "npm:^1.19.0" functions-have-names: "npm:^1.2.2" - checksum: acd21d733a9b649c2c442f067567743214af5fa248dbeee69d8278ce7df3329ea5abac572be9f7470b4ec1cd4d8f1040e3c5caccf98ebf2bf861a0deab735c27 + checksum: 5d426e5a38ac41747bcfce6191e0ec818ed18678c16cfc36b5d1ca87f56ff98c4ce958ee2c1ea2a18dc3da989844a37b1065311e2d2ae4cf12da8f82418b686b languageName: node linkType: hard "functions-have-names@npm:^1.2.2, functions-have-names@npm:^1.2.3": version: 1.2.3 resolution: "functions-have-names@npm:1.2.3" - checksum: c3f1f5ba20f4e962efb71344ce0a40722163e85bee2101ce25f88214e78182d2d2476aa85ef37950c579eb6cf6ee811c17b3101bb84004bb75655f3e33f3fdb5 + checksum: 0ddfd3ed1066a55984aaecebf5419fbd9344a5c38dd120ffb0739fac4496758dcf371297440528b115e4367fc46e3abc86a2cc0ff44612181b175ae967a11a05 languageName: node linkType: hard @@ -9472,14 +9472,14 @@ __metadata: string-width: "npm:^4.2.3" strip-ansi: "npm:^6.0.1" wide-align: "npm:^1.1.5" - checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d + checksum: 09535dd53b5ced6a34482b1fa9f3929efdeac02f9858569cde73cef3ed95050e0f3d095706c1689614059898924b7a74aa14042f51381a1ccc4ee5c29d2389c4 languageName: node linkType: hard "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" - checksum: a7437e58c6be12aa6c90f7730eac7fa9833dc78872b4ad2963d2031b00a3367a93f98aec75f9aaac7220848e4026d67a8655e870b24f20a543d103c0d65952ec + checksum: 17d8333460204fbf1f9160d067e1e77f908a5447febb49424b8ab043026049835c9ef3974445c57dbd39161f4d2b04356d7de12b2eecaa27a7a7ea7d871cbedd languageName: node linkType: hard @@ -9498,14 +9498,14 @@ __metadata: has: "npm:^1.0.3" has-proto: "npm:^1.0.1" has-symbols: "npm:^1.0.3" - checksum: 5b61d88552c24b0cf6fa2d1b3bc5459d7306f699de060d76442cce49a4721f52b8c560a33ab392cf5575b7810277d54ded9d4d39a1ea61855619ebc005aa7e5f + checksum: aee631852063f8ad0d4a374970694b5c17c2fb5c92bd1929476d7eb8798ce7aebafbf9a34022c05fd1adaa2ce846d5877a627ce1986f81fc65adf3b81824bd54 languageName: node linkType: hard "get-nonce@npm:^1.0.0": version: 1.0.1 resolution: "get-nonce@npm:1.0.1" - checksum: e2614e43b4694c78277bb61b0f04583d45786881289285c73770b07ded246a98be7e1f78b940c80cbe6f2b07f55f0b724e6db6fd6f1bcbd1e8bdac16521074ed + checksum: ad5104871d114a694ecc506a2d406e2331beccb961fe1e110dc25556b38bcdbf399a823a8a375976cd8889668156a9561e12ebe3fa6a4c6ba169c8466c2ff868 languageName: node linkType: hard @@ -9533,7 +9533,7 @@ __metadata: "get-stream@npm:^6.0.0": version: 6.0.1 resolution: "get-stream@npm:6.0.1" - checksum: e04ecece32c92eebf5b8c940f51468cd53554dcbb0ea725b2748be583c9523d00128137966afce410b9b051eb2ef16d657cd2b120ca8edafcf5a65e81af63cad + checksum: 781266d29725f35c59f1d214aedc92b0ae855800a980800e2923b3fbc4e56b3cb6e462c42e09a1cf1a00c64e056a78fa407cbe06c7c92b7e5cd49b4b85c2a497 languageName: node linkType: hard @@ -9543,7 +9543,7 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" get-intrinsic: "npm:^1.1.1" - checksum: 9ceff8fe968f9270a37a1f73bf3f1f7bda69ca80f4f80850670e0e7b9444ff99323f7ac52f96567f8b5f5fbe7ac717a0d81d3407c7313e82810c6199446a5247 + checksum: 7e5f298afe0f0872747dce4a949ce490ebc5d6dd6aefbbe5044543711c9b19a4dfaebdbc627aee99e1299d58a435b2fbfa083458c1d58be6dc03a3bada24d359 languageName: node linkType: hard @@ -9567,7 +9567,7 @@ __metadata: tar: "npm:^6.1.13" bin: giget: dist/cli.mjs - checksum: 76ad0f7e792ee95dd6c4e1096697fdcce61a2a3235a6c21761fc3e0d1053342074ce71c80059d6d4363fd34152e5d7b2e58221412f300c852ff7d4a12d0321fe + checksum: f5080b18437fcd4cb92eb8bc90f69f57008460416c5a919a5d50e94889c0a5bfec641f203bd32f91b3de3058c8be48f23ab4b4f2d29f785dcb311b5f10c51bf4 languageName: node linkType: hard @@ -9583,7 +9583,7 @@ __metadata: resolution: "glob-parent@npm:5.1.2" dependencies: is-glob: "npm:^4.0.1" - checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e + checksum: 32cd106ce8c0d83731966d31517adb766d02c3812de49c30cfe0675c7c0ae6630c11214c54a5ae67aca882cf738d27fd7768f21aa19118b9245950554be07247 languageName: node linkType: hard @@ -9610,7 +9610,7 @@ __metadata: "glob-to-regexp@npm:^0.4.1": version: 0.4.1 resolution: "glob-to-regexp@npm:0.4.1" - checksum: e795f4e8f06d2a15e86f76e4d92751cf8bbfcf0157cea5c2f0f35678a8195a750b34096b1256e436f0cebc1883b5ff0888c47348443e69546a5a87f9e1eb1167 + checksum: 9009529195a955c40d7b9690794aeff5ba665cc38f1519e111c58bb54366fd0c106bde80acf97ba4e533208eb53422c83b136611a54c5fefb1edd8dc267cb62e languageName: node linkType: hard @@ -9618,14 +9618,14 @@ __metadata: version: 10.3.10 resolution: "glob@npm:10.3.10" dependencies: - foreground-child: ^3.1.0 - jackspeak: ^2.3.5 - minimatch: ^9.0.1 - minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - path-scurry: ^1.10.1 + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^2.3.5" + minimatch: "npm:^9.0.1" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry: "npm:^1.10.1" bin: glob: dist/esm/bin.mjs - checksum: 4f2fe2511e157b5a3f525a54092169a5f92405f24d2aed3142f4411df328baca13059f4182f1db1bf933e2c69c0bd89e57ae87edd8950cba8c7ccbe84f721cf3 + checksum: 38bdb2c9ce75eb5ed168f309d4ed05b0798f640b637034800a6bf306f39d35409bf278b0eaaffaec07591085d3acb7184a201eae791468f0f617771c2486a6a8 languageName: node linkType: hard @@ -9640,7 +9640,7 @@ __metadata: path-scurry: "npm:^1.10.1" bin: glob: dist/cjs/src/bin.js - checksum: 29190d3291f422da0cb40b77a72fc8d2c51a36524e99b8bf412548b7676a6627489528b57250429612b6eec2e6fe7826d328451d3e694a9d15e575389308ec53 + checksum: 0d1a59dff5d5d7085f9c1e3b0c9c3a7e3a199a013ef8f800c0886e3cfe6f8e293f7847081021a97f96616bf778c053c6937382675f369ec8231c8b95d3ba11e2 languageName: node linkType: hard @@ -9654,14 +9654,14 @@ __metadata: minimatch: "npm:^3.1.1" once: "npm:^1.3.0" path-is-absolute: "npm:^1.0.0" - checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 + checksum: 59452a9202c81d4508a43b8af7082ca5c76452b9fcc4a9ab17655822e6ce9b21d4f8fbadabe4fe3faef448294cec249af305e2cd824b7e9aaf689240e5e96a7b languageName: node linkType: hard "globals@npm:^11.1.0": version: 11.12.0 resolution: "globals@npm:11.12.0" - checksum: 67051a45eca3db904aee189dfc7cd53c20c7d881679c93f6146ddd4c9f4ab2268e68a919df740d39c71f4445d2b38ee360fc234428baea1dbdfe68bbcb46979e + checksum: 9f054fa38ff8de8fa356502eb9d2dae0c928217b8b5c8de1f09f5c9b6c8a96d8b9bd3afc49acbcd384a98a81fea713c859e1b09e214c60509517bb8fc2bc13c2 languageName: node linkType: hard @@ -9670,7 +9670,7 @@ __metadata: resolution: "globals@npm:13.20.0" dependencies: type-fest: "npm:^0.20.2" - checksum: ad1ecf914bd051325faad281d02ea2c0b1df5d01bd94d368dcc5513340eac41d14b3c61af325768e3c7f8d44576e72780ec0b6f2d366121f8eec6e03c3a3b97a + checksum: 9df85cde2f0dce6ac9b3a5e08bec109d2f3b38ddd055a83867e0672c55704866d53ce6a4265859fa630624baadd46f50ca38602a13607ad86be853a8c179d3e7 languageName: node linkType: hard @@ -9679,7 +9679,7 @@ __metadata: resolution: "globalthis@npm:1.0.3" dependencies: define-properties: "npm:^1.1.3" - checksum: fbd7d760dc464c886d0196166d92e5ffb4c84d0730846d6621a39fbbc068aeeb9c8d1421ad330e94b7bca4bb4ea092f5f21f3d36077812af5d098b4dc006c998 + checksum: 45ae2f3b40a186600d0368f2a880ae257e8278b4c7704f0417d6024105ad7f7a393661c5c2fa1334669cd485ea44bc883a08fdd4516df2428aec40c99f52aa89 languageName: node linkType: hard @@ -9693,14 +9693,14 @@ __metadata: ignore: "npm:^5.2.0" merge2: "npm:^1.4.1" slash: "npm:^3.0.0" - checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 + checksum: 288e95e310227bbe037076ea81b7c2598ccbc3122d87abc6dab39e1eec309aa14f0e366a98cdc45237ffcfcbad3db597778c0068217dcb1950fef6249104e1b1 languageName: node linkType: hard "globrex@npm:^0.1.2": version: 0.1.2 resolution: "globrex@npm:0.1.2" - checksum: adca162494a176ce9ecf4dd232f7b802956bb1966b37f60c15e49d2e7d961b66c60826366dc2649093cad5a0d69970cfa8875bd1695b5a1a2f33dcd2aa88da3c + checksum: 81ce62ee6f800d823d6b7da7687f841676d60ee8f51f934ddd862e4057316d26665c4edc0358d4340a923ac00a514f8b67c787e28fe693aae16350f4e60d55e9 languageName: node linkType: hard @@ -9709,21 +9709,21 @@ __metadata: resolution: "gopd@npm:1.0.1" dependencies: get-intrinsic: "npm:^1.1.3" - checksum: a5ccfb8806e0917a94e0b3de2af2ea4979c1da920bc381667c260e00e7cafdbe844e2cb9c5bcfef4e5412e8bf73bab837285bc35c7ba73aaaf0134d4583393a6 + checksum: 5fbc7ad57b368ae4cd2f41214bd947b045c1a4be2f194a7be1778d71f8af9dbf4004221f3b6f23e30820eb0d052b4f819fe6ebe8221e2a3c6f0ee4ef173421ca languageName: node linkType: hard "graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" - checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 + checksum: bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 languageName: node linkType: hard "grapheme-splitter@npm:^1.0.4": version: 1.0.4 resolution: "grapheme-splitter@npm:1.0.4" - checksum: 0c22ec54dee1b05cd480f78cf14f732cb5b108edc073572c4ec205df4cd63f30f8db8025afc5debc8835a8ddeacf648a1c7992fe3dcd6ad38f9a476d84906620 + checksum: fdb2f51fd430ce881e18e44c4934ad30e59736e46213f7ad35ea5970a9ebdf7d0fe56150d15cc98230d55d2fd48c73dc6781494c38d8cf2405718366c36adb88 languageName: node linkType: hard @@ -9739,7 +9739,7 @@ __metadata: through2: "npm:^2.0.3" bin: gunzip-maybe: bin.js - checksum: bc4d4977c24a2860238df271de75d53dd72a359d19f1248d1c613807dc221d3b8ae09624e3085c8106663e3e1b59db62a85b261d1138c2cc24efad9df577d4e1 + checksum: 82a4eadb617e50ac63cb88b3c1ebef0f85de702c0c2031c5d9c0575837e1eef7c94fa4ad69ca4aec2dc3d939c89054ec07c91c233648433058efa7d44354d456 languageName: node linkType: hard @@ -9757,14 +9757,14 @@ __metadata: optional: true bin: handlebars: bin/handlebars - checksum: 1e79a43f5e18d15742977cb987923eab3e2a8f44f2d9d340982bcb69e1735ed049226e534d7c1074eaddaf37e4fb4f471a8adb71cddd5bc8cf3f894241df5cee + checksum: 617b1e689b7577734abc74564bdb8cdaddf8fd48ce72afdb489f426e9c60a7d6ee2a2707c023720c4059070128243c948bded8f2716e4543378033e3971b85ea languageName: node linkType: hard "harmony-reflect@npm:^1.4.6": version: 1.6.2 resolution: "harmony-reflect@npm:1.6.2" - checksum: 2e5bae414cd2bfae5476147f9935dc69ee9b9a413206994dcb94c5b3208d4555da3d4313aff6fd14bd9991c1e3ef69cdda5c8fac1eb1d7afc064925839339b8c + checksum: 69d30ebfb5dbd6ff0553725c7922404cf1dfe5390db1618298eed27fe6c9bd2f3f677727e9da969d21648f4a6a39041e2f46e99976be4385f9e34bac23058cd4 languageName: node linkType: hard @@ -9780,7 +9780,7 @@ __metadata: "has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": version: 1.0.2 resolution: "has-bigints@npm:1.0.2" - checksum: 390e31e7be7e5c6fe68b81babb73dfc35d413604d7ee5f56da101417027a4b4ce6a27e46eff97ad040c835b5d228676eae99a9b5c3bc0e23c8e81a49241ff45b + checksum: 4e0426c900af034d12db14abfece02ce7dbf53f2022d28af1a97913ff4c07adb8799476d57dc44fbca0e07d1dbda2a042c2928b1f33d3f09c15de0640a7fb81b languageName: node linkType: hard @@ -9817,14 +9817,14 @@ __metadata: "has-proto@npm:^1.0.1": version: 1.0.1 resolution: "has-proto@npm:1.0.1" - checksum: febc5b5b531de8022806ad7407935e2135f1cc9e64636c3916c6842bd7995994ca3b29871ecd7954bd35f9e2986c17b3b227880484d22259e2f8e6ce63fd383e + checksum: eab2ab0ed1eae6d058b9bbc4c1d99d2751b29717be80d02fd03ead8b62675488de0c7359bc1fdd4b87ef6fd11e796a9631ad4d7452d9324fdada70158c2e5be7 languageName: node linkType: hard "has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3": version: 1.0.3 resolution: "has-symbols@npm:1.0.3" - checksum: a054c40c631c0d5741a8285010a0777ea0c068f99ed43e5d6eb12972da223f8af553a455132fdb0801bdcfa0e0f443c0c03a68d8555aa529b3144b446c3f2410 + checksum: 464f97a8202a7690dadd026e6d73b1ceeddd60fe6acfd06151106f050303eaa75855aaa94969df8015c11ff7c505f196114d22f7386b4a471038da5874cf5e9b languageName: node linkType: hard @@ -9833,14 +9833,14 @@ __metadata: resolution: "has-tostringtag@npm:1.0.0" dependencies: has-symbols: "npm:^1.0.2" - checksum: cc12eb28cb6ae22369ebaad3a8ab0799ed61270991be88f208d508076a1e99abe4198c965935ce85ea90b60c94ddda73693b0920b58e7ead048b4a391b502c1c + checksum: 95546e7132efc895a9ae64a8a7cf52588601fc3d52e0304ed228f336992cdf0baaba6f3519d2655e560467db35a1ed79f6420c286cc91a13aa0647a31ed92570 languageName: node linkType: hard "has-unicode@npm:^2.0.1": version: 2.0.1 resolution: "has-unicode@npm:2.0.1" - checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 + checksum: 041b4293ad6bf391e21c5d85ed03f412506d6623786b801c4ab39e4e6ca54993f13201bceb544d92963f9e0024e6e7fbf0cb1d84c9d6b31cb9c79c8c990d13d8 languageName: node linkType: hard @@ -9888,7 +9888,7 @@ __metadata: resolution: "has@npm:1.0.3" dependencies: function-bind: "npm:^1.1.1" - checksum: b9ad53d53be4af90ce5d1c38331e712522417d017d5ef1ebd0507e07c2fbad8686fffb8e12ddecd4c39ca9b9b47431afbb975b8abf7f3c3b82c98e9aad052792 + checksum: a449f3185b1d165026e8d25f6a8c3390bd25c201ff4b8c1aaf948fc6a5fcfd6507310b8c00c13a3325795ea9791fcc3d79d61eafa313b5750438fc19183df57b languageName: node linkType: hard @@ -9908,7 +9908,7 @@ __metadata: hast-util-parse-selector: "npm:^2.0.0" property-information: "npm:^5.0.0" space-separated-tokens: "npm:^1.0.0" - checksum: 5e50b85af0d2cb7c17979cb1ddca75d6b96b53019dd999b39e7833192c9004201c3cee6445065620ea05d0087d9ae147a4844e582d64868be5bc6b0232dfe52d + checksum: 78f91b71e50506f7499c8275d67645f9f4f130e6f12b038853261d1fa7393432da4113baf3508c41b79d933f255089d6d593beea9d4cda89dfd34d0a498cf378 languageName: node linkType: hard @@ -9917,14 +9917,14 @@ __metadata: resolution: "he@npm:1.2.0" bin: he: bin/he - checksum: 3d4d6babccccd79c5c5a3f929a68af33360d6445587d628087f39a965079d84f18ce9c3d3f917ee1e3978916fc833bb8b29377c3b403f919426f91bc6965e7a7 + checksum: d09b2243da4e23f53336e8de3093e5c43d2c39f8d0d18817abfa32ce3e9355391b2edb4bb5edc376aea5d4b0b59d6a0482aab4c52bc02ef95751e4b818e847f1 languageName: node linkType: hard "highlight.js@npm:^10.4.1, highlight.js@npm:~10.7.0": version: 10.7.3 resolution: "highlight.js@npm:10.7.3" - checksum: defeafcd546b535d710d8efb8e650af9e3b369ef53e28c3dc7893eacfe263200bba4c5fcf43524ae66d5c0c296b1af0870523ceae3e3104d24b7abf6374a4fea + checksum: db8d10a541936b058e221dbde77869664b2b45bca75d660aa98065be2cd29f3924755fbc7348213f17fd931aefb6e6597448ba6fe82afba6d8313747a91983ee languageName: node linkType: hard @@ -9933,14 +9933,14 @@ __metadata: resolution: "hoist-non-react-statics@npm:3.3.2" dependencies: react-is: "npm:^16.7.0" - checksum: b1538270429b13901ee586aa44f4cc3ecd8831c061d06cb8322e50ea17b3f5ce4d0e2e66394761e6c8e152cd8c34fb3b4b690116c6ce2bd45b18c746516cb9e8 + checksum: 1acbe85f33e5a39f90c822ad4d28b24daeb60f71c545279431dc98c312cd28a54f8d64788e477fe21dc502b0e3cf58589ebe5c1ad22af27245370391c2d24ea6 languageName: node linkType: hard "hosted-git-info@npm:^2.1.4": version: 2.8.9 resolution: "hosted-git-info@npm:2.8.9" - checksum: c955394bdab888a1e9bb10eb33029e0f7ce5a2ac7b3f158099dc8c486c99e73809dca609f5694b223920ca2174db33d32b12f9a2a47141dc59607c29da5a62dd + checksum: 96da7d412303704af41c3819207a09ea2cab2de97951db4cf336bb8bce8d8e36b9a6821036ad2e55e67d3be0af8f967a7b57981203fbfb88bc05cd803407b8c3 languageName: node linkType: hard @@ -9950,7 +9950,7 @@ __metadata: dependencies: domhandler: "npm:5.0.3" htmlparser2: "npm:9.0.0" - checksum: 95e483b2c945e1158e102e4eb69768124b06c94cf3c0abff8e9b02e146b7391dcdd620df8d54331efb9952c9187e0352ea436226e9ba5f26a0cc3cfe85853d4b + checksum: 32c5201896bc3913c4e421bc923db5bc49171c284225dd2d3d408edccf9c691e75061ca8f0a2647b63e4beb4815d6bb01eb692faaf386a59de4b90b48807935f languageName: node linkType: hard @@ -9959,14 +9959,14 @@ __metadata: resolution: "html-encoding-sniffer@npm:3.0.0" dependencies: whatwg-encoding: "npm:^2.0.0" - checksum: 8d806aa00487e279e5ccb573366a951a9f68f65c90298eac9c3a2b440a7ffe46615aff2995a2f61c6746c639234e6179a97e18ca5ccbbf93d3725ef2099a4502 + checksum: 707a812ec2acaf8bb5614c8618dc81e2fb6b4399d03e95ff18b65679989a072f4e919b9bef472039301a1bbfba64063ba4c79ea6e851c653ac9db80dbefe8fe5 languageName: node linkType: hard "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" - checksum: d2df2da3ad40ca9ee3a39c5cc6475ef67c8f83c234475f24d8e9ce0dc80a2c82df8e1d6fa78ddd1e9022a586ea1bd247a615e80a5cd9273d90111ddda7d9e974 + checksum: 034d74029dcca544a34fb6135e98d427acd73019796ffc17383eaa3ec2fe1c0471dcbbc8f8ed39e46e86d43ccd753a160631615e4048285e313569609b66d5b7 languageName: node linkType: hard @@ -9980,14 +9980,14 @@ __metadata: style-to-js: "npm:1.1.3" peerDependencies: react: 0.14 || 15 || 16 || 17 || 18 - checksum: e9ac022076bf0efbb9f8488c5adc41dd8bc8757cd1f01ba1812a758deb0d9eea5a657e6fde6e6cd694b4e232ed5e4757e12c9fc5ab0ed457feede002fade04c9 + checksum: 81619f776ac4a067841cba00ffa096e07f4ec1d1720bdbc4f244c636460c87fa0b2fe870d9d3322f207c7a98317695aa11a60b65b62ef5587016c38cd9eb22e2 languageName: node linkType: hard "html-tags@npm:^3.1.0": version: 3.3.1 resolution: "html-tags@npm:3.3.1" - checksum: b4ef1d5a76b678e43cce46e3783d563607b1d550cab30b4f511211564574770aa8c658a400b100e588bc60b8234e59b35ff72c7851cc28f3b5403b13a2c6cbce + checksum: d0e808544b92d8b999cbcc86d539577255a2f0f2f4f73110d10749d1d36e6fe6ad706a0355a8477afb6e000ecdc93d8455b3602951f9a2b694ac9e28f1b52878 languageName: node linkType: hard @@ -9999,7 +9999,7 @@ __metadata: domhandler: "npm:^5.0.3" domutils: "npm:^3.1.0" entities: "npm:^4.5.0" - checksum: a234c3add821cae8308ca61ce4b8ad3e88af83cf9c3c2003059adc89c46a06ffc39cc2a92b39af8d16c3705e1055df6769d80877acb6529983867f0d7e74098d + checksum: 6b0132fee4da2f6565dfb9166917992bf67bd7827a00a4baa35e2eea8db488b3a1dfea2a597cf3a743521d5276ecd39fb297ce0e8698af6d14c8f02a5fe08e90 languageName: node linkType: hard @@ -10013,14 +10013,14 @@ __metadata: entities: "npm:^1.1.1" inherits: "npm:^2.0.1" readable-stream: "npm:^3.1.1" - checksum: 6875f7dd875aa10be17d9b130e3738cd8ed4010b1f2edaf4442c82dfafe9d9336b155870dcc39f38843cbf7fef5e4fcfdf0c4c1fd4db3a1b91a1e0ee8f6c3475 + checksum: d5297fe76c0d6b0f35f39781417eb560ef12fa121953578083f3f2b240c74d5c35a38185689d181b6a82b66a3025436f14aa3413b94f3cd50ba15733f2f72389 languageName: node linkType: hard "http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" - checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 + checksum: 362d5ed66b12ceb9c0a328fb31200b590ab1b02f4a254a697dc796850cc4385603e75f53ec59f768b2dad3bfa1464bd229f7de278d2899a0e3beffc634b6683f languageName: node linkType: hard @@ -10033,7 +10033,7 @@ __metadata: setprototypeof: "npm:1.2.0" statuses: "npm:2.0.1" toidentifier: "npm:1.0.1" - checksum: 9b0a3782665c52ce9dc658a0d1560bcb0214ba5699e4ea15aefb2a496e2ca83db03ebc42e1cce4ac1f413e4e0d2d736a3fd755772c556a9a06853ba2a0b7d920 + checksum: 0e7f76ee8ff8a33e58a3281a469815b893c41357378f408be8f6d4aa7d1efafb0da064625518e7078381b6a92325949b119dc38fcb30bdbc4e3a35f78c44c439 languageName: node linkType: hard @@ -10044,7 +10044,7 @@ __metadata: "@tootallnate/once": "npm:2" agent-base: "npm:6" debug: "npm:4" - checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 + checksum: 5ee19423bc3e0fd5f23ce991b0755699ad2a46a440ce9cec99e8126bb98448ad3479d2c0ea54be5519db5b19a4ffaa69616bac01540db18506dd4dac3dc418f0 languageName: node linkType: hard @@ -10054,7 +10054,7 @@ __metadata: dependencies: agent-base: "npm:5" debug: "npm:4" - checksum: 19471d5aae3e747b1c98b17556647e2a1362e68220c6b19585a8527498f32e62e03c41d2872d059d8720d56846bd7460a80ac06f876bccfa786468ff40dd5eef + checksum: e90ca77ec10ef9987ad464853dfee744fb13fb02ad72f31c770ba09fb55675206a1de3c8b7e74d809fc00ed3baa7e01a48c569a419a675bfa3ef1ee975822b70 languageName: node linkType: hard @@ -10064,14 +10064,14 @@ __metadata: dependencies: agent-base: "npm:6" debug: "npm:4" - checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 + checksum: f0dce7bdcac5e8eaa0be3c7368bb8836ed010fb5b6349ffb412b172a203efe8f807d9a6681319105ea1b6901e1972c7b5ea899672a7b9aad58309f766dcbe0df languageName: node linkType: hard "human-signals@npm:^2.1.0": version: 2.1.0 resolution: "human-signals@npm:2.1.0" - checksum: b87fd89fce72391625271454e70f67fe405277415b48bcc0117ca73d31fa23a4241787afdc8d67f5a116cf37258c052f59ea82daffa72364d61351423848e3b8 + checksum: df59be9e0af479036798a881d1f136c4a29e0b518d4abb863afbd11bf30efa3eeb1d0425fc65942dcc05ab3bf40205ea436b0ff389f2cd20b75b8643d539bf86 languageName: node linkType: hard @@ -10089,7 +10089,7 @@ __metadata: resolution: "hunspell-spellchecker@npm:1.0.2" bin: hunspell-tojson: ./bin/hunspell-tojson.js - checksum: 098e00a705b1b8975924ccef1b23e1d63acc139a493a392bb55f887926c518b2edae01f9a697cffa73346160c562f89610f80d354360a2cb637a67f7c54f8227 + checksum: 84f58980d354f63e81a630370d19cd36790770fb545d4e9025858ed40c0a641b90fae4925cd0b83f766eefafcedc239803c52c617dd8c63b428266bf2ff63a7d languageName: node linkType: hard @@ -10098,7 +10098,7 @@ __metadata: resolution: "husky@npm:8.0.3" bin: husky: lib/bin.js - checksum: 837bc7e4413e58c1f2946d38fb050f5d7324c6f16b0fd66411ffce5703b294bd21429e8ba58711cd331951ee86ed529c5be4f76805959ff668a337dbfa82a1b0 + checksum: b754cf70fdc97c3b60fec5b80056b9c11436464953b1691bf2b5dcf0081fb6685d2c5f47abb8b2b1c49f504aabea5321fdd6496f8b755d9f6e7525a493406abb languageName: node linkType: hard @@ -10107,7 +10107,7 @@ __metadata: resolution: "iconv-lite@npm:0.4.24" dependencies: safer-buffer: "npm:>= 2.1.2 < 3" - checksum: bd9f120f5a5b306f0bc0b9ae1edeb1577161503f5f8252a20f1a9e56ef8775c9959fd01c55f2d3a39d9a8abaf3e30c1abeb1895f367dcbbe0a8fd1c9ca01c4f6 + checksum: 6d3a2dac6e5d1fb126d25645c25c3a1209f70cceecc68b8ef51ae0da3cdc078c151fade7524a30b12a3094926336831fca09c666ef55b37e2c69638b5d6bd2e3 languageName: node linkType: hard @@ -10116,7 +10116,7 @@ __metadata: resolution: "iconv-lite@npm:0.6.3" dependencies: safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf + checksum: 24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f languageName: node linkType: hard @@ -10125,21 +10125,21 @@ __metadata: resolution: "identity-obj-proxy@npm:3.0.0" dependencies: harmony-reflect: "npm:^1.4.6" - checksum: 97559f8ea2aeaa1a880d279d8c49550dce01148321e00a2102cda5ddf9ce622fa1d7f3efc7bed63458af78889de888fdaebaf31c816312298bb3fdd0ef8aaf2c + checksum: 66fe4d2ffc67655174f6abe100ab3b36d2f5e4de5b28a7c3121e5f51bd4e7c8c1bee4f9a41ce0586ace57fb63bfedbfc39508b7cb43b9e3ed6dc42f762158b4e languageName: node linkType: hard "ieee754@npm:^1.1.13": version: 1.2.1 resolution: "ieee754@npm:1.2.1" - checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e + checksum: d9f2557a59036f16c282aaeb107832dc957a93d73397d89bbad4eb1130560560eb695060145e8e6b3b498b15ab95510226649a0b8f52ae06583575419fe10fc4 languageName: node linkType: hard "ignore@npm:^5.2.0": version: 5.2.4 resolution: "ignore@npm:5.2.4" - checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef + checksum: 4f7caf5d2005da21a382d4bd1d2aa741a3bed51de185c8562dd7f899a81a620ac4fd0619b06f7029a38ae79e4e4c134399db3bd0192c703c3ef54bb82df3086c languageName: node linkType: hard @@ -10148,21 +10148,21 @@ __metadata: resolution: "image-size@npm:0.5.5" bin: image-size: bin/image-size.js - checksum: 6709d5cb73e96d5097ae5e9aa746dd36d6a9c8cf645e7eecac72ea07dbd6f312a65183752762fa92e2f3b698d4ed8d85dd55bf5207b6367245996bd16576d8fe + checksum: f41ec6cfccfa6471980e83568033a66ec53f84d1bcb70033e946a7db9c1b6bbf5645ec90fa5a8bdcdc84d86af0032014eff6fa078a60c2398dfce6676c46bdb7 languageName: node linkType: hard "immer@npm:^9.0.21": version: 9.0.21 resolution: "immer@npm:9.0.21" - checksum: 70e3c274165995352f6936695f0ef4723c52c92c92dd0e9afdfe008175af39fa28e76aafb3a2ca9d57d1fb8f796efc4dd1e1cc36f18d33fa5b74f3dfb0375432 + checksum: 8455d6b4dc8abfe40f06eeec9bcc944d147c81279424c0f927a4d4905ae34e5af19ab6da60bcc700c14f51c452867d7089b3b9236f5a9a2248e39b4a09ee89de languageName: node linkType: hard "immutable@npm:^4.0.0": version: 4.3.1 resolution: "immutable@npm:4.3.1" - checksum: a3a5ba29bd43f3f9a2e4d599763d7455d11a0ea57e50bf43f2836672fc80003e90d69f2a4f5b589f1f3d6986faf97f08ce1e253583740dd33c00adebab88b217 + checksum: 8b37052a6e91b223e9a6d7b0e6fb4917fdfe8ba5aa4370643eaa135a0174c72fafe2cfead4e0850fc38b4621d0291a187fa1c11f9d37ab06564199de86ede824 languageName: node linkType: hard @@ -10191,14 +10191,14 @@ __metadata: "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" - checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 + checksum: 2d30b157a91fe1c1d7c6f653cbf263f039be6c5bfa959245a16d4ee191fc0f2af86c08545b6e6beeb041c56b574d2d5b9f95343d378ab49c0f37394d541e7fc8 languageName: node linkType: hard "indent-string@npm:^4.0.0": version: 4.0.0 resolution: "indent-string@npm:4.0.0" - checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 + checksum: cd3f5cbc9ca2d624c6a1f53f12e6b341659aba0e2d3254ae2b4464aaea8b4294cdb09616abbc59458f980531f2429784ed6a420d48d245bcad0811980c9efae9 languageName: node linkType: hard @@ -10208,21 +10208,21 @@ __metadata: dependencies: once: "npm:^1.3.0" wrappy: "npm:1" - checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd + checksum: d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67 languageName: node linkType: hard "inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" - checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 + checksum: cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 languageName: node linkType: hard "inline-style-parser@npm:0.1.1": version: 0.1.1 resolution: "inline-style-parser@npm:0.1.1" - checksum: 5d545056a3e1f2bf864c928a886a0e1656a3517127d36917b973de581bd54adc91b4bf1febcb0da054f204b4934763f1a4e09308b4d55002327cf1d48ac5d966 + checksum: e661f4fb6824a41076c4d23358e8b581fd3410fbfb9baea4cb542a85448b487691c3b9bbb58ad73a95613041ca616f059595f19cadd0c22476a1fffa79842b48 languageName: node linkType: hard @@ -10233,7 +10233,7 @@ __metadata: get-intrinsic: "npm:^1.2.0" has: "npm:^1.0.3" side-channel: "npm:^1.0.4" - checksum: 97e84046bf9e7574d0956bd98d7162313ce7057883b6db6c5c7b5e5f05688864b0978ba07610c726d15d66544ffe4b1050107d93f8a39ebc59b15d8b429b497a + checksum: e2eb5b348e427957dd4092cb57b9374a2cbcabbf61e5e5b4d99cb68eeaae29394e8efd79f23dc2b1831253346f3c16b82010737b84841225e934d80d04d68643 languageName: node linkType: hard @@ -10241,7 +10241,7 @@ __metadata: version: 2.2.4 resolution: "invariant@npm:2.2.4" dependencies: - loose-envify: ^1.0.0 + loose-envify: "npm:^1.0.0" checksum: cc3182d793aad82a8d1f0af697b462939cb46066ec48bbf1707c150ad5fad6406137e91a262022c269702e01621f35ef60269f6c0d7fd178487959809acdfb14 languageName: node linkType: hard @@ -10249,14 +10249,14 @@ __metadata: "ip@npm:^2.0.0": version: 2.0.0 resolution: "ip@npm:2.0.0" - checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 + checksum: 1270b11e534a466fb4cf4426cbcc3a907c429389f7f4e4e3b288b42823562e88d6a509ceda8141a507de147ca506141f745005c0aa144569d94cf24a54eb52bc languageName: node linkType: hard "ipaddr.js@npm:1.9.1": version: 1.9.1 resolution: "ipaddr.js@npm:1.9.1" - checksum: f88d3825981486f5a1942414c8d77dd6674dd71c065adcfa46f578d677edcb99fda25af42675cb59db492fdf427b34a5abfcde3982da11a8fd83a500b41cfe77 + checksum: 864d0cced0c0832700e9621913a6429ccdc67f37c1bd78fb8c6789fff35c9d167cb329134acad2290497a53336813ab4798d2794fd675d5eb33b5fdf0982b9ca languageName: node linkType: hard @@ -10308,7 +10308,7 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" has-tostringtag: "npm:^1.0.0" - checksum: 7f02700ec2171b691ef3e4d0e3e6c0ba408e8434368504bb593d0d7c891c0dbfda6d19d30808b904a6cb1929bca648c061ba438c39f296c2a8ca083229c49f27 + checksum: a170c7e26082e10de9be6e96d32ae3db4d5906194051b792e85fae3393b53cf2cb5b3557863e5c8ccbab55e2fd8f2f75aa643d437613f72052cf0356615c34be languageName: node linkType: hard @@ -10326,7 +10326,7 @@ __metadata: "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" - checksum: eef4417e3c10e60e2c810b6084942b3ead455af16c4509959a27e490e7aee87cfb3f38e01bbde92220b528a0ee1a18d52b787e1458ee86174d8c7f0e58cd488f + checksum: 73ced84fa35e59e2c57da2d01e12cd01479f381d7f122ce41dcbb713f09dbfc651315832cd2bf8accba7681a69e4d6f1e03941d94dd10040d415086360e7005e languageName: node linkType: hard @@ -10335,7 +10335,7 @@ __metadata: resolution: "is-bigint@npm:1.0.4" dependencies: has-bigints: "npm:^1.0.1" - checksum: c56edfe09b1154f8668e53ebe8252b6f185ee852a50f9b41e8d921cb2bed425652049fbe438723f6cb48a63ca1aa051e948e7e401e093477c99c84eba244f666 + checksum: cc981cf0564c503aaccc1e5f39e994ae16ae2d1a8fcd14721f14ad431809071f39ec568cfceef901cff408045f1a6d6bac90d1b43eeb0b8e3bc34c8eb1bdb4c4 languageName: node linkType: hard @@ -10344,7 +10344,7 @@ __metadata: resolution: "is-binary-path@npm:2.1.0" dependencies: binary-extensions: "npm:^2.0.0" - checksum: 84192eb88cff70d320426f35ecd63c3d6d495da9d805b19bc65b518984b7c0760280e57dbf119b7e9be6b161784a5a673ab2c6abe83abb5198a432232ad5b35c + checksum: 078e51b4f956c2c5fd2b26bb2672c3ccf7e1faff38e0ebdba45612265f4e3d9fc3127a1fa8370bbf09eab61339203c3d3b7af5662cbf8be4030f8fac37745b0e languageName: node linkType: hard @@ -10354,21 +10354,21 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" has-tostringtag: "npm:^1.0.0" - checksum: c03b23dbaacadc18940defb12c1c0e3aaece7553ef58b162a0f6bba0c2a7e1551b59f365b91e00d2dbac0522392d576ef322628cb1d036a0fe51eb466db67222 + checksum: ba794223b56a49a9f185e945eeeb6b7833b8ea52a335cec087d08196cf27b538940001615d3bb976511287cefe94e5907d55f00bb49580533f9ca9b4515fcc2e languageName: node linkType: hard "is-buffer@npm:^1.1.5": version: 1.1.6 resolution: "is-buffer@npm:1.1.6" - checksum: 4a186d995d8bbf9153b4bd9ff9fd04ae75068fe695d29025d25e592d9488911eeece84eefbd8fa41b8ddcc0711058a71d4c466dcf6f1f6e1d83830052d8ca707 + checksum: f63da109e74bbe8947036ed529d43e4ae0c5fcd0909921dce4917ad3ea212c6a87c29f525ba1d17c0858c18331cf1046d4fc69ef59ed26896b25c8288a627133 languageName: node linkType: hard "is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.7": version: 1.2.7 resolution: "is-callable@npm:1.2.7" - checksum: 61fd57d03b0d984e2ed3720fb1c7a897827ea174bd44402878e059542ea8c4aeedee0ea0985998aa5cc2736b2fa6e271c08587addb5b3959ac52cf665173d1ac + checksum: 48a9297fb92c99e9df48706241a189da362bff3003354aea4048bd5f7b2eb0d823cd16d0a383cece3d76166ba16d85d9659165ac6fcce1ac12e6c649d66dbdb9 languageName: node linkType: hard @@ -10377,7 +10377,7 @@ __metadata: resolution: "is-core-module@npm:2.12.1" dependencies: has: "npm:^1.0.3" - checksum: f04ea30533b5e62764e7b2e049d3157dc0abd95ef44275b32489ea2081176ac9746ffb1cdb107445cf1ff0e0dfcad522726ca27c27ece64dadf3795428b8e468 + checksum: 35d5f90c95f7c737d287121e924bdfcad0a47b33efd7f89c58e9ab3810b43b1f1d377b641797326bde500e47edf5a7bf74a464e0c336a5c7e827b13fa41b57af languageName: node linkType: hard @@ -10395,7 +10395,7 @@ __metadata: resolution: "is-data-descriptor@npm:1.0.0" dependencies: kind-of: "npm:^6.0.0" - checksum: e705e6816241c013b05a65dc452244ee378d1c3e3842bd140beabe6e12c0d700ef23c91803f971aa7b091fb0573c5da8963af34a2b573337d87bc3e1f53a4e6d + checksum: b8b1f13a535800a9f35caba2743b2cfd1e76312c0f94248c333d3b724d6ac6e07f06011e8b00eb2442f27dfc8fb71faf3dd52ced6bee41bb836be3df5d7811ee languageName: node linkType: hard @@ -10404,7 +10404,7 @@ __metadata: resolution: "is-date-object@npm:1.0.5" dependencies: has-tostringtag: "npm:^1.0.0" - checksum: baa9077cdf15eb7b58c79398604ca57379b2fc4cf9aa7a9b9e295278648f628c9b201400c01c5e0f7afae56507d741185730307cbe7cad3b9f90a77e5ee342fc + checksum: cc80b3a4b42238fa0d358b9a6230dae40548b349e64a477cb7c5eff9b176ba194c11f8321daaf6dd157e44073e9b7fd01f87db1f14952a88d5657acdcd3a56e2 languageName: node linkType: hard @@ -10429,7 +10429,7 @@ __metadata: is-accessor-descriptor: "npm:^0.1.6" is-data-descriptor: "npm:^0.1.4" kind-of: "npm:^5.0.0" - checksum: 0f780c1b46b465f71d970fd7754096ffdb7b69fd8797ca1f5069c163eaedcd6a20ec4a50af669075c9ebcfb5266d2e53c8b227e485eefdb0d1fee09aa1dd8ab6 + checksum: b946ba842187c2784a5a0d67bd0e0271b14678f4fdce7d2295dfda9201f3408f55f56e11e5e66bfa4d2b9d45655b6105ad872ad7d37fb63f582587464fd414d7 languageName: node linkType: hard @@ -10440,7 +10440,7 @@ __metadata: is-accessor-descriptor: "npm:^1.0.0" is-data-descriptor: "npm:^1.0.0" kind-of: "npm:^6.0.2" - checksum: 2ed623560bee035fb67b23e32ce885700bef8abe3fbf8c909907d86507b91a2c89a9d3a4d835a4d7334dd5db0237a0aeae9ca109c1e4ef1c0e7b577c0846ab5a + checksum: e68059b333db331d5ea68cb367ce12fc6810853ced0e2221e6747143bbdf223dee73ebe8f331bafe04e34fdbe3da584b6af3335e82eabfaa33d5026efa33ca34 languageName: node linkType: hard @@ -10495,7 +10495,7 @@ __metadata: resolution: "is-generator-function@npm:1.0.10" dependencies: has-tostringtag: "npm:^1.0.0" - checksum: d54644e7dbaccef15ceb1e5d91d680eb5068c9ee9f9eb0a9e04173eb5542c9b51b5ab52c5537f5703e48d5fddfd376817c1ca07a84a407b7115b769d4bdde72b + checksum: 499a3ce6361064c3bd27fbff5c8000212d48506ebe1977842bbd7b3e708832d0deb1f4cc69186ece3640770e8c4f1287b24d99588a0b8058b2dbdd344bc1f47f languageName: node linkType: hard @@ -10504,7 +10504,7 @@ __metadata: resolution: "is-glob@npm:4.0.3" dependencies: is-extglob: "npm:^2.1.1" - checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 + checksum: 3ed74f2b0cdf4f401f38edb0442ddfde3092d79d7d35c9919c86641efdbcbb32e45aa3c0f70ce5eecc946896cd5a0f26e4188b9f2b881876f7cb6c505b82da11 languageName: node linkType: hard @@ -10539,7 +10539,7 @@ __metadata: "is-map@npm:^2.0.1, is-map@npm:^2.0.2": version: 2.0.2 resolution: "is-map@npm:2.0.2" - checksum: ace3d0ecd667bbdefdb1852de601268f67f2db725624b1958f279316e13fecb8fa7df91fd60f690d7417b4ec180712f5a7ee967008e27c65cfd475cc84337728 + checksum: 60ba910f835f2eacb1fdf5b5a6c60fe1c702d012a7673e6546992bcc0c873f62ada6e13d327f9e48f1720d49c152d6cdecae1fa47a261ef3d247c3ce6f0e1d39 languageName: node linkType: hard @@ -10549,14 +10549,14 @@ __metadata: dependencies: call-bind: "npm:^1.0.0" define-properties: "npm:^1.1.3" - checksum: 5dfadcef6ad12d3029d43643d9800adbba21cf3ce2ec849f734b0e14ee8da4070d82b15fdb35138716d02587c6578225b9a22779cab34888a139cc43e4e3610a + checksum: 1f784d3472c09bc2e47acba7ffd4f6c93b0394479aa613311dc1d70f1bfa72eb0846c81350967722c959ba65811bae222204d6c65856fdce68f31986140c7b0e languageName: node linkType: hard "is-negative-zero@npm:^2.0.2": version: 2.0.2 resolution: "is-negative-zero@npm:2.0.2" - checksum: f3232194c47a549da60c3d509c9a09be442507616b69454716692e37ae9f37c4dea264fb208ad0c9f3efd15a796a46b79df07c7e53c6227c32170608b809149a + checksum: edbec1a9e6454d68bf595a114c3a72343d2d0be7761d8173dae46c0b73d05bb8fe9398c85d121e7794a66467d2f40b4a610b0be84cd804262d234fc634c86131 languageName: node linkType: hard @@ -10565,7 +10565,7 @@ __metadata: resolution: "is-number-object@npm:1.0.7" dependencies: has-tostringtag: "npm:^1.0.0" - checksum: d1e8d01bb0a7134c74649c4e62da0c6118a0bfc6771ea3c560914d52a627873e6920dd0fd0ebc0e12ad2ff4687eac4c308f7e80320b973b2c8a2c8f97a7524f7 + checksum: 8700dcf7f602e0a9625830541345b8615d04953655acbf5c6d379c58eb1af1465e71227e95d501343346e1d49b6f2d53cbc166b1fc686a7ec19151272df582f9 languageName: node linkType: hard @@ -10581,7 +10581,7 @@ __metadata: "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" - checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a + checksum: 6a6c3383f68afa1e05b286af866017c78f1226d43ac8cb064e115ff9ed85eb33f5c4f7216c96a71e4dfea289ef52c5da3aef5bbfade8ffe47a0465d70c0c8e86 languageName: node linkType: hard @@ -10635,14 +10635,14 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" has-tostringtag: "npm:^1.0.0" - checksum: 362399b33535bc8f386d96c45c9feb04cf7f8b41c182f54174c1a45c9abbbe5e31290bbad09a458583ff6bf3b2048672cdb1881b13289569a7c548370856a652 + checksum: 36d9174d16d520b489a5e9001d7d8d8624103b387be300c50f860d9414556d0485d74a612fdafc6ebbd5c89213d947dcc6b6bff6b2312093f71ea03cbb19e564 languageName: node linkType: hard "is-set@npm:^2.0.1, is-set@npm:^2.0.2": version: 2.0.2 resolution: "is-set@npm:2.0.2" - checksum: b64343faf45e9387b97a6fd32be632ee7b269bd8183701f3b3f5b71a7cf00d04450ed8669d0bd08753e08b968beda96fca73a10fd0ff56a32603f64deba55a57 + checksum: d89e82acdc7760993474f529e043f9c4a1d63ed4774d21cc2e331d0e401e5c91c27743cd7c889137028f6a742234759a4bd602368fbdbf0b0321994aefd5603f languageName: node linkType: hard @@ -10651,7 +10651,7 @@ __metadata: resolution: "is-shared-array-buffer@npm:1.0.2" dependencies: call-bind: "npm:^1.0.2" - checksum: 9508929cf14fdc1afc9d61d723c6e8d34f5e117f0bffda4d97e7a5d88c3a8681f633a74f8e3ad1fe92d5113f9b921dc5ca44356492079612f9a247efbce7032a + checksum: 23d82259d6cd6dbb7c4ff3e4efeff0c30dbc6b7f88698498c17f9821cb3278d17d2b6303a5341cbd638ab925a28f3f086a6c79b3df70ac986cc526c725d43b4f languageName: node linkType: hard @@ -10667,7 +10667,7 @@ __metadata: resolution: "is-string@npm:1.0.7" dependencies: has-tostringtag: "npm:^1.0.0" - checksum: 323b3d04622f78d45077cf89aab783b2f49d24dc641aa89b5ad1a72114cfeff2585efc8c12ef42466dff32bde93d839ad321b26884cf75e5a7892a938b089989 + checksum: 2bc292fe927493fb6dfc3338c099c3efdc41f635727c6ebccf704aeb2a27bca7acb9ce6fd34d103db78692b10b22111a8891de26e12bfa1c5e11e263c99d1fef languageName: node linkType: hard @@ -10676,7 +10676,7 @@ __metadata: resolution: "is-symbol@npm:1.0.4" dependencies: has-symbols: "npm:^1.0.2" - checksum: 92805812ef590738d9de49d677cd17dfd486794773fb6fa0032d16452af46e9b91bb43ffe82c983570f015b37136f4b53b28b8523bfb10b0ece7a66c31a54510 + checksum: a47dd899a84322528b71318a89db25c7ecdec73197182dad291df15ffea501e17e3c92c8de0bfb50e63402747399981a687b31c519971b1fa1a27413612be929 languageName: node linkType: hard @@ -10689,7 +10689,7 @@ __metadata: for-each: "npm:^0.3.3" gopd: "npm:^1.0.1" has-tostringtag: "npm:^1.0.0" - checksum: aac6ecb59d4c56a1cdeb69b1f129154ef462bbffe434cb8a8235ca89b42f258b7ae94073c41b3cb7bce37f6a1733ad4499f07882d5d5093a7ba84dfc4ebb8017 + checksum: 2392b2473bbc994f5c30d6848e32bab3cab6c80b795aaec3020baf5419ff7df38fc11b3a043eb56d50f842394c578dbb204a7a29398099f895cf111c5b27f327 languageName: node linkType: hard @@ -10703,7 +10703,7 @@ __metadata: "is-weakmap@npm:^2.0.1": version: 2.0.1 resolution: "is-weakmap@npm:2.0.1" - checksum: 1222bb7e90c32bdb949226e66d26cb7bce12e1e28e3e1b40bfa6b390ba3e08192a8664a703dff2a00a84825f4e022f9cd58c4599ff9981ab72b1d69479f4f7f6 + checksum: 289fa4e8ba1bdda40ca78481266f6925b7c46a85599e6a41a77010bf91e5a24dfb660db96863bbf655ecdbda0ab517204d6a4e0c151dbec9d022c556321f3776 languageName: node linkType: hard @@ -10712,7 +10712,7 @@ __metadata: resolution: "is-weakref@npm:1.0.2" dependencies: call-bind: "npm:^1.0.2" - checksum: 95bd9a57cdcb58c63b1c401c60a474b0f45b94719c30f548c891860f051bc2231575c290a6b420c6bc6e7ed99459d424c652bd5bf9a1d5259505dc35b4bf83de + checksum: 0023fd0e4bdf9c338438ffbe1eed7ebbbff7e7e18fb7cdc227caaf9d4bd024a2dcdf6a8c9f40c92192022eac8391243bb9e66cccebecbf6fe1d8a366108f8513 languageName: node linkType: hard @@ -10722,7 +10722,7 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" get-intrinsic: "npm:^1.1.1" - checksum: 5d8698d1fa599a0635d7ca85be9c26d547b317ed8fd83fc75f03efbe75d50001b5eececb1e9971de85fcde84f69ae6f8346bc92d20d55d46201d328e4c74a367 + checksum: 8f2ddb9639716fd7936784e175ea1183c5c4c05274c34f34f6a53175313cb1c9c35a8b795623306995e2f7cc8f25aa46302f15a2113e51c5052d447be427195c languageName: node linkType: hard @@ -10752,14 +10752,14 @@ __metadata: "isarray@npm:^2.0.5": version: 2.0.5 resolution: "isarray@npm:2.0.5" - checksum: bd5bbe4104438c4196ba58a54650116007fa0262eccef13a4c55b2e09a5b36b59f1e75b9fcc49883dd9d4953892e6fc007eef9e9155648ceea036e184b0f930a + checksum: 1d8bc7911e13bb9f105b1b3e0b396c787a9e63046af0b8fe0ab1414488ab06b2b099b87a2d8a9e31d21c9a6fad773c7fc8b257c4880f2d957274479d28ca3414 languageName: node linkType: hard "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" - checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 + checksum: 7c9f715c03aff08f35e98b1fadae1b9267b38f0615d501824f9743f3aab99ef10e303ce7db3f186763a0b70a19de5791ebfc854ff884d5a8c4d92211f642ec92 languageName: node linkType: hard @@ -10782,7 +10782,7 @@ __metadata: "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": version: 3.2.0 resolution: "istanbul-lib-coverage@npm:3.2.0" - checksum: a2a545033b9d56da04a8571ed05c8120bf10e9bce01cf8633a3a2b0d1d83dff4ac4fe78d6d5673c27fc29b7f21a41d75f83a36be09f82a61c367b56aa73c1ff9 + checksum: 31621b84ad29339242b63d454243f558a7958ee0b5177749bacf1f74be7d95d3fd93853738ef7eebcddfaf3eab014716e51392a8dbd5aa1bdc1b15c2ebc53c24 languageName: node linkType: hard @@ -10795,7 +10795,7 @@ __metadata: "@istanbuljs/schema": "npm:^0.1.2" istanbul-lib-coverage: "npm:^3.2.0" semver: "npm:^6.3.0" - checksum: bf16f1803ba5e51b28bbd49ed955a736488381e09375d830e42ddeb403855b2006f850711d95ad726f2ba3f1ae8e7366de7e51d2b9ac67dc4d80191ef7ddf272 + checksum: bbc4496c2f304d799f8ec22202ab38c010ac265c441947f075c0f7d46bd440b45c00e46017cf9053453d42182d768b1d6ed0e70a142c95ab00df9843aa5ab80e languageName: node linkType: hard @@ -10806,7 +10806,7 @@ __metadata: istanbul-lib-coverage: "npm:^3.0.0" make-dir: "npm:^3.0.0" supports-color: "npm:^7.1.0" - checksum: 3f29eb3f53c59b987386e07fe772d24c7f58c6897f34c9d7a296f4000de7ae3de9eb95c3de3df91dc65b134c84dee35c54eee572a56243e8907c48064e34ff1b + checksum: 06b37952e9cb0fe419a37c7f3d74612a098167a9eb0e5264228036e78b42ca5226501e8130738b5306d94bae2ea068ca674080d4af959992523d84aacff67728 languageName: node linkType: hard @@ -10817,7 +10817,7 @@ __metadata: debug: "npm:^4.1.1" istanbul-lib-coverage: "npm:^3.0.0" source-map: "npm:^0.6.1" - checksum: 21ad3df45db4b81852b662b8d4161f6446cd250c1ddc70ef96a585e2e85c26ed7cd9c2a396a71533cfb981d1a645508bc9618cae431e55d01a0628e7dec62ef2 + checksum: 5526983462799aced011d776af166e350191b816821ea7bcf71cab3e5272657b062c47dc30697a22a43656e3ced78893a42de677f9ccf276a28c913190953b82 languageName: node linkType: hard @@ -10827,7 +10827,7 @@ __metadata: dependencies: html-escaper: "npm:^2.0.0" istanbul-lib-report: "npm:^3.0.0" - checksum: 7867228f83ed39477b188ea07e7ccb9b4f5320b6f73d1db93a0981b7414fa4ef72d3f80c4692c442f90fc250d9406e71d8d7ab65bb615cb334e6292b73192b89 + checksum: 1fc20a133f6dbd846e7bf3dc6d85edf2b3c047c47142cd796c38717aef976195d2c0fb0399dd609c3ffac2ca43244dc15ce4ac34064d21e2d34d387df747dafb languageName: node linkType: hard @@ -10840,7 +10840,7 @@ __metadata: dependenciesMeta: "@pkgjs/parseargs": optional: true - checksum: e29291c0d0f280a063fa18fbd1e891ab8c2d7519fd34052c0ebde38538a15c603140d60c2c7f432375ff7ee4c5f1c10daa8b2ae19a97c3d4affe308c8360c1df + checksum: 69da974c05e5623743694484a9441f7dfa6b340daa20522fd9466edc132608012d5194f44167c706f62d1f87af96daf1e2b8cc62960153beea468cfaf99ed980 languageName: node linkType: hard @@ -10848,12 +10848,12 @@ __metadata: version: 2.3.6 resolution: "jackspeak@npm:2.3.6" dependencies: - "@isaacs/cliui": ^8.0.2 - "@pkgjs/parseargs": ^0.11.0 + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" dependenciesMeta: "@pkgjs/parseargs": optional: true - checksum: 57d43ad11eadc98cdfe7496612f6bbb5255ea69fe51ea431162db302c2a11011642f50cfad57288bd0aea78384a0612b16e131944ad8ecd09d619041c8531b54 + checksum: 6e6490d676af8c94a7b5b29b8fd5629f21346911ebe2e32931c2a54210134408171c24cee1a109df2ec19894ad04a429402a8438cbf5cc2794585d35428ace76 languageName: node linkType: hard @@ -10867,7 +10867,7 @@ __metadata: minimatch: "npm:^3.1.2" bin: jake: bin/cli.js - checksum: a23fd2273fb13f0d0d845502d02c791fd55ef5c6a2d207df72f72d8e1eac6d2b8ffa6caf660bc8006b3242e0daaa88a3ecc600194d72b5c6016ad56e9cd43553 + checksum: ad1cfe398836df4e6962954e5095597c21c5af1ea5a4182f6adf0869df8aca467a2eeca7869bf44f47120f4dd4ea52589d16050d295c87a5906c0d744775acc3 languageName: node linkType: hard @@ -10877,7 +10877,7 @@ __metadata: dependencies: execa: "npm:^5.0.0" p-limit: "npm:^3.1.0" - checksum: a67a7cb3c11f8f92bd1b7c79e84f724cbd11a9ad51f3cdadafe3ce7ee3c79ee50dbea128f920f5fddc807e9e4e83f5462143094391feedd959a77dd20ab96cf3 + checksum: 6e337b09dca173dc60d53a1c880817ef31f91c6ddc23d93fabb7e714d4388857332c76e7a7fc627bf150e3fba0b70ba968912f86934bd176ca0dc66883303122 languageName: node linkType: hard @@ -10905,7 +10905,7 @@ __metadata: pure-rand: "npm:^6.0.0" slash: "npm:^3.0.0" stack-utils: "npm:^2.0.3" - checksum: f3e39a74b601929448df92037f0599978d4d7a4b8f636f64e8020533d2d2b2f669d6729c80c6efed69341ca26753e5061e9787a0acd6c70af2127a94375ebb76 + checksum: 53b1c83a516c10f19889826472bbed84497c5a4da34fc36e923cf39130e7b6a20011663ef7625540b9f26ac3a9e72eedd24a29a1160ef5d2d2660b137606a29b languageName: node linkType: hard @@ -10932,7 +10932,7 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: f5854ffea977b9a12520ea71f8d0cc8a626cbb93d7e1e6eea18a2a1f2b25f70f1b6b08a89f11b4dc7dd36a1776a9ac2cf8ec5c7998086f913ee690c06c07c949 + checksum: 7cf500b590365eebbbc46228593ac3533c8c7c5bd99239fc8adb804cf0a0e4d43cf637656fd32fb56686b202d359b3f6e16782c9b320e52177928fc1f806004d languageName: node linkType: hard @@ -10970,7 +10970,7 @@ __metadata: optional: true ts-node: optional: true - checksum: 3a30afeb28cc5658ef9cd95f2551ab8a29641bb6d377eb239cba8e7522eb4611c9a98cdcf173d87f5ad7b5e1ad242c3cd5434a260107bd3c7e8305d05023e05c + checksum: 657fe666af56170ee78c49b113b6436fd70783f50eea45a868e5f4893b99d0732ba4608e2beec548e2995512f8e77d3d956d3d17d73fd336643e8df4e0c25570 languageName: node linkType: hard @@ -10982,7 +10982,7 @@ __metadata: diff-sequences: "npm:^29.4.3" jest-get-type: "npm:^29.4.3" pretty-format: "npm:^29.6.1" - checksum: c6350178ca27d92c7fd879790fb2525470c1ff1c5d29b1834a240fecd26c6904fb470ebddb98dc96dd85389c56c3b50e6965a1f5203e9236d213886ed9806219 + checksum: b4e427d19cf1e779f15e677de74f770c3916405fc83987aa1470701c8acb52764c0da115db2989b3bb433ae15127f974fffea7b808f921eb061e07965b2d687f languageName: node linkType: hard @@ -10991,7 +10991,7 @@ __metadata: resolution: "jest-docblock@npm:29.4.3" dependencies: detect-newline: "npm:^3.0.0" - checksum: e0e9df1485bb8926e5b33478cdf84b3387d9caf3658e7dc1eaa6dc34cb93dea0d2d74797f6e940f0233a88f3dadd60957f2288eb8f95506361f85b84bf8661df + checksum: fd6bb0b6c60a1d87ade37b8bd8404c64518dc42357f256eeb8cb3f313eb00c138645d602ba7c57059a3de4a6570f12ab1234cb3d2d7a9b948d9dfa255e85b1d2 languageName: node linkType: hard @@ -11004,7 +11004,7 @@ __metadata: jest-get-type: "npm:^29.4.3" jest-util: "npm:^29.6.1" pretty-format: "npm:^29.6.1" - checksum: 9d2ea7ed5326ee8c22523b22c66c85fe73754ea39f9b389881956508ee441392c61072a5fbf673e39beddd31d011bb94acae3edc77053ba4f9aa5c060114a5c8 + checksum: a6c018779ce5115d45d4dd617269d62725e05805ae64c8714f949dc0417f35bb15248cad16caee2371ebc6e5ae77a6846ae2207489ec39bd7ef81ae4a46beb26 languageName: node linkType: hard @@ -11025,7 +11025,7 @@ __metadata: peerDependenciesMeta: canvas: optional: true - checksum: 3df7fc85275711f20b483ac8cd8c04500704ed0f69791eb55c574b38f5a39470f03d775cf20c1025bc1884916ac0573aa2fa4db1bb74225bc7fdd95ba97ad0da + checksum: a7cc3691389293ef282d9698f923cb38ff171763ae6bc125d292c12dfb025d659db9a34b8ec679a6b3b171a230af6bc27c734d6ff8e94dd93367b0a7865f27d4 languageName: node linkType: hard @@ -11039,7 +11039,7 @@ __metadata: "@types/node": "npm:*" jest-mock: "npm:^29.6.1" jest-util: "npm:^29.6.1" - checksum: a50287e1ff29d131646bd09acc3222ac6ea0ad61e86bf73851d318ef2be0633a421b8558c4a15ddc67e0ffcfc32da7f6a0d8a2ddbfa85453837899dec88d256c + checksum: 52f912addbb1bc5a5b682b7aad50b1aec35e6cd201c22827b1054dbd095fbb05848308d2cc2ab46b5b8838137d1362a4f42b0d4010e1526cb4a91ce798a86f5a languageName: node linkType: hard @@ -11069,7 +11069,7 @@ __metadata: dependenciesMeta: fsevents: optional: true - checksum: 7c74d5a0f6aafa9f4e60fae7949d4774770c0243fb529c24f2f4c81229db479fa318dc8b81e8d226865aef1d600af10bd8404dd208e802318434b46f75d5d869 + checksum: b3d49d218247a365a958f262e1721d6ad9fa11d9e4533c7b476523985008db60a78ed1b38dd70b1bdf3db07ec377b45cb73d674fe8bec4d64ffbdfb62670016f languageName: node linkType: hard @@ -11091,7 +11091,7 @@ __metadata: jest-diff: "npm:^29.6.1" jest-get-type: "npm:^29.4.3" pretty-format: "npm:^29.6.1" - checksum: d2efa6aed6e4820758b732b9fefd315c7fa4508ee690da656e1c5ac4c1a0f4cee5b04c9719ee1fda9aeb883b4209186c145089ced521e715b9fa70afdfa4a9c6 + checksum: f5f223f5bc1986ce2fe91d26a0abe422fb58fdd5f984c55c7486be05509e520e33ffe6bb5425943b3be02e2df05dd95e700dd5abbdaf651d7b05c9cb099729c3 languageName: node linkType: hard @@ -11108,7 +11108,7 @@ __metadata: pretty-format: "npm:^29.6.1" slash: "npm:^3.0.0" stack-utils: "npm:^2.0.3" - checksum: 3e7cb2ff087fe72255292e151d24e4fbb4cd6134885c0a67a4b302f233fe4110bf7580b176f427f05ad7550eb878ed94237209785d09d659a7d171ffa59c068f + checksum: 2f27d8f2a5bc08b1f4e13def16ed425b65a98298bb62fd337c8a048cb5a8f56c2603e6da9b06d1d99d9a628dd7a530142de0d54d03546f1a3936631e1a3bb99a languageName: node linkType: hard @@ -11118,7 +11118,7 @@ __metadata: dependencies: "@jest/types": "npm:^27.5.1" "@types/node": "npm:*" - checksum: f5b5904bb1741b4a1687a5f492535b7b1758dc26534c72a5423305f8711292e96a601dec966df81bb313269fb52d47227e29f9c2e08324d79529172f67311be0 + checksum: be9a8777801659227d3bb85317a3aca617542779a290a6a45c9addec8bda29f494a524cb4af96c82b825ecb02171e320dfbfde3e3d9218672f9e38c9fac118f4 languageName: node linkType: hard @@ -11129,7 +11129,7 @@ __metadata: "@jest/types": "npm:^29.6.1" "@types/node": "npm:*" jest-util: "npm:^29.6.1" - checksum: 5e902f1a7eba1eb1a64eb6c19947fe1316834359d9869d0e2644d8979b9cad0465885dc4c9909c471888cddeea835c938cec6263d386d3d1aad720fc74e52ea1 + checksum: b8c79523d7bbf40415ce60184a5ffa391da2804e7a59f15fed5ec5869dcff89b0837ecc832e6164bf4675845f8c1d564636ef7d544d3b442f4f5c558b602f528 languageName: node linkType: hard @@ -11158,7 +11158,7 @@ __metadata: dependencies: jest-regex-util: "npm:^29.4.3" jest-snapshot: "npm:^29.6.1" - checksum: cee0a0fe53fd4531492a526b6ccd32377baad1eff6e6c124f04e9dc920219fd23fd39be88bb9551ee68d5fe92a3af627b423c9bc65a2aa0ac8a223c0e74dbbbb + checksum: 78e33ee5f755b56d0a2dcc2d4128f85fb1c5228a07b4a47fc3995bf3749178de348be6f4cfe29be3c5e04c9950e6aee0393ce1750abbdf239e4d352a685bfcba languageName: node linkType: hard @@ -11175,7 +11175,7 @@ __metadata: resolve: "npm:^1.20.0" resolve.exports: "npm:^2.0.0" slash: "npm:^3.0.0" - checksum: 9ce979a0f4a751bea58caea76415112df2a3f4d58e294019872244728aadd001f0ec20c873a3c805dd8f7c762143b3c14d00f87d124ed87c9981fbf8723090ef + checksum: 88a48110eb0232770bca9a72409b464c8fd2cb3473877dcd9a76572c73606de1e098422c7c4cfcc5fc91b380fa2c3564b90f098a012ebb369255d0479a34e070 languageName: node linkType: hard @@ -11204,7 +11204,7 @@ __metadata: jest-worker: "npm:^29.6.1" p-limit: "npm:^3.1.0" source-map-support: "npm:0.5.13" - checksum: 0e4dbda26669ae31fee32f8a62b3119bba510f2d17a098d6157b48a73ed2fc9842405bf893f3045c12b3632c7c0e3399fb22684b18ab5566aff4905b26c79a9a + checksum: 3e122cb101450aa169cc04c1ab7592e44d3c56923e1dd193a170a74643f68835e36560ad430dd363cd002bbc39e47307c5f70f2770e7e9e151e2764be6234ce4 languageName: node linkType: hard @@ -11234,7 +11234,7 @@ __metadata: jest-util: "npm:^29.6.1" slash: "npm:^3.0.0" strip-bom: "npm:^4.0.0" - checksum: 7c360c9694467d996f3d6d914fefa0e7bda554adda8c2b9fba31546dba663d71a64eda103ff68120a2422f3c16db8f0bc2c445923fe8fb934f37e53ef74fb429 + checksum: 22fe07ed2878f6d80fca5be5ee17775a5214952cc1c72d3539ecbb0e23f30a42f12e3adffbc62bdc2080edfed5f8254ab2799e350bb747867027885731c7b581 languageName: node linkType: hard @@ -11263,7 +11263,7 @@ __metadata: natural-compare: "npm:^1.4.0" pretty-format: "npm:^29.6.1" semver: "npm:^7.5.3" - checksum: e8f69d1fd4a29d354d4dca9eb2a22674b300f8ef509e4f1e75337c880414a00d2bdc9d3849a6855dbb5a76bfbe74603f33435378a3877e69f0838e4cc2244350 + checksum: 912c3e5b4af108179cb85a3abc72f3665629ea143dcfb580a6fa08bfd277e8dbdbb1712dbe7826f95a97fb85eecfa6883d113485fd52a606162ef31e4e6df42b languageName: node linkType: hard @@ -11277,7 +11277,7 @@ __metadata: ci-info: "npm:^3.2.0" graceful-fs: "npm:^4.2.9" picomatch: "npm:^2.2.3" - checksum: fc553556c1350c443449cadaba5fb9d604628e8b5ceb6ceaf4e7e08975b24277d0a14bf2e0f956024e03c23e556fcb074659423422a06fbedf2ab52978697ac7 + checksum: 7101a03451b96da90a0a24cbec7db9f2333835f5dff57f404b88d9d9981b624a2ec68665f41f6f1a0dde9a040dc9f132c12d6113029f00d3dba3f3d6ca87ea39 languageName: node linkType: hard @@ -11291,7 +11291,7 @@ __metadata: jest-get-type: "npm:^29.4.3" leven: "npm:^3.1.0" pretty-format: "npm:^29.6.1" - checksum: d2491f3f33d9bbc2dcaaa6acbff26f257b59c5eeceb65a52a9c1cec2f679b836ec2a4658b7004c0ef9d90cd0d9bd664e41d5ed6900f932bea742dd8e6b85e7f1 + checksum: 85d06f6fe7c8574379bba45d859a1823265ace035299d3feae6544dfbc1b1ce3fcf71212506d1559e68f42bb677c9b03afdeff532e3f284352839bad0e94fed9 languageName: node linkType: hard @@ -11307,7 +11307,7 @@ __metadata: emittery: "npm:^0.13.1" jest-util: "npm:^29.6.1" string-length: "npm:^4.0.1" - checksum: 69bd5a602284fdce6eba5486c5c57aca6b511d91cb0907c34c104d6dd931e18ce67baa7f8e280fa473e5d81ea3e7b9e7d94f712c37ab0b3b8cc2aec30676955d + checksum: 58351d8f9b39deed61cfac3f3e779d099afb67930e98f8e4223a4ba5c143ef984410741e6829f9d50b65a4855745038556b5a223e524acc1ffc2dae5114e525f languageName: node linkType: hard @@ -11319,7 +11319,7 @@ __metadata: jest-util: "npm:^29.6.1" merge-stream: "npm:^2.0.0" supports-color: "npm:^8.0.0" - checksum: 0af309ea4db17c4c47e84a9246f907960a15577683c005fdeafc8f3c06bc455136f95a6f28fa2a3e924b767eb4dacd9b40915a7707305f88586f099af3ac27a8 + checksum: 16398a6420ba1df0e4032142513ceebf2d9832b3eae04552dc2acc9c491b0c3830244c30c86e7e018e05589c80d0a789217b36d6325c62530891236d2519e195 languageName: node linkType: hard @@ -11338,35 +11338,35 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: a8ff2eb0f421623412236e23cbe67c638127fffde466cba9606bc0c0553b4c1e5cb116d7e0ef990b5d1712851652c8ee461373b578df50857fe635b94ff455d5 + checksum: 08c9b31f1d37deeb11fefd84fcc81b466c02d76f50056633d8c36951205ab7e220cd26efb49312849a2e08b43ce9f632f8a5b4f69717d9a91d8e069c0534115f languageName: node linkType: hard "js-base64@npm:3.7.5": version: 3.7.5 resolution: "js-base64@npm:3.7.5" - checksum: 67a78c8b1c47b73f1c6fba1957e9fe6fd9dc78ac93ac46cc2e43472dcb9cf150d126fb0e593192e88e0497354fa634d17d255add7cc6ee3c7b4d29870faa8e18 + checksum: 97642fdef112cb99aed25a092156029e2f44cef0e4e3bf64dba0b6f8d85b9f4ee80b65ab8fa11a051dfcd09133bcd96c130167afdf90e4e4b21933632157a4f9 languageName: node linkType: hard "js-base64@npm:^2.1.9": version: 2.6.4 resolution: "js-base64@npm:2.6.4" - checksum: 5f4084078d6c46f8529741d110df84b14fac3276b903760c21fa8cc8521370d607325dfe1c1a9fbbeaae1ff8e602665aaeef1362427d8fef704f9e3659472ce8 + checksum: c1a740a34fbb0ad0a528c2ab8749d7f873b1856a0638826306fcd98502e3c8c833334dff233085407e3201be543e5e71bf9692da7891ca680d9b03d027247a6a languageName: node linkType: hard "js-sdsl@npm:^4.1.4": version: 4.4.1 resolution: "js-sdsl@npm:4.4.1" - checksum: ba445b53531f2f353f8f66ed8c7edc7942c9bac68707161aa70528fa8ee9a89805d170cff171aa40bdac1aed5dfe97dce6f929e6f759a487ed619387a5ea1365 + checksum: f1f6faa0bdd8aa2acf58a2b2bddc85fc203937cad458b3802f4fe9dc335978753c88b28ae210e999d4b3a12f9f31f29494dff31aa46a89d3855e9a5e920bc908 languageName: node linkType: hard "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" - checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 + checksum: af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 languageName: node linkType: hard @@ -11378,7 +11378,7 @@ __metadata: esprima: "npm:^4.0.0" bin: js-yaml: bin/js-yaml.js - checksum: bef146085f472d44dee30ec34e5cf36bf89164f5d585435a3d3da89e52622dff0b188a580e4ad091c3341889e14cb88cac6e4deb16dc5b1e9623bb0601fc255c + checksum: 9e22d80b4d0105b9899135365f746d47466ed53ef4223c529b3c0f7a39907743fdbd3c4379f94f1106f02755b5e90b2faaf84801a891135544e1ea475d1a1379 languageName: node linkType: hard @@ -11389,7 +11389,7 @@ __metadata: argparse: "npm:^2.0.1" bin: js-yaml: bin/js-yaml.js - checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a + checksum: c138a34a3fd0d08ebaf71273ad4465569a483b8a639e0b118ff65698d257c2791d3199e3f303631f2cb98213fa7b5f5d6a4621fd0fff819421b990d30d967140 languageName: node linkType: hard @@ -11397,26 +11397,26 @@ __metadata: version: 0.15.1 resolution: "jscodeshift@npm:0.15.1" dependencies: - "@babel/core": ^7.23.0 - "@babel/parser": ^7.23.0 - "@babel/plugin-transform-class-properties": ^7.22.5 - "@babel/plugin-transform-modules-commonjs": ^7.23.0 - "@babel/plugin-transform-nullish-coalescing-operator": ^7.22.11 - "@babel/plugin-transform-optional-chaining": ^7.23.0 - "@babel/plugin-transform-private-methods": ^7.22.5 - "@babel/preset-flow": ^7.22.15 - "@babel/preset-typescript": ^7.23.0 - "@babel/register": ^7.22.15 - babel-core: ^7.0.0-bridge.0 - chalk: ^4.1.2 - flow-parser: 0.* - graceful-fs: ^4.2.4 - micromatch: ^4.0.4 - neo-async: ^2.5.0 - node-dir: ^0.1.17 - recast: ^0.23.3 - temp: ^0.8.4 - write-file-atomic: ^2.3.0 + "@babel/core": "npm:^7.23.0" + "@babel/parser": "npm:^7.23.0" + "@babel/plugin-transform-class-properties": "npm:^7.22.5" + "@babel/plugin-transform-modules-commonjs": "npm:^7.23.0" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.22.11" + "@babel/plugin-transform-optional-chaining": "npm:^7.23.0" + "@babel/plugin-transform-private-methods": "npm:^7.22.5" + "@babel/preset-flow": "npm:^7.22.15" + "@babel/preset-typescript": "npm:^7.23.0" + "@babel/register": "npm:^7.22.15" + babel-core: "npm:^7.0.0-bridge.0" + chalk: "npm:^4.1.2" + flow-parser: "npm:0.*" + graceful-fs: "npm:^4.2.4" + micromatch: "npm:^4.0.4" + neo-async: "npm:^2.5.0" + node-dir: "npm:^0.1.17" + recast: "npm:^0.23.3" + temp: "npm:^0.8.4" + write-file-atomic: "npm:^2.3.0" peerDependencies: "@babel/preset-env": ^7.1.6 peerDependenciesMeta: @@ -11424,7 +11424,7 @@ __metadata: optional: true bin: jscodeshift: bin/jscodeshift.js - checksum: d760dee2b634fa8a4610bdbdf787ce117a9a6bcc73e9ae55a38be77e380698d928d34a375a93ed4685e8bbdecfbd3cdbb87eb4b7e22fc58381db3d59fb554687 + checksum: 7cece7b99fe57de7d65bdd962c93b93f0080605cf7d7f1aad42da7c3beb824107067726ede681b703fd012293b7797b7f2fefbb1420b0e44a0fca669bb48e34c languageName: node linkType: hard @@ -11463,7 +11463,7 @@ __metadata: peerDependenciesMeta: canvas: optional: true - checksum: 6e2ae21db397133a061b270c26d2dbc0b9051733ea3b896a7ece78d79f475ff0974f766a413c1198a79c793159119169f2335ddb23150348fbfdcfa6f3105536 + checksum: a4cdcff5b07eed87da90b146b82936321533b5efe8124492acf7160ebd5b9cf2b3c2435683592bf1cffb479615245756efb6c173effc1906f845a86ed22af985 languageName: node linkType: hard @@ -11472,7 +11472,7 @@ __metadata: resolution: "jsesc@npm:2.5.2" bin: jsesc: bin/jsesc - checksum: 4dc190771129e12023f729ce20e1e0bfceac84d73a85bc3119f7f938843fe25a4aeccb54b6494dce26fcf263d815f5f31acdefac7cc9329efb8422a4f4d9fa9d + checksum: d2096abdcdec56969764b40ffc91d4a23408aa2f351b4d1c13f736f25476643238c43fdbaf38a191c26b1b78fd856d965f5d4d0dde7b89459cd94025190cdf13 languageName: node linkType: hard @@ -11481,14 +11481,14 @@ __metadata: resolution: "jsesc@npm:0.5.0" bin: jsesc: bin/jsesc - checksum: b8b44cbfc92f198ad972fba706ee6a1dfa7485321ee8c0b25f5cedd538dcb20cde3197de16a7265430fce8277a12db066219369e3d51055038946039f6e20e17 + checksum: fab949f585c71e169c5cbe00f049f20de74f067081bbd64a55443bad1c71e1b5a5b448f2359bf2fe06f5ed7c07e2e4a9101843b01c823c30b6afc11f5bfaf724 languageName: node linkType: hard "json-parse-even-better-errors@npm:^2.3.0": version: 2.3.1 resolution: "json-parse-even-better-errors@npm:2.3.1" - checksum: 798ed4cf3354a2d9ccd78e86d2169515a0097a5c133337807cdf7f1fc32e1391d207ccfc276518cc1d7d8d4db93288b8a50ba4293d212ad1336e52a8ec0a941f + checksum: 5f3a99009ed5f2a5a67d06e2f298cc97bc86d462034173308156f15b43a6e850be8511dc204b9b94566305da2947f7d90289657237d210351a39059ff9d666cf languageName: node linkType: hard @@ -11509,14 +11509,14 @@ __metadata: "json-schema@npm:0.4.0": version: 0.4.0 resolution: "json-schema@npm:0.4.0" - checksum: 66389434c3469e698da0df2e7ac5a3281bcff75e797a5c127db7c5b56270e01ae13d9afa3c03344f76e32e81678337a8c912bdbb75101c62e487dc3778461d72 + checksum: 8b3b64eff4a807dc2a3045b104ed1b9335cd8d57aa74c58718f07f0f48b8baa3293b00af4dcfbdc9144c3aafea1e97982cc27cc8e150fc5d93c540649507a458 languageName: node linkType: hard "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: cff44156ddce9c67c44386ad5cddf91925fe06b1d217f2da9c4910d01f358c6e3989c4d5a02683c7a5667f9727ff05831f7aa8ae66c8ff691c556f0884d49215 + checksum: 12786c2e2f22c27439e6db0532ba321f1d0617c27ad8cb1c352a0e9249a50182fd1ba8b52a18899291604b0c32eafa8afd09e51203f19109a0537f68db2b652d languageName: node linkType: hard @@ -11527,7 +11527,7 @@ __metadata: minimist: "npm:^1.2.0" bin: json5: lib/cli.js - checksum: 866458a8c58a95a49bef3adba929c625e82532bcff1fe93f01d29cb02cac7c3fe1f4b79951b7792c2da9de0b32871a8401a6e3c5b36778ad852bf5b8a61165d7 + checksum: a78d812dbbd5642c4f637dd130954acfd231b074965871c3e28a5bbd571f099d623ecf9161f1960c4ddf68e0cc98dee8bebfdb94a71ad4551f85a1afc94b63f6 languageName: node linkType: hard @@ -11536,7 +11536,7 @@ __metadata: resolution: "json5@npm:2.2.3" bin: json5: lib/cli.js - checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 + checksum: 1db67b853ff0de3534085d630691d3247de53a2ed1390ba0ddff681ea43e9b3e30ecbdb65c5e9aab49435e44059c23dbd6fee8ee619419ba37465bb0dd7135da languageName: node linkType: hard @@ -11549,7 +11549,7 @@ __metadata: dependenciesMeta: graceful-fs: optional: true - checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 + checksum: 03014769e7dc77d4cf05fa0b534907270b60890085dd5e4d60a382ff09328580651da0b8b4cdf44d91e4c8ae64d91791d965f05707beff000ed494a38b6fec85 languageName: node linkType: hard @@ -11561,7 +11561,7 @@ __metadata: array.prototype.flat: "npm:^1.3.1" object.assign: "npm:^4.1.4" object.values: "npm:^1.1.6" - checksum: a6a00d324e38f0d47e04f973d79670248a663422a4dccdc02efd6f1caf1c00042fb0aafcff1023707c85dea6f013d435b90db67c1c6841bf345628f0a720d8b3 + checksum: 6f17432a8fa2d446300be0142cbf833819b3f1e1ff6fee220087ed5daeb9f82476aaa0d2cf7c663a7686c8ee9eb0764d5d2a28f06e3531dbad4661c252263e85 languageName: node linkType: hard @@ -11570,7 +11570,7 @@ __metadata: resolution: "kind-of@npm:3.2.2" dependencies: is-buffer: "npm:^1.1.5" - checksum: e898df8ca2f31038f27d24f0b8080da7be274f986bc6ed176f37c77c454d76627619e1681f6f9d2e8d2fd7557a18ecc419a6bb54e422abcbb8da8f1a75e4b386 + checksum: b6e7eed10f9dea498500e73129c9bf289bc417568658648aecfc2e104aa32683b908e5d349563fc78d6752da0ea60c9ed1dda4b24dd85a0c8fc0c7376dc0acac languageName: node linkType: hard @@ -11579,35 +11579,35 @@ __metadata: resolution: "kind-of@npm:4.0.0" dependencies: is-buffer: "npm:^1.1.5" - checksum: 1b9e7624a8771b5a2489026e820f3bbbcc67893e1345804a56b23a91e9069965854d2a223a7c6ee563c45be9d8c6ff1ef87f28ed5f0d1a8d00d9dcbb067c529f + checksum: b35a90e0690f06bf07c8970b5290256b1740625fb3bf17ef8c9813a9e197302dbe9ad710b0d97a44556c9280becfc2132cbc3b370056f63b7e350a85f79088f1 languageName: node linkType: hard "kind-of@npm:^5.0.0, kind-of@npm:^5.0.2": version: 5.1.0 resolution: "kind-of@npm:5.1.0" - checksum: f2a0102ae0cf19c4a953397e552571bad2b588b53282874f25fca7236396e650e2db50d41f9f516bd402536e4df968dbb51b8e69e4d5d4a7173def78448f7bab + checksum: acf7cc73881f27629f700a80de77ff7fe4abc9430eac7ddb09117f75126e578ee8d7e44c4dacb6a9e802d5d881abf007ee6af3cfbe55f8b5cf0a7fdc49a02aa3 languageName: node linkType: hard "kind-of@npm:^6.0.0, kind-of@npm:^6.0.2": version: 6.0.3 resolution: "kind-of@npm:6.0.3" - checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b + checksum: 5873d303fb36aad875b7538798867da2ae5c9e328d67194b0162a3659a627d22f742fc9c4ae95cd1704132a24b00cae5041fc00c0f6ef937dc17080dc4dbb962 languageName: node linkType: hard "kleur@npm:^3.0.3": version: 3.0.3 resolution: "kleur@npm:3.0.3" - checksum: df82cd1e172f957bae9c536286265a5cdbd5eeca487cb0a3b2a7b41ef959fc61f8e7c0e9aeea9c114ccf2c166b6a8dd45a46fd619c1c569d210ecd2765ad5169 + checksum: 0c0ecaf00a5c6173d25059c7db2113850b5457016dfa1d0e3ef26da4704fbb186b4938d7611246d86f0ddf1bccf26828daa5877b1f232a65e7373d0122a83e7f languageName: node linkType: hard "language-subtag-registry@npm:~0.3.2": version: 0.3.22 resolution: "language-subtag-registry@npm:0.3.22" - checksum: 8ab70a7e0e055fe977ac16ea4c261faec7205ac43db5e806f72e5b59606939a3b972c4bd1e10e323b35d6ffa97c3e1c4c99f6553069dad2dfdd22020fa3eb56a + checksum: 5591f4abd775d1ab5945355a5ba894327d2d94c900607bdb69aac1bc5bb921dbeeeb5f616df95e8c0ae875501d19c1cfa0e852ece822121e95048deb34f2b4d2 languageName: node linkType: hard @@ -11616,7 +11616,7 @@ __metadata: resolution: "language-tags@npm:1.0.5" dependencies: language-subtag-registry: "npm:~0.3.2" - checksum: c81b5d8b9f5f9cfd06ee71ada6ddfe1cf83044dd5eeefcd1e420ad491944da8957688db4a0a9bc562df4afdc2783425cbbdfd152c01d93179cf86888903123cf + checksum: 2161292ddae73ff2f5a15fd2d753b21096b81324337dff4ad78d702c63210d5beb18892cd53a3455ee6e88065807c8e285e82c40503678951d2071d101a473b4 languageName: node linkType: hard @@ -11627,7 +11627,7 @@ __metadata: app-root-dir: "npm:^1.0.2" dotenv: "npm:^16.0.0" dotenv-expand: "npm:^10.0.0" - checksum: 196e0d701100144fbfe078d604a477573413ebf38dfe8d543748605e6a7074978508a3bb9f8135acd319db4fa947eef78836497163617d15a22163c59a00996b + checksum: 5aa4d1a01d108d1f4a565576b58e728be949ceccecef894d6a9de56cb2b8e2e033abd47424190d0a546cb22b4b4a3ab553346b9710c3294870660d4a3555dd34 languageName: node linkType: hard @@ -11644,7 +11644,7 @@ __metadata: dependencies: prelude-ls: "npm:^1.2.1" type-check: "npm:~0.4.0" - checksum: 12c5021c859bd0f5248561bf139121f0358285ec545ebf48bb3d346820d5c61a4309535c7f387ed7d84361cf821e124ce346c6b7cef8ee09a67c1473b46d0fc4 + checksum: 2e4720ff79f21ae08d42374b0a5c2f664c5be8b6c8f565bb4e1315c96ed3a8acaa9de788ffed82d7f2378cf36958573de07ef92336cb5255ed74d08b8318c9ee languageName: node linkType: hard @@ -11662,7 +11662,7 @@ __metadata: big.js: "npm:^5.2.2" emojis-list: "npm:^3.0.0" json5: "npm:^1.0.1" - checksum: eb6fb622efc0ffd1abdf68a2022f9eac62bef8ec599cf8adb75e94d1d338381780be6278534170e99edc03380a6d29bc7eb1563c89ce17c5fed3a0b17f1ad804 + checksum: 2ae94cc88ad9cf2991e322b9ddf547cff80cf6fc0f9c77546b258c5ed9f77b0827f64c2625cb0baa06432f1f441bb4744c9ab1e1412ee6f8e97d31f8e9c730d6 languageName: node linkType: hard @@ -11697,21 +11697,21 @@ __metadata: "lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "lodash.debounce@npm:4.0.8" - checksum: a3f527d22c548f43ae31c861ada88b2637eb48ac6aa3eb56e82d44917971b8aa96fbb37aa60efea674dc4ee8c42074f90f7b1f772e9db375435f6c83a19b3bc6 + checksum: cd0b2819786e6e80cb9f5cda26b1a8fc073daaf04e48d4cb462fa4663ec9adb3a5387aa22d7129e48eed1afa05b482e2a6b79bfc99b86886364449500cbb00fd languageName: node linkType: hard "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" - checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005 + checksum: d0ea2dd0097e6201be083865d50c3fb54fbfbdb247d9cc5950e086c991f448b7ab0cdab0d57eacccb43473d3f2acd21e134db39f22dac2d6c9ba6bf26978e3d6 languageName: node linkType: hard "lodash@npm:^4.17.15, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" - checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 + checksum: c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532 languageName: node linkType: hard @@ -11719,8 +11719,8 @@ __metadata: version: 4.1.0 resolution: "log-symbols@npm:4.1.0" dependencies: - chalk: ^4.1.0 - is-unicode-supported: ^0.1.0 + chalk: "npm:^4.1.0" + is-unicode-supported: "npm:^0.1.0" checksum: fce1497b3135a0198803f9f07464165e9eb83ed02ceb2273930a6f8a508951178d8cf4f0378e9d28300a2ed2bc49050995d2bd5f53ab716bb15ac84d58c6ef74 languageName: node linkType: hard @@ -11742,7 +11742,7 @@ __metadata: dependencies: fault: "npm:^1.0.0" highlight.js: "npm:~10.7.0" - checksum: 14a1815d6bae202ddee313fc60f06d46e5235c02fa483a77950b401d85b4c1e12290145ccd17a716b07f9328bd5864aa2d402b6a819ff3be7c833d9748ff8ba7 + checksum: 3294677be15bbc256556f097d9b675f23f14309aceeada7880473c57bdbdd7761f200d903fe26d8fa5e82259f70a39465d1d40754c4c049ad2bbd33d77e2c06f languageName: node linkType: hard @@ -11751,7 +11751,7 @@ __metadata: resolution: "lru-cache@npm:5.1.1" dependencies: yallist: "npm:^3.0.2" - checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb + checksum: 951d2673dcc64a7fb888bf3d13bc2fdf923faca97d89cdb405ba3dfff77e2b26e5798d405e78fcd7094c9e7b8b4dab2ddc5a4f8a11928af24a207b7c738ca3f8 languageName: node linkType: hard @@ -11760,21 +11760,21 @@ __metadata: resolution: "lru-cache@npm:6.0.0" dependencies: yallist: "npm:^4.0.0" - checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 + checksum: fc1fe2ee205f7c8855fa0f34c1ab0bcf14b6229e35579ec1fd1079f31d6fc8ef8eb6fd17f2f4d99788d7e339f50e047555551ebd5e434dda503696e7c6591825 languageName: node linkType: hard "lru-cache@npm:^7.7.1": version: 7.18.3 resolution: "lru-cache@npm:7.18.3" - checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 + checksum: 6029ca5aba3aacb554e919d7ef804fffd4adfc4c83db00fac8248c7c78811fb6d4b6f70f7fd9d55032b3823446546a007edaa66ad1f2377ae833bd983fac5d98 languageName: node linkType: hard "lru-cache@npm:^9.1.1 || ^10.0.0": version: 10.0.0 resolution: "lru-cache@npm:10.0.0" - checksum: 18f101675fe283bc09cda0ef1e3cc83781aeb8373b439f086f758d1d91b28730950db785999cd060d3c825a8571c03073e8c14512b6655af2188d623031baf50 + checksum: 590e00d6ccd76a1ada056585be3fd6dbddda395fc9359390cff38669c69c3fa1792dd6c4c46a9b1b411f032cd2e979d9e664f1628163292ecdfeada98c3da1f3 languageName: node linkType: hard @@ -11783,7 +11783,7 @@ __metadata: resolution: "lz-string@npm:1.5.0" bin: lz-string: bin/bin.js - checksum: 1ee98b4580246fd90dd54da6e346fb1caefcf05f677c686d9af237a157fdea3fd7c83a4bc58f858cd5b10a34d27afe0fdcbd0505a47e0590726a873dc8b8f65d + checksum: e86f0280e99a8d8cd4eef24d8601ddae15ce54e43ac9990dfcb79e1e081c255ad24424a30d78d2ad8e51a8ce82a66a930047fed4b4aa38c6f0b392ff9300edfc languageName: node linkType: hard @@ -11792,7 +11792,7 @@ __metadata: resolution: "magic-string@npm:0.27.0" dependencies: "@jridgewell/sourcemap-codec": "npm:^1.4.13" - checksum: 273faaa50baadb7a2df6e442eac34ad611304fc08fe16e24fe2e472fd944bfcb73ffb50d2dc972dc04e92784222002af46868cb9698b1be181c81830fd95a13e + checksum: 10a18a48d22fb14467d6cb4204aba58d6790ae7ba023835dc7a65e310cf216f042a17fab1155ba43e47117310a9b7c3fd3bb79f40be40f5124d6b1af9e96399b languageName: node linkType: hard @@ -11800,8 +11800,8 @@ __metadata: version: 0.30.5 resolution: "magic-string@npm:0.30.5" dependencies: - "@jridgewell/sourcemap-codec": ^1.4.15 - checksum: da10fecff0c0a7d3faf756913ce62bd6d5e7b0402be48c3b27bfd651b90e29677e279069a63b764bcdc1b8ecdcdb898f29a5c5ec510f2323e8d62ee057a6eb18 + "@jridgewell/sourcemap-codec": "npm:^1.4.15" + checksum: c8a6b25f813215ca9db526f3a407d6dc0bf35429c2b8111d6f1c2cf6cf6afd5e2d9f9cd189416a0e3959e20ecd635f73639f9825c73de1074b29331fe36ace59 languageName: node linkType: hard @@ -11843,7 +11843,7 @@ __metadata: promise-retry: "npm:^2.0.1" socks-proxy-agent: "npm:^7.0.0" ssri: "npm:^10.0.0" - checksum: 7268bf274a0f6dcf0343829489a4506603ff34bd0649c12058753900b0eb29191dce5dba12680719a5d0a983d3e57810f594a12f3c18494e93a1fbc6348a4540 + checksum: b4b442cfaaec81db159f752a5f2e3ee3d7aa682782868fa399200824ec6298502e01bdc456e443dc219bcd5546c8e4471644d54109c8599841dc961d17a805fa languageName: node linkType: hard @@ -11852,7 +11852,7 @@ __metadata: resolution: "makeerror@npm:1.0.12" dependencies: tmpl: "npm:1.0.5" - checksum: b38a025a12c8146d6eeea5a7f2bf27d51d8ad6064da8ca9405fcf7bf9b54acd43e3b30ddd7abb9b1bfa4ddb266019133313482570ddb207de568f71ecfcf6060 + checksum: 4c66ddfc654537333da952c084f507fa4c30c707b1635344eb35be894d797ba44c901a9cebe914aa29a7f61357543ba09b09dddbd7f65b4aee756b450f169f40 languageName: node linkType: hard @@ -11866,7 +11866,7 @@ __metadata: "map-or-similar@npm:^1.5.0": version: 1.5.0 resolution: "map-or-similar@npm:1.5.0" - checksum: f65c0d420e272d0fce4e24db35f6a08109218480bca1d61eaa442cbe6cf46270b840218d3b5e94e4bfcc2595f1d0a1fa5885df750b52aac9ab1d437b29dcce38 + checksum: 3cf43bcd0e7af41d7bade5f8b5be6bb9d021cc47e6008ad545d071cf3a709ba782884002f9eec6ccd51f572fc17841e07bf74628e0bc3694c33f4622b03e4b4c languageName: node linkType: hard @@ -11884,7 +11884,7 @@ __metadata: resolution: "markdown-to-jsx@npm:7.2.1" peerDependencies: react: ">= 0.14.0" - checksum: 0c8c715229044401ea48c2fc26c2554464100074959dafacdd9e4a0e849f0a190b02f39edb373bbdd95e38b8f910074b83b63d08752b8ae6be6ddcfb40ea50a0 + checksum: 0a0641da44af50561a64240e88ee692b259b193b1583b9fcc8beb9483cc1b23cbd7acaba444d6c2a1e775c7e8c66ab505c96e4510a908e5ac7eacf78d920ea2a languageName: node linkType: hard @@ -11893,7 +11893,7 @@ __metadata: resolution: "mdast-util-definitions@npm:4.0.0" dependencies: unist-util-visit: "npm:^2.0.0" - checksum: 2325f20b82b3fb8cb5fda77038ee0bbdd44f82cfca7c48a854724b58bc1fe5919630a3ce7c45e210726df59d46c881d020b2da7a493bfd1ee36eb2bbfef5d78e + checksum: c76da4b4f1e28f8e7c85bf664ab65060f5aa7e0fd0392a24482980984d4ba878b7635a08bcaccca060d6602f478ac6cadaffbbe65f910f75ce332fd67d0ade69 languageName: node linkType: hard @@ -11907,14 +11907,14 @@ __metadata: "mdn-data@npm:2.0.14": version: 2.0.14 resolution: "mdn-data@npm:2.0.14" - checksum: 9d0128ed425a89f4cba8f787dca27ad9408b5cb1b220af2d938e2a0629d17d879a34d2cb19318bdb26c3f14c77dd5dfbae67211f5caaf07b61b1f2c5c8c7dc16 + checksum: 64c629fcf14807e30d6dc79f97cbcafa16db066f53a294299f3932b3beb0eb0d1386d3a7fe408fc67348c449a4e0999360c894ba4c81eb209d7be4e36503de0e languageName: node linkType: hard "media-typer@npm:0.3.0": version: 0.3.0 resolution: "media-typer@npm:0.3.0" - checksum: af1b38516c28ec95d6b0826f6c8f276c58aec391f76be42aa07646b4e39d317723e869700933ca6995b056db4b09a78c92d5440dc23657e6764be5d28874bba1 + checksum: 38e0984db39139604756903a01397e29e17dcb04207bb3e081412ce725ab17338ecc47220c1b186b6bbe79a658aad1b0d41142884f5a481f36290cdefbe6aa46 languageName: node linkType: hard @@ -11923,7 +11923,7 @@ __metadata: resolution: "memoizerific@npm:1.11.3" dependencies: map-or-similar: "npm:^1.5.0" - checksum: d51bdc3ed8c39b4b73845c90eb62d243ddf21899914352d0c303f5e1d477abcb192f4c605e008caa4a31d823225eeb22a99ba5ee825fb88d0c33382db3aee95a + checksum: 72b6b80699777d000f03db6e15fdabcd4afe77feb45be51fe195cb230c64a368fcfcfbb976375eac3283bd8193d6b1a67ac3081cae07f64fca73f1aa568d59e3 languageName: node linkType: hard @@ -11960,7 +11960,7 @@ __metadata: "methods@npm:~1.1.2": version: 1.1.2 resolution: "methods@npm:1.1.2" - checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a + checksum: a385dd974faa34b5dd021b2bbf78c722881bf6f003bfe6d391d7da3ea1ed625d1ff10ddd13c57531f628b3e785be38d3eed10ad03cebd90b76932413df9a1820 languageName: node linkType: hard @@ -11981,7 +11981,7 @@ __metadata: regex-not: "npm:^1.0.0" snapdragon: "npm:^0.8.1" to-regex: "npm:^3.0.1" - checksum: 4c28b7c9e49a510f62ced8ec70dde03871931bfdae8a594762404dddd7666f3acdf1d14cadddda609d8114648a702738a0f9672a31ac4e0f4896b9e4962c6bd6 + checksum: 2cb673b02ff20e74b088056a744ec741b34c0b9cb55e7cf22fc8dffc3f08bca4c92732eb89946b9217fd011af0a8b8a1fe9441f2efb244beff8a5d3368b14af6 languageName: node linkType: hard @@ -11991,14 +11991,14 @@ __metadata: dependencies: braces: "npm:^3.0.2" picomatch: "npm:^2.3.1" - checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc + checksum: a749888789fc15cac0e03273844dbd749f9f8e8d64e70c564bcf06a033129554c789bb9e30d7566d7ff6596611a08e58ac12cf2a05f6e3c9c47c50c4c7e12fa2 languageName: node linkType: hard "mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2": version: 1.52.0 resolution: "mime-db@npm:1.52.0" - checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f + checksum: 54bb60bf39e6f8689f6622784e668a3d7f8bed6b0d886f5c3c446cb3284be28b30bf707ed05d0fe44a036f8469976b2629bbea182684977b084de9da274694d7 languageName: node linkType: hard @@ -12007,7 +12007,7 @@ __metadata: resolution: "mime-types@npm:2.1.35" dependencies: mime-db: "npm:1.52.0" - checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 + checksum: 89aa9651b67644035de2784a6e665fc685d79aba61857e02b9c8758da874a754aed4a9aced9265f5ed1171fd934331e5516b84a7f0218031b6fa0270eca1e51a languageName: node linkType: hard @@ -12016,7 +12016,7 @@ __metadata: resolution: "mime@npm:1.6.0" bin: mime: cli.js - checksum: fef25e39263e6d207580bdc629f8872a3f9772c923c7f8c7e793175cee22777bbe8bba95e5d509a40aaa292d8974514ce634ae35769faa45f22d17edda5e8557 + checksum: b7d98bb1e006c0e63e2c91b590fe1163b872abf8f7ef224d53dd31499c2197278a6d3d0864c45239b1a93d22feaf6f9477e9fc847eef945838150b8c02d03170 languageName: node linkType: hard @@ -12025,7 +12025,7 @@ __metadata: resolution: "mime@npm:2.6.0" bin: mime: cli.js - checksum: 1497ba7b9f6960694268a557eae24b743fd2923da46ec392b042469f4b901721ba0adcf8b0d3c2677839d0e243b209d76e5edcbd09cfdeffa2dfb6bb4df4b862 + checksum: 7da117808b5cd0203bb1b5e33445c330fe213f4d8ee2402a84d62adbde9716ca4fb90dd6d9ab4e77a4128c6c5c24a9c4c9f6a4d720b095b1b342132d02dba58d languageName: node linkType: hard @@ -12048,7 +12048,7 @@ __metadata: resolution: "minimatch@npm:3.1.2" dependencies: brace-expansion: "npm:^1.1.7" - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a + checksum: e0b25b04cd4ec6732830344e5739b13f8690f8a012d73445a4a19fbc623f5dd481ef7a5827fde25954cd6026fede7574cc54dc4643c99d6c6b653d6203f94634 languageName: node linkType: hard @@ -12057,7 +12057,7 @@ __metadata: resolution: "minimatch@npm:5.1.6" dependencies: brace-expansion: "npm:^2.0.1" - checksum: 7564208ef81d7065a370f788d337cd80a689e981042cb9a1d0e6580b6c6a8c9279eba80010516e258835a988363f99f54a6f711a315089b8b42694f5da9d0d77 + checksum: 126b36485b821daf96d33b5c821dac600cc1ab36c87e7a532594f9b1652b1fa89a1eebcaad4dff17c764dce1a7ac1531327f190fed5f97d8f6e5f889c116c429 languageName: node linkType: hard @@ -12066,14 +12066,14 @@ __metadata: resolution: "minimatch@npm:9.0.3" dependencies: brace-expansion: "npm:^2.0.1" - checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 + checksum: c81b47d28153e77521877649f4bab48348d10938df9e8147a58111fe00ef89559a2938de9f6632910c4f7bf7bb5cd81191a546167e58d357f0cfb1e18cecc1c5 languageName: node linkType: hard "minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" - checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 + checksum: 908491b6cc15a6c440ba5b22780a0ba89b9810e1aea684e253e43c4e3b8d56ec1dcdd7ea96dde119c29df59c936cde16062159eae4225c691e19c70b432b6e6f languageName: node linkType: hard @@ -12097,7 +12097,7 @@ __metadata: dependenciesMeta: encoding: optional: true - checksum: af5ab2552a16fcf505d35fd7ffb84b57f4a0eeb269e6e1d9a2a75824dda48b36e527083250b7cca4a4def21d9544e2ade441e4730e233c0bc2133f6abda31e18 + checksum: 045339fa8fa2f2a544da203c38e91e6329a6c8d0d563db42db2e32bd863b0d7127692f456dcdd171bcd3123af12ce04072d3fc276571c85085a9870db7dea69a languageName: node linkType: hard @@ -12124,7 +12124,7 @@ __metadata: resolution: "minipass-sized@npm:1.0.3" dependencies: minipass: "npm:^3.0.0" - checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 + checksum: 40982d8d836a52b0f37049a0a7e5d0f089637298e6d9b45df9c115d4f0520682a78258905e5c8b180fb41b593b0a82cc1361d2c74b45f7ada66334f84d1ecfdd languageName: node linkType: hard @@ -12133,21 +12133,21 @@ __metadata: resolution: "minipass@npm:3.3.6" dependencies: yallist: "npm:^4.0.0" - checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 + checksum: a5c6ef069f70d9a524d3428af39f2b117ff8cd84172e19b754e7264a33df460873e6eb3d6e55758531580970de50ae950c496256bb4ad3691a2974cddff189f0 languageName: node linkType: hard "minipass@npm:^5.0.0": version: 5.0.0 resolution: "minipass@npm:5.0.0" - checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea + checksum: 61682162d29f45d3152b78b08bab7fb32ca10899bc5991ffe98afc18c9e9543bd1e3be94f8b8373ba6262497db63607079dc242ea62e43e7b2270837b7347c93 languageName: node linkType: hard "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": version: 7.0.2 resolution: "minipass@npm:7.0.2" - checksum: 46776de732eb7cef2c7404a15fb28c41f5c54a22be50d47b03c605bf21f5c18d61a173c0a20b49a97e7a65f78d887245066410642551e45fffe04e9ac9e325bc + checksum: 25d3afc74e21e84d35134de33d8e7ba5ff3741f84c415553548e12ee21a280926b9fbdf5656c78e81dcb0ca28fd72505533415ae0b4b9b8b0c432273dffb65f6 languageName: node linkType: hard @@ -12157,7 +12157,7 @@ __metadata: dependencies: minipass: "npm:^3.0.0" yallist: "npm:^4.0.0" - checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 + checksum: ae0f45436fb51344dcb87938446a32fbebb540d0e191d63b35e1c773d47512e17307bf54aa88326cc6d176594d00e4423563a091f7266c2f9a6872cdc1e234d1 languageName: node linkType: hard @@ -12194,14 +12194,14 @@ __metadata: resolution: "mkdirp@npm:1.0.4" bin: mkdirp: bin/cmd.js - checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f + checksum: d71b8dcd4b5af2fe13ecf3bd24070263489404fe216488c5ba7e38ece1f54daf219e72a833a3a2dc404331e870e9f44963a33399589490956bff003a3404d3b2 languageName: node linkType: hard "mri@npm:^1.2.0": version: 1.2.0 resolution: "mri@npm:1.2.0" - checksum: 83f515abbcff60150873e424894a2f65d68037e5a7fcde8a9e2b285ee9c13ac581b63cfc1e6826c4732de3aeb84902f7c1e16b7aff46cd3f897a0f757a894e85 + checksum: 6775a1d2228bb9d191ead4efc220bd6be64f943ad3afd4dcb3b3ac8fc7b87034443f666e38805df38e8d047b29f910c3cc7810da0109af83e42c82c73bd3f6bc languageName: node linkType: hard @@ -12231,7 +12231,7 @@ __metadata: resolution: "nanoid@npm:3.3.6" bin: nanoid: bin/nanoid.cjs - checksum: 7d0eda657002738aa5206107bd0580aead6c95c460ef1bdd0b1a87a9c7ae6277ac2e9b945306aaa5b32c6dcb7feaf462d0f552e7f8b5718abfc6ead5c94a71b3 + checksum: 67235c39d1bc05851383dadde5cf77ae1c90c2a1d189e845c7f20f646f0488d875ad5f5226bbba072a88cebbb085a3f784a6673117daf785bdf614a852550362 languageName: node linkType: hard @@ -12250,7 +12250,7 @@ __metadata: regex-not: "npm:^1.0.0" snapdragon: "npm:^0.8.1" to-regex: "npm:^3.0.1" - checksum: 54d4166d6ef08db41252eb4e96d4109ebcb8029f0374f9db873bd91a1f896c32ec780d2a2ea65c0b2d7caf1f28d5e1ea33746a470f32146ac8bba821d80d38d8 + checksum: 5c4ec7d6264b93795248f22d19672f0b972f900772c057bc67e43ae4999165b5fea7b937359efde78707930a460ceaa6d93e0732ac1d993dab8654655a2e959b languageName: node linkType: hard @@ -12271,14 +12271,14 @@ __metadata: "negotiator@npm:0.6.3, negotiator@npm:^0.6.3": version: 0.6.3 resolution: "negotiator@npm:0.6.3" - checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 + checksum: 2723fb822a17ad55c93a588a4bc44d53b22855bf4be5499916ca0cab1e7165409d0b288ba2577d7b029f10ce18cf2ed8e703e5af31c984e1e2304277ef979837 languageName: node linkType: hard "neo-async@npm:^2.5.0, neo-async@npm:^2.6.0": version: 2.6.2 resolution: "neo-async@npm:2.6.2" - checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9 + checksum: 1a7948fea86f2b33ec766bc899c88796a51ba76a4afc9026764aedc6e7cde692a09067031e4a1bf6db4f978ccd99e7f5b6c03fe47ad9865c3d4f99050d67e002 languageName: node linkType: hard @@ -12287,14 +12287,14 @@ __metadata: resolution: "node-dir@npm:0.1.17" dependencies: minimatch: "npm:^3.0.2" - checksum: 29de9560e52cdac8d3f794d38d782f6799e13d4d11aaf96d3da8c28458e1c5e33bb5f8edfb42dc34172ec5516c50c5b8850c9e1526542616757a969267263328 + checksum: 281fdea12d9c080a7250e5b5afefa3ab39426d40753ec8126a2d1e67f189b8824723abfed74f5d8549c5d78352d8c489fe08d0b067d7684c87c07283d38374a5 languageName: node linkType: hard "node-fetch-native@npm:^1.0.2": version: 1.2.0 resolution: "node-fetch-native@npm:1.2.0" - checksum: f18d775523fc25b9fbec05a1da99cbf40214045bcaca82c8fd949b99148890c3cead4ab1764e26a92af600d14884d846481bcebf82d56815210624f836051a10 + checksum: d5f10c475c8ec8f03d19754ec5d6d2eee5fa82c50cc8f805e0a551f525c58809bd8291fc4b5a7275a5d6ff8bbe446417dbd1733d065544e2e6ac9a606aa83a20 languageName: node linkType: hard @@ -12302,13 +12302,13 @@ __metadata: version: 2.7.0 resolution: "node-fetch@npm:2.7.0" dependencies: - whatwg-url: ^5.0.0 + whatwg-url: "npm:^5.0.0" peerDependencies: encoding: ^0.1.0 peerDependenciesMeta: encoding: optional: true - checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 + checksum: b24f8a3dc937f388192e59bcf9d0857d7b6940a2496f328381641cb616efccc9866e89ec43f2ec956bbd6c3d3ee05524ce77fe7b29ccd34692b3a16f237d6676 languageName: node linkType: hard @@ -12329,28 +12329,28 @@ __metadata: which: "npm:^2.0.2" bin: node-gyp: bin/node-gyp.js - checksum: 78b404e2e0639d64e145845f7f5a3cb20c0520cdaf6dda2f6e025e9b644077202ea7de1232396ba5bde3fee84cdc79604feebe6ba3ec84d464c85d407bb5da99 + checksum: 458317127c63877365f227b18ef2362b013b7f8440b35ae722935e61b31e6b84ec0e3625ab07f90679e2f41a1d5a7df6c4049fdf8e7b3c81fcf22775147b47ac languageName: node linkType: hard "node-int64@npm:^0.4.0": version: 0.4.0 resolution: "node-int64@npm:0.4.0" - checksum: d0b30b1ee6d961851c60d5eaa745d30b5c95d94bc0e74b81e5292f7c42a49e3af87f1eb9e89f59456f80645d679202537de751b7d72e9e40ceea40c5e449057e + checksum: b7afc2b65e56f7035b1a2eec57ae0fbdee7d742b1cdcd0f4387562b6527a011ab1cbe9f64cc8b3cca61e3297c9637c8bf61cec2e6b8d3a711d4b5267dfafbe02 languageName: node linkType: hard "node-releases@npm:^2.0.12": version: 2.0.13 resolution: "node-releases@npm:2.0.13" - checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 + checksum: c9bb813aab2717ff8b3015ecd4c7c5670a5546e9577699a7c84e8d69230cd3b1ce8f863f8e9b50f18b19a5ffa4b9c1a706bbbfe4c378de955fedbab04488a338 languageName: node linkType: hard "node-releases@npm:^2.0.14": version: 2.0.14 resolution: "node-releases@npm:2.0.14" - checksum: 59443a2f77acac854c42d321bf1b43dea0aef55cd544c6a686e9816a697300458d4e82239e2d794ea05f7bbbc8a94500332e2d3ac3f11f52e4b16cbe638b3c41 + checksum: 0f7607ec7db5ef1dc616899a5f24ae90c869b6a54c2d4f36ff6d84a282ab9343c7ff3ca3670fe4669171bb1e8a9b3e286e1ef1c131f09a83d70554f855d54f24 languageName: node linkType: hard @@ -12361,7 +12361,7 @@ __metadata: abbrev: "npm:^1.0.0" bin: nopt: bin/nopt.js - checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac + checksum: 3c1128e07cd0241ae66d6e6a472170baa9f3e84dd4203950ba8df5bafac4efa2166ce917a57ef02b01ba7c40d18b2cc64b29b225fd3640791fe07b24f0b33a32 languageName: node linkType: hard @@ -12373,7 +12373,7 @@ __metadata: resolve: "npm:^1.10.0" semver: "npm:2 || 3 || 4 || 5" validate-npm-package-license: "npm:^3.0.1" - checksum: 7999112efc35a6259bc22db460540cae06564aa65d0271e3bdfa86876d08b0e578b7b5b0028ee61b23f1cae9fc0e7847e4edc0948d3068a39a2a82853efc8499 + checksum: 644f830a8bb9b7cc9bf2f6150618727659ee27cdd0840d1c1f97e8e6cab0803a098a2c19f31c6247ad9d3a0792e61521a13a6e8cd87cc6bb676e3150612c03d4 languageName: node linkType: hard @@ -12401,7 +12401,7 @@ __metadata: console-control-strings: "npm:^1.1.0" gauge: "npm:^4.0.3" set-blocking: "npm:^2.0.0" - checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a + checksum: 82b123677e62deb9e7472e27b92386c09e6e254ee6c8bcd720b3011013e4168bc7088e984f4fbd53cb6e12f8b4690e23e4fa6132689313e0d0dc4feea45489bb languageName: node linkType: hard @@ -12417,7 +12417,7 @@ __metadata: "nwsapi@npm:^2.2.2": version: 2.2.7 resolution: "nwsapi@npm:2.2.7" - checksum: cab25f7983acec7e23490fec3ef7be608041b460504229770e3bfcf9977c41d6fe58f518994d3bd9aa3a101f501089a3d4a63536f4ff8ae4b8c4ca23bdbfda4e + checksum: 22c002080f0297121ad138aba5a6509e724774d6701fe2c4777627bd939064ecd9e1b6dc1c2c716bb7ca0b9f16247892ff2f664285202ac7eff6ec9543725320 languageName: node linkType: hard @@ -12442,7 +12442,7 @@ __metadata: "object-inspect@npm:^1.12.3, object-inspect@npm:^1.9.0": version: 1.12.3 resolution: "object-inspect@npm:1.12.3" - checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db + checksum: 532b0036f0472f561180fac0d04fe328ee01f57637624c83fb054f81b5bfe966cdf4200612a499ed391a7ca3c46b20a0bc3a55fc8241d944abe687c556a32b39 languageName: node linkType: hard @@ -12452,14 +12452,14 @@ __metadata: dependencies: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.3" - checksum: 989b18c4cba258a6b74dc1d74a41805c1a1425bce29f6cabb50dcb1a6a651ea9104a1b07046739a49a5bb1bc49727bcb00efd5c55f932f6ea04ec8927a7901fe + checksum: 75365aff5da4bebad5d20efd9f9a7a13597e603f5eb03d89da8f578c3f3937fe01c6cb5fce86c0611c48795c0841401fd37c943821db0de703c7b30a290576ad languageName: node linkType: hard "object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" - checksum: b363c5e7644b1e1b04aa507e88dcb8e3a2f52b6ffd0ea801e4c7a62d5aa559affe21c55a07fd4b1fd55fc03a33c610d73426664b20032405d7b92a1414c34d6a + checksum: 3d81d02674115973df0b7117628ea4110d56042e5326413e4b4313f0bcdf7dd78d4a3acef2c831463fa3796a66762c49daef306f4a0ea1af44877d7086d73bde languageName: node linkType: hard @@ -12468,7 +12468,7 @@ __metadata: resolution: "object-visit@npm:1.0.1" dependencies: isobject: "npm:^3.0.0" - checksum: b0ee07f5bf3bb881b881ff53b467ebbde2b37ebb38649d6944a6cd7681b32eedd99da9bd1e01c55facf81f54ed06b13af61aba6ad87f0052982995e09333f790 + checksum: 77abf807de86fa65bf1ba92699b45b1e5485f2d899300d5cb92cca0863909e9528b6cbf366c237c9f5d2264dab6cfbeda2201252ed0e605ae1b3e263515c5cea languageName: node linkType: hard @@ -12480,7 +12480,7 @@ __metadata: define-properties: "npm:^1.1.4" has-symbols: "npm:^1.0.3" object-keys: "npm:^1.1.1" - checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864 + checksum: fd82d45289df0a952d772817622ecbaeb4ec933d3abb53267aede083ee38f6a395af8fadfbc569ee575115b0b7c9b286e7cfb2b7a2557b1055f7acbce513bc29 languageName: node linkType: hard @@ -12491,7 +12491,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 0f8c47517e6a9a980241eafe3b73de11e59511883173c2b93d67424a008e47e11b77c80e431ad1d8a806f6108b225a1cab9223e53e555776c612a24297117d28 + checksum: 08a09ff839fd541e8af90a47c67a3dd71721683cdc28e55470e191a8afd8b61188fb9a429fd1d1805808097d8d5950b47c0c2862157dad891226112d8321401b languageName: node linkType: hard @@ -12502,7 +12502,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 453c6d694180c0c30df451b60eaf27a5b9bca3fb43c37908fd2b78af895803dc631242bcf05582173afa40d8d0e9c96e16e8874b39471aa53f3ac1f98a085d85 + checksum: e8b813647cbc6505750cdff8b3978bb341492707a5f1df4129e2d8a904b31692e225eff92481ae5916be3bde3c2eff1d0e8a6730921ca7f4eed60bc15a70cb35 languageName: node linkType: hard @@ -12512,7 +12512,7 @@ __metadata: dependencies: define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: b936572536db0cdf38eb30afd2f1026a8b6f2cc5d2c4497c9d9bbb01eaf3e980dead4fd07580cfdd098e6383e5a9db8212d3ea0c6bdd2b5e68c60aa7e3b45566 + checksum: 94031022a2ba6006c15c6f1e0c4f51a7fa5b36aee64800192335b979fcc8bd823b18c35cb1a728af68fdfdbbe6d765f77a3c5437306c031f63654b8a34b9e639 languageName: node linkType: hard @@ -12521,7 +12521,7 @@ __metadata: resolution: "object.pick@npm:1.3.0" dependencies: isobject: "npm:^3.0.1" - checksum: 77fb6eed57c67adf75e9901187e37af39f052ef601cb4480386436561357eb9e459e820762f01fd02c5c1b42ece839ad393717a6d1850d848ee11fbabb3e580a + checksum: 92d7226a6b581d0d62694a5632b6a1594c81b3b5a4eb702a7662e0b012db532557067d6f773596c577f75322eba09cdca37ca01ea79b6b29e3e17365f15c615e languageName: node linkType: hard @@ -12532,7 +12532,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: f6fff9fd817c24cfd8107f50fb33061d81cd11bacc4e3dbb3852e9ff7692fde4dbce823d4333ea27cd9637ef1b6690df5fbb61f1ed314fa2959598dc3ae23d8e + checksum: adea807c90951df34eb2f5c6a90ab5624e15c71f0b3a3e422db16933c9f4e19551d10649fffcb4adcac01d86d7c14a64bfb500d8f058db5a52976150a917f6eb languageName: node linkType: hard @@ -12541,14 +12541,14 @@ __metadata: resolution: "on-finished@npm:2.4.1" dependencies: ee-first: "npm:1.1.1" - checksum: d20929a25e7f0bb62f937a425b5edeb4e4cde0540d77ba146ec9357f00b0d497cdb3b9b05b9c8e46222407d1548d08166bff69cc56dfa55ba0e4469228920ff0 + checksum: 8e81472c5028125c8c39044ac4ab8ba51a7cdc19a9fbd4710f5d524a74c6d8c9ded4dd0eed83f28d3d33ac1d7a6a439ba948ccb765ac6ce87f30450a26bfe2ea languageName: node linkType: hard "on-headers@npm:~1.0.2": version: 1.0.2 resolution: "on-headers@npm:1.0.2" - checksum: 2bf13467215d1e540a62a75021e8b318a6cfc5d4fc53af8e8f84ad98dbcea02d506c6d24180cd62e1d769c44721ba542f3154effc1f7579a8288c9f7873ed8e5 + checksum: 870766c16345855e2012e9422ba1ab110c7e44ad5891a67790f84610bd70a72b67fdd71baf497295f1d1bf38dd4c92248f825d48729c53c0eae5262fb69fa171 languageName: node linkType: hard @@ -12566,7 +12566,7 @@ __metadata: resolution: "onetime@npm:5.1.2" dependencies: mimic-fn: "npm:^2.1.0" - checksum: 2478859ef817fc5d4e9c2f9e5728512ddd1dbc9fb7829ad263765bb6d3b91ce699d6e2332eef6b7dff183c2f490bd3349f1666427eaba4469fba0ac38dfd0d34 + checksum: e9fd0695a01cf226652f0385bf16b7a24153dbbb2039f764c8ba6d2306a8506b0e4ce570de6ad99c7a6eb49520743afdb66edd95ee979c1a342554ed49a9aadd languageName: node linkType: hard @@ -12577,7 +12577,7 @@ __metadata: define-lazy-prop: "npm:^2.0.0" is-docker: "npm:^2.1.1" is-wsl: "npm:^2.2.0" - checksum: 6388bfff21b40cb9bd8f913f9130d107f2ed4724ea81a8fd29798ee322b361ca31fa2cdfb491a5c31e43a3996cfe9566741238c7a741ada8d7af1cb78d85cf26 + checksum: acd81a1d19879c818acb3af2d2e8e9d81d17b5367561e623248133deb7dd3aefaed527531df2677d3e6aaf0199f84df57b6b2262babff8bf46ea0029aac536c9 languageName: node linkType: hard @@ -12591,7 +12591,7 @@ __metadata: levn: "npm:^0.4.1" prelude-ls: "npm:^1.2.1" type-check: "npm:^0.4.0" - checksum: 09281999441f2fe9c33a5eeab76700795365a061563d66b098923eb719251a42bdbe432790d35064d0816ead9296dbeb1ad51a733edf4167c96bd5d0882e428a + checksum: fa28d3016395974f7fc087d6bbf0ac7f58ac3489f4f202a377e9c194969f329a7b88c75f8152b33fb08794a30dcd5c079db6bb465c28151357f113d80bbf67da languageName: node linkType: hard @@ -12599,16 +12599,16 @@ __metadata: version: 5.4.1 resolution: "ora@npm:5.4.1" dependencies: - bl: ^4.1.0 - chalk: ^4.1.0 - cli-cursor: ^3.1.0 - cli-spinners: ^2.5.0 - is-interactive: ^1.0.0 - is-unicode-supported: ^0.1.0 - log-symbols: ^4.1.0 - strip-ansi: ^6.0.0 - wcwidth: ^1.0.1 - checksum: 28d476ee6c1049d68368c0dc922e7225e3b5600c3ede88fade8052837f9ed342625fdaa84a6209302587c8ddd9b664f71f0759833cbdb3a4cf81344057e63c63 + bl: "npm:^4.1.0" + chalk: "npm:^4.1.0" + cli-cursor: "npm:^3.1.0" + cli-spinners: "npm:^2.5.0" + is-interactive: "npm:^1.0.0" + is-unicode-supported: "npm:^0.1.0" + log-symbols: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + wcwidth: "npm:^1.0.1" + checksum: 8d071828f40090a8e1c6e8f350c6eb065808e9ab2b3e57fa37e0d5ae78cb46dac00117c8f12c3c8b8da2923454afbd8265e08c10b69881170c5b269f451e7fef languageName: node linkType: hard @@ -12662,7 +12662,7 @@ __metadata: resolution: "p-map@npm:4.0.0" dependencies: aggregate-error: "npm:^3.0.0" - checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c + checksum: 7ba4a2b1e24c05e1fc14bbaea0fc6d85cf005ae7e9c9425d4575550f37e2e584b1af97bcde78eacd7559208f20995988d52881334db16cf77bc1bcf68e48ed7c languageName: node linkType: hard @@ -12676,7 +12676,7 @@ __metadata: "pako@npm:~0.2.0": version: 0.2.9 resolution: "pako@npm:0.2.9" - checksum: 055f9487cd57fbb78df84315873bbdd089ba286f3499daed47d2effdc6253e981f5db6898c23486de76d4a781559f890d643bd3a49f70f1b4a18019c98aa5125 + checksum: 627c6842e90af0b3a9ee47345bd66485a589aff9514266f4fa9318557ad819c46fedf97510f2cef9b6224c57913777966a05cb46caf6a9b31177a5401a06fe15 languageName: node linkType: hard @@ -12699,7 +12699,7 @@ __metadata: is-alphanumerical: "npm:^1.0.0" is-decimal: "npm:^1.0.0" is-hexadecimal: "npm:^1.0.0" - checksum: 7addfd3e7d747521afac33c8121a5f23043c6973809756920d37e806639b4898385d386fcf4b3c8e2ecf1bc28aac5ae97df0b112d5042034efbe80f44081ebce + checksum: feb46b516722474797d72331421f3e62856750cfb4f70ba098b36447bf0b169e819cc4fdee53e022874d5f0c81b605d86e1912b9842a70e59a54de2fee81589d languageName: node linkType: hard @@ -12720,7 +12720,7 @@ __metadata: resolution: "parse5@npm:7.1.2" dependencies: entities: "npm:^4.4.0" - checksum: 59465dd05eb4c5ec87b76173d1c596e152a10e290b7abcda1aecf0f33be49646ea74840c69af975d7887543ea45564801736356c568d6b5e71792fd0f4055713 + checksum: 3c86806bb0fb1e9a999ff3a4c883b1ca243d99f45a619a0898dbf021a95a0189ed955c31b07fe49d342b54e814f33f2c9d7489198e8630dacd5477d413ec5782 languageName: node linkType: hard @@ -12779,14 +12779,14 @@ __metadata: dependencies: lru-cache: "npm:^9.1.1 || ^10.0.0" minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: e2557cff3a8fb8bc07afdd6ab163a92587884f9969b05bbbaf6fe7379348bfb09af9ed292af12ed32398b15fb443e81692047b786d1eeb6d898a51eb17ed7d90 + checksum: eebfb8304fef1d4f7e1486df987e4fd77413de4fce16508dea69fcf8eb318c09a6b15a7a2f4c22877cec1cb7ecbd3071d18ca9de79eeece0df874a00f1f0bdc8 languageName: node linkType: hard "path-to-regexp@npm:0.1.7": version: 0.1.7 resolution: "path-to-regexp@npm:0.1.7" - checksum: 69a14ea24db543e8b0f4353305c5eac6907917031340e5a8b37df688e52accd09e3cebfe1660b70d76b6bd89152f52183f28c74813dbf454ba1a01c82a38abce + checksum: 701c99e1f08e3400bea4d701cf6f03517474bb1b608da71c78b1eb261415b645c5670dfae49808c89e12cea2dccd113b069f040a80de012da0400191c6dbd1c8 languageName: node linkType: hard @@ -12800,7 +12800,7 @@ __metadata: "pathe@npm:^1.1.0": version: 1.1.1 resolution: "pathe@npm:1.1.1" - checksum: 34ab3da2e5aa832ebc6a330ffe3f73d7ba8aec6e899b53b8ec4f4018de08e40742802deb12cf5add9c73b7bf719b62c0778246bd376ca62b0fb23e0dde44b759 + checksum: 603decdf751d511f0df10acb8807eab8cc25c1af529e6149e27166916f19db57235a7d374b125452ba6da4dd0f697656fdaf5a9236b3594929bb371726d31602 languageName: node linkType: hard @@ -12832,21 +12832,21 @@ __metadata: "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.0, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" - checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf + checksum: 60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc languageName: node linkType: hard "pify@npm:^4.0.1": version: 4.0.1 resolution: "pify@npm:4.0.1" - checksum: 9c4e34278cb09987685fa5ef81499c82546c033713518f6441778fbec623fc708777fe8ac633097c72d88470d5963094076c7305cafc7ad340aae27cfacd856b + checksum: 8b97cbf9dc6d4c1320cc238a2db0fc67547f9dc77011729ff353faf34f1936ea1a4d7f3c63b2f4980b253be77bcc72ea1e9e76ee3fd53cce2aafb6a8854d07ec languageName: node linkType: hard "pirates@npm:^4.0.4, pirates@npm:^4.0.6": version: 4.0.6 resolution: "pirates@npm:4.0.6" - checksum: 46a65fefaf19c6f57460388a5af9ab81e3d7fd0e7bc44ca59d753cb5c4d0df97c6c6e583674869762101836d68675f027d60f841c105d72734df9dfca97cbcc6 + checksum: d02dda76f4fec1cbdf395c36c11cf26f76a644f9f9a1bfa84d3167d0d3154d5289aacc72677aa20d599bb4a6937a471de1b65c995e2aea2d8687cbcd7e43ea5f languageName: node linkType: hard @@ -12882,7 +12882,7 @@ __metadata: resolution: "polished@npm:4.2.2" dependencies: "@babel/runtime": "npm:^7.17.8" - checksum: 97fb927dc55cd34aeb11b31ae2a3332463f114351c86e8aa6580d7755864a0120164fdc3770e6160c8b1775052f0eda14db9a6e34402cd4b08ab2d658a593725 + checksum: da71b15c1e1d98b7f55e143bbf9ebb1b0934286c74c333522e571e52f89e42a61d7d44c5b4f941dc927355c7ae09780877aeb8f23707376fa9f006ab861e758b languageName: node linkType: hard @@ -12898,7 +12898,7 @@ __metadata: resolution: "postcss-prefix-selector@npm:1.16.0" peerDependencies: postcss: ">4 <9" - checksum: 8bdf10628ec8b1679a4dbb9cd736a4742c5d9b8a878c35cebaad43d67e50a18ffeb34d15860374f18a89fe4c43f818f3386bdb3321f92bb35eec9ef640a46a76 + checksum: cb5f216048c206ac25be3a34f8769859ce84036c4becbc784a92984bcdf9633651245eb1288888a024d6fdd333cd80bf029f2f209f505fb40d3ffd33cefe4294 languageName: node linkType: hard @@ -12910,7 +12910,7 @@ __metadata: js-base64: "npm:^2.1.9" source-map: "npm:^0.5.6" supports-color: "npm:^3.2.3" - checksum: 0cb88e7c887b9b55d0362159846ec9fbf330892c5853b0e346929e723d215295ffae48d9a0f219f64f74767f9114802dc1b5cd21c327184f958b7efaa93dd629 + checksum: ad157696a258c37e8cdebd28c575bba8e028276b030621d7ac191f855b61d56de9fe751f405ca088693806971426a7321f0b0201e0e828e99b1960ac8f474215 languageName: node linkType: hard @@ -12921,7 +12921,7 @@ __metadata: nanoid: "npm:^3.3.6" picocolors: "npm:^1.0.0" source-map-js: "npm:^1.0.2" - checksum: 9ed3ab8af43ad5210c28f56f916fd9b8c9f94fbeaebbf645dcf579bc28bdd8056c2a7ecc934668d399b81fedb6128f0c4b299f931e50454964bc911c25a3a0a2 + checksum: 08916d50035c36e56024b7d56ed5c2a6d59420fce39e1fda77fcbda308cea6d7c39246adb46ee0649d28020e47a73ff2630a3439991ee82c539a495e6f6997d9 languageName: node linkType: hard @@ -12931,7 +12931,7 @@ __metadata: dependencies: htmlparser2: "npm:^3.8.3" isobject: "npm:^2.1.0" - checksum: 1111cced3ea995de4f72bedace828b733e7eefa953573202e596cac7c82b3ced6cae2849c00f2ed1bb801ff544f4cf85a7b94f5f23392727dc4e0a0b26a8b15f + checksum: 2ecae9b93c6b055e70222e2ebe0ff5d8a4fb458b368dedb8b517f6d6f151378df7ff233327ac2fdf97df75075b7b851d5ef318dea6517b3a0f70bcab0bbf06c7 languageName: node linkType: hard @@ -12940,14 +12940,14 @@ __metadata: resolution: "posthtml-rename-id@npm:1.0.12" dependencies: escape-string-regexp: "npm:1.0.5" - checksum: 5bfb88f9063e1057c6f5342d7100584cdcb55f4344ed3cfd68db8249fb25cc06f89b048fbf170cfb64c9a771994a2c3e79457f3bcc49988611a59769fc0a3a6b + checksum: a4a33b3337e910b1b8f1158825061566f919cc9988bc2f5c9eb25934938006243826fcc119611db690c5c45f2ceaae5833e29b9e0952af75bdee942a07770b82 languageName: node linkType: hard "posthtml-render@npm:^1.0.5, posthtml-render@npm:^1.0.6": version: 1.4.0 resolution: "posthtml-render@npm:1.4.0" - checksum: 68c5c85834d57d54bb797ae81a4ab74ad1d87f55e6a327dac9804fbed96214b57d437d7e255e9396184ab976ab7e77aed6efda9315c156ab25ef8ab2c095c16b + checksum: 88ac3e104711c8e2ac62482fd8dbc04f4b6cf6c6c0e9f3e2fdf7130d40794b471898ada95f4213c4a1c2742dc0fba3f71fb2212b154f61a9aaec1c188b2b5639 languageName: node linkType: hard @@ -12959,7 +12959,7 @@ __metadata: posthtml: "npm:^0.9.2" posthtml-parser: "npm:^0.2.1" posthtml-render: "npm:^1.0.6" - checksum: a9f88294dd7fe862a360a04d5e003fc250175bcb43f6fbd80f384f9daa6f39877a16026d00b39107a6201abe237fbfb591a0deea3bda19c606d493c96deff640 + checksum: 2055cbcbc9b66293de52bfadecdf1b7605a23cc1afee7ba061d61e61de2dcad21401e2f0ec302d72f050c8369dbdeff15ccb622f3b20568fcd487cfd813a2980 languageName: node linkType: hard @@ -12969,14 +12969,14 @@ __metadata: dependencies: posthtml-parser: "npm:^0.2.0" posthtml-render: "npm:^1.0.5" - checksum: 1464440239cc8ab745b6682142f509acc3a8837ef01e0398d7f482221030cd06c39f396feb301c4d337c920ce3281788782870c35a11349551c3a418cdc55487 + checksum: 3a0dd2d7c242eb457ecdfb4254ade7829c3a77e415b02bf70523456585fcc9fbe74329bb52d8e2974cda835870c21b3904b531d7b0513cfd929fa615467c5e8a languageName: node linkType: hard "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" - checksum: cd192ec0d0a8e4c6da3bb80e4f62afe336df3f76271ac6deb0e6a36187133b6073a19e9727a1ff108cd8b9982e4768850d413baa71214dd80c7979617dca827a + checksum: 0b9d2c76801ca652a7f64892dd37b7e3fab149a37d2424920099bf894acccc62abb4424af2155ab36dea8744843060a2d8ddc983518d0b1e22265a22324b72ed languageName: node linkType: hard @@ -12994,7 +12994,7 @@ __metadata: resolution: "prettier@npm:2.8.8" bin: prettier: bin-prettier.js - checksum: b49e409431bf129dd89238d64299ba80717b57ff5a6d1c1a8b1a28b590d998a34e083fa13573bc732bb8d2305becb4c9a4407f8486c81fa7d55100eb08263cf8 + checksum: 00cdb6ab0281f98306cd1847425c24cbaaa48a5ff03633945ab4c701901b8e96ad558eb0777364ffc312f437af9b5a07d0f45346266e8245beaf6247b9c62b24 languageName: node linkType: hard @@ -13005,7 +13005,7 @@ __metadata: ansi-regex: "npm:^5.0.1" ansi-styles: "npm:^5.0.0" react-is: "npm:^17.0.1" - checksum: cf610cffcb793885d16f184a62162f2dd0df31642d9a18edf4ca298e909a8fe80bdbf556d5c9573992c102ce8bf948691da91bf9739bee0ffb6e79c8a8a6e088 + checksum: 248990cbef9e96fb36a3e1ae6b903c551ca4ddd733f8d0912b9cc5141d3d0b3f9f8dfb4d799fb1c6723382c9c2083ffbfa4ad43ff9a0e7535d32d41fd5f01da6 languageName: node linkType: hard @@ -13016,28 +13016,28 @@ __metadata: "@jest/schemas": "npm:^29.6.0" ansi-styles: "npm:^5.0.0" react-is: "npm:^18.0.0" - checksum: 6f923a2379a37a425241dc223d76f671c73c4f37dba158050575a54095867d565c068b441843afdf3d7c37bed9df4bbadf46297976e60d4149972b779474203a + checksum: d4b10ffb2a3ab02630d4c32d29cab725b098553f75e0329cfb75034c62eba76669da2f714927828c98009a217837740e0dffd6f4667d9d0830d4d203cc3cc318 languageName: node linkType: hard "pretty-hrtime@npm:^1.0.3": version: 1.0.3 resolution: "pretty-hrtime@npm:1.0.3" - checksum: bae0e6832fe13c3de43d1a3d43df52bf6090499d74dc65a17f5552cb1a94f1f8019a23284ddf988c3c408a09678d743901e1d8f5b7a71bec31eeeac445bef371 + checksum: 0a462e88a0a3fd3320288fd8307f488974326ae8e13eea8c27f590f8ee767ccb59cf35bcae1cadff241cd8b72f3e373fc76ff1be95243649899bf8c816874af9 languageName: node linkType: hard "prismjs@npm:^1.27.0": version: 1.29.0 resolution: "prismjs@npm:1.29.0" - checksum: 007a8869d4456ff8049dc59404e32d5666a07d99c3b0e30a18bd3b7676dfa07d1daae9d0f407f20983865fd8da56de91d09cb08e6aa61f5bc420a27c0beeaf93 + checksum: 2080db382c2dde0cfc7693769e89b501ef1bfc8ff4f8d25c07fd4c37ca31bc443f6133d5b7c145a73309dc396e829ddb7cc18560026d862a887ae08864ef6b07 languageName: node linkType: hard "prismjs@npm:~1.27.0": version: 1.27.0 resolution: "prismjs@npm:1.27.0" - checksum: 85c7f4a3e999073502cc9e1882af01e3709706369ec254b60bff1149eda701f40d02512acab956012dc7e61cfd61743a3a34c1bd0737e8dbacd79141e5698bbc + checksum: dc83e2e09170b53526182f5435fae056fc200b109cac39faa88eb48d992311c7f59b94990318962fa93299190a9b33a404920ed150e5b364ce48c897f2ba1e8e languageName: node linkType: hard @@ -13051,14 +13051,14 @@ __metadata: "process@npm:^0.11.10": version: 0.11.10 resolution: "process@npm:0.11.10" - checksum: bfcce49814f7d172a6e6a14d5fa3ac92cc3d0c3b9feb1279774708a719e19acd673995226351a082a9ae99978254e320ccda4240ddc474ba31a76c79491ca7c3 + checksum: dbaa7e8d1d5cf375c36963ff43116772a989ef2bb47c9bdee20f38fd8fc061119cf38140631cf90c781aca4d3f0f0d2c834711952b728953f04fd7d238f59f5b languageName: node linkType: hard "progress@npm:^2.0.1": version: 2.0.3 resolution: "progress@npm:2.0.3" - checksum: f67403fe7b34912148d9252cb7481266a354bd99ce82c835f79070643bb3c6583d10dbcfda4d41e04bbc1d8437e9af0fb1e1f2135727878f5308682a579429b7 + checksum: e6f0bcb71f716eee9dfac0fe8a2606e3704d6a64dd93baaf49fbadbc8499989a610fe14cf1bc6f61b6d6653c49408d94f4a94e124538084efd8e4cf525e0293d languageName: node linkType: hard @@ -13068,7 +13068,7 @@ __metadata: dependencies: err-code: "npm:^2.0.2" retry: "npm:^0.12.0" - checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 + checksum: 96e1a82453c6c96eef53a37a1d6134c9f2482f94068f98a59145d0986ca4e497bf110a410adf73857e588165eab3899f0ebcf7b3890c1b3ce802abc0d65967d4 languageName: node linkType: hard @@ -13078,7 +13078,7 @@ __metadata: dependencies: kleur: "npm:^3.0.3" sisteransi: "npm:^1.0.5" - checksum: d8fd1fe63820be2412c13bfc5d0a01909acc1f0367e32396962e737cb2fc52d004f3302475d5ce7d18a1e8a79985f93ff04ee03007d091029c3f9104bffc007d + checksum: c52536521a4d21eff4f2f2aa4572446cad227464066365a7167e52ccf8d9839c099f9afec1aba0eed3d5a2514b3e79e0b3e7a1dc326b9acde6b75d27ed74b1a9 languageName: node linkType: hard @@ -13089,7 +13089,7 @@ __metadata: loose-envify: "npm:^1.4.0" object-assign: "npm:^4.1.1" react-is: "npm:^16.13.1" - checksum: c056d3f1c057cb7ff8344c645450e14f088a915d078dcda795041765047fa080d38e5d626560ccaac94a4e16e3aa15f3557c1a9a8d1174530955e992c675e459 + checksum: 7d959caec002bc964c86cdc461ec93108b27337dabe6192fb97d69e16a0c799a03462713868b40749bfc1caf5f57ef80ac3e4ffad3effa636ee667582a75e2c0 languageName: node linkType: hard @@ -13098,7 +13098,7 @@ __metadata: resolution: "property-information@npm:5.6.0" dependencies: xtend: "npm:^4.0.0" - checksum: fcf87c6542e59a8bbe31ca0b3255a4a63ac1059b01b04469680288998bcfa97f341ca989566adbb63975f4d85339030b82320c324a511532d390910d1c583893 + checksum: e4f45b100fec5968126b08102f9567f1b5fc3442aecbb5b4cdeca401f1f447672e7638a08c81c05dd3979c62d084e0cc6acbe2d8b053c05280ac5abaaf666a68 languageName: node linkType: hard @@ -13108,21 +13108,21 @@ __metadata: dependencies: forwarded: "npm:0.2.0" ipaddr.js: "npm:1.9.1" - checksum: 29c6990ce9364648255454842f06f8c46fcd124d3e6d7c5066df44662de63cdc0bad032e9bf5a3d653ff72141cc7b6019873d685708ac8210c30458ad99f2b74 + checksum: f24a0c80af0e75d31e3451398670d73406ec642914da11a2965b80b1898ca6f66a0e3e091a11a4327079b2b268795f6fa06691923fef91887215c3d0e8ea3f68 languageName: node linkType: hard "proxy-from-env@npm:^1.0.0, proxy-from-env@npm:^1.1.0": version: 1.1.0 resolution: "proxy-from-env@npm:1.1.0" - checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 + checksum: f0bb4a87cfd18f77bc2fba23ae49c3b378fb35143af16cc478171c623eebe181678f09439707ad80081d340d1593cd54a33a0113f3ccb3f4bc9451488780ee23 languageName: node linkType: hard "psl@npm:^1.1.33": version: 1.9.0 resolution: "psl@npm:1.9.0" - checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d + checksum: d07879d4bfd0ac74796306a8e5a36a93cfb9c4f4e8ee8e63fbb909066c192fe1008cd8f12abd8ba2f62ca28247949a20c8fb32e1d18831d9e71285a1569720f9 languageName: node linkType: hard @@ -13153,14 +13153,14 @@ __metadata: duplexify: "npm:^3.6.0" inherits: "npm:^2.0.3" pump: "npm:^2.0.0" - checksum: 26ca412ec8d665bd0d5e185c1b8f627728eff603440d75d22a58e421e3c66eaf86ec6fc6a6efc54808ecef65979279fa8e99b109a23ec1fa8d79f37e6978c9bd + checksum: 5d11a99f320dc2a052610399bac6d03db0a23bc23b23aa2a7d0adf879da3065a55134b975db66dc46bc79f54af3dd575d8119113a0a5b311a00580e1f053896b languageName: node linkType: hard "punycode@npm:^2.1.0, punycode@npm:^2.1.1": version: 2.3.0 resolution: "punycode@npm:2.3.0" - checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200 + checksum: d4e7fbb96f570c57d64b09a35a1182c879ac32833de7c6926a2c10619632c1377865af3dab5479f59d51da18bcd5035a20a5ef6ceb74020082a3e78025d9a9ca languageName: node linkType: hard @@ -13178,14 +13178,14 @@ __metadata: proxy-from-env: "npm:^1.0.0" rimraf: "npm:^2.6.1" ws: "npm:^6.1.0" - checksum: 2ddb597ef1b2d162b4aa49833b977734129edf7c8fa558fc38c59d273e79aa1bd079481c642de87f7163665f7f37aa52683da2716bafb7d3cab68c262c36ec28 + checksum: fcbf80c954f9562f88b53886dc377595bf478abbb47c005f9131a56b6704cdd0a26b60f2646d2340866ed9f5059aae2b9f06a0f04310f5f14520ec94a687fbe6 languageName: node linkType: hard "pure-rand@npm:^6.0.0": version: 6.0.2 resolution: "pure-rand@npm:6.0.2" - checksum: 79de33876a4f515d759c48e98d00756bbd916b4ea260cc572d7adfa4b62cace9952e89f0241d0410214554503d25061140fe325c66f845213d2b1728ba8d413e + checksum: d33f92dbac58eba65e851046905379ddd32b0af11daa49187bf2b44c4da6e5685cdcd8775388a3c706c126dcdb19bdcc0f736a0c432de25d68d21a762ff5f572 languageName: node linkType: hard @@ -13194,7 +13194,7 @@ __metadata: resolution: "qs@npm:6.11.0" dependencies: side-channel: "npm:^1.0.4" - checksum: 6e1f29dd5385f7488ec74ac7b6c92f4d09a90408882d0c208414a34dd33badc1a621019d4c799a3df15ab9b1d0292f97c1dd71dc7c045e69f81a8064e5af7297 + checksum: 5a3bfea3e2f359ede1bfa5d2f0dbe54001aa55e40e27dc3e60fab814362d83a9b30758db057c2011b6f53a2d4e4e5150194b5bac45372652aecb3e3c0d4b256e languageName: node linkType: hard @@ -13203,7 +13203,7 @@ __metadata: resolution: "qs@npm:6.11.2" dependencies: side-channel: "npm:^1.0.4" - checksum: e812f3c590b2262548647d62f1637b6989cc56656dc960b893fe2098d96e1bd633f36576f4cd7564dfbff9db42e17775884db96d846bebe4f37420d073ecdc0b + checksum: f2321d0796664d0f94e92447ccd3bdfd6b6f3a50b6b762aa79d7f5b1ea3a7a9f94063ba896b82bc2a877ed6a7426d4081e4f16568fdb04f0ee188cca9d8505b4 languageName: node linkType: hard @@ -13213,35 +13213,35 @@ __metadata: dependencies: object-assign: "npm:^4.1.0" strict-uri-encode: "npm:^1.0.0" - checksum: 3b2bae6a8454cf0edf11cf1aa4d1f920398bbdabc1c39222b9bb92147e746fcd97faf00e56f494728fb66b2961b495ba0fde699d5d3bd06b11472d664b36c6cf + checksum: 878669cd55a79d74d3818c3e2a9f0ce4cbb26c03211fa6329fc299752fd999c37aaed7ece46f282da4800a95af0312ac89281df6c250707bc7c0cf1bb829e8e6 languageName: node linkType: hard "querystringify@npm:^2.1.1": version: 2.2.0 resolution: "querystringify@npm:2.2.0" - checksum: 5641ea231bad7ef6d64d9998faca95611ed4b11c2591a8cae741e178a974f6a8e0ebde008475259abe1621cb15e692404e6b6626e927f7b849d5c09392604b15 + checksum: 46ab16f252fd892fc29d6af60966d338cdfeea68a231e9457631ffd22d67cec1e00141e0a5236a2eb16c0d7d74175d9ec1d6f963660c6f2b1c2fc85b194c5680 languageName: node linkType: hard "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" - checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 + checksum: 72900df0616e473e824202113c3df6abae59150dfb73ed13273503127235320e9c8ca4aaaaccfd58cf417c6ca92a6e68ee9a5c3182886ae949a768639b388a7b languageName: node linkType: hard "ramda@npm:0.29.0": version: 0.29.0 resolution: "ramda@npm:0.29.0" - checksum: 9ab26c06eb7545cbb7eebcf75526d6ee2fcaae19e338f165b2bf32772121e7b28192d6664d1ba222ff76188ba26ab307342d66e805dbb02c860560adc4d5dd57 + checksum: b156660f2c58b4a13bcc4f1a0eabc1145d8db11d33d26a2fb03cd6adf3983a1c1f2bbaaf708c421029e9b09684262d056752623f7e62b79a503fb9217dec69d4 languageName: node linkType: hard "range-parser@npm:~1.2.1": version: 1.2.1 resolution: "range-parser@npm:1.2.1" - checksum: 0a268d4fea508661cf5743dfe3d5f47ce214fd6b7dec1de0da4d669dd4ef3d2144468ebe4179049eff253d9d27e719c88dae55be64f954e80135a0cada804ec9 + checksum: ce21ef2a2dd40506893157970dc76e835c78cf56437e26e19189c48d5291e7279314477b06ac38abd6a401b661a6840f7b03bd0b1249da9b691deeaa15872c26 languageName: node linkType: hard @@ -13253,7 +13253,7 @@ __metadata: http-errors: "npm:2.0.0" iconv-lite: "npm:0.4.24" unpipe: "npm:1.0.0" - checksum: 5362adff1575d691bb3f75998803a0ffed8c64eabeaa06e54b4ada25a0cd1b2ae7f4f5ec46565d1bec337e08b5ac90c76eaa0758de6f72a633f025d754dec29e + checksum: 280bedc12db3490ecd06f740bdcf66093a07535374b51331242382c0e130bb273ebb611b7bc4cba1b4b4e016cc7b1f4b05a6df885a6af39c2bc3b94c02291c84 languageName: node linkType: hard @@ -13265,7 +13265,7 @@ __metadata: peerDependencies: react: ^16.9.0 || ^17 || ^18 react-dom: ^16.9.0 || ^17 || ^18 - checksum: 77648dd51d746842326a5268cfb48290df225e11b13de587313603fb8452703ba34ea4b32afa8bf386067e179212ce670adca09c5d29943ea74d8c0e43b20430 + checksum: f3cdf4bc00739196bad3ba7aa4837688a446cba3cd11c9ac115c86f19f42e4db68a84c0fe2fc740973669afd88aa7f6da39fea7093ddf34a0a24ccdaaf29fe73 languageName: node linkType: hard @@ -13275,7 +13275,7 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: e432b7cb0df57e8f0bcdc3b012d2e93fcbcb6092c9e0f85654788d5ebfc4442536d8cc35b2418061ba3c4afb8b7788cc101c606d86a1732407921de7a9244c8d + checksum: 3e02ba013454818d0c323949bd961fb2c19ac18130dfc67a4032aa5b03787c5ffe7ff159c4b97dc3475072d576828ca0c4b8e8ce85b55eaf484180596cdf0403 languageName: node linkType: hard @@ -13287,7 +13287,7 @@ __metadata: prop-types: "npm:^15.8.1" peerDependencies: react: ^15.3.0 || 16 || 17 || 18 - checksum: f00a4551b9b63c944a041a6ab46af5ef20ba1106b3bc25173e7ef9bffbfba17a613368682ab8820cfe8d4b3acc5335cd9ce20229145bcc1e6aa8d1db04c512e5 + checksum: 56a8b11a268a19d4e4ec409327f1c17d68c4f13a54330b9c0e3271acb44bb6886b72e04d77399c9945968851e8532dd192bbccffd1b2f8b010f4bb47e5743b3b languageName: node linkType: hard @@ -13296,7 +13296,7 @@ __metadata: resolution: "react-docgen-typescript@npm:2.2.2" peerDependencies: typescript: ">= 4.3.x" - checksum: a9826459ea44e818f21402728dd47f5cae60bd936574cefd4f90ad101ff3eebacd67b6e017b793309734ce62c037aa3072dbc855d2b0e29bad1a38cbf5bac115 + checksum: 081fc3a876f53b9eeffcff357e5b6c190db799d50edcf11b187857d8cb8cce28000ed777ed16dd52a1c955f332612ef6b1f02cf8adcbcb084b8da9ff1ae5fd13 languageName: node linkType: hard @@ -13304,17 +13304,17 @@ __metadata: version: 7.0.3 resolution: "react-docgen@npm:7.0.3" dependencies: - "@babel/core": ^7.18.9 - "@babel/traverse": ^7.18.9 - "@babel/types": ^7.18.9 - "@types/babel__core": ^7.18.0 - "@types/babel__traverse": ^7.18.0 - "@types/doctrine": ^0.0.9 - "@types/resolve": ^1.20.2 - doctrine: ^3.0.0 - resolve: ^1.22.1 - strip-indent: ^4.0.0 - checksum: f5dbabd16a25b3c424c4962df4b4073d03ca124c3a5c99871f8436e30468854de115f959d0d5f03df77ad8dbe54f21e679fb48ba47bc125d61ae527bc5bcf0bf + "@babel/core": "npm:^7.18.9" + "@babel/traverse": "npm:^7.18.9" + "@babel/types": "npm:^7.18.9" + "@types/babel__core": "npm:^7.18.0" + "@types/babel__traverse": "npm:^7.18.0" + "@types/doctrine": "npm:^0.0.9" + "@types/resolve": "npm:^1.20.2" + doctrine: "npm:^3.0.0" + resolve: "npm:^1.22.1" + strip-indent: "npm:^4.0.0" + checksum: 53eaed76cceb55606584c6ab603f04ec78c066cfb9ed983e1f7b388a75bfb8c2fc9c6b7ab299bac311b3daeca95adb8076b58ca96b41907b33c518299268831f languageName: node linkType: hard @@ -13326,7 +13326,7 @@ __metadata: scheduler: "npm:^0.23.0" peerDependencies: react: ^18.2.0 - checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc + checksum: ca5e7762ec8c17a472a3605b6f111895c9f87ac7d43a610ab7024f68cd833d08eda0625ce02ec7178cc1f3c957cf0b9273cdc17aa2cd02da87544331c43b1d21 languageName: node linkType: hard @@ -13340,35 +13340,35 @@ __metadata: peerDependencies: react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 - checksum: c3907cc4c1d3e9ecc8ca7727058ebcba6ec89848d9e07bfd2c77ee8f28f1ad99bf55e38359dec8a1125de83d41ac09a2874f53c41415edc86ffa9840fa1b7856 + checksum: 9a874b2f16b4624a72c4b766b096d693a382b9dc7f2264f802395852ae3435ccde8e9e47bbe45cf5f30eba70f8126af6aca832190e285b0096af3ecade994df1 languageName: node linkType: hard "react-is@npm:18.1.0": version: 18.1.0 resolution: "react-is@npm:18.1.0" - checksum: d206a0fe6790851bff168727bfb896de02c5591695afb0c441163e8630136a3e13ee1a7ddd59fdccddcc93968b4721ae112c10f790b194b03b35a3dc13a355ef + checksum: fe09c86d5e12a8531bf3e748660f3dffbe900a6da0b488c7efaf0a866e16b74ecc1b0011b0960b13594f8719f39f87a987c0c85edff0b2d3e2f14b87e7230ad2 languageName: node linkType: hard "react-is@npm:^16.13.1, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" - checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f + checksum: 5aa564a1cde7d391ac980bedee21202fc90bdea3b399952117f54fb71a932af1e5902020144fb354b4690b2414a0c7aafe798eb617b76a3d441d956db7726fdf languageName: node linkType: hard "react-is@npm:^17.0.1": version: 17.0.2 resolution: "react-is@npm:17.0.2" - checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8 + checksum: 73b36281e58eeb27c9cc6031301b6ae19ecdc9f18ae2d518bdb39b0ac564e65c5779405d623f1df9abf378a13858b79442480244bd579968afc1faf9a2ce5e05 languageName: node linkType: hard "react-is@npm:^18.0.0": version: 18.2.0 resolution: "react-is@npm:18.2.0" - checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e + checksum: 200cd65bf2e0be7ba6055f647091b725a45dd2a6abef03bf2380ce701fd5edccee40b49b9d15edab7ac08a762bf83cb4081e31ec2673a5bfb549a36ba21570df languageName: node linkType: hard @@ -13380,7 +13380,7 @@ __metadata: peerDependencies: react: ^16.14.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 - checksum: 8f411d6dbdac8b902e4e3f33063b9956b4dbdbab344085c1758864e62c45603f3f971de2ca20016100b55b040e284b3653e186961bd12d10bdbfdf1f2a409dee + checksum: 44066948d662e3aab9c9bf581e0f9310e7b2379e63e6b0d2e96ff8e663af6da6ca5152def56892dc15c9c6b9aa596ef93e755c21ee8f7e380b9f9c33092802da languageName: node linkType: hard @@ -13390,7 +13390,7 @@ __metadata: peerDependencies: react: ^16.14.0 || ^17.0.0 react-dom: ^16.14.0 || ^17.0.0 - checksum: a62d3e3afaa9fb103a0f5927c909ccfa7b95cadcc9ca648daefec261c6876d1e1af1831dbcb5128a3f27f1a99143acc2899a994cefb5271ef0a0d91c1f303016 + checksum: da2a7786a2014e99669b99de05cd9e7deb46f8bce04c3c193bf7a2c927a656d03735e50c7310a4f59d853abfc9fa1b76f8965c9afe82f4943fe672a619c766de languageName: node linkType: hard @@ -13404,7 +13404,7 @@ __metadata: "react-property@npm:2.0.0": version: 2.0.0 resolution: "react-property@npm:2.0.0" - checksum: 8a444df30ef0937689c7968dae2501a0ca523777169f450e1f7ef5beeb855d6509bd058bf612f6ed8f459aa35468335d356e50264492e1938586e59fdb988262 + checksum: 6b80f6a8f15f783b56a9ac897eb2ae3938c731c22c5ec80d74d2cb231228efa9feca87027639ff0007a870e15c80d5896f171f14a1c14e7f4fbced348a4d0c82 languageName: node linkType: hard @@ -13436,14 +13436,14 @@ __metadata: optional: true redux: optional: true - checksum: 370676330727764d78f35e9c5a0ed0591d79482fe9b70fffcab4aa6bcccc6194e4f1ebd818b4b390351dea5557e70d3bd4d95d7a0ac9baa1f45d6bf2230ee713 + checksum: 2998af1870dadc1a5c39566712481cc087af259198c419840b6b966d311ba23bb95b31441440ff4c61ac710024914ebb9c71fbd4290e6fa25d255e6f20ae737a languageName: node linkType: hard "react-refresh@npm:^0.14.0": version: 0.14.0 resolution: "react-refresh@npm:0.14.0" - checksum: dc69fa8c993df512f42dd0f1b604978ae89bd747c0ed5ec595c0cc50d535fb2696619ccd98ae28775cc01d0a7c146a532f0f7fb81dc22e1977c242a4912312f4 + checksum: 75941262ce3ed4fc79b52492943fd59692f29b84f30f3822713b7e920f28e85c62a4386f85cbfbaea95ed62d3e74209f0a0bb065904b7ab2f166a74ac3812e2a languageName: node linkType: hard @@ -13451,15 +13451,15 @@ __metadata: version: 2.3.4 resolution: "react-remove-scroll-bar@npm:2.3.4" dependencies: - react-style-singleton: ^2.2.1 - tslib: ^2.0.0 + react-style-singleton: "npm:^2.2.1" + tslib: "npm:^2.0.0" peerDependencies: "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: b5ce5f2f98d65c97a3e975823ae4043a4ba2a3b63b5ba284b887e7853f051b5cd6afb74abde6d57b421931c52f2e1fdbb625dc858b1cb5a32c27c14ab85649d4 + checksum: ac028b3ed12e66972cab8656747736729b219dff5a600178d1650300a2a750ace37f7ec82146147d37b092b19874f45cf7a45edceff68ac1f59607a828ca089f languageName: node linkType: hard @@ -13467,18 +13467,18 @@ __metadata: version: 2.5.5 resolution: "react-remove-scroll@npm:2.5.5" dependencies: - react-remove-scroll-bar: ^2.3.3 - react-style-singleton: ^2.2.1 - tslib: ^2.1.0 - use-callback-ref: ^1.3.0 - use-sidecar: ^1.1.2 + react-remove-scroll-bar: "npm:^2.3.3" + react-style-singleton: "npm:^2.2.1" + tslib: "npm:^2.1.0" + use-callback-ref: "npm:^1.3.0" + use-sidecar: "npm:^1.1.2" peerDependencies: "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 2c7fe9cbd766f5e54beb4bec2e2efb2de3583037b23fef8fa511ab426ed7f1ae992382db5acd8ab5bfb030a4b93a06a2ebca41377d6eeaf0e6791bb0a59616a4 + checksum: f0646ac384ce3852d1f41e30a9f9e251b11cf3b430d1d114c937c8fa7f90a895c06378d0d6b6ff0b2d00cbccf15e845921944fd6074ae67a0fb347a718106d88 languageName: node linkType: hard @@ -13491,7 +13491,7 @@ __metadata: peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: ba44ff37f2956bc18991f2eedb32a3fa46d35832f61ded6c5d167e853ca289868fca6635467866280c73bc3da00dce8437dbbec57da100c0a3e3e3850af00b83 + checksum: 85575793cbdb84b05e9c33fef6f81e6b09e9f2606d2ba03392f83689dbb240212e5b22634b95049fc19364e9b44d45a519387d1bff4eba8a163548aa3376bc0f languageName: node linkType: hard @@ -13502,7 +13502,7 @@ __metadata: "@remix-run/router": "npm:1.6.2" peerDependencies: react: ">=16.8" - checksum: e47f875dca70033a3b42704cb5ec076b60f9629a5cdc3be613707f3d5a5706123fb80301037455c285c6d5a1011b443e1784e0103969ebfac7071648d360c413 + checksum: a40d1ea78e3b5b3167ed6cbaf74b2e60592fd1822b9f94a2499933bf699130a81f669bc06bdf34f38489a96d31510848c21254a48e49038b18ecbf42993eaa34 languageName: node linkType: hard @@ -13510,16 +13510,16 @@ __metadata: version: 2.2.1 resolution: "react-style-singleton@npm:2.2.1" dependencies: - get-nonce: ^1.0.0 - invariant: ^2.2.4 - tslib: ^2.0.0 + get-nonce: "npm:^1.0.0" + invariant: "npm:^2.2.4" + tslib: "npm:^2.0.0" peerDependencies: "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 7ee8ef3aab74c7ae1d70ff34a27643d11ba1a8d62d072c767827d9ff9a520905223e567002e0bf6c772929d8ea1c781a3ba0cc4a563e92b1e3dc2eaa817ecbe8 + checksum: 80c58fd6aac3594e351e2e7b048d8a5b09508adb21031a38b3c40911fe58295572eddc640d4b20a7be364842c8ed1120fe30097e22ea055316b375b88d4ff02a languageName: node linkType: hard @@ -13534,7 +13534,7 @@ __metadata: refractor: "npm:^3.6.0" peerDependencies: react: ">= 0.14.0" - checksum: c082b48f30f8ba8d0c55ed1d761910630860077c7ff5793c4c912adcb5760df06436ed0ad62be0de28113aac9ad2af55eccd995f8eee98df53382e4ced2072fb + checksum: 14291a92672a79cf167e6cf2dba2547b920c24573729a95ae24035bece43f7e00e3429477be7b87455e8ce018682c8992545c405a915421eb772c5cd07c00576 languageName: node linkType: hard @@ -13543,7 +13543,7 @@ __metadata: resolution: "react@npm:18.2.0" dependencies: loose-envify: "npm:^1.1.0" - checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b + checksum: b9214a9bd79e99d08de55f8bef2b7fc8c39630be97c4e29d7be173d14a9a10670b5325e94485f74cd8bff4966ef3c78ee53c79a7b0b9b70cba20aa8973acc694 languageName: node linkType: hard @@ -13581,7 +13581,7 @@ __metadata: safe-buffer: "npm:~5.1.1" string_decoder: "npm:~1.1.1" util-deprecate: "npm:~1.0.1" - checksum: 65645467038704f0c8aaf026a72fbb588a9e2ef7a75cd57a01702ee9db1c4a1e4b03aaad36861a6a0926546a74d174149c8c207527963e0c2d3eee2f37678a42 + checksum: 8500dd3a90e391d6c5d889256d50ec6026c059fadee98ae9aa9b86757d60ac46fff24fafb7a39fa41d54cb39d8be56cc77be202ebd4cd8ffcf4cb226cbaa40d4 languageName: node linkType: hard @@ -13592,7 +13592,7 @@ __metadata: inherits: "npm:^2.0.3" string_decoder: "npm:^1.1.1" util-deprecate: "npm:^1.0.1" - checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + checksum: d9e3e53193adcdb79d8f10f2a1f6989bd4389f5936c6f8b870e77570853561c362bee69feca2bbb7b32368ce96a85504aa4cedf7cf80f36e6a9de30d64244048 languageName: node linkType: hard @@ -13601,7 +13601,7 @@ __metadata: resolution: "readdirp@npm:3.6.0" dependencies: picomatch: "npm:^2.2.1" - checksum: 1ced032e6e45670b6d7352d71d21ce7edf7b9b928494dcaba6f11fba63180d9da6cd7061ebc34175ffda6ff529f481818c962952004d273178acd70f7059b320 + checksum: 196b30ef6ccf9b6e18c4e1724b7334f72a093d011a99f3b5920470f0b3406a51770867b3e1ae9711f227ef7a7065982f6ee2ce316746b2cb42c88efe44297fe7 languageName: node linkType: hard @@ -13614,7 +13614,7 @@ __metadata: esprima: "npm:~4.0.0" source-map: "npm:~0.6.1" tslib: "npm:^2.0.1" - checksum: b1340ab0a3a8e4bf206c6c7d54168f7019ed4138a53bc746df230c01f1b6672ce9d25dceb34896b6683622d3eede4e1f18b7d0b672f5aab54ba7762de949e317 + checksum: 198105aa83f39afd0df7f3ddf9906eef4be147bfaa1c255a27a8ed1d191f996e373ac2f58a6e6753216e85acfaa56408dd729b33b32dd192dcfdcecb96dd4d39 languageName: node linkType: hard @@ -13622,12 +13622,12 @@ __metadata: version: 0.23.4 resolution: "recast@npm:0.23.4" dependencies: - assert: ^2.0.0 - ast-types: ^0.16.1 - esprima: ~4.0.0 - source-map: ~0.6.1 - tslib: ^2.0.1 - checksum: edb63bbe0457e68c0f4892f55413000e92aa7c5c53f9e109ab975d1c801cd299a62511ea72734435791f4aea6f0edf560f6a275761f66b2b6069ff6d72686029 + assert: "npm:^2.0.0" + ast-types: "npm:^0.16.1" + esprima: "npm:~4.0.0" + source-map: "npm:~0.6.1" + tslib: "npm:^2.0.1" + checksum: a82e388ded2154697ea54e6d65d060143c9cf4b521f770232a7483e253d45bdd9080b44dc5874d36fe720ba1a10cb20b95375896bd89f5cab631a751e93979f5 languageName: node linkType: hard @@ -13646,7 +13646,7 @@ __metadata: resolution: "redux-thunk@npm:2.4.2" peerDependencies: redux: ^4 - checksum: c7f757f6c383b8ec26152c113e20087818d18ed3edf438aaad43539e9a6b77b427ade755c9595c4a163b6ad3063adf3497e5fe6a36c68884eb1f1cfb6f049a5c + checksum: 9bcb1193835128ecebf1e1a1b1a37bc15e8dfbdf6b6ee1b5566dd4c8e4ca05a81175f0c6dda34ab47f87053cd13b74d9f881d59446691d7b192831852b5d7a72 languageName: node linkType: hard @@ -13655,7 +13655,7 @@ __metadata: resolution: "redux@npm:4.2.1" dependencies: "@babel/runtime": "npm:^7.9.2" - checksum: f63b9060c3a1d930ae775252bb6e579b42415aee7a23c4114e21a0b4ba7ec12f0ec76936c00f546893f06e139819f0e2855e0d55ebfce34ca9c026241a6950dd + checksum: 371e4833b671193303a7dea7803c8fdc8e0d566740c78f580e0a3b77b4161da25037626900a2205a5d616117fa6ad09a4232e5a110bd437186b5c6355a041750 languageName: node linkType: hard @@ -13666,7 +13666,7 @@ __metadata: hastscript: "npm:^6.0.0" parse-entities: "npm:^2.0.0" prismjs: "npm:~1.27.0" - checksum: 39b01c4168c77c5c8486f9bf8907bbb05f257f15026057ba5728535815a2d90eed620468a4bfbb2b8ceefbb3ce3931a1be8b17152dbdbc8b0eef92450ff750a2 + checksum: 671bbcf5ae1b4e207f98b9a3dc2cbae215be30effe9f3bdcfd10f565f45fecfe97334cf38c8e4f52d6cc012ff2ec7fb627d3d5678efc388751c8b1e1f7ca2a6c languageName: node linkType: hard @@ -13675,28 +13675,28 @@ __metadata: resolution: "regenerate-unicode-properties@npm:10.1.0" dependencies: regenerate: "npm:^1.4.2" - checksum: b1a8929588433ab8b9dc1a34cf3665b3b472f79f2af6ceae00d905fc496b332b9af09c6718fb28c730918f19a00dc1d7310adbaa9b72a2ec7ad2f435da8ace17 + checksum: 25b268659898955ad105267b4efba20e361e27b233670694b683728a2800314bec3053918d3bf71b0604376fd76fe9bc9c6f80379cfb6d1e209a58de44101aac languageName: node linkType: hard "regenerate@npm:^1.4.2": version: 1.4.2 resolution: "regenerate@npm:1.4.2" - checksum: 3317a09b2f802da8db09aa276e469b57a6c0dd818347e05b8862959c6193408242f150db5de83c12c3fa99091ad95fb42a6db2c3329bfaa12a0ea4cbbeb30cb0 + checksum: dc6c95ae4b3ba6adbd7687cafac260eee4640318c7a95239d5ce847d9b9263979758389e862fe9c93d633b5792ea4ada5708df75885dc5aa05a309fa18140a87 languageName: node linkType: hard "regenerator-runtime@npm:^0.13.11": version: 0.13.11 resolution: "regenerator-runtime@npm:0.13.11" - checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 + checksum: d493e9e118abef5b099c78170834f18540c4933cedf9bfabc32d3af94abfb59a7907bd7950259cbab0a929ebca7db77301e8024e5121e6482a82f78283dfd20c languageName: node linkType: hard "regenerator-runtime@npm:^0.14.0": version: 0.14.1 resolution: "regenerator-runtime@npm:0.14.1" - checksum: 9f57c93277b5585d3c83b0cf76be47b473ae8c6d9142a46ce8b0291a04bb2cf902059f0f8445dcabb3fb7378e5fe4bb4ea1e008876343d42e46d3b484534ce38 + checksum: 5db3161abb311eef8c45bcf6565f4f378f785900ed3945acf740a9888c792f75b98ecb77f0775f3bf95502ff423529d23e94f41d80c8256e8fa05ed4b07cf471 languageName: node linkType: hard @@ -13705,7 +13705,7 @@ __metadata: resolution: "regenerator-transform@npm:0.15.1" dependencies: "@babel/runtime": "npm:^7.8.4" - checksum: 2d15bdeadbbfb1d12c93f5775493d85874dbe1d405bec323da5c61ec6e701bc9eea36167483e1a5e752de9b2df59ab9a2dfff6bf3784f2b28af2279a673d29a4 + checksum: 52a14f325a4e4b422b4019f12e969a4a221db35ccc4cf2b13b9e70a5c7ab276503888338bdfca21f8393ce1dd7adcf9e08557f60d42bf2aec7f6a65a27cde6d0 languageName: node linkType: hard @@ -13713,8 +13713,8 @@ __metadata: version: 0.15.2 resolution: "regenerator-transform@npm:0.15.2" dependencies: - "@babel/runtime": ^7.8.4 - checksum: 20b6f9377d65954980fe044cfdd160de98df415b4bff38fbade67b3337efaf078308c4fed943067cd759827cc8cfeca9cb28ccda1f08333b85d6a2acbd022c27 + "@babel/runtime": "npm:^7.8.4" + checksum: c4fdcb46d11bbe32605b4b9ed76b21b8d3f241a45153e9dc6f5542fed4c7744fed459f42701f650d5d5956786bf7de57547329d1c05a9df2ed9e367b9d903302 languageName: node linkType: hard @@ -13735,7 +13735,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.2.0" functions-have-names: "npm:^1.2.3" - checksum: c541687cdbdfff1b9a07f6e44879f82c66bbf07665f9a7544c5fd16acdb3ec8d1436caab01662d2fbcad403f3499d49ab0b77fbc7ef29ef961d98cc4bc9755b4 + checksum: c8229ec3f59f8312248268009cb9bf9145a3982117f747499b994e8efb378ac8b62e812fd88df75225d53cb4879d2bb2fe47b2a50776cba076d8ff71fc0b1629 languageName: node linkType: hard @@ -13749,7 +13749,7 @@ __metadata: regjsparser: "npm:^0.9.1" unicode-match-property-ecmascript: "npm:^2.0.0" unicode-match-property-value-ecmascript: "npm:^2.1.0" - checksum: 95bb97088419f5396e07769b7de96f995f58137ad75fac5811fb5fe53737766dfff35d66a0ee66babb1eb55386ef981feaef392f9df6d671f3c124812ba24da2 + checksum: ed0d7c66d84c633fbe8db4939d084c780190eca11f6920807dfb8ebac59e2676952cd8f2008d9c86ae8cf0463ea5fd12c5cff09ef2ce7d51ee6b420a5eb4d177 languageName: node linkType: hard @@ -13760,7 +13760,7 @@ __metadata: jsesc: "npm:~0.5.0" bin: regjsparser: bin/parser - checksum: 5e1b76afe8f1d03c3beaf9e0d935dd467589c3625f6d65fb8ffa14f224d783a0fed4bf49c2c1b8211043ef92b6117313419edf055a098ed8342e340586741afc + checksum: be7757ef76e1db10bf6996001d1021048b5fb12f5cb470a99b8cf7f3ff943f0f0e2291c0dcdbb418b458ddc4ac10e48680a822b69ef487a0284c8b6b77beddc3 languageName: node linkType: hard @@ -13784,7 +13784,7 @@ __metadata: github-slugger: "npm:^1.0.0" mdast-util-to-string: "npm:^1.0.0" unist-util-visit: "npm:^2.0.0" - checksum: 81fff0dcfaf6d6117ef1293bb1d26c3e25483d99c65c22434298eed93583a89ea5d7b94063d9a7f47c0647a708ce84f00ff62d274503f248feec03c344cabb20 + checksum: 8c90815a0f1f0568450e923391de0183205e18befb7a7e19e111c75ad08cabf7daebe62fccc82b6fbf9f54148dd311b87463632299dbf9fdfe412f6a0a9ab3ea languageName: node linkType: hard @@ -13805,35 +13805,35 @@ __metadata: "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" - checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80 + checksum: a72468e2589270d91f06c7d36ec97a88db53ae5d6fe3787fadc943f0b0276b10347f89b363b2a82285f650bdcc135ad4a257c61bdd4d00d6df1fa24875b0ddaf languageName: node linkType: hard "require-from-string@npm:^2.0.2": version: 2.0.2 resolution: "require-from-string@npm:2.0.2" - checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b + checksum: 839a3a890102a658f4cb3e7b2aa13a1f80a3a976b512020c3d1efc418491c48a886b6e481ea56afc6c4cb5eef678f23b2a4e70575e7534eccadf5e30ed2e56eb languageName: node linkType: hard "requireindex@npm:^1.1.0": version: 1.2.0 resolution: "requireindex@npm:1.2.0" - checksum: 50d8b10a1ff1fdf6aea7a1870bc7bd238b0fb1917d8d7ca17fd03afc38a65dcd7a8a4eddd031f89128b5f0065833d5c92c4fef67f2c04e8624057fe626c9cf94 + checksum: 266d1cb31f6cbc4b6cf2e898f5bbc45581f7919bcf61bba5c45d0adb69b722b9ff5a13727be3350cde4520d7cd37f39df45d58a29854baaa4552cd6b05ae4a1a languageName: node linkType: hard "requires-port@npm:^1.0.0": version: 1.0.0 resolution: "requires-port@npm:1.0.0" - checksum: eee0e303adffb69be55d1a214e415cf42b7441ae858c76dfc5353148644f6fd6e698926fc4643f510d5c126d12a705e7c8ed7e38061113bdf37547ab356797ff + checksum: 878880ee78ccdce372784f62f52a272048e2d0827c29ae31e7f99da18b62a2b9463ea03a75f277352f4697c100183debb0532371ad515a2d49d4bfe596dd4c20 languageName: node linkType: hard "reselect@npm:^4.1.8": version: 4.1.8 resolution: "reselect@npm:4.1.8" - checksum: a4ac87cedab198769a29be92bc221c32da76cfdad6911eda67b4d3e7136dca86208c3b210e31632eae31ebd2cded18596f0dd230d3ccc9e978df22f233b5583e + checksum: 199984d9872f71cd207f4aa6e6fd2bd48d95154f7aa9b3aee3398335f39f5491059e732f28c12e9031d5d434adab2c458dc8af5afb6564d0ad37e1644445e09c languageName: node linkType: hard @@ -13849,28 +13849,28 @@ __metadata: "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" - checksum: f4ba0b8494846a5066328ad33ef8ac173801a51739eb4d63408c847da9a2e1c1de1e6cbbf72699211f3d13f8fc1325648b169bd15eb7da35688e30a5fb0e4a7f + checksum: 91eb76ce83621eea7bbdd9b55121a5c1c4a39e54a9ce04a9ad4517f102f8b5131c2cf07622c738a6683991bf54f2ce178f5a42803ecbd527ddc5105f362cc9e3 languageName: node linkType: hard "resolve-from@npm:^5.0.0": version: 5.0.0 resolution: "resolve-from@npm:5.0.0" - checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf + checksum: be18a5e4d76dd711778664829841cde690971d02b6cbae277735a09c1c28f407b99ef6ef3cd585a1e6546d4097b28df40ed32c4a287b9699dcf6d7f208495e23 languageName: node linkType: hard "resolve-url@npm:^0.2.1": version: 0.2.1 resolution: "resolve-url@npm:0.2.1" - checksum: 7b7035b9ed6e7bc7d289e90aef1eab5a43834539695dac6416ca6e91f1a94132ae4796bbd173cdacfdc2ade90b5f38a3fb6186bebc1b221cd157777a23b9ad14 + checksum: c8bbf6385730add6657103929ebd7e4aa623a2c2df29bba28a58fec73097c003edcce475efefa51c448a904aa344a4ebabe6ad85c8e75c72c4ce9a0c0b5652d2 languageName: node linkType: hard "resolve.exports@npm:^2.0.0": version: 2.0.2 resolution: "resolve.exports@npm:2.0.2" - checksum: 1c7778ca1b86a94f8ab4055d196c7d87d1874b96df4d7c3e67bbf793140f0717fd506dcafd62785b079cd6086b9264424ad634fb904409764c3509c3df1653f2 + checksum: f1cc0b6680f9a7e0345d783e0547f2a5110d8336b3c2a4227231dd007271ffd331fd722df934f017af90bae0373920ca0d4005da6f76cb3176c8ae426370f893 languageName: node linkType: hard @@ -13883,7 +13883,7 @@ __metadata: supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: fb834b81348428cb545ff1b828a72ea28feb5a97c026a1cf40aa1008352c72811ff4d4e71f2035273dc536dcfcae20c13604ba6283c612d70fa0b6e44519c374 + checksum: 3d733800d5f7525df912e9c4a68ee14574f42fa3676651debe6d2f6f55f8eef35626ad6330745da52943d695760f1ac7ee85b2c24f48be111f744aba7cb2e06d languageName: node linkType: hard @@ -13896,33 +13896,33 @@ __metadata: supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: c438ac9a650f2030fd074219d7f12ceb983b475da2d89ad3d6dd05fbf6b7a0a8cd37d4d10b43cb1f632bc19f22246ab7f36ebda54d84a29bfb2910a0680906d3 + checksum: 20d5293f5015aa0b65c488ee365f9dfc30b954b04f9074425a6fb738d78fa63825a82ba8574b7ee200af7ebd5e98c41786831d1d4c1612da3cd063980dfa06a3 languageName: node linkType: hard -"resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@npm%3A^1.10.0#~builtin, resolve@patch:resolve@npm%3A^1.14.2#~builtin, resolve@patch:resolve@npm%3A^1.20.0#~builtin, resolve@patch:resolve@npm%3A^1.22.1#~builtin": +"resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin": version: 1.22.3 - resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=c3c19d" + resolution: "resolve@patch:resolve@npm%3A1.22.3#optional!builtin::version=1.22.3&hash=c3c19d" dependencies: is-core-module: "npm:^2.12.0" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: ad59734723b596d0891321c951592ed9015a77ce84907f89c9d9307dd0c06e11a67906a3e628c4cae143d3e44898603478af0ddeb2bba3f229a9373efe342665 + checksum: b775dffbad4d4ed3ae498a37d33a96282d64de50955f7642258aeaa2886e419598f4dfe837c0e31bcc6eb448287c1578e899dffe49eca76ef393bf8605a3b543 languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^2.0.0-next.4#~builtin": +"resolve@patch:resolve@npm%3A^2.0.0-next.4#optional!builtin": version: 2.0.0-next.4 - resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=c3c19d" + resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#optional!builtin::version=2.0.0-next.4&hash=c3c19d" dependencies: is-core-module: "npm:^2.9.0" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 4bf9f4f8a458607af90518ff73c67a4bc1a38b5a23fef2bb0ccbd45e8be89820a1639b637b0ba377eb2be9eedfb1739a84cde24fe4cd670c8207d8fea922b011 + checksum: 27bff19d8219385bb1e271066317e553cff18daa2a19db9598d94ae444417ef3f5aec19e86927872d6cb241d02649cfb35a4c0d9d10ef2afa6325bce8bc8d903 languageName: node linkType: hard @@ -13930,8 +13930,8 @@ __metadata: version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" dependencies: - onetime: ^5.1.0 - signal-exit: ^3.0.2 + onetime: "npm:^5.1.0" + signal-exit: "npm:^3.0.2" checksum: f877dd8741796b909f2a82454ec111afb84eb45890eb49ac947d87991379406b3b83ff9673a46012fca0d7844bb989f45cc5b788254cf1a39b6b5a9659de0630 languageName: node linkType: hard @@ -13939,21 +13939,21 @@ __metadata: "ret@npm:~0.1.10": version: 0.1.15 resolution: "ret@npm:0.1.15" - checksum: d76a9159eb8c946586567bd934358dfc08a36367b3257f7a3d7255fdd7b56597235af23c6afa0d7f0254159e8051f93c918809962ebd6df24ca2a83dbe4d4151 + checksum: 07c9e7619b4c86053fa57689bf7606b5a40fc1231fc87682424d0b3e296641cc19c218c3b8a8917305fbcca3bfc43038a5b6a63f54755c1bbca2f91857253b03 languageName: node linkType: hard "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" - checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c + checksum: 1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 languageName: node linkType: hard "reusify@npm:^1.0.4": version: 1.0.4 resolution: "reusify@npm:1.0.4" - checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc + checksum: 14222c9e1d3f9ae01480c50d96057228a8524706db79cdeb5a2ce5bb7070dd9f409a6f84a02cbef8cdc80d39aef86f2dd03d155188a1300c599b05437dcd2ffb languageName: node linkType: hard @@ -13964,7 +13964,7 @@ __metadata: glob: "npm:^7.1.3" bin: rimraf: ./bin.js - checksum: cdc7f6eacb17927f2a075117a823e1c5951792c6498ebcce81ca8203454a811d4cf8900314154d3259bb8f0b42ab17f67396a8694a54cae3283326e57ad250cd + checksum: 4586c296c736483e297da7cffd19475e4a3e41d07b1ae124aad5d687c79e4ffa716bdac8732ed1db942caf65271cee9dd39f8b639611de161a2753e2112ffe1d languageName: node linkType: hard @@ -13975,7 +13975,7 @@ __metadata: glob: "npm:^7.1.3" bin: rimraf: bin.js - checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 + checksum: 063ffaccaaaca2cfd0ef3beafb12d6a03dd7ff1260d752d62a6077b5dfff6ae81bea571f655bb6b589d366930ec1bdd285d40d560c0dae9b12f125e54eb743d5 languageName: node linkType: hard @@ -13986,7 +13986,7 @@ __metadata: glob: "npm:^7.1.3" bin: rimraf: ./bin.js - checksum: 3ea587b981a19016297edb96d1ffe48af7e6af69660e3b371dbfc73722a73a0b0e9be5c88089fbeeb866c389c1098e07f64929c7414290504b855f54f901ab10 + checksum: 756419f2fa99aa119c46a9fc03e09d84ecf5421a80a72d1944c5088c9e4671e77128527a900a313ed9d3fdbdd37e2ae05486cd7e9116d5812d8c31f2399d7c86 languageName: node linkType: hard @@ -14000,7 +14000,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 7186beeba0e6fd33b37aa33ede7157e77af0a0be4b75d345a51dab4be5962a8e7a1c5ec8868e7c4cd361b456eb1b47bdb75e5db32ab37a546bed383d06b40384 + checksum: 845eb251924d8bbeb88bc6e6b30207a1a9c6f1a28a66793f8d55b6674178542273325d7961148e5ffe37018f15a5defa4a62a0166aa700f75425eb4e600b9232 languageName: node linkType: hard @@ -14014,7 +14014,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 6a2bf167b3587d4df709b37d149ad0300692cc5deb510f89ac7bdc77c8738c9546ae3de9322b0968e1ed2b0e984571f5f55aae28fa7de4cfcb1bc5402a4e2be6 + checksum: df087b701304432f30922bbee5f534ab189aa6938bd383b5686c03147e0d00cd1789ea10a462361326ce6b6ebe448ce272ad3f3cc40b82eeb3157df12f33663c languageName: node linkType: hard @@ -14030,14 +14030,14 @@ __metadata: "safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": version: 5.1.2 resolution: "safe-buffer@npm:5.1.2" - checksum: f2f1f7943ca44a594893a852894055cf619c1fbcb611237fc39e461ae751187e7baf4dc391a72125e0ac4fb2d8c5c0b3c71529622e6a58f46b960211e704903c + checksum: 7eb5b48f2ed9a594a4795677d5a150faa7eb54483b2318b568dc0c4fc94092a6cce5be02c7288a0500a156282f5276d5688bce7259299568d1053b2150ef374a languageName: node linkType: hard "safe-buffer@npm:5.2.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" - checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 + checksum: 32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 languageName: node linkType: hard @@ -14048,7 +14048,7 @@ __metadata: call-bind: "npm:^1.0.2" get-intrinsic: "npm:^1.1.3" is-regex: "npm:^1.1.4" - checksum: bc566d8beb8b43c01b94e67de3f070fd2781685e835959bbbaaec91cc53381145ca91f69bd837ce6ec244817afa0a5e974fc4e40a2957f0aca68ac3add1ddd34 + checksum: c7248dfa07891aa634c8b9c55da696e246f8589ca50e7fd14b22b154a106e83209ddf061baf2fa45ebfbd485b094dc7297325acfc50724de6afe7138451b42a9 languageName: node linkType: hard @@ -14057,14 +14057,14 @@ __metadata: resolution: "safe-regex@npm:1.1.0" dependencies: ret: "npm:~0.1.10" - checksum: 9a8bba57c87a841f7997b3b951e8e403b1128c1a4fd1182f40cc1a20e2d490593d7c2a21030fadfea320c8e859219019e136f678c6689ed5960b391b822f01d5 + checksum: 5405b5a3effed649e6133d51d45cecbbbb02a1dd8d5b78a5e7979a69035870c817a5d2682d0ebb62188d3a840f7b24ea00ebbad2e418d5afabed151e8db96d04 languageName: node linkType: hard "safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" - checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 + checksum: 7eaf7a0cf37cc27b42fb3ef6a9b1df6e93a1c6d98c6c6702b02fe262d5fcbd89db63320793b99b21cb5348097d0a53de81bd5f4e8b86e20cc9412e3f1cfb4e83 languageName: node linkType: hard @@ -14077,7 +14077,7 @@ __metadata: source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 1b1b3584b38a63dd94156b65f13b90e3f84b170a38c3d5e3fa578b7a32a37aeb349b4926b0eaf9448d48e955e86b1ee01b13993f19611dad8068af07a607c13b + checksum: 4e9f3db604b4a9d50bc0986b1a748cff1986d8545d744c06cac2357057817c8951c605a06f6742df7cc47f98cdb9801cbfa819f3337e7c9a70be2ab1f7d5b343 languageName: node linkType: hard @@ -14086,7 +14086,7 @@ __metadata: resolution: "saxes@npm:6.0.0" dependencies: xmlchars: "npm:^2.2.0" - checksum: d3fa3e2aaf6c65ed52ee993aff1891fc47d5e47d515164b5449cbf5da2cbdc396137e55590472e64c5c436c14ae64a8a03c29b9e7389fc6f14035cf4e982ef3b + checksum: 97b50daf6ca3a153e89842efa18a862e446248296622b7473c169c84c823ee8a16e4a43bac2f73f11fc8cb9168c73fbb0d73340f26552bac17970e9052367aa9 languageName: node linkType: hard @@ -14095,7 +14095,7 @@ __metadata: resolution: "scheduler@npm:0.23.0" dependencies: loose-envify: "npm:^1.1.0" - checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a + checksum: 0c4557aa37bafca44ff21dc0ea7c92e2dbcb298bc62eae92b29a39b029134f02fb23917d6ebc8b1fa536b4184934314c20d8864d156a9f6357f3398aaf7bfda8 languageName: node linkType: hard @@ -14104,7 +14104,7 @@ __metadata: resolution: "semver@npm:5.7.2" bin: semver: bin/semver - checksum: fb4ab5e0dd1c22ce0c937ea390b4a822147a9c53dbd2a9a0132f12fe382902beef4fbf12cf51bb955248d8d15874ce8cd89532569756384f994309825f10b686 + checksum: fca14418a174d4b4ef1fecb32c5941e3412d52a4d3d85165924ce3a47fbc7073372c26faf7484ceb4bbc2bde25880c6b97e492473dc7e9708fdfb1c6a02d546e languageName: node linkType: hard @@ -14113,7 +14113,7 @@ __metadata: resolution: "semver@npm:6.3.1" bin: semver: bin/semver.js - checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 + checksum: 1ef3a85bd02a760c6ef76a45b8c1ce18226de40831e02a00bad78485390b98b6ccaa31046245fc63bba4a47a6a592b6c7eedc65cc47126e60489f9cc1ce3ed7e languageName: node linkType: hard @@ -14124,7 +14124,7 @@ __metadata: lru-cache: "npm:^6.0.0" bin: semver: bin/semver.js - checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 + checksum: 985dec0d372370229a262c737063860fabd4a1c730662c1ea3200a2f649117761a42184c96df62a0e885e76fbd5dace41087d6c1ac0351b13c0df5d6bcb1b5ac languageName: node linkType: hard @@ -14145,7 +14145,7 @@ __metadata: on-finished: "npm:2.4.1" range-parser: "npm:~1.2.1" statuses: "npm:2.0.1" - checksum: 74fc07ebb58566b87b078ec63e5a3e41ecd987e4272ba67b7467e86c6ad51bc6b0b0154133b6d8b08a2ddda360464f71382f7ef864700f34844a76c8027817a8 + checksum: ec66c0ad109680ad8141d507677cfd8b4e40b9559de23191871803ed241718e99026faa46c398dcfb9250676076573bd6bfe5d0ec347f88f4b7b8533d1d391cb languageName: node linkType: hard @@ -14157,14 +14157,14 @@ __metadata: escape-html: "npm:~1.0.3" parseurl: "npm:~1.3.3" send: "npm:0.18.0" - checksum: af57fc13be40d90a12562e98c0b7855cf6e8bd4c107fe9a45c212bf023058d54a1871b1c89511c3958f70626fff47faeb795f5d83f8cf88514dbaeb2b724464d + checksum: 699b2d4c29807a51d9b5e0f24955346911437aebb0178b3c4833ad30d3eca93385ff9927254f5c16da345903cad39d9cd4a532198c95a5129cc4ed43911b15a4 languageName: node linkType: hard "set-blocking@npm:^2.0.0": version: 2.0.0 resolution: "set-blocking@npm:2.0.0" - checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 + checksum: 8980ebf7ae9eb945bb036b6e283c547ee783a1ad557a82babf758a065e2fb6ea337fd82cac30dd565c1e606e423f30024a19fff7afbf4977d784720c4026a8ef languageName: node linkType: hard @@ -14176,14 +14176,14 @@ __metadata: is-extendable: "npm:^0.1.1" is-plain-object: "npm:^2.0.3" split-string: "npm:^3.0.1" - checksum: 09a4bc72c94641aeae950eb60dc2755943b863780fcc32e441eda964b64df5e3f50603d5ebdd33394ede722528bd55ed43aae26e9df469b4d32e2292b427b601 + checksum: 4f1ccac2e9ad4d1b0851761d41df4bbd3780ed69805f24a80ab237a56d9629760b7b98551cd370931620defe5da329645834e1e9a18574cecad09ce7b2b83296 languageName: node linkType: hard "setprototypeof@npm:1.2.0": version: 1.2.0 resolution: "setprototypeof@npm:1.2.0" - checksum: be18cbbf70e7d8097c97f713a2e76edf84e87299b40d085c6bf8b65314e994cc15e2e317727342fa6996e38e1f52c59720b53fe621e2eb593a6847bf0356db89 + checksum: fde1630422502fbbc19e6844346778f99d449986b2f9cdcceb8326730d2f3d9964dbcb03c02aaadaefffecd0f2c063315ebea8b3ad895914bf1afc1747fc172e languageName: node linkType: hard @@ -14192,7 +14192,7 @@ __metadata: resolution: "shallow-clone@npm:3.0.1" dependencies: kind-of: "npm:^6.0.2" - checksum: 39b3dd9630a774aba288a680e7d2901f5c0eae7b8387fc5c8ea559918b29b3da144b7bdb990d7ccd9e11be05508ac9e459ce51d01fd65e583282f6ffafcba2e7 + checksum: e066bd540cfec5e1b0f78134853e0d892d1c8945fb9a926a579946052e7cb0c70ca4fc34f875a8083aa7910d751805d36ae64af250a6de6f3d28f9fa7be6c21b languageName: node linkType: hard @@ -14219,7 +14219,7 @@ __metadata: call-bind: "npm:^1.0.0" get-intrinsic: "npm:^1.0.2" object-inspect: "npm:^1.9.0" - checksum: 351e41b947079c10bd0858364f32bb3a7379514c399edb64ab3dce683933483fc63fb5e4efe0a15a2e8a7e3c436b6a91736ddb8d8c6591b0460a24bb4a1ee245 + checksum: c4998d9fc530b0e75a7fd791ad868fdc42846f072734f9080ff55cc8dc7d3899abcda24fd896aa6648c3ab7021b4bb478073eb4f44dfd55bce9714bc1a7c5d45 languageName: node linkType: hard @@ -14233,7 +14233,7 @@ __metadata: "signal-exit@npm:^4.0.1": version: 4.0.2 resolution: "signal-exit@npm:4.0.2" - checksum: 41f5928431cc6e91087bf0343db786a6313dd7c6fd7e551dbc141c95bb5fb26663444fd9df8ea47c5d7fc202f60aa7468c3162a9365cbb0615fc5e1b1328fe31 + checksum: 99d49eab7f24aeed79e44999500d5ff4b9fbb560b0e1f8d47096c54d625b995aeaec3032cce44527adf2de0c303731a8356e234a348d6801214a8a3385a1ff8e languageName: node linkType: hard @@ -14241,8 +14241,8 @@ __metadata: version: 2.0.0 resolution: "simple-update-notifier@npm:2.0.0" dependencies: - semver: ^7.5.3 - checksum: 9ba00d38ce6a29682f64a46213834e4eb01634c2f52c813a9a7b8873ca49cdbb703696f3290f3b27dc067de6d9418b0b84bef22c3eb074acf352529b2d6c27fd + semver: "npm:^7.5.3" + checksum: 40bd4f96aa89aedbf717ae9f4ab8fca70e8f7511e8b766feb15471cca3f6fe4fe673743309b08b4ba8abfe0965c9cd927e1de46550a757b819b70fc7430cc85d languageName: node linkType: hard @@ -14263,7 +14263,7 @@ __metadata: "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" - checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b + checksum: 927484aa0b1640fd9473cee3e0a0bcad6fce93fd7bbc18bac9ad0c33686f5d2e2c422fba24b5899c184524af01e11dd2bd051c2bf2b07e47aff8ca72cbfc60d2 languageName: node linkType: hard @@ -14274,7 +14274,7 @@ __metadata: define-property: "npm:^1.0.0" isobject: "npm:^3.0.0" snapdragon-util: "npm:^3.0.1" - checksum: 9bb57d759f9e2a27935dbab0e4a790137adebace832b393e350a8bf5db461ee9206bb642d4fe47568ee0b44080479c8b4a9ad0ebe3712422d77edf9992a672fd + checksum: 093c3584efc51103d8607d28cb7a3079f7e371b2320a60c685a84a57956cf9693f3dec8b2f77250ba48063cf42cb5261f3970e6d3bb7e68fd727299c991e0bff languageName: node linkType: hard @@ -14283,7 +14283,7 @@ __metadata: resolution: "snapdragon-util@npm:3.0.1" dependencies: kind-of: "npm:^3.2.0" - checksum: 684997dbe37ec995c03fd3f412fba2b711fc34cb4010452b7eb668be72e8811a86a12938b511e8b19baf853b325178c56d8b78d655305e5cfb0bb8b21677e7b7 + checksum: b776b15bf683c9ac0243582d7b13f2070f85c9036d73c2ba31da61d1effe22d4a39845b6f43ce7e7ec82c7e686dc47d9c3cffa1a75327bb16505b9afc34f516d languageName: node linkType: hard @@ -14299,7 +14299,7 @@ __metadata: source-map: "npm:^0.5.6" source-map-resolve: "npm:^0.5.0" use: "npm:^3.1.0" - checksum: a197f242a8f48b11036563065b2487e9b7068f50a20dd81d9161eca6af422174fc158b8beeadbe59ce5ef172aa5718143312b3aebaae551c124b7824387c8312 + checksum: cbe35b25dca5504be0ced90d907948d8efeda0b118d9a032bfc499e22b7f78515832f2706d9c9297c87906eaa51c12bfcaa8ea5a4f3e98ecf1116a73428e344a languageName: node linkType: hard @@ -14310,7 +14310,7 @@ __metadata: agent-base: "npm:^6.0.2" debug: "npm:^4.3.3" socks: "npm:^2.6.2" - checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 + checksum: 26c75d9c62a9ed3fd494df60e65e88da442f78e0d4bc19bfd85ac37bd2c67470d6d4bba5202e804561cda6674db52864c9e2a2266775f879bc8d89c1445a5f4c languageName: node linkType: hard @@ -14320,14 +14320,14 @@ __metadata: dependencies: ip: "npm:^2.0.0" smart-buffer: "npm:^4.2.0" - checksum: 259d9e3e8e1c9809a7f5c32238c3d4d2a36b39b83851d0f573bfde5f21c4b1288417ce1af06af1452569cd1eb0841169afd4998f0e04ba04656f6b7f0e46d748 + checksum: 5074f7d6a13b3155fa655191df1c7e7a48ce3234b8ccf99afa2ccb56591c195e75e8bb78486f8e9ea8168e95a29573cbaad55b2b5e195160ae4d2ea6811ba833 languageName: node linkType: hard "source-map-js@npm:>=0.6.2 <2.0.0, source-map-js@npm:^1.0.2": version: 1.0.2 resolution: "source-map-js@npm:1.0.2" - checksum: c049a7fc4deb9a7e9b481ae3d424cc793cb4845daa690bc5a05d428bf41bf231ced49b4cf0c9e77f9d42fdb3d20d6187619fc586605f5eabe995a316da8d377c + checksum: 38e2d2dd18d2e331522001fc51b54127ef4a5d473f53b1349c5cca2123562400e0986648b52e9407e348eaaed53bce49248b6e2641e6d793ca57cb2c360d6d51 languageName: node linkType: hard @@ -14340,7 +14340,7 @@ __metadata: resolve-url: "npm:^0.2.1" source-map-url: "npm:^0.4.0" urix: "npm:^0.1.0" - checksum: c73fa44ac00783f025f6ad9e038ab1a2e007cd6a6b86f47fe717c3d0765b4a08d264f6966f3bd7cd9dbcd69e4832783d5472e43247775b2a550d6f2155d24bae + checksum: 98e281cceb86b80c8bd3453110617b9df93132d6a50c7bf5847b5d74b4b5d6e1d4d261db276035b9b7e5ba7f32c2d6a0d2c13d581e37870a0219a524402efcab languageName: node linkType: hard @@ -14350,7 +14350,7 @@ __metadata: dependencies: buffer-from: "npm:^1.0.0" source-map: "npm:^0.6.0" - checksum: 933550047b6c1a2328599a21d8b7666507427c0f5ef5eaadd56b5da0fd9505e239053c66fe181bf1df469a3b7af9d775778eee283cbb7ae16b902ddc09e93a97 + checksum: d1514a922ac9c7e4786037eeff6c3322f461cd25da34bb9fefb15387b3490531774e6e31d95ab6d5b84a3e139af9c3a570ccaee6b47bd7ea262691ed3a8bc34e languageName: node linkType: hard @@ -14360,28 +14360,28 @@ __metadata: dependencies: buffer-from: "npm:^1.0.0" source-map: "npm:^0.6.0" - checksum: 43e98d700d79af1d36f859bdb7318e601dfc918c7ba2e98456118ebc4c4872b327773e5a1df09b0524e9e5063bb18f0934538eace60cca2710d1fa687645d137 + checksum: 8317e12d84019b31e34b86d483dd41d6f832f389f7417faf8fc5c75a66a12d9686e47f589a0554a868b8482f037e23df9d040d29387eb16fa14cb85f091ba207 languageName: node linkType: hard "source-map-url@npm:^0.4.0": version: 0.4.1 resolution: "source-map-url@npm:0.4.1" - checksum: 64c5c2c77aff815a6e61a4120c309ae4cac01298d9bcbb3deb1b46a4dd4c46d4a1eaeda79ec9f684766ae80e8dc86367b89326ce9dd2b89947bd9291fc1ac08c + checksum: 7fec0460ca017330568e1a4d67c80c397871f27d75b034e1117eaa802076db5cda5944659144d26eafd2a95008ada19296c8e0d5ec116302c32c6daa4e430003 languageName: node linkType: hard "source-map@npm:^0.5.6": version: 0.5.7 resolution: "source-map@npm:0.5.7" - checksum: 5dc2043b93d2f194142c7f38f74a24670cd7a0063acdaf4bf01d2964b402257ae843c2a8fa822ad5b71013b5fcafa55af7421383da919752f22ff488bc553f4d + checksum: 9b4ac749ec5b5831cad1f8cc4c19c4298ebc7474b24a0acf293e2f040f03f8eeccb3d01f12aa0f90cf46d555c887e03912b83a042c627f419bda5152d89c5269 languageName: node linkType: hard "source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" - checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 + checksum: 59ef7462f1c29d502b3057e822cdbdae0b0e565302c4dd1a95e11e793d8d9d62006cdc10e0fd99163ca33ff2071360cf50ee13f90440806e7ed57d81cba2f7ff languageName: node linkType: hard @@ -14398,7 +14398,7 @@ __metadata: dependencies: spdx-expression-parse: "npm:^3.0.0" spdx-license-ids: "npm:^3.0.0" - checksum: e9ae98d22f69c88e7aff5b8778dc01c361ef635580e82d29e5c60a6533cc8f4d820803e67d7432581af0cc4fb49973125076ee3b90df191d153e223c004193b2 + checksum: cc2e4dbef822f6d12142116557d63f5facf3300e92a6bd24e907e4865e17b7e1abd0ee6b67f305cae6790fc2194175a24dc394bfcc01eea84e2bdad728e9ae9a languageName: node linkType: hard @@ -14422,7 +14422,7 @@ __metadata: "spdx-license-ids@npm:^3.0.0": version: 3.0.13 resolution: "spdx-license-ids@npm:3.0.13" - checksum: 3469d85c65f3245a279fa11afc250c3dca96e9e847f2f79d57f466940c5bb8495da08a542646086d499b7f24a74b8d0b42f3fc0f95d50ff99af1f599f6360ad7 + checksum: 6328c516e958ceee80362dc657a58cab01c7fdb4667a1a4c1a3e91d069983977f87971340ee857eb66f65079b5d8561e56dc91510802cd7bebaae7632a6aa7fa languageName: node linkType: hard @@ -14431,14 +14431,14 @@ __metadata: resolution: "split-string@npm:3.1.0" dependencies: extend-shallow: "npm:^3.0.0" - checksum: ae5af5c91bdc3633628821bde92fdf9492fa0e8a63cf6a0376ed6afde93c701422a1610916f59be61972717070119e848d10dfbbd5024b7729d6a71972d2a84c + checksum: f31f4709d2b14fe4ff46b4fb88b2fb68a1c59b59e573c5417907c182397ddb2cb67903232bdc3a8b9dd3bb660c6f533ff11b5d624aff7b1fe0a213e3e4c75f20 languageName: node linkType: hard "sprintf-js@npm:~1.0.2": version: 1.0.3 resolution: "sprintf-js@npm:1.0.3" - checksum: 19d79aec211f09b99ec3099b5b2ae2f6e9cdefe50bc91ac4c69144b6d3928a640bb6ae5b3def70c2e85a2c3d9f5ec2719921e3a59d3ca3ef4b2fd1a4656a0df3 + checksum: c34828732ab8509c2741e5fd1af6b767c3daf2c642f267788f933a65b1614943c282e74c4284f4fa749c264b18ee016a0d37a3e5b73aee446da46277d3a85daa languageName: node linkType: hard @@ -14447,7 +14447,7 @@ __metadata: resolution: "ssri@npm:10.0.4" dependencies: minipass: "npm:^5.0.0" - checksum: fb14da9f8a72b04eab163eb13a9dda11d5962cd2317f85457c4e0b575e9a6e0e3a6a87b5bf122c75cb36565830cd5f263fb457571bf6f1587eb5f95d095d6165 + checksum: 3f3dc4a0bbde19a67a4e7bdbef0c94ea92643a5f835565c09107f0c3696de9079f65742e641b449e978db69751ac6e85dfdc3f2c2abfe221d1c346d5b7ed077f languageName: node linkType: hard @@ -14463,7 +14463,7 @@ __metadata: resolution: "stack-utils@npm:2.0.6" dependencies: escape-string-regexp: "npm:^2.0.0" - checksum: 052bf4d25bbf5f78e06c1d5e67de2e088b06871fa04107ca8d3f0e9d9263326e2942c8bedee3545795fc77d787d443a538345eef74db2f8e35db3558c6f91ff7 + checksum: cdc988acbc99075b4b036ac6014e5f1e9afa7e564482b687da6384eee6a1909d7eaffde85b0a17ffbe186c5247faf6c2b7544e802109f63b72c7be69b13151bb languageName: node linkType: hard @@ -14489,14 +14489,14 @@ __metadata: resolution: "stop-iteration-iterator@npm:1.0.0" dependencies: internal-slot: "npm:^1.0.4" - checksum: d04173690b2efa40e24ab70e5e51a3ff31d56d699550cfad084104ab3381390daccb36652b25755e420245f3b0737de66c1879eaa2a8d4fc0a78f9bf892fcb42 + checksum: 2a23a36f4f6bfa63f46ae2d53a3f80fe8276110b95a55345d8ed3d92125413494033bc8697eb774e8f7aeb5725f70e3d69753caa2ecacdac6258c16fa8aa8b0f languageName: node linkType: hard "store2@npm:^2.14.2": version: 2.14.2 resolution: "store2@npm:2.14.2" - checksum: 6f270fc5bab99b63f45fcc7bd8b99c2714b4adf880f557ed7ffb5ed3987131251165bccde425a00928aaf044870aee79ddeef548576d093c68703ed2edec45d7 + checksum: 896cb4c75b94b630206e0ef414f78d656a5d2498127094d9d0852e1e7b88509b3a7972c92cad3e74ee34ef6b06d25083ad2ac38880254ccb2d40b7930dc0ed01 languageName: node linkType: hard @@ -14504,7 +14504,7 @@ __metadata: version: 7.6.7 resolution: "storybook@npm:7.6.7" dependencies: - "@storybook/cli": 7.6.7 + "@storybook/cli": "npm:7.6.7" bin: sb: ./index.js storybook: ./index.js @@ -14570,7 +14570,7 @@ __metadata: internal-slot: "npm:^1.0.3" regexp.prototype.flags: "npm:^1.4.3" side-channel: "npm:^1.0.4" - checksum: 952da3a818de42ad1c10b576140a5e05b4de7b34b8d9dbf00c3ac8c1293e9c0f533613a39c5cda53e0a8221f2e710bc2150e730b1c2278d60004a8a35726efb6 + checksum: 9de2e9e33344002e08c03c13533d88d0c557d5a3d9214a4f2cc8d63349f7c35af895804dec08e43224cc4c0345651c678e14260c5933967fd97aad4640a7e485 languageName: node linkType: hard @@ -14581,7 +14581,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 05b7b2d6af63648e70e44c4a8d10d8cc457536df78b55b9d6230918bde75c5987f6b8604438c4c8652eb55e4fc9725d2912789eb4ec457d6995f3495af190c09 + checksum: a1b795bdb4b4b7d9399e99771e8a36493a30cf18095b0e8b36bcb211aad42dc59186c9a833c774f7a70429dbd3862818133d7e0da1547a0e9f0e1ebddf995635 languageName: node linkType: hard @@ -14592,7 +14592,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 0fdc34645a639bd35179b5a08227a353b88dc089adf438f46be8a7c197fc3f22f8514c1c9be4629b3cd29c281582730a8cbbad6466c60f76b5f99cf2addb132e + checksum: 3893db9267e0b8a16658c3947738536e90c400a9b7282de96925d4e210174cfe66c59d6b7eb5b4a9aaa78ef7f5e46afb117e842d93112fbd105c8d19206d8092 languageName: node linkType: hard @@ -14603,7 +14603,7 @@ __metadata: call-bind: "npm:^1.0.2" define-properties: "npm:^1.1.4" es-abstract: "npm:^1.20.4" - checksum: 89080feef416621e6ef1279588994305477a7a91648d9436490d56010a1f7adc39167cddac7ce0b9884b8cdbef086987c4dcb2960209f2af8bac0d23ceff4f41 + checksum: 05e2cd06fa5311b17f5b2c7af0a60239fa210f4bb07bbcfce4995215dce330e2b1dd2d8030d371f46252ab637522e14b6e9a78384e8515945b72654c14261d54 languageName: node linkType: hard @@ -14612,7 +14612,7 @@ __metadata: resolution: "string_decoder@npm:1.3.0" dependencies: safe-buffer: "npm:~5.2.0" - checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 + checksum: 54d23f4a6acae0e93f999a585e673be9e561b65cd4cca37714af1e893ab8cd8dfa52a9e4f58f48f87b4a44918d3a9254326cb80ed194bf2e4c226e2b21767e56 languageName: node linkType: hard @@ -14621,7 +14621,7 @@ __metadata: resolution: "string_decoder@npm:1.1.1" dependencies: safe-buffer: "npm:~5.1.0" - checksum: 9ab7e56f9d60a28f2be697419917c50cac19f3e8e6c28ef26ed5f4852289fe0de5d6997d29becf59028556f2c62983790c1d9ba1e2a3cc401768ca12d5183a5b + checksum: 7c41c17ed4dea105231f6df208002ebddd732e8e9e2d619d133cecd8e0087ddfd9587d2feb3c8caf3213cbd841ada6d057f5142cae68a4e62d3540778d9819b4 languageName: node linkType: hard @@ -14630,7 +14630,7 @@ __metadata: resolution: "strip-ansi@npm:6.0.1" dependencies: ansi-regex: "npm:^5.0.1" - checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c + checksum: ae3b5436d34fadeb6096367626ce987057713c566e1e7768818797e00ac5d62023d0f198c4e681eae9e20701721980b26a64a8f5b91238869592a9c6800719a2 languageName: node linkType: hard @@ -14648,7 +14648,7 @@ __metadata: resolution: "strip-ansi@npm:7.1.0" dependencies: ansi-regex: "npm:^6.0.1" - checksum: 859c73fcf27869c22a4e4d8c6acfe690064659e84bef9458aa6d13719d09ca88dcfd40cbf31fd0be63518ea1a643fe070b4827d353e09533a5b0b9fd4553d64d + checksum: 475f53e9c44375d6e72807284024ac5d668ee1d06010740dec0b9744f2ddf47de8d7151f80e5f6190fc8f384e802fdf9504b76a7e9020c9faee7103623338be2 languageName: node linkType: hard @@ -14686,7 +14686,7 @@ __metadata: version: 4.0.0 resolution: "strip-indent@npm:4.0.0" dependencies: - min-indent: ^1.0.1 + min-indent: "npm:^1.0.1" checksum: 06cbcd93da721c46bc13caeb1c00af93a9b18146a1c95927672d2decab6a25ad83662772417cea9317a2507fb143253ecc23c4415b64f5828cef9b638a744598 languageName: node linkType: hard @@ -14703,7 +14703,7 @@ __metadata: resolution: "style-to-js@npm:1.1.3" dependencies: style-to-object: "npm:0.4.1" - checksum: 7aaeacff909d43bbfc28e9a004019224d0eda895ac3d0d9f3160b6ad044dca8d3965f7b2b92ac649f63f62889324b560147d21cf3149f29794692c5d7b207110 + checksum: a8980fc67ce06059107ef8e74fe28e989bc637d4ddd44881cc836ac5ff47da8df725dedc2d82b6028e2bb945ca9b13706e6fb72ad4ee34edc219bd356be72e14 languageName: node linkType: hard @@ -14712,14 +14712,14 @@ __metadata: resolution: "style-to-object@npm:0.4.1" dependencies: inline-style-parser: "npm:0.1.1" - checksum: 2ea213e98eed21764ae1d1dc9359231a9f2d480d6ba55344c4c15eb275f0809f1845786e66d4caf62414a5cc8f112ce9425a58d251c77224060373e0db48f8c2 + checksum: aa597acebfa44b8468d486385fc63007d49cb1da2b2ffe5d54021bccf2d47e2f5d18ff499dcb8f028087fc1a4ac86556bebf768ac91137d43ecbb47b8470410a languageName: node linkType: hard "supports-color@npm:^2.0.0": version: 2.0.0 resolution: "supports-color@npm:2.0.0" - checksum: 602538c5812b9006404370b5a4b885d3e2a1f6567d314f8b4a41974ffe7d08e525bf92ae0f9c7030e3b4c78e4e34ace55d6a67a74f1571bc205959f5972f88f0 + checksum: d2957d19e782a806abc3e8616b6648cc1e70c3ebe94fb1c2d43160686f6d79cd7c9f22c4853bc4a362d89d1c249ab6d429788c5f6c83b3086e6d763024bf4581 languageName: node linkType: hard @@ -14728,7 +14728,7 @@ __metadata: resolution: "supports-color@npm:3.2.3" dependencies: has-flag: "npm:^1.0.0" - checksum: 56afc05fa87d00100d90148c4d0a6e20a0af0d56dca5c54d4d40b2553ee737dab0ca4e8b53c4471afc035227b5b44dfa4824747a7f01ad733173536f7da6fbbb + checksum: 476a70d263a1f7ac11c26c10dfc58f0d9439edf198005b95f0e358ea8182d06b492d96320f16a841e4e968c7189044dd8c3f3037bd533480d15c7cc00e17c5d8 languageName: node linkType: hard @@ -14737,7 +14737,7 @@ __metadata: resolution: "supports-color@npm:5.5.0" dependencies: has-flag: "npm:^3.0.0" - checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac + checksum: 5f505c6fa3c6e05873b43af096ddeb22159831597649881aeb8572d6fe3b81e798cc10840d0c9735e0026b250368851b7f77b65e84f4e4daa820a4f69947f55b languageName: node linkType: hard @@ -14746,7 +14746,7 @@ __metadata: resolution: "supports-color@npm:7.2.0" dependencies: has-flag: "npm:^4.0.0" - checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a + checksum: c8bb7afd564e3b26b50ca6ee47572c217526a1389fe018d00345856d4a9b08ffbd61fadaf283a87368d94c3dcdb8f5ffe2650a5a65863e21ad2730ca0f05210a languageName: node linkType: hard @@ -14755,14 +14755,14 @@ __metadata: resolution: "supports-color@npm:8.1.1" dependencies: has-flag: "npm:^4.0.0" - checksum: c052193a7e43c6cdc741eb7f378df605636e01ad434badf7324f17fb60c69a880d8d8fcdcb562cf94c2350e57b937d7425ab5b8326c67c2adc48f7c87c1db406 + checksum: 157b534df88e39c5518c5e78c35580c1eca848d7dbaf31bbe06cdfc048e22c7ff1a9d046ae17b25691128f631a51d9ec373c1b740c12ae4f0de6e292037e4282 languageName: node linkType: hard "supports-preserve-symlinks-flag@npm:^1.0.0": version: 1.0.0 resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae + checksum: a9dc19ae2220c952bd2231d08ddeecb1b0328b61e72071ff4000c8384e145cc07c1c0bdb3b5a1cb06e186a7b2790f1dee793418b332f6ddf320de25d9125be7e languageName: node linkType: hard @@ -14783,14 +14783,14 @@ __metadata: posthtml-svg-mode: "npm:^1.0.3" query-string: "npm:^4.3.2" traverse: "npm:^0.6.6" - checksum: 06724dd6cd098016a11a778cfa2771defac6bdcdee1e4c61669aa32ebfa52815d66cea989ea1f1d31b440634ceda54637e2d7d57687925b0d256adf9ba176b50 + checksum: fa3ecb5797f70bc0ae2c5efb3e1417f39f47370a38801fcd1df9effc8e7da54be0a75e4b30cdea8a92bb2674b373b2ac82ee0e18ccf5ca75253e410c495b35be languageName: node linkType: hard "svg-parser@npm:^2.0.4": version: 2.0.4 resolution: "svg-parser@npm:2.0.4" - checksum: b3de6653048212f2ae7afe4a423e04a76ec6d2d06e1bf7eacc618a7c5f7df7faa5105561c57b94579ec831fbbdbf5f190ba56a9205ff39ed13eabdf8ab086ddf + checksum: ec196da6ea21481868ab26911970e35488361c39ead1c6cdd977ba16c885c21a91ddcbfd113bfb01f79a822e2a751ef85b2f7f95e2cb9245558ebce12c34af1f languageName: node linkType: hard @@ -14807,28 +14807,28 @@ __metadata: stable: "npm:^0.1.8" bin: svgo: bin/svgo - checksum: b92f71a8541468ffd0b81b8cdb36b1e242eea320bf3c1a9b2c8809945853e9d8c80c19744267eb91cabf06ae9d5fff3592d677df85a31be4ed59ff78534fa420 + checksum: 2b74544da1a9521852fe2784252d6083b336e32528d0e424ee54d1613f17312edc7020c29fa399086560e96cba42ede4a2205328a08edeefa26de84cd769a64a languageName: node linkType: hard "symbol-tree@npm:^3.2.4": version: 3.2.4 resolution: "symbol-tree@npm:3.2.4" - checksum: 6e8fc7e1486b8b54bea91199d9535bb72f10842e40c79e882fc94fb7b14b89866adf2fd79efa5ebb5b658bc07fb459ccce5ac0e99ef3d72f474e74aaf284029d + checksum: c09a00aadf279d47d0c5c46ca3b6b2fbaeb45f0a184976d599637d412d3a70bbdc043ff33effe1206dea0e36e0ad226cb957112e7ce9a4bf2daedf7fa4f85c53 languageName: node linkType: hard "synchronous-promise@npm:^2.0.15": version: 2.0.17 resolution: "synchronous-promise@npm:2.0.17" - checksum: 7b1342c93741f3f92ebde1edf5d6ce8dde2278de948d84e9bd85e232c16c0d77c90c4940f9975be3effcb20f047cfb0f16fa311c3b4e092c22f3bf2889fb0fb4 + checksum: dd74b1c05caab8ea34e26c8b52a0966efd70b0229ad39447ce066501dd6931d4d97a3f88b0f306880a699660cd334180a24d9738b385aed0bd0104a5be207ec1 languageName: node linkType: hard "tabbable@npm:^6.0.1": version: 6.2.0 resolution: "tabbable@npm:6.2.0" - checksum: f8440277d223949272c74bb627a3371be21735ca9ad34c2570f7e1752bd646ccfc23a9d8b1ee65d6561243f4134f5fbbf1ad6b39ac3c4b586554accaff4a1300 + checksum: 980fa73476026e99dcacfc0d6e000d41d42c8e670faf4682496d30c625495e412c4369694f2a15cf1e5252d22de3c396f2b62edbe8d60b5dadc40d09e3f2dde3 languageName: node linkType: hard @@ -14840,7 +14840,7 @@ __metadata: mkdirp-classic: "npm:^0.5.2" pump: "npm:^3.0.0" tar-stream: "npm:^2.1.4" - checksum: f5b9a70059f5b2969e65f037b4e4da2daf0fa762d3d232ffd96e819e3f94665dbbbe62f76f084f1acb4dbdcce16c6e4dac08d12ffc6d24b8d76720f4d9cf032d + checksum: 526deae025453e825f87650808969662fbb12eb0461d033e9b447de60ec951c6c4607d0afe7ce057defe9d4e45cf80399dd74bc15f9d9e0773d5e990a78ce4ac languageName: node linkType: hard @@ -14853,7 +14853,7 @@ __metadata: fs-constants: "npm:^1.0.0" inherits: "npm:^2.0.3" readable-stream: "npm:^3.1.1" - checksum: 699831a8b97666ef50021c767f84924cfee21c142c2eb0e79c63254e140e6408d6d55a065a2992548e72b06de39237ef2b802b99e3ece93ca3904a37622a66f3 + checksum: 1a52a51d240c118cbcd30f7368ea5e5baef1eac3e6b793fb1a41e6cd7319296c79c0264ccc5859f5294aa80f8f00b9239d519e627b9aade80038de6f966fec6a languageName: node linkType: hard @@ -14867,7 +14867,7 @@ __metadata: minizlib: "npm:^2.1.1" mkdirp: "npm:^1.0.3" yallist: "npm:^4.0.0" - checksum: f23832fceeba7578bf31907aac744ae21e74a66f4a17a9e94507acf460e48f6db598c7023882db33bab75b80e027c21f276d405e4a0322d58f51c7088d428268 + checksum: 4848b92da8581e64ce4d8a760b47468dd9d212a4612846d8dd75b5c224a42c66ed5bcf8cfa9e9cd2eb64ebe1351413fb3eac93324a4eee536f0941beefa1f2eb languageName: node linkType: hard @@ -14875,8 +14875,8 @@ __metadata: version: 7.2.0 resolution: "telejson@npm:7.2.0" dependencies: - memoizerific: ^1.11.3 - checksum: 55a3380c9ff3c5ad84581bb6bda28fc33c6b7c4a0c466894637da687639b8db0d21b0ff4c1bc1a7a92ae6b70662549d09e7b9e8b1ec334b2ef93078762ecdfb9 + memoizerific: "npm:^1.11.3" + checksum: 6e89b3d3c45b5a2aced9132f6a968fcdf758c00be4c3acb115d7d81e95c9e04083a7a4a9b43057fcf48b101156c1607a38f5491615956acb28d4d1f78a4bda20 languageName: node linkType: hard @@ -14892,7 +14892,7 @@ __metadata: resolution: "temp@npm:0.8.4" dependencies: rimraf: "npm:~2.6.2" - checksum: f35bed78565355dfdf95f730b7b489728bd6b7e35071bcc6497af7c827fb6c111fbe9063afc7b8cbc19522a072c278679f9a0ee81e684aa2c8617cc0f2e9c191 + checksum: 0a7f76b49637415bc391c3f6e69377cc4c38afac95132b4158fa711e77b70b082fe56fd886f9d11ffab9d148df181a105a93c8b618fb72266eeaa5e5ddbfe37f languageName: node linkType: hard @@ -14905,7 +14905,7 @@ __metadata: temp-dir: "npm:^2.0.0" type-fest: "npm:^0.16.0" unique-string: "npm:^2.0.0" - checksum: e77ca4440af18e42dc64d8903b7ed0be673455b76680ff94a7d7c6ee7c16f7604bdcdee3c39436342b1082c23eda010dbe48f6094e836e0bd53c8b1aa63e5b95 + checksum: e3a3857cd102db84c484b8e878203b496f0e927025b7c60dd118c0c9a0962f4589321c6b3093185d529576af5c58be65d755e72c2a6ad009ff340ab8cbbe4d33 languageName: node linkType: hard @@ -14916,14 +14916,14 @@ __metadata: "@istanbuljs/schema": "npm:^0.1.2" glob: "npm:^7.1.4" minimatch: "npm:^3.0.4" - checksum: 3b34a3d77165a2cb82b34014b3aba93b1c4637a5011807557dc2f3da826c59975a5ccad765721c4648b39817e3472789f9b0fa98fc854c5c1c7a1e632aacdc28 + checksum: 8fccb2cb6c8fcb6bb4115394feb833f8b6cf4b9503ec2485c2c90febf435cac62abe882a0c5c51a37b9bbe70640cdd05acf5f45e486ac4583389f4b0855f69e5 languageName: node linkType: hard "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" - checksum: b6937a38c80c7f84d9c11dd75e49d5c44f71d95e810a3250bd1f1797fc7117c57698204adf676b71497acc205d769d65c16ae8fa10afad832ae1322630aef10a + checksum: 4383b5baaeffa9bb4cda2ac33a4aa2e6d1f8aaf811848bf73513a9b88fd76372dc461f6fd6d2e9cb5100f48b473be32c6f95bd983509b7d92bb4d92c10747452 languageName: node linkType: hard @@ -14933,7 +14933,7 @@ __metadata: dependencies: readable-stream: "npm:~2.3.6" xtend: "npm:~4.0.1" - checksum: beb0f338aa2931e5660ec7bf3ad949e6d2e068c31f4737b9525e5201b824ac40cac6a337224856b56bd1ddd866334bbfb92a9f57cd6f66bc3f18d3d86fc0fe50 + checksum: cd71f7dcdc7a8204fea003a14a433ef99384b7d4e31f5497e1f9f622b3cf3be3691f908455f98723bdc80922a53af7fa10c3b7abbe51c6fd3d536dbc7850e2c4 languageName: node linkType: hard @@ -14980,7 +14980,7 @@ __metadata: dependencies: is-number: "npm:^3.0.0" repeat-string: "npm:^1.6.1" - checksum: 46093cc14be2da905cc931e442d280b2e544e2bfdb9a24b3cf821be8d342f804785e5736c108d5be026021a05d7b38144980a61917eee3c88de0a5e710e10320 + checksum: 2eed5f897188de8ec8745137f80c0f564810082d506278dd6a80db4ea313b6d363ce8d7dc0e0406beeaba0bb7f90f01b41fa3d08fb72dd02c329b2ec579cd4e8 languageName: node linkType: hard @@ -14989,7 +14989,7 @@ __metadata: resolution: "to-regex-range@npm:5.0.1" dependencies: is-number: "npm:^7.0.0" - checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed + checksum: 10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a languageName: node linkType: hard @@ -15001,21 +15001,21 @@ __metadata: extend-shallow: "npm:^3.0.2" regex-not: "npm:^1.0.2" safe-regex: "npm:^1.1.0" - checksum: 4ed4a619059b64e204aad84e4e5f3ea82d97410988bcece7cf6cbfdbf193d11bff48cf53842d88b8bb00b1bfc0d048f61f20f0709e6f393fd8fe0122662d9db4 + checksum: ab87c22f0719f7def00145b53e2c90d2fdcc75efa0fec1227b383aaf88ed409db2542b2b16bcbfbf95fe0727f879045803bb635b777c0306762241ca3e5562c6 languageName: node linkType: hard "tocbot@npm:^4.20.1": version: 4.25.0 resolution: "tocbot@npm:4.25.0" - checksum: ac382063526ae8cde93390e42761da7aac136a452f5109ddcbcaf0d1890de478a13d2cf01ef52ec2a50934e4fa10f1d4237109cccfa651ba8c5021638528b982 + checksum: fcbe6299ec26322f51e62d54d1281b31370efab89b7a7e58c90fa431a51548e1a09b8aafd7314ed2500694bee8451713f59ecddafa7242e6bf626134b0e3cce6 languageName: node linkType: hard "toggle-selection@npm:^1.0.6": version: 1.0.6 resolution: "toggle-selection@npm:1.0.6" - checksum: a90dc80ed1e7b18db8f4e16e86a5574f87632dc729cfc07d9ea3ced50021ad42bb4e08f22c0913e0b98e3837b0b717e0a51613c65f30418e21eb99da6556a74c + checksum: 9a0ed0ecbaac72b4944888dacd79fe0a55eeea76120a4c7e46b3bb3d85b24f086e90560bb22f5a965654a25ab43d79ec47dfdb3f1850ba740b14c5a50abc7040 languageName: node linkType: hard @@ -15034,7 +15034,7 @@ __metadata: punycode: "npm:^2.1.1" universalify: "npm:^0.2.0" url-parse: "npm:^1.5.3" - checksum: c9226afff36492a52118432611af083d1d8493a53ff41ec4ea48e5b583aec744b989e4280bcf476c910ec1525a89a4a0f1cae81c08b18fb2ec3a9b3a72b91dcc + checksum: cf148c359b638a7069fc3ba9a5257bdc9616a6948a98736b92c3570b3f8401cf9237a42bf716878b656f372a1fb65b74dd13a46ccff8eceba14ffd053d33f72a languageName: node linkType: hard @@ -15043,21 +15043,21 @@ __metadata: resolution: "tr46@npm:3.0.0" dependencies: punycode: "npm:^2.1.1" - checksum: 44c3cc6767fb800490e6e9fd64fd49041aa4e49e1f6a012b34a75de739cc9ed3a6405296072c1df8b6389ae139c5e7c6496f659cfe13a04a4bff3a1422981270 + checksum: b09a15886cbfaee419a3469081223489051ce9dca3374dd9500d2378adedbee84a3c73f83bfdd6bb13d53657753fc0d4e20a46bfcd3f1b9057ef528426ad7ce4 languageName: node linkType: hard "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" - checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 + checksum: 8f1f5aa6cb232f9e1bdc86f485f916b7aa38caee8a778b378ffec0b70d9307873f253f5cbadbe2955ece2ac5c83d0dc14a77513166ccd0a0c7fe197e21396695 languageName: node linkType: hard "traverse@npm:^0.6.6": version: 0.6.7 resolution: "traverse@npm:0.6.7" - checksum: 21018085ab72f717991597e12e2b52446962ed59df591502e4d7e1a709bc0a989f7c3d451aa7d882666ad0634f1546d696c5edecda1f2fc228777df7bb529a1e + checksum: b06ea2d1db755ae21d2f5bade6e5ddfc6daf4b571fefe0de343c4fbbb022836a1e9c293b334d04b5c73cc689e9dbbdde33bb41a57508a8b82c73683f76de7a01 languageName: node linkType: hard @@ -15078,7 +15078,7 @@ __metadata: optional: true bin: tsconfck: bin/tsconfck.js - checksum: c531525f39763cbbd7e6dbf5e29f12a7ae67eb8712816c14d06a9db6cbdc9dda9ac3cd6db07ef645f8a4cdea906447ab44e2c8679e320871cf9dd598756e8c83 + checksum: ecabfabfaaa2442babacc7ad7e261432c7be63428095df532b32d5b53cab9591b2d770a5749892d690451571952e1fd8fb62b866f3958a26cf52d472f901c858 languageName: node linkType: hard @@ -15090,28 +15090,28 @@ __metadata: json5: "npm:^1.0.2" minimist: "npm:^1.2.6" strip-bom: "npm:^3.0.0" - checksum: a6162eaa1aed680537f93621b82399c7856afd10ec299867b13a0675e981acac4e0ec00896860480efc59fc10fd0b16fdc928c0b885865b52be62cadac692447 + checksum: 17f23e98612a60cf23b80dc1d3b7b840879e41fcf603868fc3618a30f061ac7b463ef98cad8c28b68733b9bfe0cc40ffa2bcf29e94cf0d26e4f6addf7ac8527d languageName: node linkType: hard "tslib@npm:^1.13.0, tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" - checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd + checksum: 7dbf34e6f55c6492637adb81b555af5e3b4f9cc6b998fb440dac82d3b42bdc91560a35a5fb75e20e24a076c651438234da6743d139e4feabf0783f3cdfe1dddb languageName: node linkType: hard "tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.4.0": version: 2.6.0 resolution: "tslib@npm:2.6.0" - checksum: c01066038f950016a18106ddeca4649b4d76caa76ec5a31e2a26e10586a59fceb4ee45e96719bf6c715648e7c14085a81fee5c62f7e9ebee68e77a5396e5538f + checksum: 52360693c62761f902e1946b350188be6505de297068b33421cb26bedd99591203a74cb2a49e1f43f0922d59b1fb3499fe5cfe61a61ca65a1743d5c92c69720a languageName: node linkType: hard "tslib@npm:^2.1.0": version: 2.6.2 resolution: "tslib@npm:2.6.2" - checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad + checksum: bd26c22d36736513980091a1e356378e8b662ded04204453d353a7f34a4c21ed0afc59b5f90719d4ba756e581a162ecbf93118dc9c6be5acf70aa309188166ca languageName: node linkType: hard @@ -15122,7 +15122,7 @@ __metadata: tslib: "npm:^1.8.1" peerDependencies: typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 1843f4c1b2e0f975e08c4c21caa4af4f7f65a12ac1b81b3b8489366826259323feb3fc7a243123453d2d1a02314205a7634e048d4a8009921da19f99755cdc48 + checksum: ea036bec1dd024e309939ffd49fda7a351c0e87a1b8eb049570dd119d447250e2c56e0e6c00554e8205760e7417793fdebff752a46e573fbe07d4f375502a5b2 languageName: node linkType: hard @@ -15131,56 +15131,56 @@ __metadata: resolution: "type-check@npm:0.4.0" dependencies: prelude-ls: "npm:^1.2.1" - checksum: ec688ebfc9c45d0c30412e41ca9c0cdbd704580eb3a9ccf07b9b576094d7b86a012baebc95681999dd38f4f444afd28504cb3a89f2ef16b31d4ab61a0739025a + checksum: 14687776479d048e3c1dbfe58a2409e00367810d6960c0f619b33793271ff2a27f81b52461f14a162f1f89a9b1d8da1b237fc7c99b0e1fdcec28ec63a86b1fec languageName: node linkType: hard "type-detect@npm:4.0.8": version: 4.0.8 resolution: "type-detect@npm:4.0.8" - checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15 + checksum: 5179e3b8ebc51fce1b13efb75fdea4595484433f9683bbc2dca6d99789dba4e602ab7922d2656f2ce8383987467f7770131d4a7f06a26287db0615d2f4c4ce7d languageName: node linkType: hard "type-fest@npm:^0.16.0": version: 0.16.0 resolution: "type-fest@npm:0.16.0" - checksum: 1a4102c06dc109db00418c753062e206cab65befd469d000ece4452ee649bf2a9cf57686d96fb42326bc9d918d9a194d4452897b486dcc41989e5c99e4e87094 + checksum: fd8c47ccb90e9fe7bae8bfc0e116e200e096120200c1ab1737bf0bc9334b344dd4925f876ed698174ffd58cd179bb56a55467be96aedc22d5d72748eac428bc8 languageName: node linkType: hard "type-fest@npm:^0.20.2": version: 0.20.2 resolution: "type-fest@npm:0.20.2" - checksum: 4fb3272df21ad1c552486f8a2f8e115c09a521ad7a8db3d56d53718d0c907b62c6e9141ba5f584af3f6830d0872c521357e512381f24f7c44acae583ad517d73 + checksum: 8907e16284b2d6cfa4f4817e93520121941baba36b39219ea36acfe64c86b9dbc10c9941af450bd60832c8f43464974d51c0957f9858bc66b952b66b6914cbb9 languageName: node linkType: hard "type-fest@npm:^0.21.3": version: 0.21.3 resolution: "type-fest@npm:0.21.3" - checksum: e6b32a3b3877f04339bae01c193b273c62ba7bfc9e325b8703c4ee1b32dc8fe4ef5dfa54bf78265e069f7667d058e360ae0f37be5af9f153b22382cd55a9afe0 + checksum: f4254070d9c3d83a6e573bcb95173008d73474ceadbbf620dd32d273940ca18734dff39c2b2480282df9afe5d1675ebed5499a00d791758748ea81f61a38961f languageName: node linkType: hard "type-fest@npm:^0.6.0": version: 0.6.0 resolution: "type-fest@npm:0.6.0" - checksum: b2188e6e4b21557f6e92960ec496d28a51d68658018cba8b597bd3ef757721d1db309f120ae987abeeda874511d14b776157ff809f23c6d1ce8f83b9b2b7d60f + checksum: 9ecbf4ba279402b14c1a0614b6761bbe95626fab11377291fecd7e32b196109551e0350dcec6af74d97ced1b000ba8060a23eca33157091e642b409c2054ba82 languageName: node linkType: hard "type-fest@npm:^0.8.1": version: 0.8.1 resolution: "type-fest@npm:0.8.1" - checksum: d61c4b2eba24009033ae4500d7d818a94fd6d1b481a8111612ee141400d5f1db46f199c014766b9fa9b31a6a7374d96fc748c6d688a78a3ce5a33123839becb7 + checksum: fd4a91bfb706aeeb0d326ebd2e9a8ea5263979e5dec8d16c3e469a5bd3a946e014a062ef76c02e3086d3d1c7209a56a20a4caafd0e9f9a5c2ab975084ea3d388 languageName: node linkType: hard "type-fest@npm:^2.19.0, type-fest@npm:~2.19": version: 2.19.0 resolution: "type-fest@npm:2.19.0" - checksum: a4ef07ece297c9fba78fc1bd6d85dff4472fe043ede98bd4710d2615d15776902b595abf62bd78339ed6278f021235fb28a96361f8be86ed754f778973a0d278 + checksum: 7bf9e8fdf34f92c8bb364c0af14ca875fac7e0183f2985498b77be129dc1b3b1ad0a6b3281580f19e48c6105c037fb966ad9934520c69c6434d17fd0af4eed78 languageName: node linkType: hard @@ -15190,7 +15190,7 @@ __metadata: dependencies: media-typer: "npm:0.3.0" mime-types: "npm:~2.1.24" - checksum: 2c8e47675d55f8b4e404bcf529abdf5036c537a04c2b20177bcf78c9e3c1da69da3942b1346e6edb09e823228c0ee656ef0e033765ec39a70d496ef601a0c657 + checksum: 0bd9eeae5efd27d98fd63519f999908c009e148039d8e7179a074f105362d4fcc214c38b24f6cda79c87e563cbd12083a4691381ed28559220d4a10c2047bed4 languageName: node linkType: hard @@ -15203,7 +15203,7 @@ __metadata: for-each: "npm:^0.3.3" has-proto: "npm:^1.0.1" is-typed-array: "npm:^1.1.10" - checksum: 04f6f02d0e9a948a95fbfe0d5a70b002191fae0b8fe0fe3130a9b2336f043daf7a3dda56a31333c35a067a97e13f539949ab261ca0f3692c41603a46a94e960b + checksum: 2d81747faae31ca79f6c597dc18e15ae3d5b7e97f7aaebce3b31f46feeb2a6c1d6c92b9a634d901c83731ffb7ec0b74d05c6ff56076f5ae39db0cd19b16a3f92 languageName: node linkType: hard @@ -15214,14 +15214,14 @@ __metadata: call-bind: "npm:^1.0.2" for-each: "npm:^0.3.3" is-typed-array: "npm:^1.1.9" - checksum: 2228febc93c7feff142b8c96a58d4a0d7623ecde6c7a24b2b98eb3170e99f7c7eff8c114f9b283085cd59dcd2bd43aadf20e25bba4b034a53c5bb292f71f8956 + checksum: 0444658acc110b233176cb0b7689dcb828b0cfa099ab1d377da430e8553b6fdcdce882360b7ffe9ae085b6330e1d39383d7b2c61574d6cd8eef651d3e4a87822 languageName: node linkType: hard "typedarray@npm:^0.0.6": version: 0.0.6 resolution: "typedarray@npm:0.0.6" - checksum: 33b39f3d0e8463985eeaeeacc3cb2e28bc3dfaf2a5ed219628c0b629d5d7b810b0eb2165f9f607c34871d5daa92ba1dc69f49051cf7d578b4cbd26c340b9d1b1 + checksum: 2cc1bcf7d8c1237f6a16c04efc06637b2c5f2d74e58e84665445cf87668b85a21ab18dd751fa49eee6ae024b70326635d7b79ad37b1c370ed2fec6aeeeb52714 languageName: node linkType: hard @@ -15231,17 +15231,17 @@ __metadata: bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: bef1dcd166acfc6934b2ec4d72f93edb8961a5fab36b8dd2aaf6f4f4cd5c0210f2e0850aef4724f3b4913d5aef203a94a28ded731b370880c8bcff7e4ff91fc1 + checksum: 1a195c619249c5a7cbcf1a725f88ea74f6db513719231000ec5af1aab269934fc73f30d55c2ee0407f8bfdcaa75a9e5731dee718dd1d796133e960bfeb99bdc6 languageName: node linkType: hard -"typescript@patch:typescript@5.0.2#~builtin": +"typescript@patch:typescript@npm%3A5.0.2#optional!builtin": version: 5.0.2 - resolution: "typescript@patch:typescript@npm%3A5.0.2#~builtin::version=5.0.2&hash=b5f058" + resolution: "typescript@patch:typescript@npm%3A5.0.2#optional!builtin::version=5.0.2&hash=b5f058" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 0411be9e19bf6a547d574b3261fa8598f55a5243123f2a50a79b0dc15a017abbf541f15b8b43331294e409cc978e548ac5ae4e0c5b98ba5ae98029304de047be + checksum: e8490236d4cd894e078632f3d1fee476dacab493680331e25e038ff19c80990b734615cb4dfc076927ddc465b8c8b7833ff62be493cb82a653fe4a251a65159a languageName: node linkType: hard @@ -15250,7 +15250,7 @@ __metadata: resolution: "uglify-js@npm:3.17.4" bin: uglifyjs: bin/uglifyjs - checksum: 7b3897df38b6fc7d7d9f4dcd658599d81aa2b1fb0d074829dd4e5290f7318dbca1f4af2f45acb833b95b1fe0ed4698662ab61b87e94328eb4c0a0d3435baf924 + checksum: 4c0b800e0ff192079d2c3ce8414fd3b656a570028c7c79af5c29c53d5c532b68bbcae4ad47307f89c2ee124d11826fff7a136b59d5c5bb18422bcdf5568afe1e languageName: node linkType: hard @@ -15262,14 +15262,14 @@ __metadata: has-bigints: "npm:^1.0.2" has-symbols: "npm:^1.0.3" which-boxed-primitive: "npm:^1.0.2" - checksum: b7a1cf5862b5e4b5deb091672ffa579aa274f648410009c81cca63fed3b62b610c4f3b773f912ce545bb4e31edc3138975b5bc777fc6e4817dca51affb6380e9 + checksum: 06e1ee41c1095e37281cb71a975cb3350f7cb470a0665d2576f02cc9564f623bd90cfc0183693b8a7fdf2d242963dcc3010b509fa3ac683f540c765c0f3e7e43 languageName: node linkType: hard "undici-types@npm:~5.26.4": version: 5.26.5 resolution: "undici-types@npm:5.26.5" - checksum: 3192ef6f3fd5df652f2dc1cd782b49d6ff14dc98e5dced492aa8a8c65425227da5da6aafe22523c67f035a272c599bb89cfe803c1db6311e44bed3042fc25487 + checksum: 0097779d94bc0fd26f0418b3a05472410408877279141ded2bd449167be1aed7ea5b76f756562cb3586a07f251b90799bab22d9019ceba49c037c76445f7cddd languageName: node linkType: hard @@ -15293,7 +15293,7 @@ __metadata: "unicode-match-property-value-ecmascript@npm:^2.1.0": version: 2.1.0 resolution: "unicode-match-property-value-ecmascript@npm:2.1.0" - checksum: 8d6f5f586b9ce1ed0e84a37df6b42fdba1317a05b5df0c249962bd5da89528771e2d149837cad11aa26bcb84c35355cb9f58a10c3d41fa3b899181ece6c85220 + checksum: 06661bc8aba2a60c7733a7044f3e13085808939ad17924ffd4f5222a650f88009eb7c09481dc9c15cfc593d4ad99bd1cde8d54042733b335672591a81c52601c languageName: node linkType: hard @@ -15330,7 +15330,7 @@ __metadata: resolution: "unique-slug@npm:4.0.0" dependencies: imurmurhash: "npm:^0.1.4" - checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 + checksum: 40912a8963fc02fb8b600cf50197df4a275c602c60de4cac4f75879d3c48558cfac48de08a25cc10df8112161f7180b3bbb4d662aadb711568602f9eddee54f0 languageName: node linkType: hard @@ -15339,14 +15339,14 @@ __metadata: resolution: "unique-string@npm:2.0.0" dependencies: crypto-random-string: "npm:^2.0.0" - checksum: ef68f639136bcfe040cf7e3cd7a8dff076a665288122855148a6f7134092e6ed33bf83a7f3a9185e46c98dddc445a0da6ac25612afa1a7c38b8b654d6c02498e + checksum: 107cae65b0b618296c2c663b8e52e4d1df129e9af04ab38d53b4f2189e96da93f599c85f4589b7ffaf1a11c9327cbb8a34f04c71b8d4950d3e385c2da2a93828 languageName: node linkType: hard "unist-util-is@npm:^4.0.0": version: 4.1.0 resolution: "unist-util-is@npm:4.1.0" - checksum: 726484cd2adc9be75a939aeedd48720f88294899c2e4a3143da413ae593f2b28037570730d5cf5fd910ff41f3bc1501e3d636b6814c478d71126581ef695f7ea + checksum: c046cc87c0a4f797b2afce76d917218e6a9af946a56cb5a88cb7f82be34f16c11050a10ddc4c66a3297dbb2782ca7d72a358cd77900b439ea9c683ba003ffe90 languageName: node linkType: hard @@ -15356,7 +15356,7 @@ __metadata: dependencies: "@types/unist": "npm:^2.0.0" unist-util-is: "npm:^4.0.0" - checksum: 1170e397dff88fab01e76d5154981666eb0291019d2462cff7a2961a3e76d3533b42eaa16b5b7e2d41ad42a5ea7d112301458283d255993e660511387bf67bc3 + checksum: 1b18343d88a0ad9cafaf8164ff8a1d3e3903328b3936b1565d61731f0b5778b9b9f400c455d3ad5284eeebcfdd7558ce24eb15c303a9cc0bd9218d01b2116923 languageName: node linkType: hard @@ -15396,11 +15396,11 @@ __metadata: version: 1.6.0 resolution: "unplugin@npm:1.6.0" dependencies: - acorn: ^8.11.2 - chokidar: ^3.5.3 - webpack-sources: ^3.2.3 - webpack-virtual-modules: ^0.6.1 - checksum: 1c2817f791f4fe59543f5b0cbedba6c37f66005c43c48260dc5934d13bb90ea347aa0040a9701bfeca072b99dd464e67133f5d5237191874499db73d62ab01fa + acorn: "npm:^8.11.2" + chokidar: "npm:^3.5.3" + webpack-sources: "npm:^3.2.3" + webpack-virtual-modules: "npm:^0.6.1" + checksum: 07ab8da12b03dbc71335ca925afcdb357a78f2c089e9af032a6a9f6112e1c69644ea8264c8ddf70d60067872f715ba2e03253f036cf1801e30b8b45c53756eb2 languageName: node linkType: hard @@ -15410,7 +15410,7 @@ __metadata: dependencies: has-value: "npm:^0.3.1" isobject: "npm:^3.0.0" - checksum: 5990ecf660672be2781fc9fb322543c4aa592b68ed9a3312fa4df0e9ba709d42e823af090fc8f95775b4cd2c9a5169f7388f0cec39238b6d0d55a69fc2ab6b29 + checksum: 0ca644870613dece963e4abb762b0da4c1cf6be4ac2f0859a463e4e9520c1ec85e512cfbfd73371ee0bb09ef536a0c4abd6f2c357715a08b43448aedc82acee6 languageName: node linkType: hard @@ -15431,7 +15431,7 @@ __metadata: browserslist: ">= 4.21.0" bin: update-browserslist-db: cli.js - checksum: b98327518f9a345c7cad5437afae4d2ae7d865f9779554baf2a200fdf4bac4969076b679b1115434bd6557376bdd37ca7583d0f9b8f8e302d7d4cc1e91b5f231 + checksum: cc1c7a38d15413046bea28ff3c7668a7cb6b4a53d83e8089fa960efd896deb6d1a9deffc2beb8dc0506186a352c8d19804efe5ec7eeb401037e14cf3ea5363f8 languageName: node linkType: hard @@ -15439,13 +15439,13 @@ __metadata: version: 1.0.13 resolution: "update-browserslist-db@npm:1.0.13" dependencies: - escalade: ^3.1.1 - picocolors: ^1.0.0 + escalade: "npm:^3.1.1" + picocolors: "npm:^1.0.0" peerDependencies: browserslist: ">= 4.21.0" bin: update-browserslist-db: cli.js - checksum: 1e47d80182ab6e4ad35396ad8b61008ae2a1330221175d0abd37689658bdb61af9b705bfc41057fd16682474d79944fb2d86767c5ed5ae34b6276b9bed353322 + checksum: 9074b4ef34d2ed931f27d390aafdd391ee7c45ad83c508e8fed6aaae1eb68f81999a768ed8525c6f88d4001a4fbf1b8c0268f099d0e8e72088ec5945ac796acf languageName: node linkType: hard @@ -15454,14 +15454,14 @@ __metadata: resolution: "uri-js@npm:4.4.1" dependencies: punycode: "npm:^2.1.0" - checksum: 7167432de6817fe8e9e0c9684f1d2de2bb688c94388f7569f7dbdb1587c9f4ca2a77962f134ec90be0cc4d004c939ff0d05acc9f34a0db39a3c797dada262633 + checksum: b271ca7e3d46b7160222e3afa3e531505161c9a4e097febae9664e4b59912f4cbe94861361a4175edac3a03fee99d91e44b6a58c17a634bc5a664b19fc76fbcb languageName: node linkType: hard "urix@npm:^0.1.0": version: 0.1.0 resolution: "urix@npm:0.1.0" - checksum: 4c076ecfbf3411e888547fe844e52378ab5ada2d2f27625139011eada79925e77f7fbf0e4016d45e6a9e9adb6b7e64981bd49b22700c7c401c5fc15f423303b3 + checksum: ebf5df5491c1d40ea88f7529ee9d8fd6501f44c47b8017d168fd1558d40f7d613c6f39869643344e58b71ba2da357a7c26f353a2a54d416492fcdca81f05b338 languageName: node linkType: hard @@ -15471,7 +15471,7 @@ __metadata: dependencies: querystringify: "npm:^2.1.1" requires-port: "npm:^1.0.0" - checksum: fbdba6b1d83336aca2216bbdc38ba658d9cfb8fc7f665eb8b17852de638ff7d1a162c198a8e4ed66001ddbf6c9888d41e4798912c62b4fd777a31657989f7bdf + checksum: c9e96bc8c5b34e9f05ddfeffc12f6aadecbb0d971b3cc26015b58d5b44676a99f50d5aeb1e5c9e61fa4d49961ae3ab1ae997369ed44da51b2f5ac010d188e6ad languageName: node linkType: hard @@ -15479,14 +15479,14 @@ __metadata: version: 1.3.1 resolution: "use-callback-ref@npm:1.3.1" dependencies: - tslib: ^2.0.0 + tslib: "npm:^2.0.0" peerDependencies: "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 6a6a3a8bfe88f466eab982b8a92e5da560a7127b3b38815e89bc4d195d4b33aa9a53dba50d93e8138e7502bcc7e39efe9f2735a07a673212630990c73483e8e9 + checksum: 7cc68dbd8bb9890e21366f153938988967f0a17168a215bf31e24519f826a2de7de596e981f016603a363362f736f2cffad05091c3857fcafbc9c3b20a3eef1e languageName: node linkType: hard @@ -15498,7 +15498,7 @@ __metadata: peerDependencies: react: 16.8.0 - 18 react-dom: 16.8.0 - 18 - checksum: 92be0ac34a3b3cf884cd55847c90792b5b44833dc258e96d650152815ad246afe45825aa223332203004d836535a927ab74f18dc0313229e2c7c69510eddf382 + checksum: 821d3f783090e36c694ef0ae3e366b364a691a8254d04337700ea79757e01e2d79f307ee517487c9246db7e8bc9625b474dd6ac7dad18d777004dee817826080 languageName: node linkType: hard @@ -15506,15 +15506,15 @@ __metadata: version: 1.1.2 resolution: "use-sidecar@npm:1.1.2" dependencies: - detect-node-es: ^1.1.0 - tslib: ^2.0.0 + detect-node-es: "npm:^1.1.0" + tslib: "npm:^2.0.0" peerDependencies: "@types/react": ^16.9.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 925d1922f9853e516eaad526b6fed1be38008073067274f0ecc3f56b17bb8ab63480140dd7c271f94150027c996cea4efe83d3e3525e8f3eda22055f6a39220b + checksum: ec99e31aefeb880f6dc4d02cb19a01d123364954f857811470ece32872f70d6c3eadbe4d073770706a9b7db6136f2a9fbf1bb803e07fbb21e936a47479281690 languageName: node linkType: hard @@ -15523,7 +15523,7 @@ __metadata: resolution: "use-sync-external-store@npm:1.2.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 5c639e0f8da3521d605f59ce5be9e094ca772bd44a4ce7322b055a6f58eeed8dda3c94cabd90c7a41fb6fa852210092008afe48f7038792fd47501f33299116a + checksum: a676216affc203876bd47981103f201f28c2731361bb186367e12d287a7566763213a8816910c6eb88265eccd4c230426eb783d64c373c4a180905be8820ed8e languageName: node linkType: hard @@ -15550,14 +15550,14 @@ __metadata: is-generator-function: "npm:^1.0.7" is-typed-array: "npm:^1.1.3" which-typed-array: "npm:^1.1.2" - checksum: 705e51f0de5b446f4edec10739752ac25856541e0254ea1e7e45e5b9f9b0cb105bc4bd415736a6210edc68245a7f903bf085ffb08dd7deb8a0e847f60538a38a + checksum: 61a10de7753353dd4d744c917f74cdd7d21b8b46379c1e48e1c4fd8e83f8190e6bd9978fc4e5102ab6a10ebda6019d1b36572fa4a325e175ec8b789a121f6147 languageName: node linkType: hard "utils-merge@npm:1.0.1": version: 1.0.1 resolution: "utils-merge@npm:1.0.1" - checksum: c81095493225ecfc28add49c106ca4f09cdf56bc66731aa8dabc2edbbccb1e1bfe2de6a115e5c6a380d3ea166d1636410b62ef216bb07b3feb1cfde1d95d5080 + checksum: 5d6949693d58cb2e636a84f3ee1c6e7b2f9c16cb1d42d0ecb386d8c025c69e327205aa1c69e2868cc06a01e5e20681fbba55a4e0ed0cce913d60334024eae798 languageName: node linkType: hard @@ -15566,7 +15566,7 @@ __metadata: resolution: "uuid@npm:9.0.0" bin: uuid: dist/bin/uuid - checksum: 8dd2c83c43ddc7e1c71e36b60aea40030a6505139af6bee0f382ebcd1a56f6cd3028f7f06ffb07f8cf6ced320b76aea275284b224b002b289f89fe89c389b028 + checksum: 23857699a616d1b48224bc2b8440eae6e57d25463c3a0200e514ba8279dfa3bde7e92ea056122237839cfa32045e57d8f8f4a30e581d720fd72935572853ae2e languageName: node linkType: hard @@ -15577,7 +15577,7 @@ __metadata: "@jridgewell/trace-mapping": "npm:^0.3.12" "@types/istanbul-lib-coverage": "npm:^2.0.1" convert-source-map: "npm:^1.6.0" - checksum: 2069d59ee46cf8d83b4adfd8a5c1a90834caffa9f675e4360f1157ffc8578ef0f763c8f32d128334424159bb6b01f3876acd39cd13297b2769405a9da241f8d1 + checksum: 95811ff2f17a31432c3fc7b3027b7e8c2c6ca5e60a7811c5050ce51920ab2b80df29feb04c52235bbfdaa9a6809acd5a5dd9668292e98c708617c19e087c3f68 languageName: node linkType: hard @@ -15587,14 +15587,14 @@ __metadata: dependencies: spdx-correct: "npm:^3.0.0" spdx-expression-parse: "npm:^3.0.0" - checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad + checksum: 86242519b2538bb8aeb12330edebb61b4eb37fd35ef65220ab0b03a26c0592c1c8a7300d32da3cde5abd08d18d95e8dabfad684b5116336f6de9e6f207eec224 languageName: node linkType: hard "vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" - checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b + checksum: 31389debef15a480849b8331b220782230b9815a8e0dbb7b9a8369559aed2e9a7800cd904d4371ea74f4c3527db456dc8e7ac5befce5f0d289014dbdf47b2242 languageName: node linkType: hard @@ -15617,7 +15617,7 @@ __metadata: resolution: "vite-plugin-react-remove-attributes@npm:1.0.3" peerDependencies: vite: ^2.4.4 - checksum: 9ae11525a6b4d111a6d655b7495c319cb99dc2aadaf2f5e1a6c311b3db32a93118f0d4b314f2c039a27e21a15a644bbfafbb7fb87963afcc06912b95c505505b + checksum: 4ffda1ac666128caaef33de2634696df9f8f18f92af9909abddfec5c1b0929bb4061003af72c24fac6c0881200cefca54184b60fd52b48ce2c3738d40761ecd9 languageName: node linkType: hard @@ -15630,7 +15630,7 @@ __metadata: svgo: "npm:^2.8.0" peerDependencies: vite: ^2 || ^3 || ^4 - checksum: 2f1ae63fae87b286548912f3da3e3b9ea4c77ee5aafd45144e29d594632e0684e9ebadb070cb088f90c275493a2a2e2df8958f288c3ac1c8e5429ff6ca79a317 + checksum: 55bd6fdc27e988291eee1677c4e6a73c0b80378fb26c98457cecf24117cdc1ad72cb2139db84ccf899079828d916da4481bdc0fdccf965d840f083b5ac07315b languageName: node linkType: hard @@ -15659,7 +15659,7 @@ __metadata: peerDependenciesMeta: vite: optional: true - checksum: 73a8467de72d7ac502328454fd00c19571cd4bad2dd5982643b24718bb95e449a3f4153cfc2d58a358bfc8f37e592fb442fc10884b59ae82138c1329160cd952 + checksum: 8550650c5f5b203e13f4975f6bfd26389000175a031be8f408f6b5d619d5fd8430e067a0661599a4d0872c431496b81239e5d5ad69d9c4b4f9ca7efd4b874bb1 languageName: node linkType: hard @@ -15699,7 +15699,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: c91d5228cd0b2410e95ea4b17279640a414f1a2d5290a01baec77351af2dda7d5901c240ed6a62de2b465567e328168d386da2aaa262d3a138fde827b289592d + checksum: d4827cdd41c8bb69c5071200a88015fa3c4d29082c46fd9f20db8df01f7b4948042e4b2e67b6a4391c0bdbfc6c4925832cc6b2411661518988c9a25d4b887598 languageName: node linkType: hard @@ -15708,7 +15708,7 @@ __metadata: resolution: "w3c-xmlserializer@npm:4.0.0" dependencies: xml-name-validator: "npm:^4.0.0" - checksum: eba070e78deb408ae8defa4d36b429f084b2b47a4741c4a9be3f27a0a3d1845e277e3072b04391a138f7e43776842627d1334e448ff13ff90ad9fb1214ee7091 + checksum: 9a00c412b5496f4f040842c9520bc0aaec6e0c015d06412a91a723cd7d84ea605ab903965f546b4ecdb3eae267f5145ba08565222b1d6cb443ee488cda9a0aee languageName: node linkType: hard @@ -15727,7 +15727,7 @@ __metadata: dependencies: glob-to-regexp: "npm:^0.4.1" graceful-fs: "npm:^4.1.2" - checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131 + checksum: 4280b45bc4b5d45d5579113f2a4af93b67ae1b9607cc3d86ae41cdd53ead10db5d9dc3237f24256d05ef88b28c69a02712f78e434cb7ecc8edaca134a56e8cab languageName: node linkType: hard @@ -15735,36 +15735,36 @@ __metadata: version: 1.0.1 resolution: "wcwidth@npm:1.0.1" dependencies: - defaults: ^1.0.3 - checksum: 814e9d1ddcc9798f7377ffa448a5a3892232b9275ebb30a41b529607691c0491de47cba426e917a4d08ded3ee7e9ba2f3fe32e62ee3cd9c7d3bafb7754bd553c + defaults: "npm:^1.0.3" + checksum: 182ebac8ca0b96845fae6ef44afd4619df6987fe5cf552fdee8396d3daa1fb9b8ec5c6c69855acb7b3c1231571393bd1f0a4cdc4028d421575348f64bb0a8817 languageName: node linkType: hard "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" - checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c + checksum: b65b9f8d6854572a84a5c69615152b63371395f0c5dcd6729c45789052296df54314db2bc3e977df41705eacb8bc79c247cee139a63fa695192f95816ed528ad languageName: node linkType: hard "webidl-conversions@npm:^7.0.0": version: 7.0.0 resolution: "webidl-conversions@npm:7.0.0" - checksum: f05588567a2a76428515333eff87200fae6c83c3948a7482ebb109562971e77ef6dc49749afa58abb993391227c5697b3ecca52018793e0cb4620a48f10bd21b + checksum: 4c4f65472c010eddbe648c11b977d048dd96956a625f7f8b9d64e1b30c3c1f23ea1acfd654648426ce5c743c2108a5a757c0592f02902cf7367adb7d14e67721 languageName: node linkType: hard "webpack-sources@npm:^3.2.3": version: 3.2.3 resolution: "webpack-sources@npm:3.2.3" - checksum: 989e401b9fe3536529e2a99dac8c1bdc50e3a0a2c8669cbafad31271eadd994bc9405f88a3039cd2e29db5e6d9d0926ceb7a1a4e7409ece021fe79c37d9c4607 + checksum: a661f41795d678b7526ae8a88cd1b3d8ce71a7d19b6503da8149b2e667fc7a12f9b899041c1665d39e38245ed3a59ab68de648ea31040c3829aa695a5a45211d languageName: node linkType: hard "webpack-virtual-modules@npm:^0.6.1": version: 0.6.1 resolution: "webpack-virtual-modules@npm:0.6.1" - checksum: 0cd993d7b00af0ed89eee96ed6dcb2307fa8dc38e37f34e78690088314976aa79a31cf146553c5e414cdc87222878c5e4979abeb0b00bf6dc9c6f018604a1310 + checksum: 12a43ecdb910185c9d7e4ec19cc3b13bff228dae362e8a487c0bd292b393555e017ad16f771d5ce5b692d91d65b71a7bcd64763958d39066a5351ea325395539 languageName: node linkType: hard @@ -15773,14 +15773,14 @@ __metadata: resolution: "whatwg-encoding@npm:2.0.0" dependencies: iconv-lite: "npm:0.6.3" - checksum: 7087810c410aa9b689cbd6af8773341a53cdc1f3aae2a882c163bd5522ec8ca4cdfc269aef417a5792f411807d5d77d50df4c24e3abb00bb60192858a40cc675 + checksum: 162d712d88fd134a4fe587e53302da812eb4215a1baa4c394dfd86eff31d0a079ff932c05233857997de07481093358d6e7587997358f49b8a580a777be22089 languageName: node linkType: hard "whatwg-mimetype@npm:^3.0.0": version: 3.0.0 resolution: "whatwg-mimetype@npm:3.0.0" - checksum: ce08bbb36b6aaf64f3a84da89707e3e6a31e5ab1c1a2379fd68df79ba712a4ab090904f0b50e6693b0dafc8e6343a6157e40bf18fdffd26e513cf95ee2a59824 + checksum: 96f9f628c663c2ae05412c185ca81b3df54bcb921ab52fe9ebc0081c1720f25d770665401eb2338ab7f48c71568133845638e18a81ed52ab5d4dcef7d22b40ef languageName: node linkType: hard @@ -15790,7 +15790,7 @@ __metadata: dependencies: tr46: "npm:^3.0.0" webidl-conversions: "npm:^7.0.0" - checksum: ed4826aaa57e66bb3488a4b25c9cd476c46ba96052747388b5801f137dd740b73fde91ad207d96baf9f17fbcc80fc1a477ad65181b5eb5fa718d27c69501d7af + checksum: dfcd51c6f4bfb54685528fb10927f3fd3d7c809b5671beef4a8cdd7b1408a7abf3343a35bc71dab83a1424f1c1e92cc2700d7930d95d231df0fac361de0c7648 languageName: node linkType: hard @@ -15800,7 +15800,7 @@ __metadata: dependencies: tr46: "npm:~0.0.3" webidl-conversions: "npm:^3.0.0" - checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c + checksum: f95adbc1e80820828b45cc671d97da7cd5e4ef9deb426c31bcd5ab00dc7103042291613b3ef3caec0a2335ed09e0d5ed026c940755dbb6d404e2b27f940fdf07 languageName: node linkType: hard @@ -15813,7 +15813,7 @@ __metadata: is-number-object: "npm:^1.0.4" is-string: "npm:^1.0.5" is-symbol: "npm:^1.0.3" - checksum: 53ce774c7379071729533922adcca47220228405e1895f26673bbd71bdf7fb09bee38c1d6399395927c6289476b5ae0629863427fd151491b71c4b6cb04f3a5e + checksum: 9c7ca7855255f25ac47f4ce8b59c4cc33629e713fd7a165c9d77a2bb47bf3d9655a5664660c70337a3221cf96742f3589fae15a3a33639908d33e29aa2941efb languageName: node linkType: hard @@ -15825,7 +15825,7 @@ __metadata: is-set: "npm:^2.0.1" is-weakmap: "npm:^2.0.1" is-weakset: "npm:^2.0.1" - checksum: c815bbd163107ef9cb84f135e6f34453eaf4cca994e7ba85ddb0d27cea724c623fae2a473ceccfd5549c53cc65a5d82692de418166df3f858e1e5dc60818581c + checksum: 85c95fcf92df7972ce66bed879e53d9dc752a30ef08e1ca4696df56bcf1c302e3b9965a39b04a20fa280a997fad6c170eb0b4d62435569b7f6c0bc7be910572b languageName: node linkType: hard @@ -15839,7 +15839,7 @@ __metadata: gopd: "npm:^1.0.1" has-tostringtag: "npm:^1.0.0" is-typed-array: "npm:^1.1.10" - checksum: 149f54f5d11773ce938c60a2c36306720a1824eccb62bda0620170932c2783fa50ad0226254c5741a962e35c7ccba5f4e4c402b8618cb3b4f2cf47bf5e6ade31 + checksum: 9a64f143ba632d8c976d5c343aed7a35d4b2d7d9cd9db62e831b1aa820e530c413e26381241d1ca4abf3167e6af994c598bf35d35b337c525c518489124dbfad languageName: node linkType: hard @@ -15850,7 +15850,7 @@ __metadata: isexe: "npm:^2.0.0" bin: node-which: ./bin/node-which - checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 + checksum: 4782f8a1d6b8fc12c65e968fea49f59752bf6302dc43036c3bf87da718a80710f61a062516e9764c70008b487929a73546125570acea95c5b5dcc8ac3052c70f languageName: node linkType: hard @@ -15859,14 +15859,14 @@ __metadata: resolution: "wide-align@npm:1.1.5" dependencies: string-width: "npm:^1.0.2 || 2 || 3 || 4" - checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 + checksum: d5f8027b9a8255a493a94e4ec1b74a27bff6679d5ffe29316a3215e4712945c84ef73ca4045c7e20ae7d0c72f5f57f296e04a4928e773d4276a2f1222e4c2e99 languageName: node linkType: hard "wordwrap@npm:^1.0.0": version: 1.0.0 resolution: "wordwrap@npm:1.0.0" - checksum: 2a44b2788165d0a3de71fd517d4880a8e20ea3a82c080ce46e294f0b68b69a2e49cff5f99c600e275c698a90d12c5ea32aff06c311f0db2eb3f1201f3e7b2a04 + checksum: 497d40beb2bdb08e6d38754faa17ce20b0bf1306327f80cb777927edb23f461ee1f6bc659b3c3c93f26b08e1cf4b46acc5bae8fda1f0be3b5ab9a1a0211034cd languageName: node linkType: hard @@ -15877,7 +15877,7 @@ __metadata: ansi-styles: "npm:^4.0.0" string-width: "npm:^4.1.0" strip-ansi: "npm:^6.0.0" - checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b + checksum: cebdaeca3a6880da410f75209e68cd05428580de5ad24535f22696d7d9cab134d1f8498599f344c3cf0fb37c1715807a183778d8c648d6cc0cb5ff2bb4236540 languageName: node linkType: hard @@ -15888,7 +15888,7 @@ __metadata: ansi-styles: "npm:^6.1.0" string-width: "npm:^5.0.1" strip-ansi: "npm:^7.0.1" - checksum: 371733296dc2d616900ce15a0049dca0ef67597d6394c57347ba334393599e800bab03c41d4d45221b6bc967b8c453ec3ae4749eff3894202d16800fdfe0e238 + checksum: 7b1e4b35e9bb2312d2ee9ee7dc95b8cb5f8b4b5a89f7dde5543fe66c1e3715663094defa50d75454ac900bd210f702d575f15f3f17fa9ec0291806d2578d1ddf languageName: node linkType: hard @@ -15906,7 +15906,7 @@ __metadata: graceful-fs: "npm:^4.1.11" imurmurhash: "npm:^0.1.4" signal-exit: "npm:^3.0.2" - checksum: 2db81f92ae974fd87ab4a5e7932feacaca626679a7c98fcc73ad8fcea5a1950eab32fa831f79e9391ac99b562ca091ad49be37a79045bd65f595efbb8f4596ae + checksum: 15ce863dce07075d0decedd7c9094f4461e46139d28a758c53162f24c0791c16cd2e7a76baa5b47b1a851fbb51e16f2fab739afb156929b22628f3225437135c languageName: node linkType: hard @@ -15916,7 +15916,7 @@ __metadata: dependencies: imurmurhash: "npm:^0.1.4" signal-exit: "npm:^3.0.7" - checksum: 5da60bd4eeeb935eec97ead3df6e28e5917a6bd317478e4a85a5285e8480b8ed96032bbcc6ecd07b236142a24f3ca871c924ec4a6575e623ec1b11bf8c1c253c + checksum: 3be1f5508a46c190619d5386b1ac8f3af3dbe951ed0f7b0b4a0961eed6fc626bd84b50cf4be768dabc0a05b672f5d0c5ee7f42daa557b14415d18c3a13c7d246 languageName: node linkType: hard @@ -15925,7 +15925,7 @@ __metadata: resolution: "ws@npm:6.2.2" dependencies: async-limiter: "npm:~1.0.0" - checksum: aec3154ec51477c094ac2cb5946a156e17561a581fa27005cbf22c53ac57f8d4e5f791dd4bbba6a488602cb28778c8ab7df06251d590507c3c550fd8ebeee949 + checksum: bb791ac02ad7e59fd4208cc6dd3a5bf7a67dff4611a128ed33365996f9fc24fa0d699043559f1798b4bc8045639fd21a1fd3ceca81de560124444abd8e321afc languageName: node linkType: hard @@ -15940,21 +15940,21 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c + checksum: 1769532b6fdab9ff659f0b17810e7501831d34ecca23fd179ee64091dd93a51f42c59f6c7bb4c7a384b6c229aca8076fb312aa35626257c18081511ef62a161d languageName: node linkType: hard "xml-name-validator@npm:^4.0.0": version: 4.0.0 resolution: "xml-name-validator@npm:4.0.0" - checksum: af100b79c29804f05fa35aa3683e29a321db9b9685d5e5febda3fa1e40f13f85abc40f45a6b2bf7bee33f68a1dc5e8eaef4cec100a304a9db565e6061d4cb5ad + checksum: f9582a3f281f790344a471c207516e29e293c6041b2c20d84dd6e58832cd7c19796c47e108fd4fd4b164a5e72ad94f2268f8ace8231cde4a2c6428d6aa220f92 languageName: node linkType: hard "xmlchars@npm:^2.2.0": version: 2.2.0 resolution: "xmlchars@npm:2.2.0" - checksum: 8c70ac94070ccca03f47a81fcce3b271bd1f37a591bf5424e787ae313fcb9c212f5f6786e1fa82076a2c632c0141552babcd85698c437506dfa6ae2d58723062 + checksum: 4ad5924974efd004a47cce6acf5c0269aee0e62f9a805a426db3337af7bcbd331099df174b024ace4fb18971b8a56de386d2e73a1c4b020e3abd63a4a9b917f1 languageName: node linkType: hard @@ -15968,28 +15968,28 @@ __metadata: "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" - checksum: 54f0fb95621ee60898a38c572c515659e51cc9d9f787fb109cef6fde4befbe1c4602dc999d30110feee37456ad0f1660fa2edcfde6a9a740f86a290999550d30 + checksum: 5f1b5f95e3775de4514edbb142398a2c37849ccfaf04a015be5d75521e9629d3be29bd4432d23c57f37e5b61ade592fb0197022e9993f81a06a5afbdcda9346d languageName: node linkType: hard "yallist@npm:^3.0.2": version: 3.1.1 resolution: "yallist@npm:3.1.1" - checksum: 48f7bb00dc19fc635a13a39fe547f527b10c9290e7b3e836b9a8f1ca04d4d342e85714416b3c2ab74949c9c66f9cebb0473e6bc353b79035356103b47641285d + checksum: 9af0a4329c3c6b779ac4736c69fae4190ac03029fa27c1aef4e6bcc92119b73dea6fe5db5fe881fb0ce2a0e9539a42cdf60c7c21eda04d1a0b8c082e38509efb languageName: node linkType: hard "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" - checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 + checksum: 4cb02b42b8a93b5cf50caf5d8e9beb409400a8a4d85e83bb0685c1457e9ac0b7a00819e9f5991ac25ffabb56a78e2f017c1acc010b3a1babfe6de690ba531abd languageName: node linkType: hard "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" - checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c + checksum: 9dc2c217ea3bf8d858041252d43e074f7166b53f3d010a8c711275e09cd3d62a002969a39858b92bbda2a6a63a585c7127014534a560b9c69ed2d923d113406e languageName: node linkType: hard @@ -16004,7 +16004,7 @@ __metadata: string-width: "npm:^4.2.3" y18n: "npm:^5.0.5" yargs-parser: "npm:^21.1.1" - checksum: 73b572e863aa4a8cbef323dd911d79d193b772defd5a51aab0aca2d446655216f5002c42c5306033968193bdbf892a7a4c110b0d77954a7fdf563e653967b56a + checksum: abb3e37678d6e38ea85485ed86ebe0d1e3464c640d7d9069805ea0da12f69d5a32df8e5625e370f9c96dd1c2dc088ab2d0a4dd32af18222ef3c4224a19471576 languageName: node linkType: hard @@ -16014,7 +16014,7 @@ __metadata: dependencies: buffer-crc32: "npm:~0.2.3" fd-slicer: "npm:~1.1.0" - checksum: 7f21fe0bbad6e2cb130044a5d1d0d5a0e5bf3d8d4f8c4e6ee12163ce798fee3de7388d22a7a0907f563ac5f9d40f8699a223d3d5c1718da90b0156da6904022b + checksum: 1e4c311050dc0cf2ee3dbe8854fe0a6cde50e420b3e561a8d97042526b4cf7a0718d6c8d89e9e526a152f4a9cec55bcea9c3617264115f48bd6704cf12a04445 languageName: node linkType: hard diff --git a/spec/_static/css/theme_custom.css b/spec/_static/css/theme_custom.css deleted file mode 100644 index c3a82c5637..0000000000 --- a/spec/_static/css/theme_custom.css +++ /dev/null @@ -1,126 +0,0 @@ -a { - color: #2b7842; - text-decoration: none; - cursor: pointer -} - -a:visited { - color: #2b7842 -} - - -table td { - white-space: normal !important; -} - -.caption-text { - color: #ffffff -} - -.wy-text-info { - color: #2b7842 !important -} - -.wy-menu-vertical a:active { - background-color: #4dc872; - cursor: pointer; - color: #fff -} - -.wy-side-nav-search { - display: block; - width: 300px; - padding: .809em; - margin-bottom: .809em; - z-index: 200; - text-align: center; - padding: .809em; - display: block; - color: #fcfcfc; - margin-bottom: .809em; - background: #343131; -} - -.wy-tray-container li.wy-tray-item-info { - background: #4dc872 -} - -.btn-info { - background-color: #4dc872 !important -} - -.btn-link { - background-color: transparent !important; - color: #2b7842 - box-shadow: none; - border-color: transparent !important -} - -.wy-dropdown-menu > dd > a:hover { - color: #2b7842 - color: #fff -} - -.wy-nav .wy-menu-vertical header { - color: #2b7842 -} - -.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover { - background: #4dc872; - color: #fff -} - -.wy-inline-validate.wy-inline-validate-info .wy-input-context { - color: #2b7842 -} - -.wy-nav-top { - display: none; - background: #4dc872; - color: #fff; - padding: .4045em .809em; - position: relative; - line-height: 50px; - text-align: center; - font-size: 100%; - * zoom: 1 -} - -.wy-nav-top img { - margin-right: 12px; - height: 45px; - width: 45px; - background-color: #4dc872; - padding: 5px; - border-radius: 100% -} - -.rst-versions a { - color: #2b7842 - text-decoration: none -} - -.rst-content a tt, .rst-content a tt, .rst-content a code { - color: #2b7842 -} - -.rst-content dl:not(.docutils) dt { - display: inline-block; - margin: 6px 0; - font-size: 90%; - line-height: normal; - background: #e7f2fa; - color: #2b7842 - border-top: solid 3px #6ab0de; - padding: 6px; - position: relative -} - -.wy-alert.wy-alert-neutral a, .rst-content .wy-alert-neutral.note a, -.rst-content .wy-alert-neutral.attention a, .rst-content .wy-alert-neutral.caution a, -.rst-content .wy-alert-neutral.danger a, .rst-content .wy-alert-neutral.error a, -.rst-content .wy-alert-neutral.hint a, .rst-content .wy-alert-neutral.important a, -.rst-content .wy-alert-neutral.tip a, .rst-content .wy-alert-neutral.warning a, -.rst-content .wy-alert-neutral.seealso a, .rst-content .wy-alert-neutral.admonition-todo a { - color: #2b7842 -} diff --git a/spec/conf.py b/spec/conf.py deleted file mode 100644 index cdc02776b4..0000000000 --- a/spec/conf.py +++ /dev/null @@ -1,350 +0,0 @@ -# -# Arenadata documentation build configuration file, created by -# sphinx-quickstart on Mon Jul 31 16:56:10 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. - -from string import Template -import datetime - -# import sphinx_markdown_tables -import sphinx_rtd_theme - -# -- General configuration ------------------------------------------------ - -# git rev-parse --abbrev-ref HEAD -version = "" # substituted via -D option -# The full version, including alpha/beta/rc tags. -release = version - -now = datetime.datetime.now() # noqa: DTZ005 - - -title = Template( - r""" - \pagenumbering{Roman} %%% to avoid page 1 conflict with actual page 1 - \begin{titlepage} - - \vspace*{-31.4mm} - \begin{center} - \makebox[\textwidth]{\includegraphics[width=\paperwidth]{logo.png}} - \end{center} - - \raggedright - - \vspace*{70mm} %%% * is used to give space from top - \textbf{\Huge {Arenadata™ #title#}} - - \vspace*{30mm} - \Large \textit{Версия - $version} - - \LARGE \textbf{{#name#}} - - %% \vfill adds at the bottom - \vfill - \normalsize \textit{ $pusblish Arenadata™} - \end{titlepage} - \pagenumbering{arabic} - \tableofcontents - \clearpage - """ -).substitute({"pusblish": now.year, "version": version}) - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - "sphinx.ext.doctest", - "sphinx.ext.intersphinx", - "sphinx.ext.mathjax", - "sphinx.ext.githubpages", - "sphinx.ext.extlinks", - "sphinx_markdown_tables", - # "sphinxpapyrus.docxbuilder", -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# - -source_parsers = { - ".md": "recommonmark.parser.CommonMarkParser", -} - -source_suffix = { - ".rst": "restructuredtext", - ".txt": "restructuredtext", - ".md": "markdown", -} - -# The master toctree document. -master_doc = "index" - -# General information about the project. - - -project = "Arenadata Cluster Manager Specs" -copyright = "{}, Arenadata.io".format(now.year) # noqa: A001, UP032 -author = "Arenadata.io" - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set 'language' from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "sphinx_rtd_theme" - -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named 'default.css' will overwrite the builtin 'default.css'. -html_static_path = ["_static"] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - "**": [ - "about.html", - "navigation.html", - "relations.html", # needs 'show_related': True theme option to display - "searchbox.html", - "donate.html", - ] -} - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = "Arenadatadoc" - -today = "{}, Arenadata™".format(now.year) # noqa: UP032 -latex_keep_old_macro_names = True - -latex_logo = "_static/logo.png" - -# -- Options for LaTeX output --------------------------------------------- -latex_elements = { - "classoptions": ",openany,oneside", # Removes blank pages - # VerbatimColor - background color of codeblocks - "sphinxsetup": "TitleColor={rgb}{0.05, 0.5, 0.06}, InnerLinkColor={rgb}{0.05, 0.5, 0.06},\ - VerbatimColor={rgb}{0.82, 0.94, 0.75}, importantBorderColor={rgb}{0.66, 0.89, 0.63},\ - OuterLinkColor={rgb}{0.04, 0.5, 0.06}, importantborder=1.5pt,\ - hmargin={0.7in,0.7in}, vmargin={1in,1in}, verbatimwithframe=true", - "fontpkg": "", - "fncychap": r"\usepackage{fncychap}", - "babel": r"\usepackage[english, russian]{babel}", - # The font size ('10pt', '11pt' or '12pt'). - # - "pointsize": "10pt", - # 'date': '2017, Arenadata™', # date is setting up by `today` variable, described above - "preamble": r""" - \usepackage{indentfirst} %% It should makes indent at first paragraph in chapter - - \setlength{\parindent}{1cm} - - % Disable 'Continue on the next page' - \renewcommand{\tablecontinued}[1]{} - - % Disable hyphenation - \hyphenpenalty10000 - \exhyphenpenalty10000 - - - \usepackage{amsmath,amsfonts,amssymb,amsthm} - \usepackage{graphicx} - - - \usepackage{color} - \usepackage{transparent} - \usepackage{eso-pic} - \usepackage{lipsum} - - \usepackage{footnotebackref} %%link at the footnote to go to the place of footnote in the text - - %% spacing between line - \usepackage{setspace} - \singlespacing - - - %%%%%%%%%%% datetime - \usepackage{datetime} - - %%%%%%%%%%% support charec - \usepackage[T1]{fontenc} - \usepackage[utf8]{inputenc} - \usepackage{newunicodechar} - - \newunicodechar{ẟ}{$\delta$} - - %% RO, LE will not work for 'oneside' layout. - %% Change oneside to twoside in document class - \usepackage{fancyhdr} - \pagestyle{fancy} - \fancyhf{} - - %%% Alternating Header for oneside - \fancyhead[L]{\ifthenelse{\isodd{\value{page}}}{ \small \nouppercase{\leftmark} }{}} - \fancyhead[R]{\ifthenelse{\isodd{\value{page}}}{}{ \small \nouppercase{\rightmark} }} - - %%% Alternating Header for two side - %\fancyhead[RO]{\small \nouppercase{\rightmark}} - %\fancyhead[LE]{\small \nouppercase{\leftmark}} - - - %%% page number - \fancyfoot[RO, RE]{\textbf{\thepage}} - - \renewcommand{\headrulewidth}{0.5pt} - \renewcommand{\footrulewidth}{0.5pt} - - \renewcommand{\baselinestretch}{1} - """, - "maketitle": title, - "tableofcontents": " ", - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# If true, figures, tables and code-blocks are automatically numbered if they have a caption. -# At same time, the numref role is enabled. -# For now, it works only with the HTML builder and LaTeX builder. -# Default is False. - -numfig = True - -# The scope of figure numbers, that is, the numfig feature numbers figures in which scope. -# 0 means “whole document”. 1 means “in a section”. -# Sphinx numbers like x.1, x.2, x.3... 2 means “in a subsection”. -# Sphinx numbers like x.x.1, x.x.2, x.x.3..., and so on. Default is 1. - -numfig_secnum_depth = 1 - -# A dictionary mapping 'figure', 'table' and 'code-block' to strings that are used for format of figure numbers. -# Default is to use 'Fig. %s' for 'figure', -# 'Table %s' for 'table' and -# 'Listing %s' for 'code-block'. - -numfig_format = {"figure": "Рис. %s.", "table": "Табл. %s.", "code-block": "Лист. %s."} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, "Arenadata.tex", "Arenadata Documentation", "Arenadata", "manual"), -] - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "arenadata", "Arenadata Documentation", [author], 1)] - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ( - master_doc, - "Arenadata", - "Arenadata Documentation", - author, - "Arenadata", - "One line description of project.", - "Miscellaneous", - ), -] - -# -- Options for Epub output ---------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = project -epub_author = author -epub_publisher = author -epub_copyright = copyright - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -# -# epub_identifier = '' - -# A unique identification for the text. -# -# epub_uid = '' - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ["search.html"] - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {"https://docs.python.org/": None} - -extlinks = {"issue": ("https://arenadata.atlassian.net/browse/%s", "")} - - -def setup(app): - app.add_stylesheet("css/theme_custom.css") - app.add_stylesheet("css/arenadata_comments.css") - app.add_javascript("js/arenadata_comments.js") diff --git a/spec/index.rst b/spec/index.rst deleted file mode 100644 index a073acd36a..0000000000 --- a/spec/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -ADCM Specs -########## - -.. toctree:: - :maxdepth: 3 - :caption: Contents: - - usecase/index.rst - objects.rst - system/index.rst - ui/index.rst diff --git a/spec/objects.rst b/spec/objects.rst deleted file mode 100644 index 2198857e82..0000000000 --- a/spec/objects.rst +++ /dev/null @@ -1,219 +0,0 @@ -Objects -======= - -.. _object-config: - -Config -~~~~~~ - -ObjectConfig is an object that contains the ID of the current and previous config - -Endpoint: */config* - -=================== ======= ======= ======== ================ ================== ================== =========== -Name Type Default Nullable :term:`Required` :term:`POSTable` :term:`Changeable` Description -=================== ======= ======= ======== ================ ================== ================== =========== -id integer auto False False False False Object id. -current FK null False False False False FK on `ConfigLog` object -previous FK null False False False False FK on `ConfigLog` object -history link null False False False False Link on list `ConfigLog` object for this object -url link null False False False False Reference to this object -=================== ======= ======= ======== ================ ================== ================== =========== - -API Calls Allowed -^^^^^^^^^^^^^^^^^ - -============= ======= -Operation Allowed -============= ======= -GET True -LIST True -POST False -PUT False -PATCH False -DELETE False -============= ======= - -.. _object-config-log: - -Config Log -~~~~~~~~~~ - -ObjectLog is an object that contains object configurations - -Endpoint: */config-log* - -=================== ======= ======= ======== ================ ================== ================== =========== -Name Type Default Nullable :term:`Required` :term:`POSTable` :term:`Changeable` Description -=================== ======= ======= ======== ================ ================== ================== =========== -id integer auto False False False False Object id. -date date auto False False False False Object creation date -obj_ref FK null False True True False FK on `ObjectConfig` object -description text '' False False True False Description -config json {} False True True False Configuration -attr json {} False False True False Additional attributes -url link null False False False False Reference to this object -=================== ======= ======= ======== ================ ================== ================== =========== - -API Calls Allowed -^^^^^^^^^^^^^^^^^ - -============= ======= -Operation Allowed -============= ======= -GET True -LIST True -POST True -PUT False -PATCH False -DELETE False -============= ======= - -.. _object-group-config: - -Group Config -~~~~~~~~~~~~ - -Group is an entity wich is capable to hold some number of host in it and connect it to some objects. Besides the group allow to pin a subset of object config and provide a way to change the config. - -Endpoint: */group-config* - -=================== ======= ======= ======== ================ ================== ================== =========== -Name Type Default Nullable :term:`Required` :term:`POSTable` :term:`Changeable` Description -=================== ======= ======= ======== ================ ================== ================== =========== -id integer auto False False False False Object id. -object_id integer null False True True False Object id for object -object_type string null False True True False Object type (`cluster`, `service`, `component`, `provider`) -name string null False True True True Name of object. -description text null False False True True Extended information provided by user. -hosts link null False False False False Reference to list `Host` objects. -host_candidate link null False False False False Reference to list host candidate for adding to a group -config link null True False False False Reference to `ObjectConfig` object -config_id integer null False False False False Additional information about config. Read Only. -url link null False False False False Reference to this object -=================== ======= ======= ======== ================ ================== ================== =========== - - -API Calls Allowed -^^^^^^^^^^^^^^^^^ - -============= ======= -Operation Allowed -============= ======= -GET True -LIST True -POST True -PUT True -PATCH True -DELETE True -============= ======= - -.. _object-group-config-hosts: - -Group Config Hosts -~~~~~~~~~~~~ - -Endpoint: */group-config//host/* - -=================== ======= ======= ======== ================ ================== ================== =========== -Name Type Default Nullable :term:`Required` :term:`POSTable` :term:`Changeable` Description -=================== ======= ======= ======== ================ ================== ================== =========== -id integer auto False True True False Object ID. -cluster_id integer null False False False False Cluster object ID -prototype_id integer null False False False False Prototype object ID -provider_id integer null False False False False Provider object ID -fqdn string null False False False False FQDN host -description text null False False False False Host description -state string null False False False False Host state -url link null False False False False Reference to this object -=================== ======= ======= ======== ================ ================== ================== =========== - -.. note:: - POST - Creating relation a host with a group - DELETE - Deleting relation a host with a group - - -API Calls Allowed -^^^^^^^^^^^^^^^^^ - -============= ======= -Operation Allowed -============= ======= -GET True -LIST True -POST True -PUT False -PATCH False -DELETE True -============= ======= - -.. _object-group-config-host-candidate: - -Group Config Host Candidate -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Endpoint: */group-config//host-candidate/* - -=================== ======= ======= ======== ================ ================== ================== =========== -Name Type Default Nullable :term:`Required` :term:`POSTable` :term:`Changeable` Description -=================== ======= ======= ======== ================ ================== ================== =========== -id integer auto False True True False Object ID. -cluster_id integer null False False False False Cluster object ID -prototype_id integer null False False False False Prototype object ID -provider_id integer null False False False False Provider object ID -fqdn string null False False False False FQDN host -description text null False False False False Host description -state string null False False False False Host state -url link null False False False False Reference to this object -=================== ======= ======= ======== ================ ================== ================== =========== - -API Calls Allowed -^^^^^^^^^^^^^^^^^ - -============= ======= -Operation Allowed -============= ======= -GET True -LIST True -POST False -PUT False -PATCH False -DELETE False -============= ======= - -.. _concern-item: - -Config -~~~~~~ - -ConcernItem is an object that contains info about single concern to address before any actions could be run on linked objects - -Endpoint: */concern* - -=================== ======= ======= ======== ================ ================== ================== =========== -Name Type Default Nullable :term:`Required` :term:`POSTable` :term:`Changeable` Description -=================== ======= ======= ======== ================ ================== ================== =========== -id integer auto False False False False Object id. -name string - False False False False Concern name for debug purposes -type string 'lock' False False False False Type of concern - lock, issue or flag -blocking boolean - False False False False Does concern locks actions running -reason json {} False False False False Templated message for use on front-end -related_objects json [] False False False False LIst of objects referencing to this concern -cause string - False False False False Cause of concern - config, job, import, service or host-component map -owner FK - False False False False Reference to a source object of concern (Cluster, Host, etc.) -url link - False False False False Reference to this object -=================== ======= ======= ======== ================ ================== ================== =========== - -API Calls Allowed -^^^^^^^^^^^^^^^^^ - -============= ======= -Operation Allowed -============= ======= -GET True -LIST True -POST False -PUT False -PATCH False -DELETE False -============= ======= diff --git a/spec/system/components.rst b/spec/system/components.rst deleted file mode 100644 index 603cc3b05b..0000000000 --- a/spec/system/components.rst +++ /dev/null @@ -1,34 +0,0 @@ -ADCM Componets -############## - -UI -=== - -The frontend part of ADCM. Based on Angular Framework and meterial design. - -Job Executor -============ - -Job executor of ADCM is quite simple. It just a script to prepare data for Ansible and some script to handle ansible-playbook command. - -Ansible -======= - -This part of ADCM responses for all operations on hosts. Playbooks are delivered of bundles. - -Currently we are using Ansible 2.8.x version. - -WSGI Backend -============ - -This is a part of backend repsponsible for most operations. It based on Django ORM framework and Django REST Framework (DRF). - -Resident Backend -================ - -Resident Backend part, also known as Status Server (SS) is part of ADCM based on Golang platform. It responsible for event fiding from Django to UI over websocket protocol and for handling of statuses. - -Nginx -===== - -It is a standart Nginx web server who route request to Resident Backend and WSGI Backend and serve static files. diff --git a/spec/system/index.rst b/spec/system/index.rst deleted file mode 100644 index 706fc35e24..0000000000 --- a/spec/system/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Software Decomposition -###################### - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - components.rst diff --git a/spec/ui/actions.rst b/spec/ui/actions.rst deleted file mode 100644 index ec7d1ebd3b..0000000000 --- a/spec/ui/actions.rst +++ /dev/null @@ -1,259 +0,0 @@ -######### -Use Cases -######### - -.. _ui_usecases_login: - -***** -Login -***** - -There is a number of scenarios related to login forms of ADCM. - -.. note:: - Upgrade of ADCM and related events is out of scope for this use case. - -User/password login -=================== - -Just a simple use case of auth for user with username and password. - -**Goal**: successful login - -1. Go to ADCM -2. Fill *Login* on :ref:`ui_elements_forms_login` -3. Fill *Password* on :ref:`ui_elements_forms_login` -4. Press button *Login* on :ref:`ui_elements_forms_login` - -Exceptions: - -2. User already logged to ADCM - a. There is no :ref:`ui_elements_forms_login` - -2. User does not fill *Login* on :ref:`ui_elements_forms_login` - a. Button *Login* on :ref:`ui_elements_forms_login` is inactive (no way to click it) - - -2. User does not fill *Password* on :ref:`ui_elements_forms_login` - a. Button *Login* on :ref:`ui_elements_forms_login` is inactive (no way to click it) - - -GAuth2 login -============ - -.. note:: - TODO: Add later as separate story. - - -******* -Cluster -******* - -.. _ui_usecases_cluster_list_view: - -Cluster list view -================= - -Use case in which the user can view the list of added clusters and information on them. - -Actors ------- - -* :term:`End User` - -User Value ----------- - -This use case will allow the :term:`End User` to view the list of added clusters. - -Pre-Conditions --------------- - -:term:`End User` has ADCM and completed the use case :ref:`ui_usecases_login`. - -Post-Conditions ---------------- - -:term:`End User` was able to view the list of clusters and information on them. - -“Used” Use Cases ----------------- - -* :ref:`ui_usecases_cluster_service_list_view` - -Flow of Events --------------- - -1. :term:`End User` goes to the "Cluster" tab of the main menu of the :ref:`ui_templates_common` template. -2. :term:`End User` sees a list of clusters and information on them. - -User Interface --------------- - -The description of the UI is available by clicking :ref:`ui_templates_clusters`. - -.. _ui_usecases_cluster_create: - -Cluster create -============== - -The way user create a cluster in UI. - -Actors ------- - -* :term:`End User` - -User Value ----------- - -That is the only way to create cluster. - -Pre-Conditions --------------- - -:term:`End User` has ADCM and completed the following use cases: - -* :ref:`ui_usecases_login` -* :ref:`ui_usecases_cluster_list_view` - - -Flow of Events --------------- - -1. :term:`End User` clicks "Create Cluster" button in :ref:`ui_form_dialogs_create_cluster` -2. :term:`End User` selects bundle from "Bundle" selector in :ref:`ui_form_dialogs_create_cluster` -3. :term:`End User` selects version from "Version" selector in :ref:`ui_form_dialogs_create_cluster` -4. :term:`End User` fills "Cluster name" field in :ref:`ui_form_dialogs_create_cluster` -5. :term:`End User` fills "Description" field in :ref:`ui_form_dialogs_create_cluster` -6. :term:`End User` clicks "Create" button in :ref:`ui_form_dialogs_create_cluster` - -Post-Conditions ---------------- - -* A Cluster has been created. -* :ref:`ui_form_dialogs_create_cluster` has beeen closed. - -Cluster service list view -========================= - -Use case in which the user can view the list of added clusters and information on them. - -Actors ------- - -* :term:`End User` - -User Value ----------- - -This use case will allow the :term:`End User` view the list of services included to cluster. - -Pre-Conditions --------------- - -:term:`End User` has ADCM and completed the following use cases: - -* :ref:`ui_usecases_login` -* :ref:`ui_usecases_cluster_list_view` - -Post-Conditions ---------------- - -* :term:`End User` was able to view the list of cluster services and information on them. -* Dialog has been closed - -“Used” Use Cases ----------------- - -Cluster host list view -====================== - -Use case in which the user can view the list of hosts added clusters. - -Actors ------- - -* :term:`End User` - -User Value ----------- - -This the only way to find out list of host included in cluster over UI. - -Pre-Conditions --------------- - -:term:`End User` has ADCM and completed the following use cases: - -* :ref:`ui_usecases_login` -* :ref:`ui_usecases_cluster_list_view` - -Post-Conditions ---------------- - -* :term:`End User` was able to view the list of cluster hosts. - -“Used” Use Cases ----------------- - - -Flow of Events --------------- - -1. :term:`End User` selects the required cluster by clicking on it in the list of clusters. -2. :term:`End User` goes to the "Hosts" section in the Left Menu. -3. :term:`End User` sees a list of cluster hosts. - -User Interface --------------- - -List of host described in :ref:`ui_templates_cluster_host_list_view`. - - -************* -Host Provider -************* - - -.. _ui_usecases_create_hostprovider: - -Host Provider Create -==================== - -The way user create a Host Provider in UI. - -Actors ------- - -* :term:`End User` - -User Value ----------- - -That is the only way to create Host Provider. - -Pre-Conditions --------------- - -:term:`End User` has ADCM and completed the following use cases: - -* :ref:`ui_usecases_login` -* :ref:`ui_usecases_hostprovider_list_view` - - -Flow of Events --------------- - -1. :term:`End User` clicks "Create provider" button in :ref:`ui_form_dialogs_create_hostprovider` -2. :term:`End User` selects bundle from "Bundle" selector in :ref:`ui_form_dialogs_create_hostprovider` -3. :term:`End User` selects version from "Version" selector in :ref:`ui_form_dialogs_create_hostprovider` -4. :term:`End User` fills "Hostprovider name" field in :ref:`ui_form_dialogs_create_hostprovider` -5. :term:`End User` fills "Description" field in :ref:`ui_form_dialogs_create_hostprovider` -6. :term:`End User` clicks "Create" button in :ref:`ui_form_dialogs_create_hostprovider` - -Post-Conditions ---------------- - -* A Hostprovider has been created. -* :ref:`ui_form_dialogs_create_hostprovider` has been closed. diff --git a/spec/ui/elements.rst b/spec/ui/elements.rst deleted file mode 100644 index 845f5efc1e..0000000000 --- a/spec/ui/elements.rst +++ /dev/null @@ -1,327 +0,0 @@ -############ -Visual parts -############ - -********* -Templates -********* - -There are a number of different templates for different pages in ADCM. Check them all here: - -.. _ui_templates_common: - -Common -====== - -Main template of the application is the following: - -.. image:: img/common_template.png - -Template parts are: - -* Main Menu - contains the following sections of ADCM: -* Navigation Menu - displays decomposition to active/current section. -* Right Menu - pop-up window when selecting sections such as "Reference section", "User section". -* Left Menu - contains the main sections when selecting a specific object (cluster, hostprovider, hosts etc) - - -.. note:: - TODO: We need to provide more information about parts. - - -Main Menu ---------- - -Main menu consist of the following elements: - - * CLUSTERS - link to :ref:`ui_templates_cluster_list_view`: - * HOSTPROVIDERS - * HOSTS - * JOBS - * BUNDLES - * Job states (three circle in the right corner) - displays information about the number of jobs in the process, success jobs, failed jobs. - * Reference section - displays information about "Ask for help" and documentation. - * User section - contains user profile settings, settings for working in ADCM, logout functionality from ADCM. - -.. _ui_templates_table_view: - -Table View -========== - -Table view is one of the main view of ADCM, which comes from adwp_ui. Table view is a container inside :ref:`ui_templates_common`. - -As example of the table view take a look at cluster list view: - -.. image:: img/template_table_view_big.png - -Table could be in a nested containers two. For example we could see a table in object details view: - -.. image:: img/cluster_services_template.png - -Templates parts are: - -* **Headers** - just a table headers -* **Text Cells** - an information in text form. In some cases it could be sorted. -* **Button Cells** - an action items in form of various icons. -* **Action Button** - an item related to some action typicly related to a new object creation. -* **Links** - an element, which is responsible for jumping to related object. - -Clusters -======== - -.. _ui_templates_cluster_list_view: - -Cluster List View ------------------ - -Cluster List View is a view based on :ref:`ui_templates_table_view` - -"CLUSTERS" element in Navigation Menu marked as selected. - -Template parts are: - -* Navigation Menu with an indication of the decomposition to the selected section. -* Button "Create cluster" - allows you to create a cluster. -* Tabular section which includes the following fields: - * **Name** - contains information about the name of the cluster (sorting supported). - * **Bundle** - contains information about the name of the :term:`Bundle` on the basis of which the cluster was added (sorting supported). - * **Description** - contains additional information. Filled when adding a cluster. - * **State** - contains information about the current state of the cluster (sorting supported). - * **Status** - contains information about the current status of the cluster (sorting supported). - * **Actions** - provides a choice of what action to perform on the cluster (install, start, stop). - * **Import** - ??? - * **Upgrade** - allows to update the selected cluster. - * **Config** - allows to go to the settings of the selected cluster. -* List of added clusters with information according to table fields. -* Button to delete an entry from the list of clusters -* Pagination of the list of clusters - -.. _ui_templates_cluster-services: - -Сluster's service list ----------------------- - -The list of cluster services looks like this: - - -Template parts are: - -* Navigation Menu with an indication of the decomposition to the selected section, actions that can be performed on the cluster (start, stop, install, update). -* Cluster name information and link to cluster bundle. -* Button "Add services" - allows you to add services to the cluster. -* Left menu with the following sections (active partition is highlighted): - * **Main** - * **Services** - * **Hosts** - * **Host - Components** - * **Configuration** - * **Status** - * **Import** - * **Actions** -* Tabular section which includes the following fields: - * **Name** - contains information about the name of the service (sorting supported). - * **Version** - contains information about the version of the service. - * **State** - contains information about the current state of the service (sorting supported). - * **Status** - contains information about the current status of the service (sorting supported). - * **Actions** - provides a choice of what action to perform on the service (check, expand, restart, shrink, start, stop). - * **Import** - ??? - * **Config** - allows to go to the settings of the selected service. -* List of added services with information according to table fields. -* Pagination of the list of clusters - -.. _ui_templates_cluster_host_list_view: - -Сluster's host list --------------------- - -The list of host include in a cluster based on :ref:`ui_templates_table_view` - -Common parameters of template: - -* "CLUSTERS" element of "Main Menu" is selected -* Navigation menu point to a Cluster -* "Hosts" element of "Left Menu" is selected - -:ref:`ui_templates_table_view` columns: - -=============== ============================== -Header Value -=============== ============================== -FQDN FQDN in string format -Provider Link to related HostProvider -State State of host -Action Action Button -Config Link to config of the host -=============== ============================== - -***** -Forms -***** - -.. _ui_elements_forms_login: - -Login -===== - -There are two variants of login form. - -First is able to login over Google GAuth2. - -.. image:: img/form_login_full.png - - -Second allows to login with user/password only. - -.. image:: img/form_login_short.png - -Input fields: - -* **Login** - is an input to pass a username -* **Password** - is an input to pass a password. This field is protected and show no password actually. - -Buttons: - -* **Sign in with Google** - is a button that triggers GAuth2 login process -* **Login** - is a button which that triggers user/password login process - - -.. _ui_form_dialogs_common: - -Operation dialog -================ - -All operation dialogs has the same unified look: - -.. image:: img/form_dialog_create_cluster.png - -Elements of the dialog: - -* **Title** - this is the top of the dialog text which is the same as a on button clicked to call this dialog -* **Form Inputs** - there are a number of input fields which is required for action to proceed. Fields can be mandatory. -* **Cancel Button** - Just a "Cancel" which is the same on dialog. You could click on it to close the dialog without any operation happend. -* **Positive Button** - A button which triiger the operation (use case** for this dialog. The caption of this button has some variation in different dialogs. - - -.. _ui_form_dialogs_create_cluster: - -Create Cluster Dialog ---------------------- - -This a subset of :ref:`ui_form_dialogs_common` with the following options: - -============== =============== -Title Positive Button -============== =============== -Create cluster Create -============== =============== - -============== ========= ========== ====================================== -Input Name Mandatory Type Meaning -============== ========= ========== ====================================== -Bundle True Drop Down A list of cluster bundles uploaded to ADCM -Version True Drop Down A list of versions for selected bundle -Cluster name True String A short name of future cluster to be identified by user -Description False String Any additional information provided by user. -============== ========= ========== ====================================== - -.. _ui_form_dialogs_create_hostprovider: - -Create Host Provider Dialog ---------------------- - -This a subset of :ref:`ui_form_dialogs_common` with the following options: - -=============== =============== -Title Positive Button -=============== =============== -Create provider Create -=============== =============== - -================== ========= ========== ====================================== -Input Name Mandatory Type Meaning -================== ========= ========== ====================================== -Bundle True Drop Down A list of Host Provider bundles uploaded to ADCM -Version True Drop Down A list of versions for selected bundle -Hostprovider name True String A short name of future Host Provider to be identified by user -Description False String Any additional information provided by user. -================== ========= ========== ====================================== - -Upload Bundle -------------- - -************** -Other Elements -************** - -Popups -====== - -Issue/Flag Popup ----------------- - -This popup is for showing flags and issue provided by backend as an "agenda" endpoint. For every object in ADCM there is a way to rise flag. - -Format of flag entry in "agenda" endpoint could be seen in this example. - -.. code-block:: json - - { - "message": "Run ${action1} on on ${component1}.", - "id": 2039, - "placeholder": { - "action1": { - "type": "component_action_run", - "ids" : { - "cluster": 1, - "service": 2, - "component": 2, - "action": 22 - }, - "name": "Restart" - }, - "component1": { - "type": "component_config", - "ids" : { - "cluster": 1, - "service": 2, - "component": 2 - }, - "name": "My Component" - } - } - } - -Main parts of the format are: - -* "message" == The string which is show in UI -* "placeholder" == The objects which should be replaced in "message" - - -Main idea behind this format is the way to represent a clickable links or other templates in this format. Most of element like links could not be build on backend because of lack of information about pages, urls and elements. - -.. code-block:: json - - { - "component1": { - "type": "component_config_link", - "ids" : { - "cluster": 1, - "service": 2, - "component": 2 - }, - "name": "My Component" - } - } - -Here we have the following elements: - -* component1 == name of placeholder in a message (see full format above) -* type == it is a type of list (the way this list should be generated) -* ids == information required to build full URL in UI -* name == just a string to be place to element. - -So for this links we should build the following HTML element - -.. code-block:: html - - My Component diff --git a/spec/ui/img/cluster_services_template.png b/spec/ui/img/cluster_services_template.png deleted file mode 100644 index ede9ddb5f6676a132b9d0c73d0f1a23c7119d504..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102729 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�%*DqYZn7f<>#&F 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

eyoq_@TT#9`Y@^Y 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⪙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 DM*eG1 diff --git a/spec/ui/img/common_template.png b/spec/ui/img/common_template.png deleted file mode 100644 index 6ae310df2b9e7015f51107743284696bd6fea235..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186739 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⪙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

h|x@eTT!^qd3MpK^dpFa*- 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

lLZK8ZQe0Y`;ts)z6pFXF2Y0vNw57Ne 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 diff --git a/spec/ui/img/form_dialog_create_cluster.png b/spec/ui/img/form_dialog_create_cluster.png deleted file mode 100644 index 5b3f154325ad03496ba487f7506b80c00c86d45b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19446 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 Maapn4htFUCU%oxRp8x;= diff --git a/spec/ui/img/form_login_full.png b/spec/ui/img/form_login_full.png deleted file mode 100644 index 865baf2676832c5cef5b2301208a958b556526be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9932 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

-``` - -####directive: -```angular2html -
display_name
-``` - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/web/angular.json b/web/angular.json deleted file mode 100644 index 4459e704e6..0000000000 --- a/web/angular.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "adcm": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "preserveSymlinks": true, - "aot": true, - "outputPath": "dist", - "index": "src/index.html", - "main": "src/main.ts", - "tsConfig": "src/tsconfig.app.json", - "polyfills": "src/polyfills.ts", - "assets": [ - "src/assets" - ], - "styles": [ - "src/adcm-theme.scss", - "src/styles.scss", - "src/adcm2.scss" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "anyComponentStyle", - "maximumWarning": "6kb" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "aot": true, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "adcm:build" - }, - "configurations": { - "production": { - "browserTarget": "adcm:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "adcm:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "preserveSymlinks": true, - "main": "src/test.ts", - "karmaConfig": "./karma.conf.js", - "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.spec.json", - "scripts": [], - "styles": [ - "src/adcm-theme.scss", - "src/styles.scss", - "src/adcm2.scss" - ], - "assets": [ - "src/assets" - ] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "src/tsconfig.app.json", - "src/tsconfig.spec.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - } - } - }, - "adcm-e2e": { - "root": "e2e", - "sourceRoot": "e2e", - "projectType": "application", - "architect": { - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "./protractor.conf.js", - "devServerTarget": "adcm:serve" - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "e2e/tsconfig.e2e.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - } - } - } - }, - "defaultProject": "adcm", - "schematics": { - "@schematics/angular:component": { - "prefix": "app", - "style": "scss" - }, - "@schematics/angular:directive": { - "prefix": "app" - } - } -} diff --git a/web/build.sh b/web/build.sh deleted file mode 100755 index fc784af352..0000000000 --- a/web/build.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -# Licensed 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. - -yarn config set registry https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ -yarn install -export PATH=./node_modules/.bin/:$PATH -ng build --prod --progress=false --no-delete-output-path --output-path /wwwroot adcm diff --git a/web/build_static.sh b/web/build_static.sh deleted file mode 100755 index 3e1ba7b0a5..0000000000 --- a/web/build_static.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -e -# Licensed 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. - -workdir=$(dirname "${0}") -cd "${workdir}/../" - -# That is dirty!!! -# Due to fact that setting.py loaded during any manage.py operation -# we have to have all environment ready. But during run of colectstatic -# on CI we have no data/log and that force logger to fails. -# So we temporary make that dir to remove after operation. -mkdir -p data/log - -python python/manage.py collectstatic --noinput - -cp ./wwwroot/static/rest_framework/css/* ./wwwroot/static/rest_framework/docs/css/ - -# If there is something in it we could leave it. -rmdir ../data/log || true diff --git a/web/documentation.json b/web/documentation.json deleted file mode 100644 index fb5159ad1f..0000000000 --- a/web/documentation.json +++ /dev/null @@ -1,68306 +0,0 @@ -{ - "pipes": [ - { - "name": "BellTaskLinkPipe", - "id": "pipe-BellTaskLinkPipe-9d9997d3625a3b7380aaa04dc1ee6953", - "file": "src/app/pipes/bell-task-link.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "task", - "type": "TaskRaw", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "[]", - "typeParameters": [], - "line": 10, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "task", - "type": "TaskRaw", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "bellTaskLink", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\nimport { TaskRaw } from '@app/core/types';\n\n@Pipe({\n name: 'bellTaskLink'\n})\nexport class BellTaskLinkPipe implements PipeTransform {\n\n transform(task: TaskRaw): (string | number)[] {\n if (task?.jobs?.length > 0) {\n if (task.status === 'failed') {\n const failedJob = task.jobs.find(job => job.status === 'failed');\n if (failedJob) {\n return ['job', failedJob.id, 'main'];\n }\n } else {\n return ['job', task.jobs[0].id, 'main'];\n }\n }\n\n return ['job', task.id, 'main'];\n }\n\n}\n" - }, - { - "name": "BreakRowPipe", - "id": "pipe-BreakRowPipe-e121b6c3f4d1307214e75bdbdcf6e163", - "file": "src/app/shared/pipes/break-row.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "args", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 17, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "args", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "breakRow", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n@Pipe({\n name: 'breakRow',\n})\nexport class BreakRowPipe implements PipeTransform {\n transform(value: string, args?: any): any {\n return value.replace(/\\n|\\\\n/g, '
');\n }\n}\n" - }, - { - "name": "ConcernMenuItemPipe", - "id": "pipe-ConcernMenuItemPipe-4f809746194426f5a960a43fdca41da2", - "file": "src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "value", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cause", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 9, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cause", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "concernMenuItem", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\nimport { BaseEntity } from '@app/core/types';\n\n@Pipe({\n name: 'concernMenuItem'\n})\nexport class ConcernMenuItemPipe implements PipeTransform {\n\n transform(value: BaseEntity, cause: string): boolean {\n const concerns = value && value.concerns;\n if (!(concerns && concerns.length)) return false;\n\n return !!concerns.filter((c) => c.cause === cause).length;\n }\n\n}\n" - }, - { - "name": "EntityStatusToStatusTreePipe", - "id": "pipe-EntityStatusToStatusTreePipe-05231230e000cae557009614e36b27a7", - "file": "src/app/pipes/entity-status-to-status-tree.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "value", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "entityService", - "type": "HavingStatusTreeAbstractService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "StatusTree[]", - "typeParameters": [ - "StatusTreeType", - "EntityType" - ], - "line": 12, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "entityService", - "type": "HavingStatusTreeAbstractService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "entityStatusToStatusTree", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\nimport { StatusTree, StatusTreeSubject } from '@app/models/status-tree';\nimport { HavingStatusTreeAbstractService } from '../abstract/having-status-tree.abstract.service';\nimport { AdcmEntity } from '@app/models/entity';\n\n@Pipe({\n name: 'entityStatusToStatusTree'\n})\nexport class EntityStatusToStatusTreePipe implements PipeTransform {\n\n transform(\n value: StatusTreeType,\n entityService: HavingStatusTreeAbstractService,\n data: any,\n ): StatusTree[] {\n return value ? entityService.entityStatusTreeToStatusTree(value, data) : [];\n }\n\n}\n" - }, - { - "name": "IsArrayPipe", - "id": "pipe-IsArrayPipe-ac031b1519dc2821002587933eab9e74", - "file": "src/app/pipes/is-array.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "value", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "", - "typeParameters": [], - "line": 8, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "isArray", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'isArray'\n})\nexport class IsArrayPipe implements PipeTransform {\n\n transform(value: any): unknown {\n return Array.isArray(value);\n }\n\n}\n" - }, - { - "name": "IssueMessagePlaceholderPipe", - "id": "pipe-IssueMessagePlaceholderPipe-cce498d96653998b9928324c51e8370d", - "file": "src/app/pipes/issue-message-placeholder.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 8, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "issueMessagePlaceholder", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'issueMessagePlaceholder'\n})\nexport class IssueMessagePlaceholderPipe implements PipeTransform {\n\n transform(value: string): string {\n return value.replace(/(\\$\\{)|(\\})/g, '');\n }\n\n}\n" - }, - { - "name": "IssuePathPipe", - "id": "pipe-IssuePathPipe-81cb5ca7b4ee8c3de81f1f39c6eddfec", - "file": "src/app/pipes/issue-path.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "issueName", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "issueType", - "type": "IssueType", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 19, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "issueName", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "issueType", - "type": "IssueType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "issuePath", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\nimport { map } from 'rxjs/operators';\nimport { Observable, of } from 'rxjs';\n\nimport { ServiceService } from '@app/services/service.service';\nimport { IssueType } from '@app/models/issue';\nimport { ServiceComponentService } from '@app/services/service-component.service';\n\n@Pipe({\n name: 'issuePath'\n})\nexport class IssuePathPipe implements PipeTransform {\n\n constructor(\n private serviceService: ServiceService,\n private serviceComponentService: ServiceComponentService,\n ) {}\n\n transform(issueName: string, issueType: IssueType, id: number): Observable {\n let issue = issueName;\n if (issue === 'required_import') {\n issue = 'import';\n }\n\n if (issueType === 'service') {\n return this.serviceService.get(id)\n .pipe(map(\n service => `/cluster/${service.cluster_id}/${issueType}/${id}/${issue}`,\n ));\n } else if (issueType === 'servicecomponent' || issueType === 'component') {\n return this.serviceComponentService.get(id)\n .pipe(map(\n component => `/cluster/${component.cluster_id}/service/${component.service_id}/component/${id}/${issue}`,\n ));\n } {\n return of(`/${issueType}/${id}/${issue}`);\n }\n }\n\n}\n" - }, - { - "name": "KeysPipe", - "id": "pipe-KeysPipe-357d3d3ef0d1196244276cefc9850ae4", - "file": "src/app/pipes/keys.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "value", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "", - "typeParameters": [], - "line": 8, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "keys", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'keys'\n})\nexport class KeysPipe implements PipeTransform {\n\n transform(value: any): unknown {\n return Object.keys(value || {});\n }\n\n}\n" - }, - { - "name": "NavItemPipe", - "id": "pipe-NavItemPipe-baf8797bee82dd34036d8703298cbaf4", - "file": "src/app/pipes/nav-item.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "getEntityTitle", - "args": [ - { - "name": "entity", - "type": "AdcmTypedEntity", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 90, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "AdcmTypedEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getGroupName", - "args": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 12, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getLink", - "args": [ - { - "name": "path", - "type": "AdcmTypedEntity[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "index", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "group", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "path", - "type": "AdcmTypedEntity[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "index", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "group", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "transform", - "args": [ - { - "name": "path", - "type": "AdcmTypedEntity[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IStyledNavItem[]", - "typeParameters": [], - "line": 94, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "path", - "type": "AdcmTypedEntity[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "navItem", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\nimport { AdcmTypedEntity } from '@app/models/entity';\nimport { IStyledNavItem } from '@app/models/details';\nimport { ApiFlat, TypeName } from '@app/core/types';\n\n@Pipe({\n name: 'navItem'\n})\nexport class NavItemPipe implements PipeTransform {\n\n getGroupName(typeName: TypeName): string {\n switch (typeName) {\n case 'cluster':\n return 'clusters';\n case 'service':\n return 'services';\n case 'servicecomponent':\n return 'components';\n case 'component':\n return 'components';\n case 'host':\n return 'hosts';\n case 'provider':\n return 'hostproviders';\n case 'group_config':\n return 'groupconfigs';\n }\n }\n\n getLink(path: AdcmTypedEntity[], index: number, group: boolean): string {\n let cluster: AdcmTypedEntity;\n\n switch (path[index].typeName) {\n case 'cluster':\n return group ? `/${path[index].typeName}` : `/${path[index].typeName}/${path[index].id}`;\n case 'service':\n return group ? (\n `/${path[index - 1].typeName}/${path[index - 1].id}/service`\n ) : (\n `/${path[index - 1].typeName}/${path[index - 1].id}/service/${path[index].id}`\n );\n case 'servicecomponent':\n case 'component':\n return group ? (\n `/${path[index - 2].typeName}/${path[index - 2].id}/service/${path[index - 1].id}/component`\n ) : (\n `/${path[index - 2].typeName}/${path[index - 2].id}/service/${path[index - 1].id}/component/${path[index].id}`\n );\n case 'host':\n cluster = path.find(item => item.typeName === 'cluster');\n if (cluster) {\n return group ? (\n `/${cluster.typeName}/${cluster.id}/host`\n ) : (\n `/${cluster.typeName}/${cluster.id}/host/${path[index].id}`\n );\n\n }\n return group ? `/${path[index].typeName}` : `/${path[index].typeName}/${path[index].id}`;\n case 'provider':\n return group ? `/${path[index].typeName}` : `/${path[index].typeName}/${path[index].id}`;\n case 'group_config':\n cluster = path[0];\n const { object_type, object_id, id } = (path[index] as unknown as ApiFlat);\n if (object_type === 'service') {\n return group ? (\n `/${cluster.typeName}/${cluster.id}/${object_type}/${object_id}/group_config`\n ) : (\n `/${cluster.typeName}/${cluster.id}/${object_type}/${object_id}/group_config/${id}`\n );\n } else if (object_type === 'component') {\n return group ? (\n `/${path[index - 3].typeName}/${path[index - 3].id}/service/${path[index - 2].id}/component/${path[index-1].id}/group_config`\n ) : (\n `/${path[index - 3].typeName}/${path[index - 3].id}/service/${path[index - 2].id}/component/${path[index-1].id}/group_config/${id}`\n );\n }\n {\n return group ? (\n `/${object_type}/${object_id}/group_config`\n ) : (\n `/${object_type}/${object_id}/group_config/${id}`\n );\n }\n\n }\n }\n\n getEntityTitle(entity: AdcmTypedEntity): string {\n return entity.typeName === 'host' ? entity.fqdn : entity.display_name || entity.name;\n }\n\n transform(path: AdcmTypedEntity[]): IStyledNavItem[] {\n return path?.reduce((acc, item, index) => {\n return [\n ...acc,\n {\n title: this.getGroupName(item.typeName),\n url: this.getLink(path, index, true),\n class: 'type-name',\n },\n {\n title: this.getEntityTitle(item),\n url: this.getLink(path, index, false),\n class: 'entity',\n entity: item,\n }\n ] as IStyledNavItem[];\n }, []);\n }\n\n}\n" - }, - { - "name": "ObjectLinkColumnPipe", - "id": "pipe-ObjectLinkColumnPipe-0e1e1798558147aca01c6c701d261f5a", - "file": "src/app/pipes/object-link-column.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "object", - "type": "JobObject", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "task", - "type": "Task", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "ILinkColumn", - "typeParameters": [], - "line": 16, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "object", - "type": "JobObject", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "task", - "type": "Task", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "url", - "args": [ - { - "name": "object", - "type": "JobObject", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "task", - "type": "Task", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string[]", - "typeParameters": [], - "line": 12, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "object", - "type": "JobObject", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "task", - "type": "Task", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "objectLinkColumn", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\nimport { ILinkColumn } from '@adwp-ui/widgets';\n\nimport { JobObject, Task } from '../core/types';\nimport { ObjectsHelper } from '../helpers/objects-helper';\n\n@Pipe({\n name: 'objectLinkColumn'\n})\nexport class ObjectLinkColumnPipe implements PipeTransform {\n\n url(object: JobObject, task: Task): string[] {\n return ObjectsHelper.getObjectUrl(object, task.objects);\n }\n\n transform(object: JobObject, task: Task): ILinkColumn {\n return {\n label: '',\n type: 'link',\n value: () => object.name,\n url: () => this.url(object, task).join('/'),\n };\n }\n\n}\n" - }, - { - "name": "PickKeysPipe", - "id": "pipe-PickKeysPipe-56dd529d300aaf1182c279ee7b62e12e", - "file": "src/app/pipes/pick-keys.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "object", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "keys", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "literal type", - "typeParameters": [], - "line": 8, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "object", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "keys", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "pickKeys", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'pickKeys'\n})\nexport class PickKeysPipe implements PipeTransform {\n\n transform(object: { [key: string]: any }, keys: string[]): { [key: string]: any } {\n return keys.reduce((result, key) => ({ ...result, [key]: object[key] }), {});\n }\n\n}\n" - }, - { - "name": "SortObjectsPipe", - "id": "pipe-SortObjectsPipe-cebb9ffc281835f71f3dcd9a322ecc6c", - "file": "src/app/pipes/sort-objects.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "JobObject[]", - "typeParameters": [], - "line": 11, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "sortObjects", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\nimport { JobObject } from '../core/types';\nimport { ObjectsHelper } from '../helpers/objects-helper';\n\n@Pipe({\n name: 'sortObjects'\n})\nexport class SortObjectsPipe implements PipeTransform {\n\n transform(objects: JobObject[]): JobObject[] {\n return ObjectsHelper.sortObjects(objects);\n }\n\n}\n" - }, - { - "name": "StatusTreeLinkPipe", - "id": "pipe-StatusTreeLinkPipe-51e68f2e6658409914d30c35f033e987", - "file": "src/app/pipes/status-tree-link.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "tree", - "type": "StatusTree[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "func", - "type": "StatusTreeLinkFunc", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string[]", - "typeParameters": [], - "line": 10, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "tree", - "type": "StatusTree[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "func", - "type": "StatusTreeLinkFunc", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "statusTreeLink", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\nimport { StatusTree, StatusTreeLinkFunc } from '@app/models/status-tree';\n\n@Pipe({\n name: 'statusTreeLink'\n})\nexport class StatusTreeLinkPipe implements PipeTransform {\n\n transform(id: number, tree: StatusTree[], func: StatusTreeLinkFunc): string[] {\n return func(id, tree);\n }\n\n}\n" - }, - { - "name": "TagEscPipe", - "id": "pipe-TagEscPipe-11f3e8d00e60a7047a20fce0420b7125", - "file": "src/app/shared/pipes/tag-esc.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "args", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 18, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "args", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "tagEsc", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'tagEsc',\n})\nexport class TagEscPipe implements PipeTransform {\n transform(value: string, args?: any): any {\n if (value) return value.replace(//g, '>').replace(/\\\\n/g, '
');\n }\n}\n" - }, - { - "name": "ToDataSourcePipe", - "id": "pipe-ToDataSourcePipe-98af7b501fba5e70ded56ababac271df", - "file": "src/app/pipes/to-data-source.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "model", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "literal type", - "typeParameters": [], - "line": 8, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "model", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "toDataSource", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'toDataSource'\n})\nexport class ToDataSourcePipe implements PipeTransform {\n\n transform(model: { [key: string]: any }): { results: any[]; count: number; } {\n if (!model) {\n return { results: [], count: 0 };\n }\n\n const results = Object.entries(model)\n .reduce((acc, [key, value]) => {\n return [...acc, { key, value }];\n }, []);\n\n return { results, count: 0 };\n }\n\n}\n" - }, - { - "name": "TranslateKeysPipe", - "id": "pipe-TranslateKeysPipe-9dde61c630ab134f977afae6517a5dae", - "file": "src/app/pipes/translate-object-keys.pipe.ts", - "type": "pipe", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "properties": [], - "methods": [ - { - "name": "transform", - "args": [ - { - "name": "object", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "literal type", - "typeParameters": [], - "line": 11, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "object", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "ngname": "translateKeys", - "sourceCode": "import { Pipe, PipeTransform } from '@angular/core';\nimport { TranslateService } from '@ngx-translate/core';\n\n@Pipe({\n name: 'translateKeys'\n})\nexport class TranslateKeysPipe implements PipeTransform {\n\n constructor(private _translate: TranslateService) {}\n\n transform(object: { [key: string]: any }): { [key: string]: any } {\n if (!object) {\n return {};\n }\n\n return Object.entries(object)\n .reduce((acc, [key, value]) => {\n return {\n ...acc,\n [this._translate.instant(key)]: value\n }\n }, {});\n }\n\n}\n" - } - ], - "interfaces": [ - { - "name": "ActionParameters", - "id": "interface-ActionParameters-4a99492dc98d6050cef89c3777395d3d", - "file": "src/app/shared/components/actions/actions.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Directive, HostListener, Input } from '@angular/core';\nimport { MatDialog, MatDialogConfig } from '@angular/material/dialog';\nimport { IAction } from '@app/core/types';\n\nimport { DialogComponent } from '../dialog.component';\nimport { ActionMasterComponent as component } from './master/master.component';\n\nexport interface ActionParameters {\n cluster?: {\n id: number;\n hostcomponent: string;\n };\n actions: IAction[];\n}\n\n@Directive({\n selector: '[appActions]'\n})\nexport class ActionsDirective {\n @Input('appActions') inputData: ActionParameters;\n\n constructor(private dialog: MatDialog) {}\n\n @HostListener('click')\n onClick() {\n this.dialog.closeAll();\n const dialogModel: MatDialogConfig = this.prepare();\n this.dialog.open(DialogComponent, dialogModel);\n }\n\n prepare(): MatDialogConfig {\n const maxWidth = '1400px';\n const model = this.inputData;\n\n if (!model.actions?.length) return { data: { title: 'No parameters for run the action', model: null, component: null } };\n\n const act = model.actions[0];\n const isMulty = model.actions.length > 1;\n\n const width = isMulty || act.config?.config.length || act.hostcomponentmap?.length ? '90%' : '400px';\n const title = act.ui_options?.disclaimer ? act.ui_options.disclaimer : isMulty ? 'Run an actions?' : `Run an action [ ${act.display_name} ]?`;\n\n return {\n width,\n maxWidth,\n data: {\n title,\n model,\n component,\n }\n };\n }\n}\n", - "properties": [ - { - "name": "actions", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction[]", - "optional": false, - "description": "", - "line": 24 - }, - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": true, - "description": "", - "line": 20 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "AdcmEntity", - "id": "interface-AdcmEntity-c446613764b686aea3918d5bb5bb4586", - "file": "src/app/models/entity.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Entity } from '@adwp-ui/widgets';\nimport { TypeName } from '@app/core/types';\n\nexport interface AdcmEntity extends Entity {\n name?: string;\n display_name?: string;\n fqdn?: string;\n}\n\nexport interface AdcmTypedEntity extends AdcmEntity {\n typeName: TypeName;\n}\n", - "properties": [ - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 6 - }, - { - "name": "fqdn", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 7 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 5 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "Entity" - }, - { - "name": "AdcmTypedEntity", - "id": "interface-AdcmTypedEntity-c446613764b686aea3918d5bb5bb4586", - "file": "src/app/models/entity.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Entity } from '@adwp-ui/widgets';\nimport { TypeName } from '@app/core/types';\n\nexport interface AdcmEntity extends Entity {\n name?: string;\n display_name?: string;\n fqdn?: string;\n}\n\nexport interface AdcmTypedEntity extends AdcmEntity {\n typeName: TypeName;\n}\n", - "properties": [ - { - "name": "typeName", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 11 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "AdcmEntity" - }, - { - "name": "AddClusterEventData", - "id": "interface-AddClusterEventData-b821baa6ddbe88af207bd4338cb664ea", - "file": "src/app/components/columns/cluster-column/cluster-column.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, Input, Output, EventEmitter } from '@angular/core';\nimport { AdwpCellComponent, ILinkColumn, EventHelper } from '@adwp-ui/widgets';\n\nimport { IHost } from '@app/models/host';\nimport { UniversalAdcmEventData } from '@app/models/universal-adcm-event-data';\nimport { ICluster } from '@app/models/cluster';\n\nexport interface AddClusterEventData extends UniversalAdcmEventData {\n cluster: ICluster;\n}\n\n@Component({\n selector: 'app-cluster-column',\n template: `\n \n \n\n \n \n ...\n \n {{ item.title }}\n \n \n \n\n \n `,\n styles: [`\n :host {\n width: 100%;\n }\n `],\n})\nexport class ClusterColumnComponent implements AdwpCellComponent {\n\n EventHelper = EventHelper;\n\n @Input() row: IHost;\n\n @Output() onGetNextPageCluster = new EventEmitter>();\n @Output() onGetClusters = new EventEmitter>();\n @Output() onAddCluster = new EventEmitter();\n\n linkColumn: ILinkColumn = {\n label: '',\n type: 'link',\n value: (row) => row.cluster_name,\n url: (row) => `/cluster/${row.cluster_id}`,\n };\n\n getNextPageCluster(event: MouseEvent) {\n this.onGetNextPageCluster.emit({ event, action: 'getNextPageCluster', row: this.row });\n }\n\n getClusters(event: MouseEvent) {\n this.onGetClusters.emit({ event, action: 'getClusters', row: this.row });\n }\n\n addCluster(event: MouseEvent, cluster: ICluster) {\n this.onAddCluster.emit({ event, action: 'addCluster', row: this.row, cluster });\n }\n\n}\n", - "properties": [ - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "ICluster", - "optional": false, - "description": "", - "line": 9 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "UniversalAdcmEventData" - }, - { - "name": "ApiFlat", - "id": "interface-ApiFlat-0cbb246102564bc134c66dc61b2dabe6", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IAction } from './actions';\nimport { IComponent } from './host-component';\nimport { Job, Task } from './task-job';\nimport { AdcmEntity } from '@app/models/entity';\nimport { IIssues } from '@app/models/issue';\nimport { ICluster } from '@app/models/cluster';\nimport { Concern } from '@app/models/concern/concern';\n\nexport type TypeName =\n 'bundle' |\n 'cluster' |\n 'host' |\n 'provider' |\n 'service' |\n 'job' |\n 'task' |\n 'user' |\n 'profile' |\n 'adcm' |\n 'stats' |\n 'hostcomponent' |\n 'service2cluster' |\n 'host2cluster' |\n 'servicecomponent' |\n 'component' |\n 'group_config' |\n 'group_config_hosts';\nexport type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle;\n\n/**\n *```\n {\n [key: string]: string;\n }\n ```\n */\nexport interface IRoot {\n [key: string]: string;\n}\n\nexport interface BaseEntity extends AdcmEntity {\n typeName: TypeName;\n description?: string;\n url: string;\n state?: string;\n config: string;\n action?: string;\n actions?: IAction[];\n issue?: IIssues;\n prototype_id?: number;\n prototype_name?: string;\n prototype_display_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n status?: number | string;\n concerns: Concern[];\n locked: boolean;\n}\n\nexport interface ApiFlat {\n id: number;\n object_id: number;\n object_type: TypeName;\n url: string;\n}\n\nexport interface Provider extends BaseEntity {\n host: string;\n}\n\nexport interface Host extends BaseEntity {\n fqdn: string;\n provider_id: number;\n cluster: string;\n cluster_id?: number;\n cluster_name?: string;\n}\n\nexport interface Service extends BaseEntity {\n components: IComponent[];\n status: number;\n hostcomponent: string;\n display_name: string;\n cluster_id?: number;\n group_config: string;\n}\n\nexport interface CanLicensed {\n license: 'unaccepted' | 'accepted' | 'absent';\n license_url: string;\n}\n\nexport interface License {\n accept: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n text: string;\n}\n\nexport interface Bundle extends BaseEntity, CanLicensed {\n [key: string]: any;\n}\n", - "properties": [ - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 73 - }, - { - "name": "object_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 74 - }, - { - "name": "object_type", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 75 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 76 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ApiState", - "id": "interface-ApiState-18a90fa4fedd48681bf24a69bde5f2f7", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IRoot } from '@app/core/types/api';\nimport { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props } from '@ngrx/store';\n\nexport const loadRoot = createAction('[API] LoadRoot');\nexport const loadStack = createAction('[API] LoadStack');\nexport const rootSuccess = createAction('[API] LoadRootSuccess', props<{ root: IRoot }>());\nexport const rootError = createAction('[API] LoadRootError');\nexport const stackSuccess = createAction('[API] LoadStackSuccess', props<{ stack: IRoot }>());\n\nexport interface ApiState {\n root: IRoot;\n stack: IRoot;\n}\n\nconst InitState: ApiState = {\n root: null,\n stack: null,\n};\n\nconst reducer = createReducer(\n InitState,\n on(rootSuccess, (state, { root }) => ({ ...state, root })),\n on(rootError, state => ({ root: null, stack: null })),\n on(stackSuccess, (state, { stack }) => ({ ...state, stack }))\n);\n\nexport function apiReducer(state: ApiState, action: Action) {\n return reducer(state, action);\n}\n\nexport const getApiState = createFeatureSelector('api');\nexport const getRoot = createSelector(\n getApiState,\n (state: ApiState) => state.root\n);\nexport const getStack = createSelector(\n getApiState,\n (state: ApiState) => state.stack\n);\n", - "properties": [ - { - "name": "root", - "deprecated": false, - "deprecationMessage": "", - "type": "IRoot", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "stack", - "deprecated": false, - "deprecationMessage": "", - "type": "IRoot", - "optional": false, - "description": "", - "line": 23 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "AttributeOptions", - "id": "interface-AttributeOptions-651cfdba3f000923bbee8d3d05505de6", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Inject, Injectable, InjectionToken, TemplateRef, Type } from '@angular/core';\nimport { FormBuilder, FormGroup } from '@angular/forms';\nimport { IFieldOptions } from '@app/shared/configuration/types';\nimport { isBoolean, isEmptyObject } from '@app/core/types';\nimport { FieldComponent } from '@app/shared/configuration/field/field.component';\n\nexport const ATTRIBUTES_OPTIONS = new InjectionToken('Attributes options');\n\nexport interface AttributeOptions {\n name: ConfigAttributeNames;\n wrapper?: Type;\n options?: ConfigAttributeOptions;\n}\n\nexport type AttributesOptions = Record\n\nexport interface AttributeWrapper {\n fieldTemplate: TemplateRef;\n wrapperOptions: ConfigAttributeOptions;\n fieldOptions: IFieldOptions;\n attributeForm: FormGroup;\n parametersForm: FormGroup;\n field: FieldComponent;\n}\n\nexport enum ConfigAttributeNames {\n // an attribute for adding config parameters to group\n GROUP_KEYS = 'group_keys',\n // an attribute for config parameters that determines whether this parameter can be added to the config group\n CUSTOM_GROUP_KEYS = 'custom_group_keys'\n}\n\nexport interface ConfigAttributesJSON {\n [key: string]: any;\n}\n\nexport interface ConfigAttributeOptions {\n tooltipText?: string;\n\n [key: string]: any;\n}\n\nexport type ConfigAttribute = AttributeOptions & { value: ConfigAttributesJSON, form: FormGroup };\n\nexport type Attributes = Map;\n\n@Injectable()\nexport class AttributeService {\n\n private readonly _activeAttributes: Partial[] = [\n ConfigAttributeNames.GROUP_KEYS,\n ConfigAttributeNames.CUSTOM_GROUP_KEYS\n ];\n\n get attributes(): Attributes {\n return this._attributes;\n }\n\n private _attributes: Attributes;\n\n constructor(@Inject(ATTRIBUTES_OPTIONS) private _configs: AttributesOptions, private _fb: FormBuilder) {\n }\n\n init(json: ConfigAttributesJSON): void {\n this._attributes = this._createAttributes(this._activeAttributes, json, this._configs);\n }\n\n getByName(name: ConfigAttributeNames): ConfigAttribute {\n return this._attributes.has(name) ? this._attributes.get(name) : undefined;\n }\n\n private _createAttributes(_activeAttributes: Partial[], json: ConfigAttributesJSON, configs: AttributesOptions): Attributes {\n const isEmptyAttrs = !Object.keys(json || {}).length;\n const isActiveAttrsPresent = !!Object.keys(json || {}).filter((x: ConfigAttributeNames) => this._activeAttributes.includes(x)).length;\n if (isEmptyAttrs || !isActiveAttrsPresent) {\n return;\n }\n\n return new Map(this._activeAttributes.map((attr) => [\n attr,\n new ConfigAttributeFactory(this._fb).create(attr, json[attr], configs[attr], json),\n ]));\n }\n\n\n rawAttributes() {\n let json = {};\n if (this._attributes) {\n for (const [key, value] of this._attributes.entries()) {\n json = {\n ...json,\n [key]: value.form.value\n };\n }\n }\n\n return json;\n }\n}\n\nexport const createFormForAttribute = (fb: FormBuilder, json: ConfigAttributesJSON, attr: ConfigAttributeNames, disabled: boolean = false): FormGroup => {\n const buildFormGroup = (json: boolean | ConfigAttributesJSON) => {\n const data = Object.entries(json).map(([key, value]) => [key, value]).reduce((acc, [key, value]: [string, boolean | ConfigAttributesJSON]) => {\n\n if (isBoolean(value) || isEmptyObject(value)) {\n return {\n ...acc,\n [key]: { value, disabled }\n };\n } else if (!isEmptyObject(value)) {\n return { ...acc, [key]: buildFormGroup(value) };\n }\n\n }, {});\n\n return fb.group(data);\n };\n\n return buildFormGroup(json[attr]);\n};\n\n\nexport class ConfigAttributeFactory {\n\n constructor(private fb: FormBuilder) {}\n\n create(name: ConfigAttributeNames, value: ConfigAttributesJSON, options: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n if (!this[name]) {\n return;\n }\n\n return this[name](value, options, json);\n }\n\n [ConfigAttributeNames.GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options,\n wrapper\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return {\n name,\n value,\n wrapper,\n options,\n form\n };\n }\n\n [ConfigAttributeNames.CUSTOM_GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return { name, value, options, form };\n }\n\n}\n", - "properties": [ - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "ConfigAttributeNames", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "options", - "deprecated": false, - "deprecationMessage": "", - "type": "ConfigAttributeOptions", - "optional": true, - "description": "", - "line": 12 - }, - { - "name": "wrapper", - "deprecated": false, - "deprecationMessage": "", - "type": "Type", - "optional": true, - "description": "", - "line": 11 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "AttributeWrapper", - "id": "interface-AttributeWrapper-651cfdba3f000923bbee8d3d05505de6", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Inject, Injectable, InjectionToken, TemplateRef, Type } from '@angular/core';\nimport { FormBuilder, FormGroup } from '@angular/forms';\nimport { IFieldOptions } from '@app/shared/configuration/types';\nimport { isBoolean, isEmptyObject } from '@app/core/types';\nimport { FieldComponent } from '@app/shared/configuration/field/field.component';\n\nexport const ATTRIBUTES_OPTIONS = new InjectionToken('Attributes options');\n\nexport interface AttributeOptions {\n name: ConfigAttributeNames;\n wrapper?: Type;\n options?: ConfigAttributeOptions;\n}\n\nexport type AttributesOptions = Record\n\nexport interface AttributeWrapper {\n fieldTemplate: TemplateRef;\n wrapperOptions: ConfigAttributeOptions;\n fieldOptions: IFieldOptions;\n attributeForm: FormGroup;\n parametersForm: FormGroup;\n field: FieldComponent;\n}\n\nexport enum ConfigAttributeNames {\n // an attribute for adding config parameters to group\n GROUP_KEYS = 'group_keys',\n // an attribute for config parameters that determines whether this parameter can be added to the config group\n CUSTOM_GROUP_KEYS = 'custom_group_keys'\n}\n\nexport interface ConfigAttributesJSON {\n [key: string]: any;\n}\n\nexport interface ConfigAttributeOptions {\n tooltipText?: string;\n\n [key: string]: any;\n}\n\nexport type ConfigAttribute = AttributeOptions & { value: ConfigAttributesJSON, form: FormGroup };\n\nexport type Attributes = Map;\n\n@Injectable()\nexport class AttributeService {\n\n private readonly _activeAttributes: Partial[] = [\n ConfigAttributeNames.GROUP_KEYS,\n ConfigAttributeNames.CUSTOM_GROUP_KEYS\n ];\n\n get attributes(): Attributes {\n return this._attributes;\n }\n\n private _attributes: Attributes;\n\n constructor(@Inject(ATTRIBUTES_OPTIONS) private _configs: AttributesOptions, private _fb: FormBuilder) {\n }\n\n init(json: ConfigAttributesJSON): void {\n this._attributes = this._createAttributes(this._activeAttributes, json, this._configs);\n }\n\n getByName(name: ConfigAttributeNames): ConfigAttribute {\n return this._attributes.has(name) ? this._attributes.get(name) : undefined;\n }\n\n private _createAttributes(_activeAttributes: Partial[], json: ConfigAttributesJSON, configs: AttributesOptions): Attributes {\n const isEmptyAttrs = !Object.keys(json || {}).length;\n const isActiveAttrsPresent = !!Object.keys(json || {}).filter((x: ConfigAttributeNames) => this._activeAttributes.includes(x)).length;\n if (isEmptyAttrs || !isActiveAttrsPresent) {\n return;\n }\n\n return new Map(this._activeAttributes.map((attr) => [\n attr,\n new ConfigAttributeFactory(this._fb).create(attr, json[attr], configs[attr], json),\n ]));\n }\n\n\n rawAttributes() {\n let json = {};\n if (this._attributes) {\n for (const [key, value] of this._attributes.entries()) {\n json = {\n ...json,\n [key]: value.form.value\n };\n }\n }\n\n return json;\n }\n}\n\nexport const createFormForAttribute = (fb: FormBuilder, json: ConfigAttributesJSON, attr: ConfigAttributeNames, disabled: boolean = false): FormGroup => {\n const buildFormGroup = (json: boolean | ConfigAttributesJSON) => {\n const data = Object.entries(json).map(([key, value]) => [key, value]).reduce((acc, [key, value]: [string, boolean | ConfigAttributesJSON]) => {\n\n if (isBoolean(value) || isEmptyObject(value)) {\n return {\n ...acc,\n [key]: { value, disabled }\n };\n } else if (!isEmptyObject(value)) {\n return { ...acc, [key]: buildFormGroup(value) };\n }\n\n }, {});\n\n return fb.group(data);\n };\n\n return buildFormGroup(json[attr]);\n};\n\n\nexport class ConfigAttributeFactory {\n\n constructor(private fb: FormBuilder) {}\n\n create(name: ConfigAttributeNames, value: ConfigAttributesJSON, options: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n if (!this[name]) {\n return;\n }\n\n return this[name](value, options, json);\n }\n\n [ConfigAttributeNames.GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options,\n wrapper\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return {\n name,\n value,\n wrapper,\n options,\n form\n };\n }\n\n [ConfigAttributeNames.CUSTOM_GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return { name, value, options, form };\n }\n\n}\n", - "properties": [ - { - "name": "attributeForm", - "deprecated": false, - "deprecationMessage": "", - "type": "FormGroup", - "optional": false, - "description": "", - "line": 21 - }, - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "type": "FieldComponent", - "optional": false, - "description": "", - "line": 23 - }, - { - "name": "fieldOptions", - "deprecated": false, - "deprecationMessage": "", - "type": "IFieldOptions", - "optional": false, - "description": "", - "line": 20 - }, - { - "name": "fieldTemplate", - "deprecated": false, - "deprecationMessage": "", - "type": "TemplateRef", - "optional": false, - "description": "", - "line": 18 - }, - { - "name": "parametersForm", - "deprecated": false, - "deprecationMessage": "", - "type": "FormGroup", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "wrapperOptions", - "deprecated": false, - "deprecationMessage": "", - "type": "ConfigAttributeOptions", - "optional": false, - "description": "", - "line": 19 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "AuthState", - "id": "interface-AuthState-c93cd801beead75ee8f3180f3314d660", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\nimport { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props } from '@ngrx/store';\nimport { of } from 'rxjs';\nimport { catchError, map, switchMap, tap } from 'rxjs/operators';\n\nimport { AuthService } from './auth.service';\n\nexport const authCheck = createAction('[Auth] Check');\nexport const authLogin = createAction('[Auth] Login', props<{ login: string; password: string }>());\nexport const authSuccess = createAction('[Auth] LoginSuccess', props<{ login: string }>());\nexport const authFaled = createAction('[Auth] LoginFaled', props<{ message: string }>());\nexport const authLogout = createAction('[Auth] Logout');\n\nexport interface AuthState {\n isValid: boolean;\n message: string;\n}\n\nconst initialState: AuthState = {\n isValid: false,\n message: '',\n};\n\nconst reducer = createReducer(\n initialState,\n on(authSuccess, state => ({ isValid: true, message: 'Auth is success.' })),\n on(authFaled, (state, { message }) => ({ isValid: false, message })),\n on(authLogout, state => ({ isValid: false, message: '' }))\n);\n\nexport function authReducer(state: AuthState, action: Action) {\n return reducer(state, action);\n}\n\nexport const getAuthState = createFeatureSelector('auth');\nexport const isAuthenticated = createSelector(\n getAuthState,\n state => state.isValid\n);\n\n@Injectable()\nexport class AuthEffects {\n check$ = createEffect(() =>\n this.actions$.pipe(\n ofType(authCheck),\n map(() =>\n this.authService.auth.token\n ? authSuccess({ login: this.authService.auth.login })\n : authFaled({ message: 'User is not authorized!' })\n )\n )\n );\n\n auth$ = createEffect(\n () =>\n this.actions$.pipe(\n ofType(authLogin),\n switchMap(a =>\n this.authService.login(a.login, a.password).pipe(\n map(() => authSuccess({ login: a.login })),\n catchError(() => of(authFaled({ message: 'Incorrect password or user.' })))\n )\n )\n ),\n { useEffectsErrorHandler: true }\n );\n\n logout$ = createEffect(\n () =>\n this.actions$.pipe(\n ofType(authLogout),\n tap(() => this.authService.logout())\n ),\n { dispatch: false }\n );\n\n constructor(private actions$: Actions, private authService: AuthService) {}\n}\n", - "properties": [ - { - "name": "isValid", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "message", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 28 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "BaseEntity", - "id": "interface-BaseEntity-0cbb246102564bc134c66dc61b2dabe6", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IAction } from './actions';\nimport { IComponent } from './host-component';\nimport { Job, Task } from './task-job';\nimport { AdcmEntity } from '@app/models/entity';\nimport { IIssues } from '@app/models/issue';\nimport { ICluster } from '@app/models/cluster';\nimport { Concern } from '@app/models/concern/concern';\n\nexport type TypeName =\n 'bundle' |\n 'cluster' |\n 'host' |\n 'provider' |\n 'service' |\n 'job' |\n 'task' |\n 'user' |\n 'profile' |\n 'adcm' |\n 'stats' |\n 'hostcomponent' |\n 'service2cluster' |\n 'host2cluster' |\n 'servicecomponent' |\n 'component' |\n 'group_config' |\n 'group_config_hosts';\nexport type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle;\n\n/**\n *```\n {\n [key: string]: string;\n }\n ```\n */\nexport interface IRoot {\n [key: string]: string;\n}\n\nexport interface BaseEntity extends AdcmEntity {\n typeName: TypeName;\n description?: string;\n url: string;\n state?: string;\n config: string;\n action?: string;\n actions?: IAction[];\n issue?: IIssues;\n prototype_id?: number;\n prototype_name?: string;\n prototype_display_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n status?: number | string;\n concerns: Concern[];\n locked: boolean;\n}\n\nexport interface ApiFlat {\n id: number;\n object_id: number;\n object_type: TypeName;\n url: string;\n}\n\nexport interface Provider extends BaseEntity {\n host: string;\n}\n\nexport interface Host extends BaseEntity {\n fqdn: string;\n provider_id: number;\n cluster: string;\n cluster_id?: number;\n cluster_name?: string;\n}\n\nexport interface Service extends BaseEntity {\n components: IComponent[];\n status: number;\n hostcomponent: string;\n display_name: string;\n cluster_id?: number;\n group_config: string;\n}\n\nexport interface CanLicensed {\n license: 'unaccepted' | 'accepted' | 'absent';\n license_url: string;\n}\n\nexport interface License {\n accept: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n text: string;\n}\n\nexport interface Bundle extends BaseEntity, CanLicensed {\n [key: string]: any;\n}\n", - "properties": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 59 - }, - { - "name": "actions", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction[]", - "optional": true, - "description": "", - "line": 60 - }, - { - "name": "bundle_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 66 - }, - { - "name": "concerns", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern[]", - "optional": false, - "description": "", - "line": 68 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 58 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 55 - }, - { - "name": "issue", - "deprecated": false, - "deprecationMessage": "", - "type": "IIssues", - "optional": true, - "description": "", - "line": 61 - }, - { - "name": "locked", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 69 - }, - { - "name": "prototype_display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 64 - }, - { - "name": "prototype_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 62 - }, - { - "name": "prototype_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 63 - }, - { - "name": "prototype_version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 65 - }, - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 57 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number | string", - "optional": true, - "description": "", - "line": 67 - }, - { - "name": "typeName", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 54 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 56 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "AdcmEntity" - }, - { - "name": "Bundle", - "id": "interface-Bundle-0cbb246102564bc134c66dc61b2dabe6", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IAction } from './actions';\nimport { IComponent } from './host-component';\nimport { Job, Task } from './task-job';\nimport { AdcmEntity } from '@app/models/entity';\nimport { IIssues } from '@app/models/issue';\nimport { ICluster } from '@app/models/cluster';\nimport { Concern } from '@app/models/concern/concern';\n\nexport type TypeName =\n 'bundle' |\n 'cluster' |\n 'host' |\n 'provider' |\n 'service' |\n 'job' |\n 'task' |\n 'user' |\n 'profile' |\n 'adcm' |\n 'stats' |\n 'hostcomponent' |\n 'service2cluster' |\n 'host2cluster' |\n 'servicecomponent' |\n 'component' |\n 'group_config' |\n 'group_config_hosts';\nexport type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle;\n\n/**\n *```\n {\n [key: string]: string;\n }\n ```\n */\nexport interface IRoot {\n [key: string]: string;\n}\n\nexport interface BaseEntity extends AdcmEntity {\n typeName: TypeName;\n description?: string;\n url: string;\n state?: string;\n config: string;\n action?: string;\n actions?: IAction[];\n issue?: IIssues;\n prototype_id?: number;\n prototype_name?: string;\n prototype_display_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n status?: number | string;\n concerns: Concern[];\n locked: boolean;\n}\n\nexport interface ApiFlat {\n id: number;\n object_id: number;\n object_type: TypeName;\n url: string;\n}\n\nexport interface Provider extends BaseEntity {\n host: string;\n}\n\nexport interface Host extends BaseEntity {\n fqdn: string;\n provider_id: number;\n cluster: string;\n cluster_id?: number;\n cluster_name?: string;\n}\n\nexport interface Service extends BaseEntity {\n components: IComponent[];\n status: number;\n hostcomponent: string;\n display_name: string;\n cluster_id?: number;\n group_config: string;\n}\n\nexport interface CanLicensed {\n license: 'unaccepted' | 'accepted' | 'absent';\n license_url: string;\n}\n\nexport interface License {\n accept: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n text: string;\n}\n\nexport interface Bundle extends BaseEntity, CanLicensed {\n [key: string]: any;\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-0cbb246102564bc134c66dc61b2dabe6", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "any", - "line": 111, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "methods": [], - "extends": "BaseEntity" - }, - { - "name": "CanLicensed", - "id": "interface-CanLicensed-0cbb246102564bc134c66dc61b2dabe6", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IAction } from './actions';\nimport { IComponent } from './host-component';\nimport { Job, Task } from './task-job';\nimport { AdcmEntity } from '@app/models/entity';\nimport { IIssues } from '@app/models/issue';\nimport { ICluster } from '@app/models/cluster';\nimport { Concern } from '@app/models/concern/concern';\n\nexport type TypeName =\n 'bundle' |\n 'cluster' |\n 'host' |\n 'provider' |\n 'service' |\n 'job' |\n 'task' |\n 'user' |\n 'profile' |\n 'adcm' |\n 'stats' |\n 'hostcomponent' |\n 'service2cluster' |\n 'host2cluster' |\n 'servicecomponent' |\n 'component' |\n 'group_config' |\n 'group_config_hosts';\nexport type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle;\n\n/**\n *```\n {\n [key: string]: string;\n }\n ```\n */\nexport interface IRoot {\n [key: string]: string;\n}\n\nexport interface BaseEntity extends AdcmEntity {\n typeName: TypeName;\n description?: string;\n url: string;\n state?: string;\n config: string;\n action?: string;\n actions?: IAction[];\n issue?: IIssues;\n prototype_id?: number;\n prototype_name?: string;\n prototype_display_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n status?: number | string;\n concerns: Concern[];\n locked: boolean;\n}\n\nexport interface ApiFlat {\n id: number;\n object_id: number;\n object_type: TypeName;\n url: string;\n}\n\nexport interface Provider extends BaseEntity {\n host: string;\n}\n\nexport interface Host extends BaseEntity {\n fqdn: string;\n provider_id: number;\n cluster: string;\n cluster_id?: number;\n cluster_name?: string;\n}\n\nexport interface Service extends BaseEntity {\n components: IComponent[];\n status: number;\n hostcomponent: string;\n display_name: string;\n cluster_id?: number;\n group_config: string;\n}\n\nexport interface CanLicensed {\n license: 'unaccepted' | 'accepted' | 'absent';\n license_url: string;\n}\n\nexport interface License {\n accept: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n text: string;\n}\n\nexport interface Bundle extends BaseEntity, CanLicensed {\n [key: string]: any;\n}\n", - "properties": [ - { - "name": "license", - "deprecated": false, - "deprecationMessage": "", - "type": "\"unaccepted\" | \"accepted\" | \"absent\"", - "optional": false, - "description": "", - "line": 101 - }, - { - "name": "license_url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 102 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "CheckLog", - "id": "interface-CheckLog-a25a180383c9eab0fd04d0bffbe4860c", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { BaseEntity } from './api';\nimport { Entity } from '@adwp-ui/widgets';\n\nexport type JobStatus = 'created' | 'running' | 'failed' | 'success' | 'aborted';\n\nexport type JobType = 'component' | 'service' | 'cluster' | 'host' | 'provider';\n\nexport interface JobObject {\n id: number;\n name: string;\n type: JobType;\n url?: string[];\n}\n\ninterface TaskBase extends Entity {\n start_date: string;\n finish_date: string;\n objects: JobObject[];\n status: JobStatus;\n action: JobAction;\n terminatable: boolean;\n cancel: string;\n}\n\nexport interface JobAction {\n prototype_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n display_name: string;\n}\ninterface JobRaw extends TaskBase {\n log_files: LogFile[];\n start_date: string;\n finish_date: string;\n}\n\nexport interface TaskRaw extends TaskBase {\n jobs: Job[];\n}\n\nexport type Job = JobRaw & BaseEntity;\nexport type Task = TaskRaw & BaseEntity;\n\nexport interface LogFile {\n id: number;\n url: string;\n name: string;\n type: string;\n format: 'txt' | 'json';\n download_url: string;\n content: string | CheckLog[];\n}\n\nexport interface CheckLog {\n title: string;\n message: string;\n result: boolean;\n type: 'group' | 'check';\n content?: CheckLog[];\n}\n", - "properties": [ - { - "name": "content", - "deprecated": false, - "deprecationMessage": "", - "type": "CheckLog[]", - "optional": true, - "description": "", - "line": 70 - }, - { - "name": "message", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 67 - }, - { - "name": "result", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 68 - }, - { - "name": "title", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 66 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "\"group\" | \"check\"", - "optional": false, - "description": "", - "line": 69 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ClusterStatusTree", - "id": "interface-ClusterStatusTree-c0578eccc6c0f17562e0f3175dee1006", - "file": "src/app/models/status-tree.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export type StatusTreeLinkFunc = (id: number, tree: StatusTree[]) => string[];\n\nexport interface StatusTreeSubject {\n id?: number;\n name: string;\n status?: number;\n link?: StatusTreeLinkFunc;\n}\n\nexport interface StatusTree {\n subject: StatusTreeSubject;\n children: StatusTree[];\n}\n\nexport interface ClusterStatusTree extends StatusTreeSubject {\n chilren: {\n hosts: StatusTreeSubject[];\n services: ServiceStatusTree[];\n };\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n\nexport interface HostComponentStatusTree extends StatusTreeSubject {\n hosts: StatusTreeSubject[];\n}\n\nexport interface HostStatusTree extends StatusTreeSubject {\n hc: StatusTreeSubject[];\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n", - "properties": [ - { - "name": "chilren", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 16 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "StatusTreeSubject" - }, - { - "name": "CompareConfig", - "id": "interface-CompareConfig-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "color", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 151 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IConfig" - }, - { - "name": "Concern", - "id": "interface-Concern-148a13da0121427561184af2494fce44", - "file": "src/app/models/concern/concern.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Entity } from '@adwp-ui/widgets';\nimport { ConcernReason } from './concern-reason';\n\nexport type ConcernType = 'issue' | 'lock';\n\nexport interface Concern extends Entity {\n blocking: boolean;\n reason: ConcernReason;\n type: ConcernType;\n url?: string;\n cause: string;\n}\n", - "properties": [ - { - "name": "blocking", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 7 - }, - { - "name": "cause", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "reason", - "deprecated": false, - "deprecationMessage": "", - "type": "ConcernReason", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "ConcernType", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 10 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "Entity" - }, - { - "name": "ConcernEventFilter", - "id": "interface-ConcernEventFilter-70a6210b9e5b1aba1f56cd28e16d0494", - "file": "src/app/models/eventable-service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Observable } from 'rxjs';\n\nimport { EntityEvent, EventMessage } from '@app/core/store';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\nexport interface EventFilter {\n events?: EntityEvent[];\n}\n\nexport interface ConcernEventFilter extends EventFilter {\n types?: ConcernEventType[];\n}\n\nexport interface EventableService {\n\n events(eventFilter?: EventFilter): Observable;\n\n}\n", - "properties": [ - { - "name": "types", - "deprecated": false, - "deprecationMessage": "", - "type": "ConcernEventType[]", - "optional": true, - "description": "", - "line": 11 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "EventFilter" - }, - { - "name": "ConcernReason", - "id": "interface-ConcernReason-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "message", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 94 - }, - { - "name": "placeholder", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholder", - "optional": false, - "description": "", - "line": 95 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ConfigAttributeOptions", - "id": "interface-ConfigAttributeOptions-651cfdba3f000923bbee8d3d05505de6", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Inject, Injectable, InjectionToken, TemplateRef, Type } from '@angular/core';\nimport { FormBuilder, FormGroup } from '@angular/forms';\nimport { IFieldOptions } from '@app/shared/configuration/types';\nimport { isBoolean, isEmptyObject } from '@app/core/types';\nimport { FieldComponent } from '@app/shared/configuration/field/field.component';\n\nexport const ATTRIBUTES_OPTIONS = new InjectionToken('Attributes options');\n\nexport interface AttributeOptions {\n name: ConfigAttributeNames;\n wrapper?: Type;\n options?: ConfigAttributeOptions;\n}\n\nexport type AttributesOptions = Record\n\nexport interface AttributeWrapper {\n fieldTemplate: TemplateRef;\n wrapperOptions: ConfigAttributeOptions;\n fieldOptions: IFieldOptions;\n attributeForm: FormGroup;\n parametersForm: FormGroup;\n field: FieldComponent;\n}\n\nexport enum ConfigAttributeNames {\n // an attribute for adding config parameters to group\n GROUP_KEYS = 'group_keys',\n // an attribute for config parameters that determines whether this parameter can be added to the config group\n CUSTOM_GROUP_KEYS = 'custom_group_keys'\n}\n\nexport interface ConfigAttributesJSON {\n [key: string]: any;\n}\n\nexport interface ConfigAttributeOptions {\n tooltipText?: string;\n\n [key: string]: any;\n}\n\nexport type ConfigAttribute = AttributeOptions & { value: ConfigAttributesJSON, form: FormGroup };\n\nexport type Attributes = Map;\n\n@Injectable()\nexport class AttributeService {\n\n private readonly _activeAttributes: Partial[] = [\n ConfigAttributeNames.GROUP_KEYS,\n ConfigAttributeNames.CUSTOM_GROUP_KEYS\n ];\n\n get attributes(): Attributes {\n return this._attributes;\n }\n\n private _attributes: Attributes;\n\n constructor(@Inject(ATTRIBUTES_OPTIONS) private _configs: AttributesOptions, private _fb: FormBuilder) {\n }\n\n init(json: ConfigAttributesJSON): void {\n this._attributes = this._createAttributes(this._activeAttributes, json, this._configs);\n }\n\n getByName(name: ConfigAttributeNames): ConfigAttribute {\n return this._attributes.has(name) ? this._attributes.get(name) : undefined;\n }\n\n private _createAttributes(_activeAttributes: Partial[], json: ConfigAttributesJSON, configs: AttributesOptions): Attributes {\n const isEmptyAttrs = !Object.keys(json || {}).length;\n const isActiveAttrsPresent = !!Object.keys(json || {}).filter((x: ConfigAttributeNames) => this._activeAttributes.includes(x)).length;\n if (isEmptyAttrs || !isActiveAttrsPresent) {\n return;\n }\n\n return new Map(this._activeAttributes.map((attr) => [\n attr,\n new ConfigAttributeFactory(this._fb).create(attr, json[attr], configs[attr], json),\n ]));\n }\n\n\n rawAttributes() {\n let json = {};\n if (this._attributes) {\n for (const [key, value] of this._attributes.entries()) {\n json = {\n ...json,\n [key]: value.form.value\n };\n }\n }\n\n return json;\n }\n}\n\nexport const createFormForAttribute = (fb: FormBuilder, json: ConfigAttributesJSON, attr: ConfigAttributeNames, disabled: boolean = false): FormGroup => {\n const buildFormGroup = (json: boolean | ConfigAttributesJSON) => {\n const data = Object.entries(json).map(([key, value]) => [key, value]).reduce((acc, [key, value]: [string, boolean | ConfigAttributesJSON]) => {\n\n if (isBoolean(value) || isEmptyObject(value)) {\n return {\n ...acc,\n [key]: { value, disabled }\n };\n } else if (!isEmptyObject(value)) {\n return { ...acc, [key]: buildFormGroup(value) };\n }\n\n }, {});\n\n return fb.group(data);\n };\n\n return buildFormGroup(json[attr]);\n};\n\n\nexport class ConfigAttributeFactory {\n\n constructor(private fb: FormBuilder) {}\n\n create(name: ConfigAttributeNames, value: ConfigAttributesJSON, options: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n if (!this[name]) {\n return;\n }\n\n return this[name](value, options, json);\n }\n\n [ConfigAttributeNames.GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options,\n wrapper\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return {\n name,\n value,\n wrapper,\n options,\n form\n };\n }\n\n [ConfigAttributeNames.CUSTOM_GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return { name, value, options, form };\n }\n\n}\n", - "properties": [ - { - "name": "tooltipText", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 38 - } - ], - "indexSignatures": [ - { - "id": "index-declaration-651cfdba3f000923bbee8d3d05505de6", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "any", - "line": 38, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "methods": [] - }, - { - "name": "ConfigAttributesJSON", - "id": "interface-ConfigAttributesJSON-651cfdba3f000923bbee8d3d05505de6", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Inject, Injectable, InjectionToken, TemplateRef, Type } from '@angular/core';\nimport { FormBuilder, FormGroup } from '@angular/forms';\nimport { IFieldOptions } from '@app/shared/configuration/types';\nimport { isBoolean, isEmptyObject } from '@app/core/types';\nimport { FieldComponent } from '@app/shared/configuration/field/field.component';\n\nexport const ATTRIBUTES_OPTIONS = new InjectionToken('Attributes options');\n\nexport interface AttributeOptions {\n name: ConfigAttributeNames;\n wrapper?: Type;\n options?: ConfigAttributeOptions;\n}\n\nexport type AttributesOptions = Record\n\nexport interface AttributeWrapper {\n fieldTemplate: TemplateRef;\n wrapperOptions: ConfigAttributeOptions;\n fieldOptions: IFieldOptions;\n attributeForm: FormGroup;\n parametersForm: FormGroup;\n field: FieldComponent;\n}\n\nexport enum ConfigAttributeNames {\n // an attribute for adding config parameters to group\n GROUP_KEYS = 'group_keys',\n // an attribute for config parameters that determines whether this parameter can be added to the config group\n CUSTOM_GROUP_KEYS = 'custom_group_keys'\n}\n\nexport interface ConfigAttributesJSON {\n [key: string]: any;\n}\n\nexport interface ConfigAttributeOptions {\n tooltipText?: string;\n\n [key: string]: any;\n}\n\nexport type ConfigAttribute = AttributeOptions & { value: ConfigAttributesJSON, form: FormGroup };\n\nexport type Attributes = Map;\n\n@Injectable()\nexport class AttributeService {\n\n private readonly _activeAttributes: Partial[] = [\n ConfigAttributeNames.GROUP_KEYS,\n ConfigAttributeNames.CUSTOM_GROUP_KEYS\n ];\n\n get attributes(): Attributes {\n return this._attributes;\n }\n\n private _attributes: Attributes;\n\n constructor(@Inject(ATTRIBUTES_OPTIONS) private _configs: AttributesOptions, private _fb: FormBuilder) {\n }\n\n init(json: ConfigAttributesJSON): void {\n this._attributes = this._createAttributes(this._activeAttributes, json, this._configs);\n }\n\n getByName(name: ConfigAttributeNames): ConfigAttribute {\n return this._attributes.has(name) ? this._attributes.get(name) : undefined;\n }\n\n private _createAttributes(_activeAttributes: Partial[], json: ConfigAttributesJSON, configs: AttributesOptions): Attributes {\n const isEmptyAttrs = !Object.keys(json || {}).length;\n const isActiveAttrsPresent = !!Object.keys(json || {}).filter((x: ConfigAttributeNames) => this._activeAttributes.includes(x)).length;\n if (isEmptyAttrs || !isActiveAttrsPresent) {\n return;\n }\n\n return new Map(this._activeAttributes.map((attr) => [\n attr,\n new ConfigAttributeFactory(this._fb).create(attr, json[attr], configs[attr], json),\n ]));\n }\n\n\n rawAttributes() {\n let json = {};\n if (this._attributes) {\n for (const [key, value] of this._attributes.entries()) {\n json = {\n ...json,\n [key]: value.form.value\n };\n }\n }\n\n return json;\n }\n}\n\nexport const createFormForAttribute = (fb: FormBuilder, json: ConfigAttributesJSON, attr: ConfigAttributeNames, disabled: boolean = false): FormGroup => {\n const buildFormGroup = (json: boolean | ConfigAttributesJSON) => {\n const data = Object.entries(json).map(([key, value]) => [key, value]).reduce((acc, [key, value]: [string, boolean | ConfigAttributesJSON]) => {\n\n if (isBoolean(value) || isEmptyObject(value)) {\n return {\n ...acc,\n [key]: { value, disabled }\n };\n } else if (!isEmptyObject(value)) {\n return { ...acc, [key]: buildFormGroup(value) };\n }\n\n }, {});\n\n return fb.group(data);\n };\n\n return buildFormGroup(json[attr]);\n};\n\n\nexport class ConfigAttributeFactory {\n\n constructor(private fb: FormBuilder) {}\n\n create(name: ConfigAttributeNames, value: ConfigAttributesJSON, options: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n if (!this[name]) {\n return;\n }\n\n return this[name](value, options, json);\n }\n\n [ConfigAttributeNames.GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options,\n wrapper\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return {\n name,\n value,\n wrapper,\n options,\n form\n };\n }\n\n [ConfigAttributeNames.CUSTOM_GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return { name, value, options, form };\n }\n\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-651cfdba3f000923bbee8d3d05505de6", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "any", - "line": 33, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "methods": [] - }, - { - "name": "ConfigGroup", - "id": "interface-ConfigGroup-8e9ab1169297eb2457ce4f4f82dfafda", - "file": "src/app/config-groups/model/config-group.model.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { ApiFlat } from '@app/core/types';\n\nexport interface ConfigGroup extends ApiFlat {\n name: string;\n description: string;\n hosts: string;\n config: string;\n host_candidate: string;\n}\n", - "properties": [ - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 7 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 5 - }, - { - "name": "host_candidate", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "hosts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 6 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 4 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "ApiFlat" - }, - { - "name": "CountedStatusTree", - "id": "interface-CountedStatusTree-91f369d83e4defa92ad4e5e0aa366670", - "file": "src/app/components/status-tree/status-tree.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, Input, ViewChild } from '@angular/core';\nimport { FlatTreeControl } from '@angular/cdk/tree';\nimport { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';\n\nimport { StatusTree, StatusTreeSubject } from '@app/models/status-tree';\n\ninterface ExampleFlatNode {\n expandable: boolean;\n subject: StatusTreeSubject;\n level: number;\n}\n\ninterface Counts {\n total: number;\n succeed: number;\n}\n\ninterface CountedStatusTree extends StatusTree {\n counts?: Counts;\n}\n\nexport enum Folding {\n Collapsed,\n Expanded,\n}\n\n@Component({\n selector: 'app-status-tree',\n templateUrl: './status-tree.component.html',\n styleUrls: ['./status-tree.component.scss']\n})\nexport class StatusTreeComponent {\n\n @ViewChild('treeNode', { static: true }) treeNode: any;\n\n private calcCounts = (children: CountedStatusTree[]): Counts => {\n return children.reduce((acc: Counts, child: CountedStatusTree) => {\n acc.total++;\n if ('status' in child.subject) {\n if (child.subject.status === 0) {\n acc.succeed++;\n }\n } else {\n const childrenSucceed = child.children.reduce((accum, item) => item.subject.status === 0 ? accum + 1 : accum, 0);\n if (childrenSucceed === child.children.length) {\n acc.succeed++;\n }\n }\n return acc;\n },\n { total: 0, succeed: 0 } as Counts,\n ) as Counts;\n }\n\n private transformer = (node: StatusTree, level: number) => {\n return {\n expandable: !!node.children && node.children.length > 0,\n subject: node.subject,\n level: level,\n counts: node.children ? this.calcCounts(node.children) : { total: 0, succeed: 0 },\n };\n }\n\n treeControl = new FlatTreeControl(\n node => node.level,\n node => node.expandable,\n );\n\n treeFlattener = new MatTreeFlattener(\n this.transformer,\n node => node.level,\n node => node.expandable,\n node => node.children,\n );\n\n dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);\n\n private ownTree: StatusTree[];\n @Input() set tree(tree: StatusTree[]) {\n this.ownTree = tree;\n this.dataSource.data = tree;\n\n if (this.folding === Folding.Expanded) {\n this.treeControl.expandAll();\n }\n\n if (this.folding === Folding.Collapsed) {\n this.treeControl.collapseAll();\n }\n }\n get tree(): StatusTree[] {\n return this.ownTree;\n }\n\n hasChild = (_: number, node: ExampleFlatNode) => node.expandable;\n\n private ownFolding: Folding;\n @Input() set folding(folding: Folding) {\n this.ownFolding = folding;\n this.tree = this.tree;\n }\n get folding(): Folding {\n return this.ownFolding;\n }\n\n expandAll() {\n this.treeControl.expandAll();\n }\n\n collapseAll() {\n this.treeControl.collapseAll();\n }\n\n hasCollapsed(): boolean {\n for (const item of this.treeControl.dataNodes) {\n if (!this.treeControl.isExpanded(item)) {\n return true;\n }\n }\n return false;\n }\n\n}\n", - "properties": [ - { - "name": "counts", - "deprecated": false, - "deprecationMessage": "", - "type": "Counts", - "optional": true, - "description": "", - "line": 20 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "StatusTree" - }, - { - "name": "Counts", - "id": "interface-Counts-91f369d83e4defa92ad4e5e0aa366670", - "file": "src/app/components/status-tree/status-tree.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, Input, ViewChild } from '@angular/core';\nimport { FlatTreeControl } from '@angular/cdk/tree';\nimport { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';\n\nimport { StatusTree, StatusTreeSubject } from '@app/models/status-tree';\n\ninterface ExampleFlatNode {\n expandable: boolean;\n subject: StatusTreeSubject;\n level: number;\n}\n\ninterface Counts {\n total: number;\n succeed: number;\n}\n\ninterface CountedStatusTree extends StatusTree {\n counts?: Counts;\n}\n\nexport enum Folding {\n Collapsed,\n Expanded,\n}\n\n@Component({\n selector: 'app-status-tree',\n templateUrl: './status-tree.component.html',\n styleUrls: ['./status-tree.component.scss']\n})\nexport class StatusTreeComponent {\n\n @ViewChild('treeNode', { static: true }) treeNode: any;\n\n private calcCounts = (children: CountedStatusTree[]): Counts => {\n return children.reduce((acc: Counts, child: CountedStatusTree) => {\n acc.total++;\n if ('status' in child.subject) {\n if (child.subject.status === 0) {\n acc.succeed++;\n }\n } else {\n const childrenSucceed = child.children.reduce((accum, item) => item.subject.status === 0 ? accum + 1 : accum, 0);\n if (childrenSucceed === child.children.length) {\n acc.succeed++;\n }\n }\n return acc;\n },\n { total: 0, succeed: 0 } as Counts,\n ) as Counts;\n }\n\n private transformer = (node: StatusTree, level: number) => {\n return {\n expandable: !!node.children && node.children.length > 0,\n subject: node.subject,\n level: level,\n counts: node.children ? this.calcCounts(node.children) : { total: 0, succeed: 0 },\n };\n }\n\n treeControl = new FlatTreeControl(\n node => node.level,\n node => node.expandable,\n );\n\n treeFlattener = new MatTreeFlattener(\n this.transformer,\n node => node.level,\n node => node.expandable,\n node => node.children,\n );\n\n dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);\n\n private ownTree: StatusTree[];\n @Input() set tree(tree: StatusTree[]) {\n this.ownTree = tree;\n this.dataSource.data = tree;\n\n if (this.folding === Folding.Expanded) {\n this.treeControl.expandAll();\n }\n\n if (this.folding === Folding.Collapsed) {\n this.treeControl.collapseAll();\n }\n }\n get tree(): StatusTree[] {\n return this.ownTree;\n }\n\n hasChild = (_: number, node: ExampleFlatNode) => node.expandable;\n\n private ownFolding: Folding;\n @Input() set folding(folding: Folding) {\n this.ownFolding = folding;\n this.tree = this.tree;\n }\n get folding(): Folding {\n return this.ownFolding;\n }\n\n expandAll() {\n this.treeControl.expandAll();\n }\n\n collapseAll() {\n this.treeControl.collapseAll();\n }\n\n hasCollapsed(): boolean {\n for (const item of this.treeControl.dataNodes) {\n if (!this.treeControl.isExpanded(item)) {\n return true;\n }\n }\n return false;\n }\n\n}\n", - "properties": [ - { - "name": "succeed", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 16 - }, - { - "name": "total", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 15 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "DialogData", - "id": "interface-DialogData-068900a1cc4916fa3b799a2be53b23f7", - "file": "src/app/shared/components/dialog.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, ComponentFactoryResolver, EventEmitter, Inject, OnInit, Type, ViewChild, HostListener } from '@angular/core';\nimport { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';\n\nimport { DynamicComponent, DynamicDirective, DynamicEvent } from '../directives/dynamic.directive';\nimport { ChannelService } from '@app/core/services';\nimport { keyChannelStrim } from '@app/core/services';\nimport { ActionParameters } from '@app/shared/components/actions/actions.directive';\n\nexport interface DialogData {\n title: string;\n component: Type;\n model?: ActionParameters | any;\n event?: EventEmitter;\n text?: string;\n controls?: any[] | any;\n disabled?: boolean;\n}\n\n@Component({\n selector: 'app-dialog',\n template: `\n

{{ data.title || 'Notification' }}

\n \n
{{ data.text }}
\n \n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n `,\n styles: ['pre {white-space: pre-wrap;}'],\n})\nexport class DialogComponent implements OnInit {\n controls: string[];\n noClose: boolean | undefined;\n\n instance: DynamicComponent;\n\n @ViewChild(DynamicDirective, { static: true }) dynamic: DynamicDirective;\n\n @HostListener('window:keydown', ['$event'])\n handleKeyDown(event: KeyboardEvent) {\n if (event.key === 'Enter') {\n const c = this.instance;\n if (c?.onEnterKey) c.onEnterKey();\n }\n }\n\n constructor(\n public dialogRef: MatDialogRef,\n @Inject(MAT_DIALOG_DATA) public data: DialogData,\n private componentFactoryResolever: ComponentFactoryResolver,\n private channel: ChannelService\n ) {}\n\n controlsIsArray() {\n return Array.isArray(this.data.controls);\n }\n\n ngOnInit(): void {\n if (this.data.component) {\n const componentFactory = this.componentFactoryResolever.resolveComponentFactory(this.data.component);\n const viewContainerRef = this.dynamic.viewContainerRef;\n viewContainerRef.clear();\n\n const componentRef = viewContainerRef.createComponent(componentFactory);\n this.instance = componentRef.instance;\n this.instance.model = this.data.model;\n // event define in the component\n if (this.instance.event) this.instance.event.subscribe((e: DynamicEvent) => this.dialogRef.close(e));\n\n if (this.data.event) this.instance.event = this.data.event;\n }\n }\n\n scroll(stop: { direct: -1 | 1 | 0; screenTop: number }) {\n this.channel.next(keyChannelStrim.scroll, stop);\n }\n\n _noClick(): void {\n this.dialogRef.close();\n }\n}\n", - "properties": [ - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "type": "Type", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "controls", - "deprecated": false, - "deprecationMessage": "", - "type": "any[] | any", - "optional": true, - "description": "", - "line": 26 - }, - { - "name": "disabled", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 27 - }, - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "type": "EventEmitter", - "optional": true, - "description": "", - "line": 24 - }, - { - "name": "model", - "deprecated": false, - "deprecationMessage": "", - "type": "ActionParameters | any", - "optional": true, - "description": "", - "line": 23 - }, - { - "name": "text", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 25 - }, - { - "name": "title", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 21 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "DynamicComponent", - "id": "interface-DynamicComponent-417b7397318b007b139d072bc712681f", - "file": "src/app/shared/directives/dynamic.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Directive, ViewContainerRef, EventEmitter } from '@angular/core';\n\n/**\n * @param name string required name action\n * @param data any\n */\nexport interface DynamicEvent {\n name: string;\n data?: any;\n}\n\nexport interface DynamicComponent {\n event?: EventEmitter;\n model?: any;\n onEnterKey?: () => void;\n}\n\n@Directive({\n selector: '[appDynamic]',\n})\nexport class DynamicDirective {\n constructor(public viewContainerRef: ViewContainerRef) {}\n}\n", - "properties": [ - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "type": "EventEmitter", - "optional": true, - "description": "", - "line": 24 - }, - { - "name": "model", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": true, - "description": "", - "line": 25 - }, - { - "name": "onEnterKey", - "deprecated": false, - "deprecationMessage": "", - "type": "function", - "optional": true, - "description": "", - "line": 26 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "DynamicEvent", - "id": "interface-DynamicEvent-417b7397318b007b139d072bc712681f", - "file": "src/app/shared/directives/dynamic.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Directive, ViewContainerRef, EventEmitter } from '@angular/core';\n\n/**\n * @param name string required name action\n * @param data any\n */\nexport interface DynamicEvent {\n name: string;\n data?: any;\n}\n\nexport interface DynamicComponent {\n event?: EventEmitter;\n model?: any;\n onEnterKey?: () => void;\n}\n\n@Directive({\n selector: '[appDynamic]',\n})\nexport class DynamicDirective {\n constructor(public viewContainerRef: ViewContainerRef) {}\n}\n", - "properties": [ - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": true, - "description": "", - "line": 20 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 19 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "EmmitRow", - "id": "interface-EmmitRow-48bdc39db9b8bb2237d76b204a2e01dc", - "file": "src/app/core/types/utils.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface EmmitRow {\n cmd: string;\n row: any;\n item?: any;\n}\n\nexport interface SelectOption {\n id: number | string;\n name: string;\n}\n\nexport interface IError {\n code: string;\n desc: string;\n level: string;\n}\n", - "properties": [ - { - "name": "cmd", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 20 - }, - { - "name": "item", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": true, - "description": "", - "line": 22 - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 21 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "

For lists

\n", - "rawdescription": "\n\nFor lists\n", - "methods": [] - }, - { - "name": "EventableService", - "id": "interface-EventableService-70a6210b9e5b1aba1f56cd28e16d0494", - "file": "src/app/models/eventable-service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Observable } from 'rxjs';\n\nimport { EntityEvent, EventMessage } from '@app/core/store';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\nexport interface EventFilter {\n events?: EntityEvent[];\n}\n\nexport interface ConcernEventFilter extends EventFilter {\n types?: ConcernEventType[];\n}\n\nexport interface EventableService {\n\n events(eventFilter?: EventFilter): Observable;\n\n}\n", - "properties": [], - "indexSignatures": [], - "kind": 165, - "methods": [ - { - "name": "events", - "args": [ - { - "name": "eventFilter", - "type": "EventFilter", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 16, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "eventFilter", - "type": "EventFilter", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ] - }, - { - "name": "EventFilter", - "id": "interface-EventFilter-70a6210b9e5b1aba1f56cd28e16d0494", - "file": "src/app/models/eventable-service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Observable } from 'rxjs';\n\nimport { EntityEvent, EventMessage } from '@app/core/store';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\nexport interface EventFilter {\n events?: EntityEvent[];\n}\n\nexport interface ConcernEventFilter extends EventFilter {\n types?: ConcernEventType[];\n}\n\nexport interface EventableService {\n\n events(eventFilter?: EventFilter): Observable;\n\n}\n", - "properties": [ - { - "name": "events", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityEvent[]", - "optional": true, - "description": "", - "line": 7 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "EventMessage", - "id": "interface-EventMessage-ca14b9fd2a8ab6897860f58a705daf52", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { TypeName } from '@app/core/types';\nimport {\n Action,\n createAction,\n createFeatureSelector,\n createReducer,\n createSelector,\n on,\n props,\n select\n} from '@ngrx/store';\nimport { pipe } from 'rxjs';\nimport { skip } from 'rxjs/operators';\n\n/**\n * Event Message Object dispatched from socket\n */\nexport interface IEMObject {\n type: TypeName;\n id: number;\n details: {\n id?: number;\n type: string;\n value: any;\n };\n}\n\nexport type EntityEvent =\n | 'add'\n | 'add_job_log'\n | 'create'\n | 'delete'\n | 'remove'\n | 'change_config'\n | 'change_state'\n | 'change_status'\n | 'change_job_status'\n | 'change_hostcomponentmap'\n | 'upgrade'\n | 'concern';\n\nexport interface EventMessage {\n event: EntityEvent;\n object?: IEMObject;\n}\n\nexport type StatusType = 'open' | 'close' | 're-open';\n\nexport const socketInit = createAction('[Socket] Init');\nexport const socketOpen = createAction('[Socket] Open', props<{ status: StatusType }>());\nexport const socketClose = createAction('[Socket] Close', props<{ status: StatusType }>());\nexport const socketResponse = createAction('[Socket] Response', props<{ message: EventMessage }>());\nexport const clearMessages = createAction('[Socket] Clear messages');\n\nexport interface SocketState {\n status: StatusType;\n message: EventMessage;\n}\n\nconst initialState: SocketState = {\n status: null,\n message: null,\n};\n\nconst reducer = createReducer(\n initialState,\n on(socketInit, (state) => ({ ...state })),\n on(socketOpen, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketClose, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketResponse, (state, { message }) => ({\n ...state,\n message,\n })),\n on(clearMessages, (state) => ({ ...state, message: null }))\n);\n\nexport function socketReducer(state: SocketState, action: Action) {\n return reducer(state, action);\n}\n\nexport const getSocketState = createFeatureSelector('socket');\nexport const getConnectStatus = createSelector(getSocketState, (state: SocketState) => state.status);\nexport const getMessage = createSelector(getSocketState, (state) => state.message);\nexport const selectMessage = pipe(\n select(getMessage),\n skip(1),\n);\n", - "properties": [ - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityEvent", - "optional": false, - "description": "", - "line": 54 - }, - { - "name": "object", - "deprecated": false, - "deprecationMessage": "", - "type": "IEMObject", - "optional": true, - "description": "", - "line": 55 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ExampleFlatNode", - "id": "interface-ExampleFlatNode-91f369d83e4defa92ad4e5e0aa366670", - "file": "src/app/components/status-tree/status-tree.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, Input, ViewChild } from '@angular/core';\nimport { FlatTreeControl } from '@angular/cdk/tree';\nimport { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';\n\nimport { StatusTree, StatusTreeSubject } from '@app/models/status-tree';\n\ninterface ExampleFlatNode {\n expandable: boolean;\n subject: StatusTreeSubject;\n level: number;\n}\n\ninterface Counts {\n total: number;\n succeed: number;\n}\n\ninterface CountedStatusTree extends StatusTree {\n counts?: Counts;\n}\n\nexport enum Folding {\n Collapsed,\n Expanded,\n}\n\n@Component({\n selector: 'app-status-tree',\n templateUrl: './status-tree.component.html',\n styleUrls: ['./status-tree.component.scss']\n})\nexport class StatusTreeComponent {\n\n @ViewChild('treeNode', { static: true }) treeNode: any;\n\n private calcCounts = (children: CountedStatusTree[]): Counts => {\n return children.reduce((acc: Counts, child: CountedStatusTree) => {\n acc.total++;\n if ('status' in child.subject) {\n if (child.subject.status === 0) {\n acc.succeed++;\n }\n } else {\n const childrenSucceed = child.children.reduce((accum, item) => item.subject.status === 0 ? accum + 1 : accum, 0);\n if (childrenSucceed === child.children.length) {\n acc.succeed++;\n }\n }\n return acc;\n },\n { total: 0, succeed: 0 } as Counts,\n ) as Counts;\n }\n\n private transformer = (node: StatusTree, level: number) => {\n return {\n expandable: !!node.children && node.children.length > 0,\n subject: node.subject,\n level: level,\n counts: node.children ? this.calcCounts(node.children) : { total: 0, succeed: 0 },\n };\n }\n\n treeControl = new FlatTreeControl(\n node => node.level,\n node => node.expandable,\n );\n\n treeFlattener = new MatTreeFlattener(\n this.transformer,\n node => node.level,\n node => node.expandable,\n node => node.children,\n );\n\n dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);\n\n private ownTree: StatusTree[];\n @Input() set tree(tree: StatusTree[]) {\n this.ownTree = tree;\n this.dataSource.data = tree;\n\n if (this.folding === Folding.Expanded) {\n this.treeControl.expandAll();\n }\n\n if (this.folding === Folding.Collapsed) {\n this.treeControl.collapseAll();\n }\n }\n get tree(): StatusTree[] {\n return this.ownTree;\n }\n\n hasChild = (_: number, node: ExampleFlatNode) => node.expandable;\n\n private ownFolding: Folding;\n @Input() set folding(folding: Folding) {\n this.ownFolding = folding;\n this.tree = this.tree;\n }\n get folding(): Folding {\n return this.ownFolding;\n }\n\n expandAll() {\n this.treeControl.expandAll();\n }\n\n collapseAll() {\n this.treeControl.collapseAll();\n }\n\n hasCollapsed(): boolean {\n for (const item of this.treeControl.dataNodes) {\n if (!this.treeControl.isExpanded(item)) {\n return true;\n }\n }\n return false;\n }\n\n}\n", - "properties": [ - { - "name": "expandable", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "level", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "subject", - "deprecated": false, - "deprecationMessage": "", - "type": "StatusTreeSubject", - "optional": false, - "description": "", - "line": 10 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "FormModel", - "id": "interface-FormModel-f3a9e248a30b8e9f987ceff03428a9ad", - "file": "src/app/shared/add-component/add-service-model.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { EventEmitter, InjectionToken, Type } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { Observable, Subscription } from 'rxjs';\nimport { Host, Service, StackBase, TypeName } from '@app/core/types';\nimport { Params } from '@angular/router';\nimport { BaseFormDirective } from '@app/shared/add-component/base-form.directive';\nimport { ICluster } from '@app/models/cluster';\nimport { ListResult } from '@app/models/list-result';\n\nexport const ADD_SERVICE_PROVIDER = new InjectionToken('AddService');\n\nexport interface FormModel {\n name: string;\n title?: string;\n form?: FormGroup;\n success?: EventEmitter<{ flag: boolean; obj: any }>;\n component?: Type;\n}\n\nexport interface IAddService {\n model(name?: string): FormModel;\n\n Cluster: ICluster;\n\n Current: any;\n\n add?(data: any, name?: TypeName, prototype?: StackBase): Observable;\n\n getList?(type: TypeName, param: Params): Observable;\n\n addHost?(host: Partial): Observable;\n\n genName?(form: FormGroup): Subscription;\n\n addHostInCluster?(ids: number[]): Observable;\n\n getListResults?(type: TypeName, param: Params): Observable>;\n\n getProtoServiceForCurrentCluster?(): Observable<{ name: string, id: number, url: string, version: string, edition: string, description: string, display_name: string, license: 'unaccepted' | 'accepted' | 'absent', bundle_id: number, bundle_edition: string, selected: boolean }[]>;\n\n addService?(data: { prototype_id: number }[]): Observable;\n}\n", - "properties": [ - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "type": "Type", - "optional": true, - "description": "", - "line": 17 - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "type": "FormGroup", - "optional": true, - "description": "", - "line": 15 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 13 - }, - { - "name": "success", - "deprecated": false, - "deprecationMessage": "", - "type": "EventEmitter", - "optional": true, - "description": "", - "line": 16 - }, - { - "name": "title", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 14 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "Host", - "id": "interface-Host-0cbb246102564bc134c66dc61b2dabe6", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IAction } from './actions';\nimport { IComponent } from './host-component';\nimport { Job, Task } from './task-job';\nimport { AdcmEntity } from '@app/models/entity';\nimport { IIssues } from '@app/models/issue';\nimport { ICluster } from '@app/models/cluster';\nimport { Concern } from '@app/models/concern/concern';\n\nexport type TypeName =\n 'bundle' |\n 'cluster' |\n 'host' |\n 'provider' |\n 'service' |\n 'job' |\n 'task' |\n 'user' |\n 'profile' |\n 'adcm' |\n 'stats' |\n 'hostcomponent' |\n 'service2cluster' |\n 'host2cluster' |\n 'servicecomponent' |\n 'component' |\n 'group_config' |\n 'group_config_hosts';\nexport type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle;\n\n/**\n *```\n {\n [key: string]: string;\n }\n ```\n */\nexport interface IRoot {\n [key: string]: string;\n}\n\nexport interface BaseEntity extends AdcmEntity {\n typeName: TypeName;\n description?: string;\n url: string;\n state?: string;\n config: string;\n action?: string;\n actions?: IAction[];\n issue?: IIssues;\n prototype_id?: number;\n prototype_name?: string;\n prototype_display_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n status?: number | string;\n concerns: Concern[];\n locked: boolean;\n}\n\nexport interface ApiFlat {\n id: number;\n object_id: number;\n object_type: TypeName;\n url: string;\n}\n\nexport interface Provider extends BaseEntity {\n host: string;\n}\n\nexport interface Host extends BaseEntity {\n fqdn: string;\n provider_id: number;\n cluster: string;\n cluster_id?: number;\n cluster_name?: string;\n}\n\nexport interface Service extends BaseEntity {\n components: IComponent[];\n status: number;\n hostcomponent: string;\n display_name: string;\n cluster_id?: number;\n group_config: string;\n}\n\nexport interface CanLicensed {\n license: 'unaccepted' | 'accepted' | 'absent';\n license_url: string;\n}\n\nexport interface License {\n accept: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n text: string;\n}\n\nexport interface Bundle extends BaseEntity, CanLicensed {\n [key: string]: any;\n}\n", - "properties": [ - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 86 - }, - { - "name": "cluster_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 87 - }, - { - "name": "cluster_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 88 - }, - { - "name": "fqdn", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 84 - }, - { - "name": "provider_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 85 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "BaseEntity" - }, - { - "name": "HostComponent", - "id": "interface-HostComponent-50993353cad3d133a2be743502171874", - "file": "src/app/core/types/host-component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface HostComponent {\n id: number;\n /** host name */\n host: string;\n host_id: number;\n /** component name */\n component: string;\n component_display_name: string;\n component_id: number;\n service_id: number;\n service_display_name: string;\n service_name: string;\n service_version: string;\n state: string;\n url: string;\n host_url: string;\n status: number;\n monitoring: 'passive' | 'active';\n}\n\n/**\n * A service component that may be installed on hosts in a cluster.\n */\nexport interface IComponent {\n id: number;\n prototype_id: number;\n service_id: number;\n service_name: string;\n service_state: string;\n name: string;\n display_name: string;\n status: number;\n constraint: any;\n monitoring?: 'passive' | 'active'; // status page\n requires?: IRequires[];\n}\n\nexport interface IRequires {\n // id: number;\n prototype_id: number;\n name: string;\n display_name: string;\n components?: IRequires[];\n}\n", - "properties": [ - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "

component name

\n", - "line": 24, - "rawdescription": "\ncomponent name" - }, - { - "name": "component_display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 25 - }, - { - "name": "component_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "host", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "

host name

\n", - "line": 21, - "rawdescription": "\nhost name" - }, - { - "name": "host_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "host_url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 33 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "monitoring", - "deprecated": false, - "deprecationMessage": "", - "type": "\"passive\" | \"active\"", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "service_display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "service_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "service_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 29 - }, - { - "name": "service_version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 32 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "

Information about the installed service component on a specific host

\n", - "rawdescription": "\n\nInformation about the installed service component on a specific host\n", - "methods": [] - }, - { - "name": "HostComponentStatusTree", - "id": "interface-HostComponentStatusTree-c0578eccc6c0f17562e0f3175dee1006", - "file": "src/app/models/status-tree.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export type StatusTreeLinkFunc = (id: number, tree: StatusTree[]) => string[];\n\nexport interface StatusTreeSubject {\n id?: number;\n name: string;\n status?: number;\n link?: StatusTreeLinkFunc;\n}\n\nexport interface StatusTree {\n subject: StatusTreeSubject;\n children: StatusTree[];\n}\n\nexport interface ClusterStatusTree extends StatusTreeSubject {\n chilren: {\n hosts: StatusTreeSubject[];\n services: ServiceStatusTree[];\n };\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n\nexport interface HostComponentStatusTree extends StatusTreeSubject {\n hosts: StatusTreeSubject[];\n}\n\nexport interface HostStatusTree extends StatusTreeSubject {\n hc: StatusTreeSubject[];\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n", - "properties": [ - { - "name": "hosts", - "deprecated": false, - "deprecationMessage": "", - "type": "StatusTreeSubject[]", - "optional": false, - "description": "", - "line": 27 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "StatusTreeSubject" - }, - { - "name": "HostStatusTree", - "id": "interface-HostStatusTree-c0578eccc6c0f17562e0f3175dee1006", - "file": "src/app/models/status-tree.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export type StatusTreeLinkFunc = (id: number, tree: StatusTree[]) => string[];\n\nexport interface StatusTreeSubject {\n id?: number;\n name: string;\n status?: number;\n link?: StatusTreeLinkFunc;\n}\n\nexport interface StatusTree {\n subject: StatusTreeSubject;\n children: StatusTree[];\n}\n\nexport interface ClusterStatusTree extends StatusTreeSubject {\n chilren: {\n hosts: StatusTreeSubject[];\n services: ServiceStatusTree[];\n };\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n\nexport interface HostComponentStatusTree extends StatusTreeSubject {\n hosts: StatusTreeSubject[];\n}\n\nexport interface HostStatusTree extends StatusTreeSubject {\n hc: StatusTreeSubject[];\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n", - "properties": [ - { - "name": "hc", - "deprecated": false, - "deprecationMessage": "", - "type": "StatusTreeSubject[]", - "optional": false, - "description": "", - "line": 31 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "StatusTreeSubject" - }, - { - "name": "IAction", - "id": "interface-IAction-a0c38196ca8bbe306182b7cac1b6764b", - "file": "src/app/models/action.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface IActionConfig {\n attr: any;\n config: any[];\n}\n\nexport interface IAction {\n button: any;\n config: IActionConfig;\n display_name: string;\n hostcomponentmap: any[];\n name: string;\n run: string;\n}\n", - "properties": [ - { - "name": "button", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 7 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "IActionConfig", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "hostcomponentmap", - "deprecated": false, - "deprecationMessage": "", - "type": "any[]", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "run", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 12 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IAction", - "id": "interface-IAction-735f0912aeff33ab88d1ab8e400a23cb-1", - "file": "src/app/core/types/actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IConfig } from '@app/shared/configuration/types';\n\n/**\n * \n *```\n{\n action: 'add' | 'remove'; \n component: string; // name of servise to work with \n service: string; // name of component to work with\n}\n```\n *\n */\nexport interface IActionParameter {\n action: 'add' | 'remove';\n component: string;\n service: string;\n}\n\nexport interface IUIOptions {\n disclaimer?: string;\n}\n\nexport interface IAction {\n name: string;\n description: string;\n display_name: string;\n run: string;\n config: IConfig;\n hostcomponentmap: IActionParameter[];\n button: 'create_host' | null;\n ui_options: IUIOptions;\n children?: IAction[];\n}\n", - "properties": [ - { - "name": "button", - "deprecated": false, - "deprecationMessage": "", - "type": "\"create_host\" | null", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "children", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction[]", - "optional": true, - "description": "", - "line": 44 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "IConfig", - "optional": false, - "description": "", - "line": 40 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 37 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 38 - }, - { - "name": "hostcomponentmap", - "deprecated": false, - "deprecationMessage": "", - "type": "IActionParameter[]", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 36 - }, - { - "name": "run", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 39 - }, - { - "name": "ui_options", - "deprecated": false, - "deprecationMessage": "", - "type": "IUIOptions", - "optional": false, - "description": "", - "line": 43 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "isDuplicate": true, - "duplicateId": 1, - "duplicateName": "IAction-1" - }, - { - "name": "IActionConfig", - "id": "interface-IActionConfig-a0c38196ca8bbe306182b7cac1b6764b", - "file": "src/app/models/action.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface IActionConfig {\n attr: any;\n config: any[];\n}\n\nexport interface IAction {\n button: any;\n config: IActionConfig;\n display_name: string;\n hostcomponentmap: any[];\n name: string;\n run: string;\n}\n", - "properties": [ - { - "name": "attr", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 2 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "any[]", - "optional": false, - "description": "", - "line": 3 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IActionParameter", - "id": "interface-IActionParameter-735f0912aeff33ab88d1ab8e400a23cb", - "file": "src/app/core/types/actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IConfig } from '@app/shared/configuration/types';\n\n/**\n * \n *```\n{\n action: 'add' | 'remove'; \n component: string; // name of servise to work with \n service: string; // name of component to work with\n}\n```\n *\n */\nexport interface IActionParameter {\n action: 'add' | 'remove';\n component: string;\n service: string;\n}\n\nexport interface IUIOptions {\n disclaimer?: string;\n}\n\nexport interface IAction {\n name: string;\n description: string;\n display_name: string;\n run: string;\n config: IConfig;\n hostcomponentmap: IActionParameter[];\n button: 'create_host' | null;\n ui_options: IUIOptions;\n children?: IAction[];\n}\n", - "properties": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "\"add\" | \"remove\"", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 28 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "
{\naction: 'add' | 'remove';\ncomponent: string;    // name of servise to work with\nservice: string;      // name of component to work with\n}
", - "rawdescription": "\n\n\n```\n{\naction: 'add' | 'remove';\ncomponent: string; // name of servise to work with\nservice: string; // name of component to work with\n}\n```\n\n", - "methods": [] - }, - { - "name": "IAddService", - "id": "interface-IAddService-f3a9e248a30b8e9f987ceff03428a9ad", - "file": "src/app/shared/add-component/add-service-model.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { EventEmitter, InjectionToken, Type } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { Observable, Subscription } from 'rxjs';\nimport { Host, Service, StackBase, TypeName } from '@app/core/types';\nimport { Params } from '@angular/router';\nimport { BaseFormDirective } from '@app/shared/add-component/base-form.directive';\nimport { ICluster } from '@app/models/cluster';\nimport { ListResult } from '@app/models/list-result';\n\nexport const ADD_SERVICE_PROVIDER = new InjectionToken('AddService');\n\nexport interface FormModel {\n name: string;\n title?: string;\n form?: FormGroup;\n success?: EventEmitter<{ flag: boolean; obj: any }>;\n component?: Type;\n}\n\nexport interface IAddService {\n model(name?: string): FormModel;\n\n Cluster: ICluster;\n\n Current: any;\n\n add?(data: any, name?: TypeName, prototype?: StackBase): Observable;\n\n getList?(type: TypeName, param: Params): Observable;\n\n addHost?(host: Partial): Observable;\n\n genName?(form: FormGroup): Subscription;\n\n addHostInCluster?(ids: number[]): Observable;\n\n getListResults?(type: TypeName, param: Params): Observable>;\n\n getProtoServiceForCurrentCluster?(): Observable<{ name: string, id: number, url: string, version: string, edition: string, description: string, display_name: string, license: 'unaccepted' | 'accepted' | 'absent', bundle_id: number, bundle_edition: string, selected: boolean }[]>;\n\n addService?(data: { prototype_id: number }[]): Observable;\n}\n", - "properties": [ - { - "name": "Cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "ICluster", - "optional": false, - "description": "", - "line": 23 - }, - { - "name": "Current", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 25 - } - ], - "indexSignatures": [], - "kind": 165, - "methods": [ - { - "name": "add", - "args": [ - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "name", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "optional": true - }, - { - "name": "prototype", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": true, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "name", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - }, - { - "name": "prototype", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "addHost", - "args": [ - { - "name": "host", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": true, - "returnType": "Observable", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "host", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "addHostInCluster", - "args": [ - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": true, - "returnType": "Observable<[]>", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "addService", - "args": [ - { - "name": "data", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": true, - "returnType": "Observable", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "genName", - "args": [ - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": true, - "returnType": "Subscription", - "typeParameters": [], - "line": 33, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getList", - "args": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": true, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getListResults", - "args": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": true, - "returnType": "Observable>", - "typeParameters": [ - "T" - ], - "line": 37, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getProtoServiceForCurrentCluster", - "args": [], - "optional": true, - "returnType": "Observable", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "model", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "FormModel", - "typeParameters": [], - "line": 21, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ] - }, - { - "name": "IAllStatus", - "id": "interface-IAllStatus-f4479ba0b2419eab84b2be3a638f7417", - "file": "src/app/shared/components/status/status.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { combineLatest, Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { ApiService } from '@app/core/api';\nimport { IComponent, Host, HostComponent } from '@app/core/types';\nimport { ICluster } from '@app/models/cluster';\n\ninterface IStatus {\n [key: number]: { status: number };\n}\n\nexport interface IAllStatus {\n hosts: IStatus;\n services: { details: [{ host: string | number; component: string | number; status: number }]; status: number }[];\n components: IStatus;\n status: number;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class StatusService {\n constructor(private api: ApiService) { }\n\n getStatusInfo(id: number, hostcomponent_link: string) {\n const statuses$ = this.getAllClusterStatus(id),\n host_components$ = this.getHostComponents(hostcomponent_link);\n return combineLatest([statuses$, host_components$]);\n }\n\n getHostComponents(url: string): Observable {\n return this.api\n .get<{ host: Host[]; hc: HostComponent[]; component: IComponent[] }>(url)\n .pipe(map((a) => a.hc.map((hc) => ({ ...hc, monitoring: a.component.find((b) => b.id === hc.component_id).monitoring }))));\n }\n\n getServiceComponentsByCluster(cluster: ICluster, service_id?: number): Observable {\n return this.api.get(cluster.status_url).pipe(map((s) => s.filter((se) => (service_id ? se.service_id === service_id : true))));\n }\n\n getHostcomponentStatus(k: HostComponent, all: IAllStatus) {\n const c = all.services[k.service_id]?.details.find((e) => +e.host === k.host_id && +e.component === k.component_id);\n return c ? c.status : null;\n }\n\n getComponentsOnly(a: [IAllStatus, HostComponent[]], host_id?: number) {\n const all: IAllStatus = a[0],\n hc: HostComponent[] = a[1];\n return hc\n .filter((h) => (host_id ? host_id === h.host_id : true))\n .reduce((acc, cur) => (!acc.some((c) => c.host_id === cur.host_id && c.service_id === cur.service_id) ? [...acc, cur] : acc), [])\n .map((k) => ({ ...k, status: this.getHostcomponentStatus(k, all) }))\n .filter((b) => b.status !== 0);\n }\n\n getClusterById(id: number) {\n return this.api.getOne('cluster', id);\n }\n\n getAllClusterStatus(id: number) {\n return this.api.get(`/status/api/v1/cluster/${id}/`);\n }\n\n}\n", - "properties": [ - { - "name": "components", - "deprecated": false, - "deprecationMessage": "", - "type": "IStatus", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "hosts", - "deprecated": false, - "deprecationMessage": "", - "type": "IStatus", - "optional": false, - "description": "", - "line": 25 - }, - { - "name": "services", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type[]", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 28 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IBroadcast", - "id": "interface-IBroadcast-74d64d1aba32ec1d01c0f425b85ec663", - "file": "src/app/core/services/channel.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\nimport { filter, map } from 'rxjs/operators';\n\nexport enum keyChannelStrim {\n 'scroll',\n 'notifying',\n 'load_complete'\n}\n\nexport interface IBroadcast {\n key: TKey;\n value: any;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ChannelService {\n private event = new Subject>();\n\n next(key: TKey, value: T) {\n this.event.next({ key, value });\n }\n\n on(key: TKey): Observable {\n return this.event.asObservable().pipe(\n filter((e) => e.key === key),\n map, T>((a) => a.value)\n );\n }\n}\n", - "properties": [ - { - "name": "key", - "deprecated": false, - "deprecationMessage": "", - "type": "TKey", - "optional": false, - "description": "", - "line": 23 - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 24 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IBundle", - "id": "interface-IBundle-14a63993c33f6fefcc2d321ed9d1c399", - "file": "src/app/models/bundle.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { AdcmEntity } from './entity';\n\nexport interface IBundle extends AdcmEntity {\n adcm_min_version: string;\n date: string;\n description: string;\n edition: string;\n hash: string;\n license: string;\n license_hash: any;\n license_path: any;\n license_url: string;\n name: string;\n update: string;\n url: string;\n version: string;\n}\n", - "properties": [ - { - "name": "adcm_min_version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 4 - }, - { - "name": "date", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 5 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 6 - }, - { - "name": "edition", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 7 - }, - { - "name": "hash", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "license", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "license_hash", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "license_path", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "license_url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 12 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 13 - }, - { - "name": "update", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 14 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 15 - }, - { - "name": "version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 16 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "AdcmEntity" - }, - { - "name": "ICanGroup", - "id": "interface-ICanGroup-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "group", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 172 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ICluster", - "id": "interface-ICluster-02d66359bf89ff72a6106d0bf26393d7", - "file": "src/app/models/cluster.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { BaseEntity } from '@app/core/types';\n\nexport interface ICluster extends BaseEntity {\n bind: string;\n edition: string;\n host: string;\n hostcomponent: string;\n imports: string;\n license: string;\n name: string;\n prototype: string;\n service: string;\n serviceprototype: string;\n status_url: string;\n upgradable: boolean;\n upgrade: string;\n group_config: string;\n}\n", - "properties": [ - { - "name": "bind", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 4 - }, - { - "name": "edition", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 5 - }, - { - "name": "group_config", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 17 - }, - { - "name": "host", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 6 - }, - { - "name": "hostcomponent", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 7 - }, - { - "name": "imports", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "license", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "prototype", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 12 - }, - { - "name": "serviceprototype", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 13 - }, - { - "name": "status_url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 14 - }, - { - "name": "upgradable", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 15 - }, - { - "name": "upgrade", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 16 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "BaseEntity" - }, - { - "name": "IClusterService", - "id": "interface-IClusterService-f8899584d3dd5452c7417e7f5ca0f1fb", - "file": "src/app/models/cluster-service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IComponent } from './component';\nimport { BaseEntity } from '@app/core/types';\n\nexport interface IClusterService extends BaseEntity {\n bind: string;\n cluster_id: number;\n component: string;\n components: IComponent[];\n imports: string;\n monitoring: string;\n prototype: string;\n version: string;\n}\n", - "properties": [ - { - "name": "bind", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 5 - }, - { - "name": "cluster_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 6 - }, - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 7 - }, - { - "name": "components", - "deprecated": false, - "deprecationMessage": "", - "type": "IComponent[]", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "imports", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "monitoring", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "prototype", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 12 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "BaseEntity" - }, - { - "name": "ICompare", - "id": "interface-ICompare-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "color", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 158 - }, - { - "name": "date", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 156 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 155 - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 157 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IComponent", - "id": "interface-IComponent-a7191288c15d96f4122bd712c71ca797", - "file": "src/app/models/component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { AdcmEntity } from './entity';\n\nexport interface IComponent extends AdcmEntity {\n action: string;\n bound_to: any;\n config: string;\n constraint: Array;\n description: string;\n monitoring: string;\n prototype_id: number;\n requires: any[];\n status: number;\n url: string;\n}\n", - "properties": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 4 - }, - { - "name": "bound_to", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 5 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 6 - }, - { - "name": "constraint", - "deprecated": false, - "deprecationMessage": "", - "type": "Array", - "optional": false, - "description": "", - "line": 7 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "monitoring", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "prototype_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "requires", - "deprecated": false, - "deprecationMessage": "", - "type": "any[]", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 12 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 13 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "AdcmEntity" - }, - { - "name": "IComponent", - "id": "interface-IComponent-50993353cad3d133a2be743502171874-1", - "file": "src/app/core/types/host-component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface HostComponent {\n id: number;\n /** host name */\n host: string;\n host_id: number;\n /** component name */\n component: string;\n component_display_name: string;\n component_id: number;\n service_id: number;\n service_display_name: string;\n service_name: string;\n service_version: string;\n state: string;\n url: string;\n host_url: string;\n status: number;\n monitoring: 'passive' | 'active';\n}\n\n/**\n * A service component that may be installed on hosts in a cluster.\n */\nexport interface IComponent {\n id: number;\n prototype_id: number;\n service_id: number;\n service_name: string;\n service_state: string;\n name: string;\n display_name: string;\n status: number;\n constraint: any;\n monitoring?: 'passive' | 'active'; // status page\n requires?: IRequires[];\n}\n\nexport interface IRequires {\n // id: number;\n prototype_id: number;\n name: string;\n display_name: string;\n components?: IRequires[];\n}\n", - "properties": [ - { - "name": "constraint", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 50 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 48 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "monitoring", - "deprecated": false, - "deprecationMessage": "", - "type": "\"passive\" | \"active\"", - "optional": true, - "description": "", - "line": 51 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 47 - }, - { - "name": "prototype_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "requires", - "deprecated": false, - "deprecationMessage": "", - "type": "IRequires[]", - "optional": true, - "description": "", - "line": 52 - }, - { - "name": "service_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 44 - }, - { - "name": "service_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "service_state", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 46 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 49 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "

A service component that may be installed on hosts in a cluster.

\n", - "rawdescription": "\n\nA service component that may be installed on hosts in a cluster.\n", - "methods": [], - "isDuplicate": true, - "duplicateId": 1, - "duplicateName": "IComponent-1" - }, - { - "name": "IComposite", - "id": "interface-IComposite-3c17dd4f9160f4d8db43f357e0ec37f1", - "file": "src/app/shared/components/import/import.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, Input, OnInit } from '@angular/core';\nimport { AbstractControl, FormControl, FormGroup, ValidatorFn } from '@angular/forms';\nimport { MatCheckboxChange } from '@angular/material/checkbox';\nimport { Observable } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\nimport { ChannelService } from '@app/core/services';\nimport { keyChannelStrim } from '@app/core/services';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { IExport, IImport } from '@app/core/types';\n\ninterface IComposite {\n [key: string]: number;\n}\n\nconst trueOnly = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (control.value ? null : { trueOnly: !control.value });\n\nconst requiredObject = (): ValidatorFn => (control: AbstractControl): { [key: string]: boolean } | null =>\n Object.keys(control.value).some((key) => control.value[key]) ? null : { requiered: true };\n\n@Component({\n selector: 'app-exports',\n template: `\n \n \n
\n {{ item.obj_name }}\n
{{ item.bundle_name }} {{ item.bundle_version }}
\n
\n
\n
\n `,\n styles: ['.component {padding: 6px 8px; margin-bottom: 18px; font-size: 18px;}', '.component div {font-size: 12px;margin-left: 24px; margin-top: 4px;}'],\n})\nexport class ExportComponent {\n @Input() form: FormGroup;\n @Input() import: IImport;\n\n getKey(id: IComposite) {\n return JSON.stringify(id);\n }\n\n change(e: MatCheckboxChange, item: IExport) {\n if (!this.import.multibind) {\n const group = this.form.controls[this.getKey({ import_id: this.import.id })] as FormGroup;\n\n if (e.checked)\n Object.keys(group.controls)\n .map((key) => {\n group.controls[key].clearValidators();\n return key;\n })\n .filter((key) => key !== this.getKey(item.id))\n .map((key) => group.controls[key].setValue(false));\n else if (this.import.required) {\n Object.keys(group.controls).map((key) => {\n const c = group.controls[key];\n c.setValidators(trueOnly());\n c.updateValueAndValidity();\n });\n }\n }\n }\n}\n\n@Component({\n selector: 'app-import',\n template: `\n

\n \n

\n
\n
\n

\n {{ item.name }}\n This import is required!\n

\n \n
\n
\n `,\n styleUrls: ['./import.component.scss'],\n})\nexport class ImportComponent implements OnInit {\n form = new FormGroup({});\n data$: Observable;\n asIs = false;\n\n constructor(private current: ClusterService, private channel: ChannelService) {}\n\n getKey(id: IComposite) {\n return JSON.stringify(id);\n }\n\n hasError(id: number) {\n return this.form.get(this.getKey({ import_id: id })).invalid;\n }\n\n ngOnInit() {\n this.data$ = this.current.getImportData().pipe(\n tap((a) => (this.asIs = !!a.length)),\n tap((a) =>\n a.map((i: IImport) => {\n const validFlag = i.required && !i.multibind && i.exports.every((e) => !e.binded);\n const exportGroup = i.exports.reduce((p, c) => {\n const fc = {};\n fc[`${this.getKey(c.id)}`] = new FormControl(c.binded, validFlag ? trueOnly() : null);\n return { ...p, ...fc };\n }, {});\n const import_id = this.getKey({ import_id: i.id });\n this.form.addControl(import_id, new FormGroup(exportGroup, i.required ? requiredObject() : null));\n })\n )\n );\n }\n\n go() {\n if (!this.form.invalid) {\n let bind = [];\n Object.keys(this.form.controls)\n .filter((a) => Object.keys(this.form.controls[a].value).length)\n .map((key) => {\n const obj = JSON.parse(key);\n const value = this.form.controls[key].value;\n const items = Object.keys(value)\n .filter((a) => value[a] === true)\n .map((a) => ({ ...obj, export_id: JSON.parse(a) }));\n bind = [...bind, ...items];\n });\n this.current.bindImport({ bind }).subscribe((_) => this.channel.next(keyChannelStrim.notifying, 'Successfully saved'));\n }\n }\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-3c17dd4f9160f4d8db43f357e0ec37f1", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "number", - "line": 23, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "methods": [] - }, - { - "name": "IConfig", - "id": "interface-IConfig-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "attr", - "deprecated": false, - "deprecationMessage": "", - "type": "IConfigAttr", - "optional": true, - "description": "", - "line": 98 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "IFieldStack[]", - "optional": false, - "description": "", - "line": 97 - }, - { - "name": "date", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 95 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 96 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 94 - }, - { - "name": "obj_ref", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 99 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "

The object for config for backend

\n", - "rawdescription": "\n\nThe object for config for backend\n", - "methods": [] - }, - { - "name": "IConfigAttr", - "id": "interface-IConfigAttr-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "custom_group_keys", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": true, - "description": "", - "line": 113 - }, - { - "name": "group_keys", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": true, - "description": "", - "line": 112 - } - ], - "indexSignatures": [ - { - "id": "index-declaration-312293bd783a3bdacb9b6b1a75808e99", - "args": [ - { - "name": "group", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "literal type", - "line": 109, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 163, - "description": "
{\n[group: string]: { active: boolean };\n}
", - "rawdescription": "\n\n```\n{\n[group: string]: { active: boolean };\n}\n```\n", - "methods": [] - }, - { - "name": "IConfigListResponse", - "id": "interface-IConfigListResponse-22030f6a941975f09576eee3ff38c576", - "file": "src/app/shared/configuration/services/config.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { CompareConfig, IConfig } from '../types';\nimport { map, switchMap } from 'rxjs/operators';\nimport { getRandomColor } from '@app/core/types';\nimport { ApiService } from '@app/core/api';\n\nexport interface IConfigResponse {\n current: string;\n history: string;\n previous: string;\n}\n\nexport interface IConfigListResponse {\n count: 1;\n next: null;\n previous: null;\n results: IConfig[];\n}\n\n\nexport interface IConfigService {\n getConfig(url: string): Observable;\n\n getHistoryList(url: string, currentVersionId: number): Observable;\n\n send(url: string, data: any): Observable;\n\n changeVersion(id: number, url?: string): Observable;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigService implements IConfigService {\n constructor(private api: ApiService) { }\n\n changeVersion(id: number, url: string): Observable {\n return this.api.get(`${url}history/${id}/`);\n }\n\n getConfig(url: string): Observable {\n return this.api.get(`${url}current/`);\n }\n\n getHistoryList(url: string, currentVersionId: number): Observable {\n return this.api.get(url).pipe(\n switchMap((config) => this.api.get(config.history)),\n // ToDo remove it when API will be consistent\n map((value) => Array.isArray(value) ? value as IConfig[] : value.results),\n map((h) => h.filter((a) => a.id !== currentVersionId).map((b) => ({\n ...b,\n color: getRandomColor()\n }))));\n }\n\n send(url: string, data: any): Observable {\n return this.api.post(`${url}history/`, data);\n }\n}\n", - "properties": [ - { - "name": "count", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 15 - }, - { - "name": "next", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 16 - }, - { - "name": "previous", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 17 - }, - { - "name": "results", - "deprecated": false, - "deprecationMessage": "", - "type": "IConfig[]", - "optional": false, - "description": "", - "line": 18 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IConfigResponse", - "id": "interface-IConfigResponse-22030f6a941975f09576eee3ff38c576", - "file": "src/app/shared/configuration/services/config.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { CompareConfig, IConfig } from '../types';\nimport { map, switchMap } from 'rxjs/operators';\nimport { getRandomColor } from '@app/core/types';\nimport { ApiService } from '@app/core/api';\n\nexport interface IConfigResponse {\n current: string;\n history: string;\n previous: string;\n}\n\nexport interface IConfigListResponse {\n count: 1;\n next: null;\n previous: null;\n results: IConfig[];\n}\n\n\nexport interface IConfigService {\n getConfig(url: string): Observable;\n\n getHistoryList(url: string, currentVersionId: number): Observable;\n\n send(url: string, data: any): Observable;\n\n changeVersion(id: number, url?: string): Observable;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigService implements IConfigService {\n constructor(private api: ApiService) { }\n\n changeVersion(id: number, url: string): Observable {\n return this.api.get(`${url}history/${id}/`);\n }\n\n getConfig(url: string): Observable {\n return this.api.get(`${url}current/`);\n }\n\n getHistoryList(url: string, currentVersionId: number): Observable {\n return this.api.get(url).pipe(\n switchMap((config) => this.api.get(config.history)),\n // ToDo remove it when API will be consistent\n map((value) => Array.isArray(value) ? value as IConfig[] : value.results),\n map((h) => h.filter((a) => a.id !== currentVersionId).map((b) => ({\n ...b,\n color: getRandomColor()\n }))));\n }\n\n send(url: string, data: any): Observable {\n return this.api.post(`${url}history/`, data);\n }\n}\n", - "properties": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "history", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "previous", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 11 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IConfigService", - "id": "interface-IConfigService-22030f6a941975f09576eee3ff38c576", - "file": "src/app/shared/configuration/services/config.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { CompareConfig, IConfig } from '../types';\nimport { map, switchMap } from 'rxjs/operators';\nimport { getRandomColor } from '@app/core/types';\nimport { ApiService } from '@app/core/api';\n\nexport interface IConfigResponse {\n current: string;\n history: string;\n previous: string;\n}\n\nexport interface IConfigListResponse {\n count: 1;\n next: null;\n previous: null;\n results: IConfig[];\n}\n\n\nexport interface IConfigService {\n getConfig(url: string): Observable;\n\n getHistoryList(url: string, currentVersionId: number): Observable;\n\n send(url: string, data: any): Observable;\n\n changeVersion(id: number, url?: string): Observable;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigService implements IConfigService {\n constructor(private api: ApiService) { }\n\n changeVersion(id: number, url: string): Observable {\n return this.api.get(`${url}history/${id}/`);\n }\n\n getConfig(url: string): Observable {\n return this.api.get(`${url}current/`);\n }\n\n getHistoryList(url: string, currentVersionId: number): Observable {\n return this.api.get(url).pipe(\n switchMap((config) => this.api.get(config.history)),\n // ToDo remove it when API will be consistent\n map((value) => Array.isArray(value) ? value as IConfig[] : value.results),\n map((h) => h.filter((a) => a.id !== currentVersionId).map((b) => ({\n ...b,\n color: getRandomColor()\n }))));\n }\n\n send(url: string, data: any): Observable {\n return this.api.post(`${url}history/`, data);\n }\n}\n", - "properties": [], - "indexSignatures": [], - "kind": 165, - "methods": [ - { - "name": "changeVersion", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getConfig", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getHistoryList", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "currentVersionId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "currentVersionId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "send", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ] - }, - { - "name": "IControl", - "id": "interface-IControl-19b19308484527efdbe79aeeb38c9a3d", - "file": "src/app/shared/configuration/scheme/scheme.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { AbstractControl, FormArray, FormControl, FormGroup, ValidatorFn } from '@angular/forms';\nimport { isObject } from '@app/core/types/func';\n\nimport { FieldService } from '../services/field.service';\nimport { IFieldOptions, TNForm, TNReq, TValue } from '../types';\nimport { IYContainer, IYField } from '../yspec/yspec.service';\n\nexport interface IValue {\n [key: string]: TValue;\n}\n\nexport interface IControl {\n name: string;\n type: TNForm;\n rules: IYField | IYContainer | (IYField | IYContainer)[];\n form: FormGroup | FormArray;\n value: IValue | TValue;\n parent: TNReq;\n}\n\n@Injectable()\nexport class SchemeService {\n constructor(private service: FieldService) {}\n\n emptyValidator() {\n // const isEmptyArray = (v: any) => (Array.isArray(v) && v.length ? v.some((a) => isEmptyValue(a)) : false);\n // const isEmptyObj = (v: any) => (isObject(v) && Object.keys(v).length ? Object.keys(v).some((a) => isEmptyValue(v[a])) : false);\n const isEmptyValue = (v: any) => !v || (Array.isArray(v) && !v.length) || (isObject(v) && !Object.keys(v).length);\n return (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (isEmptyValue(control.value) ? { isEmpty: true } : null);\n }\n\n setCurrentForm(type: TNForm, parent: FormGroup, field: IFieldOptions) {\n const v = field.required ? this.emptyValidator()() : null;\n const current = type === 'list' || type === 'dict' ? (type === 'list' ? new FormArray([], v) : new FormGroup({}, v)) : new FormControl('', v);\n parent.setControl(field.name, current);\n return current;\n }\n\n addControlsDict(name: string, source: TValue | IValue, currentForm: FormArray, rules: IYContainer[]): IControl {\n const value = !source ? rules.reduce((p, c) => ({ ...p, [c.name]: '' }), {}) : source;\n\n const checkValue = () => {\n if (Array.isArray(rules)) {\n if (Array.isArray(value)) {\n return rules.some((a) => a.name === value[0]);\n } else if (typeof value === 'object') {\n return Object.keys(value).every((x) => rules.some((a) => a.name === x));\n }\n }\n };\n\n if (checkValue()) {\n const form = new FormGroup({});\n currentForm.push(form);\n return { name, value, type: 'dict', rules, form, parent: 'list' };\n }\n }\n\n addControls(name: string, value: TValue | IValue, currentForm: FormGroup | FormArray, opt: IYContainer | IYField | (IYContainer | IYField)[], type: TNReq): IControl {\n const rules = Array.isArray(opt) ? opt.find((a) => a.name === name) : opt;\n if (!rules) return;\n let form = currentForm;\n if (rules.type !== 'list' && rules.type !== 'dict') {\n const { validator, controlType } = rules as IYField;\n if (Array.isArray(currentForm.controls)) {\n name = currentForm.controls.length.toString();\n (currentForm as FormArray).push(new FormControl(value || '', this.service.setValidator({ validator, controlType })));\n } else (currentForm as FormGroup).addControl(rules.name, new FormControl(rules.type !== 'bool' ? value || '' : value, this.service.setValidator({ validator, controlType })));\n } else {\n form = rules.type === 'list' ? new FormArray([]) : new FormGroup({});\n (currentForm as FormGroup).addControl(rules.name, form);\n }\n\n return { name, value, type: rules.type, rules, form, parent: type };\n }\n}\n", - "properties": [ - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "type": "FormGroup | FormArray", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 25 - }, - { - "name": "parent", - "deprecated": false, - "deprecationMessage": "", - "type": "TNReq", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "rules", - "deprecated": false, - "deprecationMessage": "", - "type": "IYField | IYContainer | (IYField | IYContainer)[]", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "TNForm", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "IValue | TValue", - "optional": false, - "description": "", - "line": 29 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IDetails", - "id": "interface-IDetails-39eefd83a4c8cabaa98c367c8d80a8a1", - "file": "src/app/models/details.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { ICluster } from './cluster';\nimport { IAction, JobObject, LogFile, TypeName } from '../core/types';\nimport { IIssues } from './issue';\nimport { AdcmTypedEntity } from './entity';\n\nexport interface IDetails {\n parent?: ICluster;\n typeName: TypeName;\n id: number;\n name: string;\n upgradable: boolean;\n upgrade: string;\n status: string | number;\n /** link to actionss */\n action: string;\n actions: IAction[];\n issue: IIssues;\n log_files?: LogFile[];\n objects: JobObject[];\n prototype_name: string;\n prototype_display_name: string;\n prototype_version: string;\n provider_id: number;\n bundle_id: number;\n hostcomponent: string;\n state: string;\n}\n\nexport interface INavItem {\n id?: number;\n title: string;\n url: string;\n issue?: string;\n status?: number;\n statusMessage?: string;\n action?: () => void;\n}\n\nexport interface IStyledNavItem {\n class?: string;\n entity?: AdcmTypedEntity;\n}\n", - "properties": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "

link to actionss

\n", - "line": 15, - "rawdescription": "\nlink to actionss" - }, - { - "name": "actions", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction[]", - "optional": false, - "description": "", - "line": 16 - }, - { - "name": "bundle_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 24 - }, - { - "name": "hostcomponent", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 25 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "issue", - "deprecated": false, - "deprecationMessage": "", - "type": "IIssues", - "optional": false, - "description": "", - "line": 17 - }, - { - "name": "log_files", - "deprecated": false, - "deprecationMessage": "", - "type": "LogFile[]", - "optional": true, - "description": "", - "line": 18 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "objects", - "deprecated": false, - "deprecationMessage": "", - "type": "JobObject[]", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "parent", - "deprecated": false, - "deprecationMessage": "", - "type": "ICluster", - "optional": true, - "description": "", - "line": 7 - }, - { - "name": "prototype_display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 21 - }, - { - "name": "prototype_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 20 - }, - { - "name": "prototype_version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "provider_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 23 - }, - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "string | number", - "optional": false, - "description": "", - "line": 13 - }, - { - "name": "typeName", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "upgradable", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "upgrade", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 12 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IEMObject", - "id": "interface-IEMObject-ca14b9fd2a8ab6897860f58a705daf52", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { TypeName } from '@app/core/types';\nimport {\n Action,\n createAction,\n createFeatureSelector,\n createReducer,\n createSelector,\n on,\n props,\n select\n} from '@ngrx/store';\nimport { pipe } from 'rxjs';\nimport { skip } from 'rxjs/operators';\n\n/**\n * Event Message Object dispatched from socket\n */\nexport interface IEMObject {\n type: TypeName;\n id: number;\n details: {\n id?: number;\n type: string;\n value: any;\n };\n}\n\nexport type EntityEvent =\n | 'add'\n | 'add_job_log'\n | 'create'\n | 'delete'\n | 'remove'\n | 'change_config'\n | 'change_state'\n | 'change_status'\n | 'change_job_status'\n | 'change_hostcomponentmap'\n | 'upgrade'\n | 'concern';\n\nexport interface EventMessage {\n event: EntityEvent;\n object?: IEMObject;\n}\n\nexport type StatusType = 'open' | 'close' | 're-open';\n\nexport const socketInit = createAction('[Socket] Init');\nexport const socketOpen = createAction('[Socket] Open', props<{ status: StatusType }>());\nexport const socketClose = createAction('[Socket] Close', props<{ status: StatusType }>());\nexport const socketResponse = createAction('[Socket] Response', props<{ message: EventMessage }>());\nexport const clearMessages = createAction('[Socket] Clear messages');\n\nexport interface SocketState {\n status: StatusType;\n message: EventMessage;\n}\n\nconst initialState: SocketState = {\n status: null,\n message: null,\n};\n\nconst reducer = createReducer(\n initialState,\n on(socketInit, (state) => ({ ...state })),\n on(socketOpen, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketClose, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketResponse, (state, { message }) => ({\n ...state,\n message,\n })),\n on(clearMessages, (state) => ({ ...state, message: null }))\n);\n\nexport function socketReducer(state: SocketState, action: Action) {\n return reducer(state, action);\n}\n\nexport const getSocketState = createFeatureSelector('socket');\nexport const getConnectStatus = createSelector(getSocketState, (state: SocketState) => state.status);\nexport const getMessage = createSelector(getSocketState, (state) => state.message);\nexport const selectMessage = pipe(\n select(getMessage),\n skip(1),\n);\n", - "properties": [ - { - "name": "details", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 30 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "

Event Message Object dispatched from socket

\n", - "rawdescription": "\n\nEvent Message Object dispatched from socket\n", - "methods": [] - }, - { - "name": "IError", - "id": "interface-IError-48bdc39db9b8bb2237d76b204a2e01dc", - "file": "src/app/core/types/utils.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface EmmitRow {\n cmd: string;\n row: any;\n item?: any;\n}\n\nexport interface SelectOption {\n id: number | string;\n name: string;\n}\n\nexport interface IError {\n code: string;\n desc: string;\n level: string;\n}\n", - "properties": [ - { - "name": "code", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "desc", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "level", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 33 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IExport", - "id": "interface-IExport-7a91966a6c85b1069e53ba02065de454", - "file": "src/app/core/types/import-export.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface IExport {\n id: { [key: string]: number };\n bind_id: number | null;\n obj_name: string;\n bundle_name: string;\n bundle_version: string;\n binded: boolean;\n}\n\n/** Model for import the configuration of cluster or service */\nexport interface IImport {\n id: number;\n name: string;\n required: boolean;\n multibind: boolean;\n exports: IExport[];\n}\n", - "properties": [ - { - "name": "bind_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number | null", - "optional": false, - "description": "", - "line": 15 - }, - { - "name": "binded", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "bundle_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 17 - }, - { - "name": "bundle_version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 18 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 14 - }, - { - "name": "obj_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 16 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IFieldOptions", - "id": "interface-IFieldOptions-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "compare", - "deprecated": false, - "deprecationMessage": "", - "type": "ICompare[]", - "optional": false, - "description": "", - "line": 178 - }, - { - "name": "controlType", - "deprecated": false, - "deprecationMessage": "", - "type": "controlType", - "optional": false, - "description": "", - "line": 176 - }, - { - "name": "validator", - "deprecated": false, - "deprecationMessage": "", - "type": "IValidator", - "optional": false, - "description": "", - "line": 177 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IFormOptions" - }, - { - "name": "IFieldStack", - "id": "interface-IFieldStack-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "activatable", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 83 - }, - { - "name": "default", - "deprecated": false, - "deprecationMessage": "", - "type": "TValue", - "optional": false, - "description": "", - "line": 80 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 85 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 78 - }, - { - "name": "limits", - "deprecated": false, - "deprecationMessage": "", - "type": "ILimits", - "optional": true, - "description": "", - "line": 86 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 76 - }, - { - "name": "read_only", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 84 - }, - { - "name": "required", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 82 - }, - { - "name": "subname", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 77 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "TNForm", - "optional": false, - "description": "", - "line": 79 - }, - { - "name": "ui_options", - "deprecated": false, - "deprecationMessage": "", - "type": "IUIoptions", - "optional": true, - "description": "", - "line": 87 - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "TValue", - "optional": false, - "description": "", - "line": 81 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "

Property config object from backend

\n", - "rawdescription": "\n\nProperty config object from backend\n", - "methods": [] - }, - { - "name": "IFormOptions", - "id": "interface-IFormOptions-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "hidden", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 163 - }, - { - "name": "key", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 162 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IFieldStack" - }, - { - "name": "IHost", - "id": "interface-IHost-eb2188e7e91204407f369b63cefcc28d", - "file": "src/app/models/host.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { BaseEntity } from '@app/core/types';\n\nexport interface IHost extends BaseEntity {\n cluster_id?: number;\n cluster_url?: string;\n cluster_name?: string;\n clusters: any[];\n fqdn: string;\n host_id: number;\n host_url: string;\n monitoring: string;\n provider_id: number;\n provider_name: number;\n upgradable: boolean;\n}\n", - "properties": [ - { - "name": "cluster_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 4 - }, - { - "name": "cluster_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 6 - }, - { - "name": "cluster_url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 5 - }, - { - "name": "clusters", - "deprecated": false, - "deprecationMessage": "", - "type": "any[]", - "optional": false, - "description": "", - "line": 7 - }, - { - "name": "fqdn", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "host_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "host_url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "monitoring", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "provider_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 12 - }, - { - "name": "provider_name", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 13 - }, - { - "name": "upgradable", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 14 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "BaseEntity" - }, - { - "name": "IImport", - "id": "interface-IImport-7a91966a6c85b1069e53ba02065de454", - "file": "src/app/core/types/import-export.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface IExport {\n id: { [key: string]: number };\n bind_id: number | null;\n obj_name: string;\n bundle_name: string;\n bundle_version: string;\n binded: boolean;\n}\n\n/** Model for import the configuration of cluster or service */\nexport interface IImport {\n id: number;\n name: string;\n required: boolean;\n multibind: boolean;\n exports: IExport[];\n}\n", - "properties": [ - { - "name": "exports", - "deprecated": false, - "deprecationMessage": "", - "type": "IExport[]", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 24 - }, - { - "name": "multibind", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 25 - }, - { - "name": "required", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 26 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "

Model for import the configuration of cluster or service

\n", - "rawdescription": "\nModel for import the configuration of cluster or service", - "methods": [] - }, - { - "name": "IIssueInfo", - "id": "interface-IIssueInfo-aa24c13e7e5ce20ee9dbfb0bcd56e06c", - "file": "src/app/shared/components/issue-info.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, Input, OnInit } from '@angular/core';\n\nimport { ComponentData } from './tooltip/tooltip.service';\nimport { IIssues } from '@app/models/issue';\n\nexport interface IIssueInfo {\n id: number;\n issue: IIssues;\n cluster_id?: number;\n name?: string;\n path?: string;\n}\n\n@Component({\n selector: 'app-issue-info',\n template: `\n
{{ intro }}
\n
\n `,\n styles: ['a, .item-step { display: block; margin: 6px 0 8px 12px; white-space: nowrap;}'],\n})\nexport class IssueInfoComponent implements OnInit {\n\n @Input() intro = 'Issues in:';\n @Input() path: string;\n @Input() current: IIssueInfo;\n @Input() parent: IIssueInfo;\n\n IssuePatch = {\n required_service: 'service',\n required_import: 'import',\n };\n\n IssueNames = {\n config: 'Configuration',\n host_component: 'Host - Components',\n required_service: 'Required a service',\n required_import: 'Required a import',\n };\n\n constructor(private componentData: ComponentData) {}\n\n ngOnInit(): void {\n this.current = this.current || this.componentData.current;\n this.path = this.path || this.componentData.path;\n this.current.path = this.path;\n this.componentData.emitter.emit('Done');\n }\n\n get Path() {\n return this.parent && this.parent.cluster_id !== this.current.id ? `${this.parent.path}/${this.parent.id}/${this.path}` : this.path;\n }\n\n isArray(issue: [] | false): boolean {\n return Array.isArray(issue);\n }\n\n get namesIssue() {\n return Object.keys(this.current.issue || {});\n }\n}\n", - "properties": [ - { - "name": "cluster_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 20 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 18 - }, - { - "name": "issue", - "deprecated": false, - "deprecationMessage": "", - "type": "IIssues", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 21 - }, - { - "name": "path", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 22 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IIssues", - "id": "interface-IIssues-0f92d1325e593762aa0c9547bc0fbddf", - "file": "src/app/models/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { AdcmEntity } from '@app/models/entity';\n\nexport type IssueType = 'cluster' | 'service' | 'servicecomponent' | 'component';\n\nexport interface IssueEntity extends AdcmEntity {\n issue: IIssues;\n}\n\nexport interface IIssues {\n config?: boolean;\n required_import?: boolean;\n host_component?: false;\n cluster?: IssueEntity[];\n service?: IssueEntity[];\n}\n", - "properties": [ - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "IssueEntity[]", - "optional": true, - "description": "", - "line": 13 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 10 - }, - { - "name": "host_component", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": true, - "description": "", - "line": 12 - }, - { - "name": "required_import", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 11 - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "IssueEntity[]", - "optional": true, - "description": "", - "line": 14 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ILimits", - "id": "interface-ILimits-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "active", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 68 - }, - { - "name": "max", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 63 - }, - { - "name": "min", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 62 - }, - { - "name": "option", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": true, - "description": "", - "line": 64 - }, - { - "name": "read_only", - "deprecated": false, - "deprecationMessage": "", - "type": "stateType[]", - "optional": true, - "description": "", - "line": 65 - }, - { - "name": "rules", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": true, - "description": "", - "line": 67 - }, - { - "name": "source", - "deprecated": false, - "deprecationMessage": "", - "type": "IVariantSet", - "optional": true, - "description": "", - "line": 69 - }, - { - "name": "yspec", - "deprecated": false, - "deprecationMessage": "", - "type": "IYspec", - "optional": true, - "description": "", - "line": 66 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IListService", - "id": "interface-IListService-3c12cd1c1b7e9c952df7e5ee215ece55", - "file": "src/app/shared/components/list/list-service-token.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { InjectionToken } from '@angular/core';\nimport { TypeName } from '@app/core/types';\nimport { ParamMap } from '@angular/router';\nimport { Observable } from 'rxjs';\nimport { ListResult } from '@app/models/list-result';\n\nexport const LIST_SERVICE_PROVIDER = new InjectionToken>('ListService');\n\nexport interface ListInstance {\n typeName: TypeName;\n columns: string[];\n}\n\nexport interface IListService {\n current: ListInstance;\n\n initInstance(typeName?: TypeName): ListInstance;\n\n getList(p: ParamMap, typeName?: string): Observable>\n\n delete(row: T): Observable;\n}\n", - "properties": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "ListInstance", - "optional": false, - "description": "", - "line": 15 - } - ], - "indexSignatures": [], - "kind": 165, - "methods": [ - { - "name": "delete", - "args": [ - { - "name": "row", - "type": "T", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 21, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "T", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getList", - "args": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable>", - "typeParameters": [], - "line": 19, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "initInstance", - "args": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "ListInstance", - "typeParameters": [], - "line": 17, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ] - }, - { - "name": "IMasterData", - "id": "interface-IMasterData-4cd1f32b2d3db5ce944b66105c7f592e", - "file": "src/app/shared/components/actions/master/master.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { ApiService } from '@app/core/api';\nimport { IAction } from '@app/core/types';\nimport { FieldService } from '@app/shared/configuration/services/field.service';\nimport { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component';\nimport { ServiceHostComponent } from '@app/shared/host-components-map/services2hosts/service-host.component';\nimport { Post } from '@app/shared/host-components-map/types';\nimport { IConfigAttr } from '@app/shared/configuration/types';\nimport { IOutput } from '@app/shared/configuration/services/field.service';\n\nexport interface IValue {\n config?: ConfigFieldsComponent;\n hostmap?: ServiceHostComponent;\n}\n\nexport enum whatShow {\n none = 'none',\n config = 'config',\n hostMap = 'hostmap',\n stepper = 'stepper',\n}\n\nexport interface IMasterData {\n attr: IConfigAttr;\n config: IOutput;\n hc: Post[];\n verbose?: boolean;\n}\n\n@Injectable()\nexport class MasterService {\n constructor(private api: ApiService, private configService: FieldService) {}\n\n spotShow(action: IAction): whatShow {\n const config = action.config?.config?.length;\n const hm = action.hostcomponentmap?.length;\n return config ? (hm ? whatShow.stepper : whatShow.config) : hm ? whatShow.hostMap : whatShow.none;\n }\n\n parseData(v: IValue): IMasterData {\n const getData = (attr: IConfigAttr, c: ConfigFieldsComponent, h: ServiceHostComponent) => {\n const config = c ? this.configService.parseValue(c.form.value, c.rawConfig.config) : undefined;\n const hc = h?.statePost.data;\n return { attr, config, hc };\n };\n return v ? getData(v.config?.attr, v.config, v.hostmap) : undefined;\n }\n\n send(url: string, value: { config: any; hc: Post[] }) {\n return this.api.post(url, value);\n }\n}\n", - "properties": [ - { - "name": "attr", - "deprecated": false, - "deprecationMessage": "", - "type": "IConfigAttr", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "IOutput", - "optional": false, - "description": "", - "line": 36 - }, - { - "name": "hc", - "deprecated": false, - "deprecationMessage": "", - "type": "Post[]", - "optional": false, - "description": "", - "line": 37 - }, - { - "name": "verbose", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 38 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IMPlaceholder", - "id": "interface-IMPlaceholder-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-e0274bfcdeb483b95ff4b27fb1e2b7af", - "args": [ - { - "name": "itemKey", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "IMPlaceholderItem", - "line": 89, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "methods": [] - }, - { - "name": "IMPlaceholderActionRun", - "id": "interface-IMPlaceholderActionRun-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "ids", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholderItemType.ComponentActionRun", - "optional": false, - "description": "", - "line": 27 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IMPlaceholderItem" - }, - { - "name": "IMPlaceholderCluster", - "id": "interface-IMPlaceholderCluster-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "ids", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 47 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholderItemType.Cluster", - "optional": false, - "description": "", - "line": 46 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IMPlaceholderItem" - }, - { - "name": "IMPlaceholderComponent", - "id": "interface-IMPlaceholderComponent-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "ids", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 62 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholderItemType.Component", - "optional": false, - "description": "", - "line": 61 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IMPlaceholderItem" - }, - { - "name": "IMPlaceholderComponentConfig", - "id": "interface-IMPlaceholderComponentConfig-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "ids", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 38 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholderItemType.ComponentConfig", - "optional": false, - "description": "", - "line": 37 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IMPlaceholderItem" - }, - { - "name": "IMPlaceholderHost", - "id": "interface-IMPlaceholderHost-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "ids", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 78 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholderItemType.Host", - "optional": false, - "description": "", - "line": 77 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IMPlaceholderItem" - }, - { - "name": "IMPlaceholderHostProvider", - "id": "interface-IMPlaceholderHostProvider-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "ids", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 71 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholderItemType.HostProvider", - "optional": false, - "description": "", - "line": 70 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IMPlaceholderItem" - }, - { - "name": "IMPlaceholderItem", - "id": "interface-IMPlaceholderItem-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "ids", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type | number", - "optional": false, - "description": "", - "line": 23 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholderItemType", - "optional": true, - "description": "", - "line": 21 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IMPlaceholderJob", - "id": "interface-IMPlaceholderJob-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "ids", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 86 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholderItemType.Job", - "optional": false, - "description": "", - "line": 85 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IMPlaceholderItem" - }, - { - "name": "IMPlaceholderService", - "id": "interface-IMPlaceholderService-e0274bfcdeb483b95ff4b27fb1e2b7af", - "file": "src/app/models/concern/concern-reason.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export enum ConcernEventType {\n Cluster = 'cluster-concerns',\n Service = 'cluster-object-concerns',\n Host = 'host-concerns',\n HostProvider = 'host-provider-concerns',\n ServiceComponent = 'service-component-concerns',\n}\n\nexport enum IMPlaceholderItemType {\n ComponentActionRun = 'component_action_run',\n ComponentConfig = 'component_config',\n Cluster = 'cluster',\n Service = 'service',\n Component = 'component',\n HostProvider = 'provider',\n Host = 'host',\n Job = 'job',\n}\n\nexport interface IMPlaceholderItem {\n type?: IMPlaceholderItemType;\n name: string;\n ids: { [id: string]: number } | number;\n}\n\nexport interface IMPlaceholderActionRun extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentActionRun;\n ids: {\n cluster: number;\n service: number;\n component: number;\n action: number;\n };\n}\n\nexport interface IMPlaceholderComponentConfig extends IMPlaceholderItem {\n type: IMPlaceholderItemType.ComponentConfig;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderCluster extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Cluster;\n ids: {\n cluster: number;\n };\n}\n\nexport interface IMPlaceholderService extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Service;\n ids: {\n cluster: number;\n service: number;\n };\n}\n\nexport interface IMPlaceholderComponent extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Component;\n ids: {\n cluster: number;\n service: number;\n component: number;\n };\n}\n\nexport interface IMPlaceholderHostProvider extends IMPlaceholderItem {\n type: IMPlaceholderItemType.HostProvider;\n ids: {\n provider: number;\n };\n}\n\nexport interface IMPlaceholderHost extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Host;\n ids: {\n host: number;\n provider: number;\n };\n}\n\nexport interface IMPlaceholderJob extends IMPlaceholderItem {\n type: IMPlaceholderItemType.Job;\n ids: number;\n}\n\nexport interface IMPlaceholder {\n [itemKey: string]: IMPlaceholderItem;\n}\n\nexport interface ConcernReason {\n message: string;\n placeholder: IMPlaceholder;\n}\n", - "properties": [ - { - "name": "ids", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 54 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "IMPlaceholderItemType.Service", - "optional": false, - "description": "", - "line": 53 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IMPlaceholderItem" - }, - { - "name": "INavItem", - "id": "interface-INavItem-39eefd83a4c8cabaa98c367c8d80a8a1", - "file": "src/app/models/details.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { ICluster } from './cluster';\nimport { IAction, JobObject, LogFile, TypeName } from '../core/types';\nimport { IIssues } from './issue';\nimport { AdcmTypedEntity } from './entity';\n\nexport interface IDetails {\n parent?: ICluster;\n typeName: TypeName;\n id: number;\n name: string;\n upgradable: boolean;\n upgrade: string;\n status: string | number;\n /** link to actionss */\n action: string;\n actions: IAction[];\n issue: IIssues;\n log_files?: LogFile[];\n objects: JobObject[];\n prototype_name: string;\n prototype_display_name: string;\n prototype_version: string;\n provider_id: number;\n bundle_id: number;\n hostcomponent: string;\n state: string;\n}\n\nexport interface INavItem {\n id?: number;\n title: string;\n url: string;\n issue?: string;\n status?: number;\n statusMessage?: string;\n action?: () => void;\n}\n\nexport interface IStyledNavItem {\n class?: string;\n entity?: AdcmTypedEntity;\n}\n", - "properties": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "function", - "optional": true, - "description": "", - "line": 36 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 30 - }, - { - "name": "issue", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 33 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 34 - }, - { - "name": "statusMessage", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 35 - }, - { - "name": "title", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 32 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IOutput", - "id": "interface-IOutput-d78cb6aa832432b3e07848b2b3bbd66d", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms';\nimport { isEmptyObject } from '@app/core/types';\n\nimport { ISearchParam } from '../main/main.service';\nimport {\n controlType,\n IConfig,\n IConfigAttr,\n IFieldOptions,\n IFieldStack,\n ILimits,\n IPanelOptions,\n IValidator,\n resultTypes,\n TNBase,\n TNForm\n} from '../types';\nimport { AttributeService } from '@app/shared/configuration/attributes/attribute.service';\n\nexport type TFormOptions = IFieldOptions | IPanelOptions;\n\nexport interface IOutput {\n [key: string]: resultTypes;\n}\n\nexport interface ISource {\n name: string;\n subname: string;\n type: TNForm;\n read_only: boolean;\n limits?: ILimits;\n value: any;\n}\n\nexport interface IToolsEvent {\n name: string;\n conditions?: { advanced: boolean; search: string } | boolean;\n}\n\nconst isVisibleField = (a: TFormOptions) => !a.ui_options?.invisible;\nconst isAdvancedField = (a: TFormOptions) => isVisibleField(a) && a.ui_options?.advanced;\nconst isHidden = (a: IFieldStack) => !!(a.ui_options?.invisible || a.ui_options?.advanced);\n\nconst typeToControl: Partial<{ [key in TNForm | controlType]: controlType }> = {\n bool: 'boolean',\n int: 'textbox',\n integer: 'textbox',\n float: 'textbox',\n string: 'textbox',\n file: 'textarea',\n text: 'textarea',\n};\n\nexport const getControlType = (t: TNForm): controlType => typeToControl[t] || (t as controlType);\n\nconst intPattern = () => new RegExp(/^[-]?\\d+$/);\nconst patternFn = {\n integer: intPattern,\n int: intPattern,\n float: () => new RegExp(/^[-]?[0-9]+(\\.[0-9]+)?$/),\n};\n\nexport const getPattern = (t: TNForm): RegExp => (patternFn[t] ? patternFn[t]() : null);\n\nconst fn = {\n boolean: (v: boolean | null, d: boolean | null, r: boolean): boolean | null => (String(v) === 'true' || String(v) === 'false' || String(v) === 'null' ? v : r ? d : null),\n json: (v: string): string => (v === null ? '' : JSON.stringify(v, undefined, 4)),\n map: (v: object, d: object): object => (!v ? d : v),\n list: (v: string[], d: string[]): string[] => (!v ? d : v),\n structure: (v: any): any => v,\n};\n\nexport const getValue = (t: TNForm) => {\n const def = (value: number | string) => (value === null || value === undefined ? '' : String(value));\n return fn[t] ? fn[t] : def;\n};\n\nexport const getKey = (name: string, subname: string): string => (subname ? `${subname}/${name}` : name);\n\nexport const getValidator = (required: boolean, min: number, max: number, type: TNForm) => ({\n required,\n min,\n max,\n pattern: getPattern(type),\n});\n\nconst getField = (item: IFieldStack): IFieldOptions => {\n return {\n ...item,\n key: getKey(item.name, item.subname),\n value: getValue(item.type)(item.value, item.default, item.required),\n validator: getValidator(item.required, item.limits?.min, item.limits?.max, item.type),\n controlType: getControlType(item.type),\n hidden: item.name === '__main_info' || isHidden(item),\n compare: []\n };\n};\n\nconst fo = (n: string) => (b: IFieldStack) => b.type !== 'group' && b.subname && b.name === n;\nconst isActive = (a: IConfigAttr, n: string) => a[n]?.active;\nexport const getOptions = (a: IFieldStack, d: IConfig) =>\n d.config\n .filter(fo(a.name))\n .map((f) => getField(f))\n // switch off validation for field if !(activatable: true && active: false) - line: 146\n .map((c) => ({ ...c, name: c.subname, activatable: a.activatable && !isActive(d.attr, a.name) }));\n\nconst getPanel = (a: IFieldStack, d: IConfig): IPanelOptions => ({\n ...a,\n hidden: isHidden(a),\n active: a.activatable ? isActive(d.attr, a.name) : true,\n options: getOptions(a, d),\n});\n\nconst handleTree = (c: ISearchParam): ((a: TFormOptions) => TFormOptions) => (a: TFormOptions): TFormOptions => {\n if ('options' in a) {\n a.options = a.options.map(handleTree(c));\n if (c.search) a.hidden = a.options.filter((b) => !b.hidden).length === 0;\n else a.hidden = isAdvancedField(a) ? !c.advanced : false;\n } else if (isVisibleField(a)) {\n a.hidden = !(a.display_name.toLowerCase().includes(c.search.toLowerCase()) || String(a.value).toLocaleLowerCase().includes(c.search.toLocaleLowerCase()));\n if (!a.hidden && isAdvancedField(a)) a.hidden = !c.advanced;\n }\n return a;\n};\n\nconst findAttrValue = (obj: T, key: string): boolean => {\n let value;\n for (let i in obj) {\n if (!obj.hasOwnProperty(i)) continue;\n if (typeof obj[i] === 'object') {\n value = findAttrValue(obj[i], key);\n } else if (i === key) {\n value = obj[i];\n }\n }\n return value;\n};\n\n@Injectable()\nexport class FieldService {\n attributesService: AttributeService | undefined;\n\n constructor(public fb: FormBuilder) {}\n\n /**\n * Parse and prepare source data from backend\n */\n public getPanels(data: IConfig): TFormOptions[] {\n return data?.config\n ?.filter((a) => a.name !== '__main_info')\n .reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, getField(c)];\n else return [...p, getPanel(c, data)];\n }, []);\n }\n\n /**\n * Generate FormGroup\n * @param options\n */\n public toFormGroup(options: TFormOptions[] = []): FormGroup {\n const check = (a: TFormOptions): boolean =>\n 'options' in a\n ? a.activatable\n ? isVisibleField(a) // if group.activatable - only visible\n : isVisibleField(a) && !a.read_only // else visible an not read_only\n ? a.options.some((b) => check(b)) // check inner fields\n : false\n : isVisibleField(a) && !a.read_only; // for fields in group\n\n return this.fb.group(\n options.reduce((p, c) => this.runByTree(c, p), {}),\n {\n validator: () => (options.filter(check).length === 0 ? { error: 'Form is empty' } : null),\n }\n );\n }\n\n // TODO:\n private runByTree(field: TFormOptions, controls: { [key: string]: {} }): { [key: string]: {} } {\n if ('options' in field) {\n controls[field.name] = this.fb.group(\n field.options.reduce((p, a) => {\n if ('options' in a) this.fb.group(this.runByTree(a, p));\n else this.fillForm(a, p);\n return p;\n }, {})\n );\n return controls;\n } else {\n return this.fillForm(field, controls);\n }\n }\n\n private fillForm(field: IFieldOptions, controls: {}) {\n const name = field.subname || field.name;\n controls[name] = this.fb.control(field.value, field.activatable ? [] : this.setValidator(field));\n return controls;\n }\n\n /**\n * External use (scheme.service) to set validator for FormControl by type\n * @param field Partial{ ValidatorInfo, controlType }\n * @param controlToCompare\n */\n public setValidator(field: { validator: IValidator; controlType: controlType }, controlToCompare?: AbstractControl) {\n const v: ValidatorFn[] = [];\n\n if (field.validator.required) v.push(Validators.required);\n if (field.validator.pattern) v.push(Validators.pattern(field.validator.pattern));\n //if (field.validator.max !== null)\n v.push(Validators.max(field.validator.max));\n //if (field.validator.min !== null)\n v.push(Validators.min(field.validator.min));\n\n if (field.controlType === 'password') {\n const passwordConfirm = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => {\n if (controlToCompare && controlToCompare.value !== control.value) return { notEqual: true };\n return null;\n };\n v.push(passwordConfirm());\n }\n\n if (field.controlType === 'json') {\n const jsonParse = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => {\n if (control.value) {\n try {\n JSON.parse(control.value);\n return null;\n } catch (e) {\n return { jsonParseError: { value: control.value } };\n }\n } else return null;\n };\n\n v.push(jsonParse());\n }\n\n if (field.controlType === 'map') {\n const parseKey = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null =>\n control.value && Object.keys(control.value).length && Object.keys(control.value).some((a) => !a) ? { parseKey: true } : null;\n v.push(parseKey());\n }\n return v;\n }\n\n /**\n * Filter by group and all fields\n */\n public filterApply(options: TFormOptions[], c: ISearchParam): TFormOptions[] {\n return options.filter((a) => isVisibleField(a)).map(handleTree(c));\n }\n\n /**\n * Output form, cast to source type\n */\n public parseValue(output: IOutput, source: ISource[]): IOutput {\n const findField = (name: string, p?: string): Partial => source.find((a) => (p ? a.name === p && a.subname === name : a.name === name));\n\n const runYspecParse = (v: any, f: Partial) => ((!v || !Object.keys(v).length) && !f.value ? f.value : this.runYspec(v, f.limits.rules));\n\n const runParse = (v: IOutput, parentName?: string): IOutput => {\n const runByValue = (p: IOutput, c: string) => {\n const checkType = (data: resultTypes | IOutput, field: Partial): resultTypes => {\n const { type } = field;\n if (type === 'structure') return runYspecParse(data, field);\n else if (type === 'group') return this.checkValue(runParse(data as IOutput, field.name), type);\n else return this.checkValue(data, type);\n };\n\n const f = findField(c, parentName);\n if (f) {\n const result = checkType(v[c], f);\n return f.type !== 'group' || result ? { ...p, [c]: result } : p;\n }\n return p;\n };\n\n return Object.keys(v).reduce(runByValue, {});\n };\n\n const __main_info = findField('__main_info');\n return runParse(__main_info?.required ? { ...output, __main_info: __main_info.value } : { ...output });\n }\n\n private runYspec(value: resultTypes, rules: any) {\n switch (rules?.type) {\n case 'list': {\n return (value as Array).filter((a) => !!a).map((a) => this.runYspec(a, rules.options));\n }\n case 'dict': {\n return Object.keys(value).reduce((p, c) => {\n const r = rules.options.find((b: any) => b.name === c);\n const v = r ? this.runYspec(value[c], r) : null;\n return v !== null ? { ...p, [c]: v } : { ...p };\n }, {});\n }\n default: {\n return this.checkValue(value, rules?.type);\n }\n }\n }\n\n checkValue(value: resultTypes, type: TNForm): resultTypes {\n if ((value === '' || isEmptyObject(value)) && type === 'map') return {};\n\n if ((value === '' || isEmptyObject(value)) && type === 'list') return [];\n\n if (value === '' || value === null || isEmptyObject(value)) return null;\n\n if (typeof value === 'boolean') return value;\n else if (typeof value === 'string')\n switch (type) {\n case 'option':\n return !isNaN(+value) ? parseInt(value, 10) : value;\n case 'integer':\n case 'int':\n return parseInt(value, 10);\n case 'float':\n return parseFloat(value);\n case 'json':\n return JSON.parse(value);\n }\n else\n switch (type) {\n case 'map':\n return Object.keys(value)\n .filter((a) => !!a)\n .reduce((p, c) => ({ ...p, [c]: value[c] }), {});\n\n case 'list':\n return Array.isArray(value) ? (value as Array).filter((a) => !!a) : null;\n }\n\n return value;\n }\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-d78cb6aa832432b3e07848b2b3bbd66d", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "resultTypes", - "line": 35, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "methods": [] - }, - { - "name": "IPanelOptions", - "id": "interface-IPanelOptions-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "active", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 168 - }, - { - "name": "options", - "deprecated": false, - "deprecationMessage": "", - "type": "TFormOptions[]", - "optional": false, - "description": "", - "line": 167 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IFormOptions" - }, - { - "name": "IProfile", - "id": "interface-IProfile-c3fd6c62e5104c98cb26311a52248a16", - "file": "src/app/core/store/profile/profile.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { HttpClient } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { environment } from '@env/environment';\nimport { Observable, throwError } from 'rxjs';\nimport { map, tap } from 'rxjs/operators';\n\nimport { AuthService } from '@app/core/auth/auth.service';\n\nconst PROFILE_LINK = `${environment.apiRoot}profile/`;\n\nexport interface LastViewedTask {\n id: number;\n}\n\nexport interface IProfile {\n textarea: { [key: string]: number };\n settingsSaved: boolean;\n lastViewedTask?: LastViewedTask;\n}\n\nexport interface IUser {\n username: string;\n change_password: string;\n profile: IProfile;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class ProfileService {\n private user: IUser;\n\n constructor(private http: HttpClient, private auth: AuthService) {}\n\n public getProfile(): Observable {\n const source$ = this.http.get(`${PROFILE_LINK}${this.auth.auth.login}/`).pipe(\n map(user => (!user.profile ? { ...user, profile: this.emptyProfile() } : user)),\n tap(user => (this.user = user))\n );\n return this.auth.auth.login ? source$ : throwError('Not authorized!');\n }\n\n emptyProfile() {\n return { textarea: {}, settingsSaved: false };\n }\n\n setUser(key: string, value: string | boolean | { [key: string]: number }) {\n const profile = { ...this.user.profile };\n profile[key] = value;\n this.user = { ...this.user, profile };\n }\n\n setProfile(): Observable {\n const { username, profile } = { ...this.user };\n return this.http.patch(`${PROFILE_LINK}${this.user.username}/`, { username, profile });\n }\n\n setTextareaProfile(data: { key: string; value: number }): Observable {\n const textarea = { ...this.user.profile.textarea };\n textarea[data.key] = data.value;\n this.setUser('textarea', textarea);\n return this.setProfile();\n }\n\n setLastViewedTask(id: number): Observable {\n this.setUser('lastViewedTask', { id });\n return this.setProfile();\n }\n\n addUser(user: { username: string; profile: string }): Observable {\n return this.http.post(`${PROFILE_LINK}`, user);\n }\n\n setPassword(password: string) {\n return this.http.patch(this.user.change_password, { password });\n }\n}\n", - "properties": [ - { - "name": "lastViewedTask", - "deprecated": false, - "deprecationMessage": "", - "type": "LastViewedTask", - "optional": true, - "description": "", - "line": 29 - }, - { - "name": "settingsSaved", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "textarea", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 27 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IRawHosComponent", - "id": "interface-IRawHosComponent-a875bd9ec8a9450bd7b364337c366dfb", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IComponent, Host, IRequires } from '@app/core/types';\n\nexport type ActionParam = 'add' | 'remove';\nexport type TConstraintValue = number | '+' | 'odd' | 'depend';\nexport type TConstraint = TConstraintValue[];\n\nexport interface IRawHosComponent {\n component: IComponent[];\n host: Partial[];\n hc: Post[];\n}\n\nexport interface Post {\n id?: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class Post implements Post {\n constructor(public host_id: number, public service_id: number, public component_id: number, public id?: number) {}\n}\n\n/**\n *```\n {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: Constraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n }\n ```\n * @class Tile\n */\nexport class Tile {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: TConstraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n}\n\nexport class HostTile extends Tile {\n constructor(rawHost: Partial) {\n super();\n this.id = rawHost.id;\n this.name = rawHost.fqdn;\n }\n}\n\nexport class CompTile extends Tile {\n prototype_id: number;\n service_id: number;\n component: string;\n requires: IRequires[];\n constructor(rawComponent: IComponent, public actions?: ActionParam[]) {\n super();\n this.id = rawComponent.id;\n this.service_id = rawComponent.service_id;\n this.component = `${rawComponent.service_name}/${rawComponent.name}`;\n this.name = rawComponent.display_name;\n this.disabled = rawComponent.service_state !== 'created';\n this.limit = rawComponent.constraint;\n this.requires = rawComponent.requires;\n this.prototype_id = rawComponent.prototype_id;\n }\n}\n\n/**\n * State user selection\n *\n * @class StatePost\n */\nexport class StatePost {\n private _data: Post[];\n\n constructor() {\n this._data = [];\n }\n\n private _compare(a: Post, b: Post) {\n return a.host_id === b.host_id && a.service_id === b.service_id && a.component_id === b.component_id;\n }\n\n get data() {\n return this._data;\n }\n\n add(post: Post) {\n const f = this._data.find((p) => this._compare(p, post));\n if (!f) this._data.push(post);\n else if (!f.id) f.id = post.id;\n }\n\n delete(post: Post) {\n this._data = this._data.filter((p) => !this._compare(p, post));\n }\n\n clear() {\n this._data = [];\n }\n\n update(data: Post[]) {\n data.forEach((a) => this.add(new Post(a.host_id, a.service_id, a.component_id, a.id)));\n }\n}\n/**\n *```\n {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n }\n *```\n */\nexport interface IStream {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n}\n", - "properties": [ - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "type": "IComponent[]", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "hc", - "deprecated": false, - "deprecationMessage": "", - "type": "Post[]", - "optional": false, - "description": "", - "line": 21 - }, - { - "name": "host", - "deprecated": false, - "deprecationMessage": "", - "type": "Partial[]", - "optional": false, - "description": "", - "line": 20 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IRequires", - "id": "interface-IRequires-50993353cad3d133a2be743502171874", - "file": "src/app/core/types/host-component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface HostComponent {\n id: number;\n /** host name */\n host: string;\n host_id: number;\n /** component name */\n component: string;\n component_display_name: string;\n component_id: number;\n service_id: number;\n service_display_name: string;\n service_name: string;\n service_version: string;\n state: string;\n url: string;\n host_url: string;\n status: number;\n monitoring: 'passive' | 'active';\n}\n\n/**\n * A service component that may be installed on hosts in a cluster.\n */\nexport interface IComponent {\n id: number;\n prototype_id: number;\n service_id: number;\n service_name: string;\n service_state: string;\n name: string;\n display_name: string;\n status: number;\n constraint: any;\n monitoring?: 'passive' | 'active'; // status page\n requires?: IRequires[];\n}\n\nexport interface IRequires {\n // id: number;\n prototype_id: number;\n name: string;\n display_name: string;\n components?: IRequires[];\n}\n", - "properties": [ - { - "name": "components", - "deprecated": false, - "deprecationMessage": "", - "type": "IRequires[]", - "optional": true, - "description": "", - "line": 60 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 59 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 58 - }, - { - "name": "prototype_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 57 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IRoot", - "id": "interface-IRoot-0cbb246102564bc134c66dc61b2dabe6", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IAction } from './actions';\nimport { IComponent } from './host-component';\nimport { Job, Task } from './task-job';\nimport { AdcmEntity } from '@app/models/entity';\nimport { IIssues } from '@app/models/issue';\nimport { ICluster } from '@app/models/cluster';\nimport { Concern } from '@app/models/concern/concern';\n\nexport type TypeName =\n 'bundle' |\n 'cluster' |\n 'host' |\n 'provider' |\n 'service' |\n 'job' |\n 'task' |\n 'user' |\n 'profile' |\n 'adcm' |\n 'stats' |\n 'hostcomponent' |\n 'service2cluster' |\n 'host2cluster' |\n 'servicecomponent' |\n 'component' |\n 'group_config' |\n 'group_config_hosts';\nexport type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle;\n\n/**\n *```\n {\n [key: string]: string;\n }\n ```\n */\nexport interface IRoot {\n [key: string]: string;\n}\n\nexport interface BaseEntity extends AdcmEntity {\n typeName: TypeName;\n description?: string;\n url: string;\n state?: string;\n config: string;\n action?: string;\n actions?: IAction[];\n issue?: IIssues;\n prototype_id?: number;\n prototype_name?: string;\n prototype_display_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n status?: number | string;\n concerns: Concern[];\n locked: boolean;\n}\n\nexport interface ApiFlat {\n id: number;\n object_id: number;\n object_type: TypeName;\n url: string;\n}\n\nexport interface Provider extends BaseEntity {\n host: string;\n}\n\nexport interface Host extends BaseEntity {\n fqdn: string;\n provider_id: number;\n cluster: string;\n cluster_id?: number;\n cluster_name?: string;\n}\n\nexport interface Service extends BaseEntity {\n components: IComponent[];\n status: number;\n hostcomponent: string;\n display_name: string;\n cluster_id?: number;\n group_config: string;\n}\n\nexport interface CanLicensed {\n license: 'unaccepted' | 'accepted' | 'absent';\n license_url: string;\n}\n\nexport interface License {\n accept: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n text: string;\n}\n\nexport interface Bundle extends BaseEntity, CanLicensed {\n [key: string]: any;\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-0cbb246102564bc134c66dc61b2dabe6", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "string", - "line": 49, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "description": "
{\n[key: string]: string;\n}
", - "rawdescription": "\n\n```\n{\n[key: string]: string;\n}\n```\n", - "methods": [] - }, - { - "name": "IRowHost", - "id": "interface-IRowHost-8686b2996dc23fd6b135de183a41f1f3", - "file": "src/app/shared/components/list/base-list.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { MatDialog } from '@angular/material/dialog';\nimport { ParamMap } from '@angular/router';\nimport { select, Store } from '@ngrx/store';\nimport { filter, mergeMap, switchMap, takeUntil, tap } from 'rxjs/operators';\nimport { IListResult } from '@adwp-ui/widgets';\nimport { Sort } from '@angular/material/sort';\nimport { Observable, Subject } from 'rxjs';\n\nimport { clearMessages, EventMessage, getMessage, SocketState } from '@app/core/store';\nimport { Bundle, EmmitRow, Entities, Host as AdcmHost, TypeName } from '@app/core/types';\nimport { DialogComponent } from '@app/shared/components';\nimport { ListResult } from '@app/models/list-result';\nimport { ListService } from './list.service';\nimport { ListDirective } from '@app/abstract-directives/list.directive';\nimport { ICluster } from '@app/models/cluster';\n\n\nconst TemporaryEntityNameConverter = (currentName: Partial): string => {\n\n if (currentName === 'group_config') return 'group-config';\n if (currentName === 'group_config_hosts') return 'group-config-hosts';\n\n return currentName;\n};\n\ninterface IRowHost extends AdcmHost {\n clusters: Partial[];\n page: number;\n}\n\nexport class BaseListDirective {\n\n socket$: Observable;\n destroy$ = new Subject();\n\n row: Entities;\n listParams: ParamMap;\n limit = 10;\n typeName: TypeName;\n\n reload: (result: ListResult) => void;\n\n constructor(\n protected parent: ListDirective,\n protected service: ListService,\n protected store: Store,\n ) {}\n\n takeUntil() {\n return takeUntil(this.destroy$);\n }\n\n startListenSocket(): void {\n this.socket$.pipe(tap(m => this.socketListener(m))).subscribe();\n }\n\n initSocket() {\n this.socket$ = this.store.pipe(\n this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object));\n }\n\n initColumns() {\n this.parent.columns = this.service.initInstance(this.typeName).columns;\n }\n\n initListItemEvent() {\n this.parent.listItemEvt\n .pipe(this.takeUntil())\n .subscribe({ next: (event: EmmitRow) => this.listEvents(event) });\n }\n\n calcSort(ordering: string): Sort {\n let sort: Sort;\n if (ordering) {\n sort = {\n direction: ordering[0] === '-' ? 'desc' : 'asc',\n active: ordering[0] === '-' ? ordering.substr(1) : ordering,\n };\n }\n\n return sort;\n }\n\n routeListener(limit: number, page: number, ordering: string, params: ParamMap) {\n\n this.parent.paginator.pageSize = limit;\n if (page === 0) {\n this.parent.paginator.firstPage();\n } else {\n this.parent.paginator.pageIndex = page;\n }\n if (ordering && !this.parent.sort.active) {\n this.parent.sort.direction = ordering[0] === '-' ? 'desc' : 'asc';\n this.parent.sort.active = ordering[0] === '-' ? ordering.substr(1) : ordering;\n this.parent.sortParam = ordering;\n }\n\n this.listParams = params;\n this.refresh();\n }\n\n initRouteListener() {\n this.parent.route.paramMap\n .pipe(\n this.takeUntil(),\n filter((p) => this.checkParam(p))\n )\n .subscribe((p) => this.routeListener(+p.get('limit') || 10, +p.get('page'), p.get('ordering'), p));\n }\n\n init(): void {\n this.initSocket();\n this.initColumns();\n this.initListItemEvent();\n this.initRouteListener();\n this.startListenSocket();\n }\n\n destroy() {\n this.parent.listItemEvt.complete();\n\n this.destroy$.next();\n this.destroy$.complete();\n\n this.store.dispatch(clearMessages());\n }\n\n checkParam(p: ParamMap): boolean {\n const listParamStr = localStorage.getItem('list:param');\n if (!p.keys.length && listParamStr) {\n const json = JSON.parse(listParamStr);\n if (json[this.typeName]) {\n this.parent.router.navigate(['./', json[this.typeName]], { relativeTo: this.parent.route });\n return false;\n }\n }\n return true;\n }\n\n checkType(typeName: string, referenceTypeName: TypeName): boolean {\n return (referenceTypeName ? referenceTypeName.split('2')[0] : referenceTypeName) === typeName;\n }\n\n socketListener(m: EventMessage): void {\n const stype = (x: string) => `${m.object.type}${m.object.details.type ? `2${m.object.details.type}` : ''}` === x;\n\n const checkUpgradable = () => (m.event === 'create' || m.event === 'delete') && m.object.type === 'bundle' && this.typeName === 'cluster';\n const changeList = (name?: string) => stype(name ?? this.typeName) && (m.event === 'create' || m.event === 'delete' || m.event === 'add' || m.event === 'remove');\n const createHostPro = () => stype('host2provider') && m.event === 'create';\n const jobComplete = () => (m.event === 'change_job_status') && m.object.type === 'task' && m.object.details.value === 'success';\n const rewriteRow = (row: Entities) => this.service.checkItem(row).subscribe((item) => Object.keys(row).map((a) => (row[a] = item[a])));\n\n if (checkUpgradable() || changeList(TemporaryEntityNameConverter(this.typeName)) || createHostPro() || jobComplete()) {\n this.refresh(m.object.id);\n return;\n }\n\n // events for the row of list\n if (this.parent.data.data.length) {\n const row = this.parent.data.data.find((a) => a.id === m.object.id);\n if (!row) return;\n\n if (m.event === 'add' && stype('host2cluster')) rewriteRow(row);\n\n if (this.checkType(m.object.type, this.typeName)) {\n if (m.event === 'change_state') row.state = m.object.details.value;\n if (m.event === 'change_status') row.status = +m.object.details.value;\n if (m.event === 'change_job_status') row.status = m.object.details.value;\n if (m.event === 'upgrade') rewriteRow(row);\n }\n }\n }\n\n refresh(id?: number) {\n if (id) this.parent.current = { id };\n this.service.getList(this.listParams, this.typeName).subscribe((list: IListResult) => {\n if (this.reload) {\n this.reload(list);\n }\n this.parent.dataSource = list;\n });\n }\n\n listEvents(event: EmmitRow) {\n const createUrl = (a: string[]) => this.parent.router.createUrlTree(['./', this.row.id, ...a], { relativeTo: this.parent.route });\n const nav = (a: string[]) => this.parent.router.navigateByUrl(createUrl(a));\n\n this.row = event.row;\n const { cmd, row, item } = event;\n\n if (['title', 'status', 'config', 'import'].includes(cmd)) {\n nav(cmd === 'title' ? [] : [cmd]);\n } else if (cmd === 'new-tab') {\n const url = this.parent.router.serializeUrl(createUrl([]));\n window.open(url, '_blank');\n } else {\n this[cmd](row || item);\n }\n }\n\n onLoad() {}\n\n license() {\n const row = this.row as Bundle;\n\n const closedDialog$ = (text: string, dialog: MatDialog) =>\n dialog\n .open(DialogComponent, {\n data: {\n title: `Accept license agreement`,\n text,\n controls: { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] },\n },\n })\n .beforeClosed();\n\n const showDialog = (info: { text: string }) =>\n closedDialog$(info.text, this.parent.dialog).pipe(\n filter((yes) => yes),\n switchMap(() => this.service.acceptLicense(`${row.license_url}accept/`).pipe(tap((_) => (row.license = 'accepted'))))\n );\n\n this.service.getLicenseInfo(row.license_url).pipe(this.takeUntil(), mergeMap(showDialog)).subscribe();\n }\n\n delete(item?: Entities) {\n this.service\n .delete(item ?? this.row)\n .pipe(this.takeUntil())\n .subscribe(() => (this.parent.current = null));\n }\n\n // host\n getClusters() {\n const row = this.row as IRowHost;\n if (!row.clusters) {\n row.page = 0;\n this.service\n .getClustersForHost({ limit: this.limit, page: 0 })\n .pipe(this.takeUntil())\n .subscribe((list) => (row.clusters = list));\n }\n }\n\n getNextPageCluster() {\n const row = this.row as IRowHost;\n const count = row.clusters.length;\n if (count === (row.page + 1) * this.limit) {\n row.page++;\n this.service\n .getClustersForHost({ limit: this.limit, page: row.page })\n .pipe(this.takeUntil())\n .subscribe((list) => (row.clusters = [...row.clusters, ...list]));\n }\n }\n}\n", - "properties": [ - { - "name": "clusters", - "deprecated": false, - "deprecationMessage": "", - "type": "Partial[]", - "optional": false, - "description": "", - "line": 39 - }, - { - "name": "page", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 40 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "AdcmHost" - }, - { - "name": "ISearchParam", - "id": "interface-ISearchParam-bfe1187b2f621020ae1b5f2e70d5b6f1", - "file": "src/app/shared/configuration/main/main.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { animate, state, style, transition, trigger } from '@angular/animations';\nimport { Injectable, InjectionToken, Injector } from '@angular/core';\nimport { isObject, TypeName } from '@app/core/types';\nimport { FieldService, IOutput, TFormOptions } from '../services/field.service';\nimport { CompareConfig, IFieldOptions, IFieldStack } from '../types';\nimport { ConfigService, IConfigService } from '@app/shared/configuration/services/config.service';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ConfigGroupService } from '@app/config-groups/service/config-group.service';\n\n/**\n *```\n advanced: boolean;\n search: string;\n ```\n */\nexport interface ISearchParam {\n advanced: boolean;\n search: string;\n}\n\nexport const historyAnime = [\n trigger('history', [\n state('hide', style({ top: '70px' })),\n state('show', style({ top: '134px' })),\n state('hideTools', style({ opacity: 0 })),\n state('showTools', style({ opacity: 0.8 })),\n transition('hideTools => showTools', animate('.5s .3s ease-in')),\n transition('showTools => hideTools', animate('.2s ease-out')),\n transition('hide <=> show', animate('.3s')),\n ]),\n];\n\n@Injectable({\n providedIn: 'root'\n})\nexport class MainService {\n configService: IConfigService;\n\n constructor(private fields: FieldService,\n public cluster: ClusterService,\n injector: Injector) {\n const current: TypeName | undefined = cluster.Current?.typeName;\n if (current === 'group_config') {\n this.configService = injector.get(ConfigGroupService);\n } else {\n this.configService = injector.get(ConfigService);\n }\n }\n\n get worker$() {\n return this.cluster.worker$;\n }\n\n get Current() {\n return this.cluster.Current;\n }\n\n getConfig(url: string) {\n return this.configService.getConfig(url);\n }\n\n changeVersion(url: string, id: number) {\n return this.configService.changeVersion(id, url);\n }\n\n filterApply(options: TFormOptions[], search: ISearchParam) {\n this.fields.filterApply(options, search);\n }\n\n parseValue(output: IOutput, source: IFieldStack[]) {\n return this.fields.parseValue(output, source);\n }\n\n send(url: string, data: any) {\n return this.configService.send(url, data);\n }\n\n getHistoryList(url: string, currentVersionId: number) {\n return this.configService.getHistoryList(url, currentVersionId);\n }\n\n compareConfig(ids: number[], dataOptions: TFormOptions[], compareConfig: CompareConfig[]) {\n dataOptions.map((a) => this.runClear(a, ids));\n const cc = ids.map((id) => compareConfig.find((a) => a.id === id));\n dataOptions.map((a) => this.runCheck(a, cc));\n }\n\n runClear(a: TFormOptions, ids: number[]) {\n if ('options' in a) a.options.map((b) => this.runClear(b, ids));\n else if (a.compare.length) a.compare = a.compare.filter((b) => ids.includes(b.id));\n return a;\n }\n\n runCheck(a: TFormOptions, configs: CompareConfig[]) {\n if ('options' in a) a.options.map((b) => this.runCheck(b, configs));\n else this.checkField(a, configs);\n return a;\n }\n\n checkField(a: IFieldOptions, configs: CompareConfig[]) {\n configs\n .filter((b) => a.compare.every((e) => e.id !== b.id))\n .map((c) => {\n const co = this.findFieldiCompare(a.key, c);\n if (!co) {\n if (String(a.value) && String(a.value) !== 'null') a.compare.push({\n id: c.id,\n date: c.date,\n color: c.color,\n value: 'null'\n });\n } else {\n if (isObject(co.value)) {\n if (isObject(a.value)) {\n if (JSON.stringify(a.value) !== JSON.stringify(co.value)) a.compare.push({\n ...co,\n value: JSON.stringify(co.value)\n });\n } else if (typeof a.value === 'string') {\n if (JSON.stringify(JSON.parse(a.value)) !== JSON.stringify(co.value)) a.compare.push({\n ...co,\n value: JSON.stringify(co.value)\n });\n }\n } else if (String(co.value) !== String(a.value)) a.compare.push(co);\n }\n });\n return a;\n }\n\n findFieldiCompare(key: string, cc: CompareConfig) {\n const value = key\n .split('/')\n .reverse()\n .reduce((p, c) => p[c], cc.config);\n if (value !== null && value !== undefined && String(value)) {\n const { id, date, color } = { ...cc };\n return { id, date, color, value };\n }\n }\n\n}\n", - "properties": [ - { - "name": "advanced", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "search", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 29 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "
advanced: boolean;\nsearch: string;
", - "rawdescription": "\n\n```\nadvanced: boolean;\nsearch: string;\n```\n", - "methods": [] - }, - { - "name": "IServiceComponent", - "id": "interface-IServiceComponent-776e0b50a5c5634d7986c19f4e57aaad", - "file": "src/app/models/service-component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IssueEntity } from '@app/models/issue';\nimport { IAction } from '@app/models/action';\n\nexport interface IServiceComponent extends IssueEntity {\n cluster_id: number;\n service_id: number;\n description: string;\n constraint: Array;\n monitoring: string;\n prototype_id: number;\n requires: Array;\n bound_to: any;\n status: number;\n url: string;\n state: string;\n action: string;\n config: string;\n prototype: string;\n actions: IAction[];\n version: string;\n}\n", - "properties": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 16 - }, - { - "name": "actions", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction[]", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "bound_to", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 12 - }, - { - "name": "cluster_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 5 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 17 - }, - { - "name": "constraint", - "deprecated": false, - "deprecationMessage": "", - "type": "Array", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 7 - }, - { - "name": "monitoring", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 9 - }, - { - "name": "prototype", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 18 - }, - { - "name": "prototype_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "requires", - "deprecated": false, - "deprecationMessage": "", - "type": "Array", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "service_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 6 - }, - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 15 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 13 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 14 - }, - { - "name": "version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 20 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IssueEntity" - }, - { - "name": "ISocketListener", - "id": "interface-ISocketListener-7f95d972aa2e0bf28838c5beb72bc3dc", - "file": "src/app/shared/directives/base.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Directive, OnDestroy } from '@angular/core';\nimport { EventMessage } from '@app/core/store';\nimport { MonoTypeOperatorFunction, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\n@Directive({\n selector: '[appBase]'\n})\nexport class BaseDirective implements OnDestroy {\n destroy$ = new Subject();\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n takeUntil(): MonoTypeOperatorFunction {\n return takeUntil(this.destroy$);\n }\n}\nexport interface ISocketListener {\n socketListener: (m: EventMessage) => void;\n}\n", - "properties": [ - { - "name": "socketListener", - "deprecated": false, - "deprecationMessage": "", - "type": "function", - "optional": false, - "description": "", - "line": 33 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ISource", - "id": "interface-ISource-d78cb6aa832432b3e07848b2b3bbd66d", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms';\nimport { isEmptyObject } from '@app/core/types';\n\nimport { ISearchParam } from '../main/main.service';\nimport {\n controlType,\n IConfig,\n IConfigAttr,\n IFieldOptions,\n IFieldStack,\n ILimits,\n IPanelOptions,\n IValidator,\n resultTypes,\n TNBase,\n TNForm\n} from '../types';\nimport { AttributeService } from '@app/shared/configuration/attributes/attribute.service';\n\nexport type TFormOptions = IFieldOptions | IPanelOptions;\n\nexport interface IOutput {\n [key: string]: resultTypes;\n}\n\nexport interface ISource {\n name: string;\n subname: string;\n type: TNForm;\n read_only: boolean;\n limits?: ILimits;\n value: any;\n}\n\nexport interface IToolsEvent {\n name: string;\n conditions?: { advanced: boolean; search: string } | boolean;\n}\n\nconst isVisibleField = (a: TFormOptions) => !a.ui_options?.invisible;\nconst isAdvancedField = (a: TFormOptions) => isVisibleField(a) && a.ui_options?.advanced;\nconst isHidden = (a: IFieldStack) => !!(a.ui_options?.invisible || a.ui_options?.advanced);\n\nconst typeToControl: Partial<{ [key in TNForm | controlType]: controlType }> = {\n bool: 'boolean',\n int: 'textbox',\n integer: 'textbox',\n float: 'textbox',\n string: 'textbox',\n file: 'textarea',\n text: 'textarea',\n};\n\nexport const getControlType = (t: TNForm): controlType => typeToControl[t] || (t as controlType);\n\nconst intPattern = () => new RegExp(/^[-]?\\d+$/);\nconst patternFn = {\n integer: intPattern,\n int: intPattern,\n float: () => new RegExp(/^[-]?[0-9]+(\\.[0-9]+)?$/),\n};\n\nexport const getPattern = (t: TNForm): RegExp => (patternFn[t] ? patternFn[t]() : null);\n\nconst fn = {\n boolean: (v: boolean | null, d: boolean | null, r: boolean): boolean | null => (String(v) === 'true' || String(v) === 'false' || String(v) === 'null' ? v : r ? d : null),\n json: (v: string): string => (v === null ? '' : JSON.stringify(v, undefined, 4)),\n map: (v: object, d: object): object => (!v ? d : v),\n list: (v: string[], d: string[]): string[] => (!v ? d : v),\n structure: (v: any): any => v,\n};\n\nexport const getValue = (t: TNForm) => {\n const def = (value: number | string) => (value === null || value === undefined ? '' : String(value));\n return fn[t] ? fn[t] : def;\n};\n\nexport const getKey = (name: string, subname: string): string => (subname ? `${subname}/${name}` : name);\n\nexport const getValidator = (required: boolean, min: number, max: number, type: TNForm) => ({\n required,\n min,\n max,\n pattern: getPattern(type),\n});\n\nconst getField = (item: IFieldStack): IFieldOptions => {\n return {\n ...item,\n key: getKey(item.name, item.subname),\n value: getValue(item.type)(item.value, item.default, item.required),\n validator: getValidator(item.required, item.limits?.min, item.limits?.max, item.type),\n controlType: getControlType(item.type),\n hidden: item.name === '__main_info' || isHidden(item),\n compare: []\n };\n};\n\nconst fo = (n: string) => (b: IFieldStack) => b.type !== 'group' && b.subname && b.name === n;\nconst isActive = (a: IConfigAttr, n: string) => a[n]?.active;\nexport const getOptions = (a: IFieldStack, d: IConfig) =>\n d.config\n .filter(fo(a.name))\n .map((f) => getField(f))\n // switch off validation for field if !(activatable: true && active: false) - line: 146\n .map((c) => ({ ...c, name: c.subname, activatable: a.activatable && !isActive(d.attr, a.name) }));\n\nconst getPanel = (a: IFieldStack, d: IConfig): IPanelOptions => ({\n ...a,\n hidden: isHidden(a),\n active: a.activatable ? isActive(d.attr, a.name) : true,\n options: getOptions(a, d),\n});\n\nconst handleTree = (c: ISearchParam): ((a: TFormOptions) => TFormOptions) => (a: TFormOptions): TFormOptions => {\n if ('options' in a) {\n a.options = a.options.map(handleTree(c));\n if (c.search) a.hidden = a.options.filter((b) => !b.hidden).length === 0;\n else a.hidden = isAdvancedField(a) ? !c.advanced : false;\n } else if (isVisibleField(a)) {\n a.hidden = !(a.display_name.toLowerCase().includes(c.search.toLowerCase()) || String(a.value).toLocaleLowerCase().includes(c.search.toLocaleLowerCase()));\n if (!a.hidden && isAdvancedField(a)) a.hidden = !c.advanced;\n }\n return a;\n};\n\nconst findAttrValue = (obj: T, key: string): boolean => {\n let value;\n for (let i in obj) {\n if (!obj.hasOwnProperty(i)) continue;\n if (typeof obj[i] === 'object') {\n value = findAttrValue(obj[i], key);\n } else if (i === key) {\n value = obj[i];\n }\n }\n return value;\n};\n\n@Injectable()\nexport class FieldService {\n attributesService: AttributeService | undefined;\n\n constructor(public fb: FormBuilder) {}\n\n /**\n * Parse and prepare source data from backend\n */\n public getPanels(data: IConfig): TFormOptions[] {\n return data?.config\n ?.filter((a) => a.name !== '__main_info')\n .reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, getField(c)];\n else return [...p, getPanel(c, data)];\n }, []);\n }\n\n /**\n * Generate FormGroup\n * @param options\n */\n public toFormGroup(options: TFormOptions[] = []): FormGroup {\n const check = (a: TFormOptions): boolean =>\n 'options' in a\n ? a.activatable\n ? isVisibleField(a) // if group.activatable - only visible\n : isVisibleField(a) && !a.read_only // else visible an not read_only\n ? a.options.some((b) => check(b)) // check inner fields\n : false\n : isVisibleField(a) && !a.read_only; // for fields in group\n\n return this.fb.group(\n options.reduce((p, c) => this.runByTree(c, p), {}),\n {\n validator: () => (options.filter(check).length === 0 ? { error: 'Form is empty' } : null),\n }\n );\n }\n\n // TODO:\n private runByTree(field: TFormOptions, controls: { [key: string]: {} }): { [key: string]: {} } {\n if ('options' in field) {\n controls[field.name] = this.fb.group(\n field.options.reduce((p, a) => {\n if ('options' in a) this.fb.group(this.runByTree(a, p));\n else this.fillForm(a, p);\n return p;\n }, {})\n );\n return controls;\n } else {\n return this.fillForm(field, controls);\n }\n }\n\n private fillForm(field: IFieldOptions, controls: {}) {\n const name = field.subname || field.name;\n controls[name] = this.fb.control(field.value, field.activatable ? [] : this.setValidator(field));\n return controls;\n }\n\n /**\n * External use (scheme.service) to set validator for FormControl by type\n * @param field Partial{ ValidatorInfo, controlType }\n * @param controlToCompare\n */\n public setValidator(field: { validator: IValidator; controlType: controlType }, controlToCompare?: AbstractControl) {\n const v: ValidatorFn[] = [];\n\n if (field.validator.required) v.push(Validators.required);\n if (field.validator.pattern) v.push(Validators.pattern(field.validator.pattern));\n //if (field.validator.max !== null)\n v.push(Validators.max(field.validator.max));\n //if (field.validator.min !== null)\n v.push(Validators.min(field.validator.min));\n\n if (field.controlType === 'password') {\n const passwordConfirm = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => {\n if (controlToCompare && controlToCompare.value !== control.value) return { notEqual: true };\n return null;\n };\n v.push(passwordConfirm());\n }\n\n if (field.controlType === 'json') {\n const jsonParse = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => {\n if (control.value) {\n try {\n JSON.parse(control.value);\n return null;\n } catch (e) {\n return { jsonParseError: { value: control.value } };\n }\n } else return null;\n };\n\n v.push(jsonParse());\n }\n\n if (field.controlType === 'map') {\n const parseKey = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null =>\n control.value && Object.keys(control.value).length && Object.keys(control.value).some((a) => !a) ? { parseKey: true } : null;\n v.push(parseKey());\n }\n return v;\n }\n\n /**\n * Filter by group and all fields\n */\n public filterApply(options: TFormOptions[], c: ISearchParam): TFormOptions[] {\n return options.filter((a) => isVisibleField(a)).map(handleTree(c));\n }\n\n /**\n * Output form, cast to source type\n */\n public parseValue(output: IOutput, source: ISource[]): IOutput {\n const findField = (name: string, p?: string): Partial => source.find((a) => (p ? a.name === p && a.subname === name : a.name === name));\n\n const runYspecParse = (v: any, f: Partial) => ((!v || !Object.keys(v).length) && !f.value ? f.value : this.runYspec(v, f.limits.rules));\n\n const runParse = (v: IOutput, parentName?: string): IOutput => {\n const runByValue = (p: IOutput, c: string) => {\n const checkType = (data: resultTypes | IOutput, field: Partial): resultTypes => {\n const { type } = field;\n if (type === 'structure') return runYspecParse(data, field);\n else if (type === 'group') return this.checkValue(runParse(data as IOutput, field.name), type);\n else return this.checkValue(data, type);\n };\n\n const f = findField(c, parentName);\n if (f) {\n const result = checkType(v[c], f);\n return f.type !== 'group' || result ? { ...p, [c]: result } : p;\n }\n return p;\n };\n\n return Object.keys(v).reduce(runByValue, {});\n };\n\n const __main_info = findField('__main_info');\n return runParse(__main_info?.required ? { ...output, __main_info: __main_info.value } : { ...output });\n }\n\n private runYspec(value: resultTypes, rules: any) {\n switch (rules?.type) {\n case 'list': {\n return (value as Array).filter((a) => !!a).map((a) => this.runYspec(a, rules.options));\n }\n case 'dict': {\n return Object.keys(value).reduce((p, c) => {\n const r = rules.options.find((b: any) => b.name === c);\n const v = r ? this.runYspec(value[c], r) : null;\n return v !== null ? { ...p, [c]: v } : { ...p };\n }, {});\n }\n default: {\n return this.checkValue(value, rules?.type);\n }\n }\n }\n\n checkValue(value: resultTypes, type: TNForm): resultTypes {\n if ((value === '' || isEmptyObject(value)) && type === 'map') return {};\n\n if ((value === '' || isEmptyObject(value)) && type === 'list') return [];\n\n if (value === '' || value === null || isEmptyObject(value)) return null;\n\n if (typeof value === 'boolean') return value;\n else if (typeof value === 'string')\n switch (type) {\n case 'option':\n return !isNaN(+value) ? parseInt(value, 10) : value;\n case 'integer':\n case 'int':\n return parseInt(value, 10);\n case 'float':\n return parseFloat(value);\n case 'json':\n return JSON.parse(value);\n }\n else\n switch (type) {\n case 'map':\n return Object.keys(value)\n .filter((a) => !!a)\n .reduce((p, c) => ({ ...p, [c]: value[c] }), {});\n\n case 'list':\n return Array.isArray(value) ? (value as Array).filter((a) => !!a) : null;\n }\n\n return value;\n }\n}\n", - "properties": [ - { - "name": "limits", - "deprecated": false, - "deprecationMessage": "", - "type": "ILimits", - "optional": true, - "description": "", - "line": 44 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 40 - }, - { - "name": "read_only", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "subname", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "TNForm", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 45 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IssueEntity", - "id": "interface-IssueEntity-0f92d1325e593762aa0c9547bc0fbddf", - "file": "src/app/models/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { AdcmEntity } from '@app/models/entity';\n\nexport type IssueType = 'cluster' | 'service' | 'servicecomponent' | 'component';\n\nexport interface IssueEntity extends AdcmEntity {\n issue: IIssues;\n}\n\nexport interface IIssues {\n config?: boolean;\n required_import?: boolean;\n host_component?: false;\n cluster?: IssueEntity[];\n service?: IssueEntity[];\n}\n", - "properties": [ - { - "name": "issue", - "deprecated": false, - "deprecationMessage": "", - "type": "IIssues", - "optional": false, - "description": "", - "line": 6 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "AdcmEntity" - }, - { - "name": "IssueState", - "id": "interface-IssueState-a6605e20804c67a3c80aae8f5f6181fc", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\nimport { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props, Store } from '@ngrx/store';\nimport { exhaustMap, filter, map, withLatestFrom } from 'rxjs/operators';\n\nimport { ApiService } from '../api';\nimport { State } from '../store';\nimport { BaseEntity } from '../types';\nimport { IIssues } from '@app/models/issue';\n\nexport interface IssueState {\n value: IIssues;\n url: string;\n}\n\nconst InitState = {\n value: null,\n url: '',\n};\n\nexport const loadIssue = createAction('[Issue] LoadIssue');\nexport const fillIssue = createAction('[Issue] FillIssue', props<{ value: IIssues; url: string }>());\n\nconst reducer = createReducer(InitState, on(loadIssue, state => ({ ...state })), on(fillIssue, (state, { value, url }) => ({ value, url })));\n\nexport function issueReducer(state: IssueState, action: Action) {\n return reducer(state, action);\n}\n\n@Injectable()\nexport class IssueEffect {\n load$ = createEffect(() =>\n this.actions$.pipe(\n ofType(loadIssue),\n withLatestFrom(this.store, (action, state) => state.issue.url),\n filter(url => !!url),\n exhaustMap(url => this.api.get(url).pipe(map(o => fillIssue({ value: o.issue, url: o.url }))))\n )\n );\n\n constructor(private actions$: Actions, private api: ApiService, private store: Store) {}\n}\n\nexport const getIssueSelector = createFeatureSelector('issue');\n\nexport const checkIssue = createSelector(\n getIssueSelector,\n state => state\n);\n", - "properties": [ - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 24 - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "IIssues", - "optional": false, - "description": "", - "line": 23 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IStatus", - "id": "interface-IStatus-f4479ba0b2419eab84b2be3a638f7417", - "file": "src/app/shared/components/status/status.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { combineLatest, Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { ApiService } from '@app/core/api';\nimport { IComponent, Host, HostComponent } from '@app/core/types';\nimport { ICluster } from '@app/models/cluster';\n\ninterface IStatus {\n [key: number]: { status: number };\n}\n\nexport interface IAllStatus {\n hosts: IStatus;\n services: { details: [{ host: string | number; component: string | number; status: number }]; status: number }[];\n components: IStatus;\n status: number;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class StatusService {\n constructor(private api: ApiService) { }\n\n getStatusInfo(id: number, hostcomponent_link: string) {\n const statuses$ = this.getAllClusterStatus(id),\n host_components$ = this.getHostComponents(hostcomponent_link);\n return combineLatest([statuses$, host_components$]);\n }\n\n getHostComponents(url: string): Observable {\n return this.api\n .get<{ host: Host[]; hc: HostComponent[]; component: IComponent[] }>(url)\n .pipe(map((a) => a.hc.map((hc) => ({ ...hc, monitoring: a.component.find((b) => b.id === hc.component_id).monitoring }))));\n }\n\n getServiceComponentsByCluster(cluster: ICluster, service_id?: number): Observable {\n return this.api.get(cluster.status_url).pipe(map((s) => s.filter((se) => (service_id ? se.service_id === service_id : true))));\n }\n\n getHostcomponentStatus(k: HostComponent, all: IAllStatus) {\n const c = all.services[k.service_id]?.details.find((e) => +e.host === k.host_id && +e.component === k.component_id);\n return c ? c.status : null;\n }\n\n getComponentsOnly(a: [IAllStatus, HostComponent[]], host_id?: number) {\n const all: IAllStatus = a[0],\n hc: HostComponent[] = a[1];\n return hc\n .filter((h) => (host_id ? host_id === h.host_id : true))\n .reduce((acc, cur) => (!acc.some((c) => c.host_id === cur.host_id && c.service_id === cur.service_id) ? [...acc, cur] : acc), [])\n .map((k) => ({ ...k, status: this.getHostcomponentStatus(k, all) }))\n .filter((b) => b.status !== 0);\n }\n\n getClusterById(id: number) {\n return this.api.getOne('cluster', id);\n }\n\n getAllClusterStatus(id: number) {\n return this.api.get(`/status/api/v1/cluster/${id}/`);\n }\n\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-f4479ba0b2419eab84b2be3a638f7417", - "args": [ - { - "name": "key", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "literal type", - "line": 20, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "methods": [] - }, - { - "name": "IStream", - "id": "interface-IStream-a875bd9ec8a9450bd7b364337c366dfb", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IComponent, Host, IRequires } from '@app/core/types';\n\nexport type ActionParam = 'add' | 'remove';\nexport type TConstraintValue = number | '+' | 'odd' | 'depend';\nexport type TConstraint = TConstraintValue[];\n\nexport interface IRawHosComponent {\n component: IComponent[];\n host: Partial[];\n hc: Post[];\n}\n\nexport interface Post {\n id?: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class Post implements Post {\n constructor(public host_id: number, public service_id: number, public component_id: number, public id?: number) {}\n}\n\n/**\n *```\n {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: Constraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n }\n ```\n * @class Tile\n */\nexport class Tile {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: TConstraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n}\n\nexport class HostTile extends Tile {\n constructor(rawHost: Partial) {\n super();\n this.id = rawHost.id;\n this.name = rawHost.fqdn;\n }\n}\n\nexport class CompTile extends Tile {\n prototype_id: number;\n service_id: number;\n component: string;\n requires: IRequires[];\n constructor(rawComponent: IComponent, public actions?: ActionParam[]) {\n super();\n this.id = rawComponent.id;\n this.service_id = rawComponent.service_id;\n this.component = `${rawComponent.service_name}/${rawComponent.name}`;\n this.name = rawComponent.display_name;\n this.disabled = rawComponent.service_state !== 'created';\n this.limit = rawComponent.constraint;\n this.requires = rawComponent.requires;\n this.prototype_id = rawComponent.prototype_id;\n }\n}\n\n/**\n * State user selection\n *\n * @class StatePost\n */\nexport class StatePost {\n private _data: Post[];\n\n constructor() {\n this._data = [];\n }\n\n private _compare(a: Post, b: Post) {\n return a.host_id === b.host_id && a.service_id === b.service_id && a.component_id === b.component_id;\n }\n\n get data() {\n return this._data;\n }\n\n add(post: Post) {\n const f = this._data.find((p) => this._compare(p, post));\n if (!f) this._data.push(post);\n else if (!f.id) f.id = post.id;\n }\n\n delete(post: Post) {\n this._data = this._data.filter((p) => !this._compare(p, post));\n }\n\n clear() {\n this._data = [];\n }\n\n update(data: Post[]) {\n data.forEach((a) => this.add(new Post(a.host_id, a.service_id, a.component_id, a.id)));\n }\n}\n/**\n *```\n {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n }\n *```\n */\nexport interface IStream {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n}\n", - "properties": [ - { - "name": "link", - "deprecated": false, - "deprecationMessage": "", - "type": "Tile", - "optional": false, - "description": "", - "line": 139 - }, - { - "name": "linkSource", - "deprecated": false, - "deprecationMessage": "", - "type": "Tile[]", - "optional": false, - "description": "", - "line": 140 - }, - { - "name": "selected", - "deprecated": false, - "deprecationMessage": "", - "type": "Tile", - "optional": false, - "description": "", - "line": 141 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "
{\nlink: Tile;\nlinkSource: Tile[];\nselected: Tile;\n}
", - "rawdescription": "\n\n```\n{\nlink: Tile;\nlinkSource: Tile[];\nselected: Tile;\n}\n```\n", - "methods": [] - }, - { - "name": "IStructure", - "id": "interface-IStructure-236ea186c68ad07c4fefea3b5504940f", - "file": "src/app/shared/configuration/yspec/yspec.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { IRoot } from '@app/core/types';\n\nimport { IFieldOptions, controlType, IValidator, TNBase, TNReq } from '../types';\nimport { getControlType, getPattern } from '../services/field.service';\n\nexport type TMatch = TNBase | TNReq;\n\n/**\n *```\n {\n match: matchType;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot; // { [key: string]: string; }\n required_items?: string[];\n default_item?: string;\n }\n ```\n */\ninterface IYRoot {\n match: TMatch;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot;\n required_items?: string[];\n default_item?: string;\n}\n\n/**\n *```\n {\n [key: string]: IYRoot;\n }\n ```\n */\nexport interface IYspec {\n [key: string]: IYRoot;\n}\n\n/**\n *```\n{\n name: string;\n path: string[];\n type: simpleType;\n controlType: controlType;\n validator: ValidatorInfo;\n}\n *```\n */\nexport interface IYField {\n name: string;\n path: string[];\n type: TNBase;\n controlType: controlType;\n validator: IValidator;\n}\n\n/**\n * ```\n * {\n * name: string;\n * type: reqursionType; // 'list' | 'dict'\n * options: IYContainer | IYField | (IYContainer | IYField)[];\n * }\n *```\n */\nexport interface IYContainer {\n name: string;\n type: TNReq;\n options: IYContainer | IYField | (IYContainer | IYField)[];\n}\n\nexport interface IStructure extends IFieldOptions {\n rules: { options: any; type: string; name: string };\n}\n\n@Injectable()\nexport class YspecService {\n private root: IYspec;\n\n set Root(yspec: IYspec) {\n this.root = yspec;\n }\n\n get Root() {\n return this.root;\n }\n\n build(rule = 'root', path: string[] = []): IYContainer | IYField {\n const { match, item, items } = this.Root[rule];\n\n switch (match) {\n case 'list':\n return this.list(item, path);\n case 'dict':\n return this.dict(items, path);\n // case 'one_of':\n // return this.one_of();\n // case 'dict_key_selection':\n // return this.dict_key_selection();\n default:\n return this.field({ type: match, path });\n }\n }\n\n field(field: { type: TNBase; path: string[] }): IYField {\n const name = field.path.reverse()[0];\n return {\n name,\n type: field.type,\n path: field.path,\n controlType: getControlType(field.type),\n validator: {\n required: this.findRule(field.path, 'required_items'),\n pattern: getPattern(field.type),\n },\n };\n }\n\n findRule(path: string[], name: string): boolean {\n const [field, parent] = path;\n const rule = this.Root[parent];\n return !!(rule && rule[name] && Array.isArray(rule[name]) && rule[name].includes(field));\n }\n\n list(item: string, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return { type: 'list', name, options: this.build(item, [...path, item]) };\n }\n\n dict(items: IRoot, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return {\n type: 'dict',\n name,\n options: Object.keys(items).map((item_name: string) => this.build(items[item_name], [...path, item_name])),\n };\n }\n\n one_of() {}\n\n dict_key_selection() {}\n}\n", - "properties": [ - { - "name": "rules", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 89 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "IFieldOptions" - }, - { - "name": "IStyledNavItem", - "id": "interface-IStyledNavItem-39eefd83a4c8cabaa98c367c8d80a8a1", - "file": "src/app/models/details.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { ICluster } from './cluster';\nimport { IAction, JobObject, LogFile, TypeName } from '../core/types';\nimport { IIssues } from './issue';\nimport { AdcmTypedEntity } from './entity';\n\nexport interface IDetails {\n parent?: ICluster;\n typeName: TypeName;\n id: number;\n name: string;\n upgradable: boolean;\n upgrade: string;\n status: string | number;\n /** link to actionss */\n action: string;\n actions: IAction[];\n issue: IIssues;\n log_files?: LogFile[];\n objects: JobObject[];\n prototype_name: string;\n prototype_display_name: string;\n prototype_version: string;\n provider_id: number;\n bundle_id: number;\n hostcomponent: string;\n state: string;\n}\n\nexport interface INavItem {\n id?: number;\n title: string;\n url: string;\n issue?: string;\n status?: number;\n statusMessage?: string;\n action?: () => void;\n}\n\nexport interface IStyledNavItem {\n class?: string;\n entity?: AdcmTypedEntity;\n}\n", - "properties": [ - { - "name": "class", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 40 - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "AdcmTypedEntity", - "optional": true, - "description": "", - "line": 41 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ITimeInfo", - "id": "interface-ITimeInfo-a4ca3857c8a3fa9637042e138d2d1c95", - "file": "src/app/entry/job/log/log.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, OnInit, ViewChild } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Subject } from 'rxjs';\nimport { filter, switchMap } from 'rxjs/operators';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { Job, JobStatus, LogFile } from '@app/core/types';\nimport { TextComponent } from './text.component';\nimport { JobService } from '@app/services/job.service';\nimport { EventMessage } from '@app/core/store';\n\nexport interface ITimeInfo {\n start: string;\n end: string;\n time: string;\n}\n\n@Component({\n selector: 'app-job-log',\n styles: [\n `\n :host {\n display: flex;\n flex: 1;\n padding: 10px 20px;\n }\n\n div.wrap {\n display: flex;\n flex: 1;\n }\n\n .accordion {\n flex: 1;\n display: flex;\n flex-direction: column;\n }\n `,\n ],\n template: `\n \n \n
\n \n \n \n \n
\n
\n `,\n})\nexport class LogComponent extends BaseDirective implements OnInit {\n currentLog$ = new Subject();\n timeInfo: ITimeInfo;\n logUrl: string;\n\n job: Job;\n\n @ViewChild(TextComponent, { static: true }) textComp: TextComponent;\n\n constructor(\n private service: ClusterService,\n private route: ActivatedRoute,\n private jobService: JobService,\n ) {\n super();\n }\n\n socketListener(event: EventMessage) {\n if (event.event === 'change_job_status') {\n this.job.status = event.object.details.value as JobStatus;\n this.job.finish_date = new Date().toISOString();\n this.timeInfo = this.service.getOperationTimeData(this.job);\n if (this.textComp) this.textComp.update(this.job.status);\n }\n this.refresh();\n }\n\n startListenSocket() {\n this.jobService.events().pipe(\n this.takeUntil(),\n filter(event => event?.object?.id === this.job.id),\n ).subscribe((event) => this.socketListener(event));\n }\n\n ngOnInit() {\n this.route.paramMap.pipe(\n this.takeUntil(),\n switchMap(() => this.jobService.get(+this.route.parent.snapshot.paramMap.get('job'))),\n ).subscribe((job) => {\n this.job = job;\n this.timeInfo = this.service.getOperationTimeData(this.job);\n this.logUrl = this.job.log_files.find((a) => a.id === +this.route.snapshot.paramMap.get('log')).url;\n this.refresh();\n });\n this.startListenSocket();\n }\n\n refresh() {\n if (!this.logUrl) return;\n this.service.getLog(this.logUrl).subscribe((a) => this.currentLog$.next(a));\n }\n\n}\n", - "properties": [ - { - "name": "end", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "start", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 25 - }, - { - "name": "time", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 27 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IToolsEvent", - "id": "interface-IToolsEvent-d78cb6aa832432b3e07848b2b3bbd66d", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms';\nimport { isEmptyObject } from '@app/core/types';\n\nimport { ISearchParam } from '../main/main.service';\nimport {\n controlType,\n IConfig,\n IConfigAttr,\n IFieldOptions,\n IFieldStack,\n ILimits,\n IPanelOptions,\n IValidator,\n resultTypes,\n TNBase,\n TNForm\n} from '../types';\nimport { AttributeService } from '@app/shared/configuration/attributes/attribute.service';\n\nexport type TFormOptions = IFieldOptions | IPanelOptions;\n\nexport interface IOutput {\n [key: string]: resultTypes;\n}\n\nexport interface ISource {\n name: string;\n subname: string;\n type: TNForm;\n read_only: boolean;\n limits?: ILimits;\n value: any;\n}\n\nexport interface IToolsEvent {\n name: string;\n conditions?: { advanced: boolean; search: string } | boolean;\n}\n\nconst isVisibleField = (a: TFormOptions) => !a.ui_options?.invisible;\nconst isAdvancedField = (a: TFormOptions) => isVisibleField(a) && a.ui_options?.advanced;\nconst isHidden = (a: IFieldStack) => !!(a.ui_options?.invisible || a.ui_options?.advanced);\n\nconst typeToControl: Partial<{ [key in TNForm | controlType]: controlType }> = {\n bool: 'boolean',\n int: 'textbox',\n integer: 'textbox',\n float: 'textbox',\n string: 'textbox',\n file: 'textarea',\n text: 'textarea',\n};\n\nexport const getControlType = (t: TNForm): controlType => typeToControl[t] || (t as controlType);\n\nconst intPattern = () => new RegExp(/^[-]?\\d+$/);\nconst patternFn = {\n integer: intPattern,\n int: intPattern,\n float: () => new RegExp(/^[-]?[0-9]+(\\.[0-9]+)?$/),\n};\n\nexport const getPattern = (t: TNForm): RegExp => (patternFn[t] ? patternFn[t]() : null);\n\nconst fn = {\n boolean: (v: boolean | null, d: boolean | null, r: boolean): boolean | null => (String(v) === 'true' || String(v) === 'false' || String(v) === 'null' ? v : r ? d : null),\n json: (v: string): string => (v === null ? '' : JSON.stringify(v, undefined, 4)),\n map: (v: object, d: object): object => (!v ? d : v),\n list: (v: string[], d: string[]): string[] => (!v ? d : v),\n structure: (v: any): any => v,\n};\n\nexport const getValue = (t: TNForm) => {\n const def = (value: number | string) => (value === null || value === undefined ? '' : String(value));\n return fn[t] ? fn[t] : def;\n};\n\nexport const getKey = (name: string, subname: string): string => (subname ? `${subname}/${name}` : name);\n\nexport const getValidator = (required: boolean, min: number, max: number, type: TNForm) => ({\n required,\n min,\n max,\n pattern: getPattern(type),\n});\n\nconst getField = (item: IFieldStack): IFieldOptions => {\n return {\n ...item,\n key: getKey(item.name, item.subname),\n value: getValue(item.type)(item.value, item.default, item.required),\n validator: getValidator(item.required, item.limits?.min, item.limits?.max, item.type),\n controlType: getControlType(item.type),\n hidden: item.name === '__main_info' || isHidden(item),\n compare: []\n };\n};\n\nconst fo = (n: string) => (b: IFieldStack) => b.type !== 'group' && b.subname && b.name === n;\nconst isActive = (a: IConfigAttr, n: string) => a[n]?.active;\nexport const getOptions = (a: IFieldStack, d: IConfig) =>\n d.config\n .filter(fo(a.name))\n .map((f) => getField(f))\n // switch off validation for field if !(activatable: true && active: false) - line: 146\n .map((c) => ({ ...c, name: c.subname, activatable: a.activatable && !isActive(d.attr, a.name) }));\n\nconst getPanel = (a: IFieldStack, d: IConfig): IPanelOptions => ({\n ...a,\n hidden: isHidden(a),\n active: a.activatable ? isActive(d.attr, a.name) : true,\n options: getOptions(a, d),\n});\n\nconst handleTree = (c: ISearchParam): ((a: TFormOptions) => TFormOptions) => (a: TFormOptions): TFormOptions => {\n if ('options' in a) {\n a.options = a.options.map(handleTree(c));\n if (c.search) a.hidden = a.options.filter((b) => !b.hidden).length === 0;\n else a.hidden = isAdvancedField(a) ? !c.advanced : false;\n } else if (isVisibleField(a)) {\n a.hidden = !(a.display_name.toLowerCase().includes(c.search.toLowerCase()) || String(a.value).toLocaleLowerCase().includes(c.search.toLocaleLowerCase()));\n if (!a.hidden && isAdvancedField(a)) a.hidden = !c.advanced;\n }\n return a;\n};\n\nconst findAttrValue = (obj: T, key: string): boolean => {\n let value;\n for (let i in obj) {\n if (!obj.hasOwnProperty(i)) continue;\n if (typeof obj[i] === 'object') {\n value = findAttrValue(obj[i], key);\n } else if (i === key) {\n value = obj[i];\n }\n }\n return value;\n};\n\n@Injectable()\nexport class FieldService {\n attributesService: AttributeService | undefined;\n\n constructor(public fb: FormBuilder) {}\n\n /**\n * Parse and prepare source data from backend\n */\n public getPanels(data: IConfig): TFormOptions[] {\n return data?.config\n ?.filter((a) => a.name !== '__main_info')\n .reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, getField(c)];\n else return [...p, getPanel(c, data)];\n }, []);\n }\n\n /**\n * Generate FormGroup\n * @param options\n */\n public toFormGroup(options: TFormOptions[] = []): FormGroup {\n const check = (a: TFormOptions): boolean =>\n 'options' in a\n ? a.activatable\n ? isVisibleField(a) // if group.activatable - only visible\n : isVisibleField(a) && !a.read_only // else visible an not read_only\n ? a.options.some((b) => check(b)) // check inner fields\n : false\n : isVisibleField(a) && !a.read_only; // for fields in group\n\n return this.fb.group(\n options.reduce((p, c) => this.runByTree(c, p), {}),\n {\n validator: () => (options.filter(check).length === 0 ? { error: 'Form is empty' } : null),\n }\n );\n }\n\n // TODO:\n private runByTree(field: TFormOptions, controls: { [key: string]: {} }): { [key: string]: {} } {\n if ('options' in field) {\n controls[field.name] = this.fb.group(\n field.options.reduce((p, a) => {\n if ('options' in a) this.fb.group(this.runByTree(a, p));\n else this.fillForm(a, p);\n return p;\n }, {})\n );\n return controls;\n } else {\n return this.fillForm(field, controls);\n }\n }\n\n private fillForm(field: IFieldOptions, controls: {}) {\n const name = field.subname || field.name;\n controls[name] = this.fb.control(field.value, field.activatable ? [] : this.setValidator(field));\n return controls;\n }\n\n /**\n * External use (scheme.service) to set validator for FormControl by type\n * @param field Partial{ ValidatorInfo, controlType }\n * @param controlToCompare\n */\n public setValidator(field: { validator: IValidator; controlType: controlType }, controlToCompare?: AbstractControl) {\n const v: ValidatorFn[] = [];\n\n if (field.validator.required) v.push(Validators.required);\n if (field.validator.pattern) v.push(Validators.pattern(field.validator.pattern));\n //if (field.validator.max !== null)\n v.push(Validators.max(field.validator.max));\n //if (field.validator.min !== null)\n v.push(Validators.min(field.validator.min));\n\n if (field.controlType === 'password') {\n const passwordConfirm = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => {\n if (controlToCompare && controlToCompare.value !== control.value) return { notEqual: true };\n return null;\n };\n v.push(passwordConfirm());\n }\n\n if (field.controlType === 'json') {\n const jsonParse = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => {\n if (control.value) {\n try {\n JSON.parse(control.value);\n return null;\n } catch (e) {\n return { jsonParseError: { value: control.value } };\n }\n } else return null;\n };\n\n v.push(jsonParse());\n }\n\n if (field.controlType === 'map') {\n const parseKey = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null =>\n control.value && Object.keys(control.value).length && Object.keys(control.value).some((a) => !a) ? { parseKey: true } : null;\n v.push(parseKey());\n }\n return v;\n }\n\n /**\n * Filter by group and all fields\n */\n public filterApply(options: TFormOptions[], c: ISearchParam): TFormOptions[] {\n return options.filter((a) => isVisibleField(a)).map(handleTree(c));\n }\n\n /**\n * Output form, cast to source type\n */\n public parseValue(output: IOutput, source: ISource[]): IOutput {\n const findField = (name: string, p?: string): Partial => source.find((a) => (p ? a.name === p && a.subname === name : a.name === name));\n\n const runYspecParse = (v: any, f: Partial) => ((!v || !Object.keys(v).length) && !f.value ? f.value : this.runYspec(v, f.limits.rules));\n\n const runParse = (v: IOutput, parentName?: string): IOutput => {\n const runByValue = (p: IOutput, c: string) => {\n const checkType = (data: resultTypes | IOutput, field: Partial): resultTypes => {\n const { type } = field;\n if (type === 'structure') return runYspecParse(data, field);\n else if (type === 'group') return this.checkValue(runParse(data as IOutput, field.name), type);\n else return this.checkValue(data, type);\n };\n\n const f = findField(c, parentName);\n if (f) {\n const result = checkType(v[c], f);\n return f.type !== 'group' || result ? { ...p, [c]: result } : p;\n }\n return p;\n };\n\n return Object.keys(v).reduce(runByValue, {});\n };\n\n const __main_info = findField('__main_info');\n return runParse(__main_info?.required ? { ...output, __main_info: __main_info.value } : { ...output });\n }\n\n private runYspec(value: resultTypes, rules: any) {\n switch (rules?.type) {\n case 'list': {\n return (value as Array).filter((a) => !!a).map((a) => this.runYspec(a, rules.options));\n }\n case 'dict': {\n return Object.keys(value).reduce((p, c) => {\n const r = rules.options.find((b: any) => b.name === c);\n const v = r ? this.runYspec(value[c], r) : null;\n return v !== null ? { ...p, [c]: v } : { ...p };\n }, {});\n }\n default: {\n return this.checkValue(value, rules?.type);\n }\n }\n }\n\n checkValue(value: resultTypes, type: TNForm): resultTypes {\n if ((value === '' || isEmptyObject(value)) && type === 'map') return {};\n\n if ((value === '' || isEmptyObject(value)) && type === 'list') return [];\n\n if (value === '' || value === null || isEmptyObject(value)) return null;\n\n if (typeof value === 'boolean') return value;\n else if (typeof value === 'string')\n switch (type) {\n case 'option':\n return !isNaN(+value) ? parseInt(value, 10) : value;\n case 'integer':\n case 'int':\n return parseInt(value, 10);\n case 'float':\n return parseFloat(value);\n case 'json':\n return JSON.parse(value);\n }\n else\n switch (type) {\n case 'map':\n return Object.keys(value)\n .filter((a) => !!a)\n .reduce((p, c) => ({ ...p, [c]: value[c] }), {});\n\n case 'list':\n return Array.isArray(value) ? (value as Array).filter((a) => !!a) : null;\n }\n\n return value;\n }\n}\n", - "properties": [ - { - "name": "conditions", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type | boolean", - "optional": true, - "description": "", - "line": 50 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 49 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IUIOptions", - "id": "interface-IUIOptions-735f0912aeff33ab88d1ab8e400a23cb", - "file": "src/app/core/types/actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IConfig } from '@app/shared/configuration/types';\n\n/**\n * \n *```\n{\n action: 'add' | 'remove'; \n component: string; // name of servise to work with \n service: string; // name of component to work with\n}\n```\n *\n */\nexport interface IActionParameter {\n action: 'add' | 'remove';\n component: string;\n service: string;\n}\n\nexport interface IUIOptions {\n disclaimer?: string;\n}\n\nexport interface IAction {\n name: string;\n description: string;\n display_name: string;\n run: string;\n config: IConfig;\n hostcomponentmap: IActionParameter[];\n button: 'create_host' | null;\n ui_options: IUIOptions;\n children?: IAction[];\n}\n", - "properties": [ - { - "name": "disclaimer", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 32 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IUIoptions", - "id": "interface-IUIoptions-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "advanced", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 38 - }, - { - "name": "invisible", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 36 - }, - { - "name": "no_confirm", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 37 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "
{\ninvisible?: boolean;\nno_confirm?: boolean;\nadvanced?: boolean;\n}
", - "rawdescription": "\n\n```\n{\ninvisible?: boolean;\nno_confirm?: boolean;\nadvanced?: boolean;\n}\n```\n\n", - "methods": [] - }, - { - "name": "IUser", - "id": "interface-IUser-c3fd6c62e5104c98cb26311a52248a16", - "file": "src/app/core/store/profile/profile.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { HttpClient } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { environment } from '@env/environment';\nimport { Observable, throwError } from 'rxjs';\nimport { map, tap } from 'rxjs/operators';\n\nimport { AuthService } from '@app/core/auth/auth.service';\n\nconst PROFILE_LINK = `${environment.apiRoot}profile/`;\n\nexport interface LastViewedTask {\n id: number;\n}\n\nexport interface IProfile {\n textarea: { [key: string]: number };\n settingsSaved: boolean;\n lastViewedTask?: LastViewedTask;\n}\n\nexport interface IUser {\n username: string;\n change_password: string;\n profile: IProfile;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class ProfileService {\n private user: IUser;\n\n constructor(private http: HttpClient, private auth: AuthService) {}\n\n public getProfile(): Observable {\n const source$ = this.http.get(`${PROFILE_LINK}${this.auth.auth.login}/`).pipe(\n map(user => (!user.profile ? { ...user, profile: this.emptyProfile() } : user)),\n tap(user => (this.user = user))\n );\n return this.auth.auth.login ? source$ : throwError('Not authorized!');\n }\n\n emptyProfile() {\n return { textarea: {}, settingsSaved: false };\n }\n\n setUser(key: string, value: string | boolean | { [key: string]: number }) {\n const profile = { ...this.user.profile };\n profile[key] = value;\n this.user = { ...this.user, profile };\n }\n\n setProfile(): Observable {\n const { username, profile } = { ...this.user };\n return this.http.patch(`${PROFILE_LINK}${this.user.username}/`, { username, profile });\n }\n\n setTextareaProfile(data: { key: string; value: number }): Observable {\n const textarea = { ...this.user.profile.textarea };\n textarea[data.key] = data.value;\n this.setUser('textarea', textarea);\n return this.setProfile();\n }\n\n setLastViewedTask(id: number): Observable {\n this.setUser('lastViewedTask', { id });\n return this.setProfile();\n }\n\n addUser(user: { username: string; profile: string }): Observable {\n return this.http.post(`${PROFILE_LINK}`, user);\n }\n\n setPassword(password: string) {\n return this.http.patch(this.user.change_password, { password });\n }\n}\n", - "properties": [ - { - "name": "change_password", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "profile", - "deprecated": false, - "deprecationMessage": "", - "type": "IProfile", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "username", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 33 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IValidator", - "id": "interface-IValidator-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "max", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 146 - }, - { - "name": "min", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 147 - }, - { - "name": "pattern", - "deprecated": false, - "deprecationMessage": "", - "type": "string | RegExp", - "optional": true, - "description": "", - "line": 144 - }, - { - "name": "required", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 145 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "
pattern?: string | RegExp;\nrequired?: boolean;\nmax?: number;\nmin?: number;
", - "rawdescription": "\n\n```\npattern?: string | RegExp;\nrequired?: boolean;\nmax?: number;\nmin?: number;\n```\n", - "methods": [] - }, - { - "name": "IValue", - "id": "interface-IValue-19b19308484527efdbe79aeeb38c9a3d", - "file": "src/app/shared/configuration/scheme/scheme.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { AbstractControl, FormArray, FormControl, FormGroup, ValidatorFn } from '@angular/forms';\nimport { isObject } from '@app/core/types/func';\n\nimport { FieldService } from '../services/field.service';\nimport { IFieldOptions, TNForm, TNReq, TValue } from '../types';\nimport { IYContainer, IYField } from '../yspec/yspec.service';\n\nexport interface IValue {\n [key: string]: TValue;\n}\n\nexport interface IControl {\n name: string;\n type: TNForm;\n rules: IYField | IYContainer | (IYField | IYContainer)[];\n form: FormGroup | FormArray;\n value: IValue | TValue;\n parent: TNReq;\n}\n\n@Injectable()\nexport class SchemeService {\n constructor(private service: FieldService) {}\n\n emptyValidator() {\n // const isEmptyArray = (v: any) => (Array.isArray(v) && v.length ? v.some((a) => isEmptyValue(a)) : false);\n // const isEmptyObj = (v: any) => (isObject(v) && Object.keys(v).length ? Object.keys(v).some((a) => isEmptyValue(v[a])) : false);\n const isEmptyValue = (v: any) => !v || (Array.isArray(v) && !v.length) || (isObject(v) && !Object.keys(v).length);\n return (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (isEmptyValue(control.value) ? { isEmpty: true } : null);\n }\n\n setCurrentForm(type: TNForm, parent: FormGroup, field: IFieldOptions) {\n const v = field.required ? this.emptyValidator()() : null;\n const current = type === 'list' || type === 'dict' ? (type === 'list' ? new FormArray([], v) : new FormGroup({}, v)) : new FormControl('', v);\n parent.setControl(field.name, current);\n return current;\n }\n\n addControlsDict(name: string, source: TValue | IValue, currentForm: FormArray, rules: IYContainer[]): IControl {\n const value = !source ? rules.reduce((p, c) => ({ ...p, [c.name]: '' }), {}) : source;\n\n const checkValue = () => {\n if (Array.isArray(rules)) {\n if (Array.isArray(value)) {\n return rules.some((a) => a.name === value[0]);\n } else if (typeof value === 'object') {\n return Object.keys(value).every((x) => rules.some((a) => a.name === x));\n }\n }\n };\n\n if (checkValue()) {\n const form = new FormGroup({});\n currentForm.push(form);\n return { name, value, type: 'dict', rules, form, parent: 'list' };\n }\n }\n\n addControls(name: string, value: TValue | IValue, currentForm: FormGroup | FormArray, opt: IYContainer | IYField | (IYContainer | IYField)[], type: TNReq): IControl {\n const rules = Array.isArray(opt) ? opt.find((a) => a.name === name) : opt;\n if (!rules) return;\n let form = currentForm;\n if (rules.type !== 'list' && rules.type !== 'dict') {\n const { validator, controlType } = rules as IYField;\n if (Array.isArray(currentForm.controls)) {\n name = currentForm.controls.length.toString();\n (currentForm as FormArray).push(new FormControl(value || '', this.service.setValidator({ validator, controlType })));\n } else (currentForm as FormGroup).addControl(rules.name, new FormControl(rules.type !== 'bool' ? value || '' : value, this.service.setValidator({ validator, controlType })));\n } else {\n form = rules.type === 'list' ? new FormArray([]) : new FormGroup({});\n (currentForm as FormGroup).addControl(rules.name, form);\n }\n\n return { name, value, type: rules.type, rules, form, parent: type };\n }\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-19b19308484527efdbe79aeeb38c9a3d", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "TValue", - "line": 20, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "methods": [] - }, - { - "name": "IValue", - "id": "interface-IValue-4cd1f32b2d3db5ce944b66105c7f592e-1", - "file": "src/app/shared/components/actions/master/master.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { ApiService } from '@app/core/api';\nimport { IAction } from '@app/core/types';\nimport { FieldService } from '@app/shared/configuration/services/field.service';\nimport { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component';\nimport { ServiceHostComponent } from '@app/shared/host-components-map/services2hosts/service-host.component';\nimport { Post } from '@app/shared/host-components-map/types';\nimport { IConfigAttr } from '@app/shared/configuration/types';\nimport { IOutput } from '@app/shared/configuration/services/field.service';\n\nexport interface IValue {\n config?: ConfigFieldsComponent;\n hostmap?: ServiceHostComponent;\n}\n\nexport enum whatShow {\n none = 'none',\n config = 'config',\n hostMap = 'hostmap',\n stepper = 'stepper',\n}\n\nexport interface IMasterData {\n attr: IConfigAttr;\n config: IOutput;\n hc: Post[];\n verbose?: boolean;\n}\n\n@Injectable()\nexport class MasterService {\n constructor(private api: ApiService, private configService: FieldService) {}\n\n spotShow(action: IAction): whatShow {\n const config = action.config?.config?.length;\n const hm = action.hostcomponentmap?.length;\n return config ? (hm ? whatShow.stepper : whatShow.config) : hm ? whatShow.hostMap : whatShow.none;\n }\n\n parseData(v: IValue): IMasterData {\n const getData = (attr: IConfigAttr, c: ConfigFieldsComponent, h: ServiceHostComponent) => {\n const config = c ? this.configService.parseValue(c.form.value, c.rawConfig.config) : undefined;\n const hc = h?.statePost.data;\n return { attr, config, hc };\n };\n return v ? getData(v.config?.attr, v.config, v.hostmap) : undefined;\n }\n\n send(url: string, value: { config: any; hc: Post[] }) {\n return this.api.post(url, value);\n }\n}\n", - "properties": [ - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "ConfigFieldsComponent", - "optional": true, - "description": "", - "line": 23 - }, - { - "name": "hostmap", - "deprecated": false, - "deprecationMessage": "", - "type": "ServiceHostComponent", - "optional": true, - "description": "", - "line": 24 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "isDuplicate": true, - "duplicateId": 1, - "duplicateName": "IValue-1" - }, - { - "name": "IVariantSet", - "id": "interface-IVariantSet-312293bd783a3bdacb9b6b1a75808e99", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IYspec } from './yspec/yspec.service';\nimport { TFormOptions } from './services/field.service';\n\nexport type stateType = 'created' | 'locked';\n\nexport type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float';\nexport type TNReq = 'dict' | 'list';\nexport type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'variant';\nexport type TNForm = TNBase | TNReq | TNSpec;\nexport type simpleTypes = string | number | boolean;\nexport type resultTypes = simpleTypes | simpleTypes[] | object;\nexport type TValue = string | number | boolean | object | any[];\n\n/**\n *```\n {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n }\n ```\n *\n */\nexport interface IUIoptions {\n invisible?: boolean;\n no_confirm?: boolean;\n advanced?: boolean;\n}\n\n/**\n * ```\n {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[]; // created | locked\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n}\n * ```\n */\nexport interface IVariantSet {\n name?: string;\n strict: boolean;\n type: 'config' | 'inline';\n value: string[];\n}\n\nexport interface ILimits {\n min?: number;\n max?: number;\n option?: any;\n read_only?: stateType[];\n yspec?: IYspec;\n rules?: any;\n active?: boolean;\n source?: IVariantSet;\n}\n\n/**\n * Property config object from backend\n */\nexport interface IFieldStack {\n name: string;\n subname: string;\n display_name: string;\n type: TNForm;\n default: TValue;\n value: TValue;\n required: boolean;\n activatable: boolean;\n read_only: boolean;\n description?: string;\n limits?: ILimits;\n ui_options?: IUIoptions;\n}\n\n/**\n * The object for config for backend\n */\nexport interface IConfig {\n id?: number;\n date?: string;\n description?: string;\n config: IFieldStack[];\n attr?: IConfigAttr;\n obj_ref?: number;\n}\n\n/**\n *```\n {\n [group: string]: { active: boolean };\n}\n ```\n */\nexport interface IConfigAttr {\n [group: string]: { active?: boolean };\n\n group_keys?: { [key: string]: boolean };\n custom_group_keys?: { [key: string]: boolean };\n}\n\n//#region Modified data for ngForm build\n\n/**\n * Mark for rendering required component\n */\nexport type controlType =\n 'boolean'\n | 'textbox'\n | 'textarea'\n | 'json'\n | 'password'\n | 'list'\n | 'map'\n | 'dropdown'\n | 'file'\n | 'text'\n | 'structure'\n | 'secrettext';\n\n/**\n *```\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n ```\n */\nexport interface IValidator {\n pattern?: string | RegExp;\n required?: boolean;\n max?: number;\n min?: number;\n}\n\nexport interface CompareConfig extends IConfig {\n color: string;\n}\n\nexport interface ICompare {\n id: number;\n date: string;\n value: string;\n color: string;\n}\n\nexport interface IFormOptions extends IFieldStack {\n key?: string;\n hidden: boolean;\n}\n\nexport interface IPanelOptions extends IFormOptions {\n options: TFormOptions[];\n active: boolean;\n}\n\nexport interface ICanGroup {\n group?: boolean;\n}\n\nexport interface IFieldOptions extends IFormOptions, ICanGroup {\n controlType: controlType;\n validator: IValidator;\n compare: ICompare[];\n}\n\n//#endregion\n", - "properties": [ - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 55 - }, - { - "name": "strict", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 56 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "\"config\" | \"inline\"", - "optional": false, - "description": "", - "line": 57 - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "optional": false, - "description": "", - "line": 58 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "
{\nmin?: number;\nmax?: number;\noption?: any;\nread_only?: stateType[];   // created | locked\nyspec?: IYspec;\nrules?: any;\nactive?: boolean;\n}
", - "rawdescription": "\n\n```\n{\nmin?: number;\nmax?: number;\noption?: any;\nread_only?: stateType[]; // created | locked\nyspec?: IYspec;\nrules?: any;\nactive?: boolean;\n}\n```\n", - "methods": [] - }, - { - "name": "IVersionInfo", - "id": "interface-IVersionInfo-7ae880838369c63d70d654bd977c19c3", - "file": "src/app/core/services/config.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { HttpClient } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nconst CONFIG_URL = '/assets/config.json';\nexport interface IVersionInfo {\n version: string;\n commit_id: string;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ConfigService {\n appConfig$: Observable;\n\n constructor(private http: HttpClient) {}\n\n get version() {\n return localStorage.getItem('adcm:version') || '';\n }\n\n set version(version: string) {\n localStorage.setItem('adcm:version', version);\n }\n\n checkVersion(c: IVersionInfo): IVersionInfo {\n const version = `${c.version}-${c.commit_id}`;\n if (!this.version) this.version = version;\n else if (this.version !== version) {\n this.version = version;\n return null;\n }\n return c;\n }\n\n load() {\n return this.http.get(`${CONFIG_URL}?nocache=${Date.now()}`).pipe(map((c) => this.checkVersion(c)));\n }\n}\n", - "properties": [ - { - "name": "commit_id", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 20 - }, - { - "name": "version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 19 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "IYContainer", - "id": "interface-IYContainer-236ea186c68ad07c4fefea3b5504940f", - "file": "src/app/shared/configuration/yspec/yspec.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { IRoot } from '@app/core/types';\n\nimport { IFieldOptions, controlType, IValidator, TNBase, TNReq } from '../types';\nimport { getControlType, getPattern } from '../services/field.service';\n\nexport type TMatch = TNBase | TNReq;\n\n/**\n *```\n {\n match: matchType;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot; // { [key: string]: string; }\n required_items?: string[];\n default_item?: string;\n }\n ```\n */\ninterface IYRoot {\n match: TMatch;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot;\n required_items?: string[];\n default_item?: string;\n}\n\n/**\n *```\n {\n [key: string]: IYRoot;\n }\n ```\n */\nexport interface IYspec {\n [key: string]: IYRoot;\n}\n\n/**\n *```\n{\n name: string;\n path: string[];\n type: simpleType;\n controlType: controlType;\n validator: ValidatorInfo;\n}\n *```\n */\nexport interface IYField {\n name: string;\n path: string[];\n type: TNBase;\n controlType: controlType;\n validator: IValidator;\n}\n\n/**\n * ```\n * {\n * name: string;\n * type: reqursionType; // 'list' | 'dict'\n * options: IYContainer | IYField | (IYContainer | IYField)[];\n * }\n *```\n */\nexport interface IYContainer {\n name: string;\n type: TNReq;\n options: IYContainer | IYField | (IYContainer | IYField)[];\n}\n\nexport interface IStructure extends IFieldOptions {\n rules: { options: any; type: string; name: string };\n}\n\n@Injectable()\nexport class YspecService {\n private root: IYspec;\n\n set Root(yspec: IYspec) {\n this.root = yspec;\n }\n\n get Root() {\n return this.root;\n }\n\n build(rule = 'root', path: string[] = []): IYContainer | IYField {\n const { match, item, items } = this.Root[rule];\n\n switch (match) {\n case 'list':\n return this.list(item, path);\n case 'dict':\n return this.dict(items, path);\n // case 'one_of':\n // return this.one_of();\n // case 'dict_key_selection':\n // return this.dict_key_selection();\n default:\n return this.field({ type: match, path });\n }\n }\n\n field(field: { type: TNBase; path: string[] }): IYField {\n const name = field.path.reverse()[0];\n return {\n name,\n type: field.type,\n path: field.path,\n controlType: getControlType(field.type),\n validator: {\n required: this.findRule(field.path, 'required_items'),\n pattern: getPattern(field.type),\n },\n };\n }\n\n findRule(path: string[], name: string): boolean {\n const [field, parent] = path;\n const rule = this.Root[parent];\n return !!(rule && rule[name] && Array.isArray(rule[name]) && rule[name].includes(field));\n }\n\n list(item: string, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return { type: 'list', name, options: this.build(item, [...path, item]) };\n }\n\n dict(items: IRoot, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return {\n type: 'dict',\n name,\n options: Object.keys(items).map((item_name: string) => this.build(items[item_name], [...path, item_name])),\n };\n }\n\n one_of() {}\n\n dict_key_selection() {}\n}\n", - "properties": [ - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 83 - }, - { - "name": "options", - "deprecated": false, - "deprecationMessage": "", - "type": "IYContainer | IYField | (IYContainer | IYField)[]", - "optional": false, - "description": "", - "line": 85 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "TNReq", - "optional": false, - "description": "", - "line": 84 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "
{\n  name:      string;\n  type:      reqursionType;    // 'list' | 'dict'\n  options:   IYContainer | IYField | (IYContainer | IYField)[];\n}
", - "rawdescription": "\n\n```\n{\n name: string;\n type: reqursionType; // 'list' | 'dict'\n options: IYContainer | IYField | (IYContainer | IYField)[];\n}\n```\n", - "methods": [] - }, - { - "name": "IYField", - "id": "interface-IYField-236ea186c68ad07c4fefea3b5504940f", - "file": "src/app/shared/configuration/yspec/yspec.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { IRoot } from '@app/core/types';\n\nimport { IFieldOptions, controlType, IValidator, TNBase, TNReq } from '../types';\nimport { getControlType, getPattern } from '../services/field.service';\n\nexport type TMatch = TNBase | TNReq;\n\n/**\n *```\n {\n match: matchType;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot; // { [key: string]: string; }\n required_items?: string[];\n default_item?: string;\n }\n ```\n */\ninterface IYRoot {\n match: TMatch;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot;\n required_items?: string[];\n default_item?: string;\n}\n\n/**\n *```\n {\n [key: string]: IYRoot;\n }\n ```\n */\nexport interface IYspec {\n [key: string]: IYRoot;\n}\n\n/**\n *```\n{\n name: string;\n path: string[];\n type: simpleType;\n controlType: controlType;\n validator: ValidatorInfo;\n}\n *```\n */\nexport interface IYField {\n name: string;\n path: string[];\n type: TNBase;\n controlType: controlType;\n validator: IValidator;\n}\n\n/**\n * ```\n * {\n * name: string;\n * type: reqursionType; // 'list' | 'dict'\n * options: IYContainer | IYField | (IYContainer | IYField)[];\n * }\n *```\n */\nexport interface IYContainer {\n name: string;\n type: TNReq;\n options: IYContainer | IYField | (IYContainer | IYField)[];\n}\n\nexport interface IStructure extends IFieldOptions {\n rules: { options: any; type: string; name: string };\n}\n\n@Injectable()\nexport class YspecService {\n private root: IYspec;\n\n set Root(yspec: IYspec) {\n this.root = yspec;\n }\n\n get Root() {\n return this.root;\n }\n\n build(rule = 'root', path: string[] = []): IYContainer | IYField {\n const { match, item, items } = this.Root[rule];\n\n switch (match) {\n case 'list':\n return this.list(item, path);\n case 'dict':\n return this.dict(items, path);\n // case 'one_of':\n // return this.one_of();\n // case 'dict_key_selection':\n // return this.dict_key_selection();\n default:\n return this.field({ type: match, path });\n }\n }\n\n field(field: { type: TNBase; path: string[] }): IYField {\n const name = field.path.reverse()[0];\n return {\n name,\n type: field.type,\n path: field.path,\n controlType: getControlType(field.type),\n validator: {\n required: this.findRule(field.path, 'required_items'),\n pattern: getPattern(field.type),\n },\n };\n }\n\n findRule(path: string[], name: string): boolean {\n const [field, parent] = path;\n const rule = this.Root[parent];\n return !!(rule && rule[name] && Array.isArray(rule[name]) && rule[name].includes(field));\n }\n\n list(item: string, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return { type: 'list', name, options: this.build(item, [...path, item]) };\n }\n\n dict(items: IRoot, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return {\n type: 'dict',\n name,\n options: Object.keys(items).map((item_name: string) => this.build(items[item_name], [...path, item_name])),\n };\n }\n\n one_of() {}\n\n dict_key_selection() {}\n}\n", - "properties": [ - { - "name": "controlType", - "deprecated": false, - "deprecationMessage": "", - "type": "controlType", - "optional": false, - "description": "", - "line": 69 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 66 - }, - { - "name": "path", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "optional": false, - "description": "", - "line": 67 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "TNBase", - "optional": false, - "description": "", - "line": 68 - }, - { - "name": "validator", - "deprecated": false, - "deprecationMessage": "", - "type": "IValidator", - "optional": false, - "description": "", - "line": 70 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "
{\nname:         string;\npath:         string[];\ntype:         simpleType;\ncontrolType:  controlType;\nvalidator:    ValidatorInfo;\n}
", - "rawdescription": "\n\n```\n{\nname: string;\npath: string[];\ntype: simpleType;\ncontrolType: controlType;\nvalidator: ValidatorInfo;\n}\n```\n", - "methods": [] - }, - { - "name": "IYRoot", - "id": "interface-IYRoot-236ea186c68ad07c4fefea3b5504940f", - "file": "src/app/shared/configuration/yspec/yspec.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { IRoot } from '@app/core/types';\n\nimport { IFieldOptions, controlType, IValidator, TNBase, TNReq } from '../types';\nimport { getControlType, getPattern } from '../services/field.service';\n\nexport type TMatch = TNBase | TNReq;\n\n/**\n *```\n {\n match: matchType;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot; // { [key: string]: string; }\n required_items?: string[];\n default_item?: string;\n }\n ```\n */\ninterface IYRoot {\n match: TMatch;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot;\n required_items?: string[];\n default_item?: string;\n}\n\n/**\n *```\n {\n [key: string]: IYRoot;\n }\n ```\n */\nexport interface IYspec {\n [key: string]: IYRoot;\n}\n\n/**\n *```\n{\n name: string;\n path: string[];\n type: simpleType;\n controlType: controlType;\n validator: ValidatorInfo;\n}\n *```\n */\nexport interface IYField {\n name: string;\n path: string[];\n type: TNBase;\n controlType: controlType;\n validator: IValidator;\n}\n\n/**\n * ```\n * {\n * name: string;\n * type: reqursionType; // 'list' | 'dict'\n * options: IYContainer | IYField | (IYContainer | IYField)[];\n * }\n *```\n */\nexport interface IYContainer {\n name: string;\n type: TNReq;\n options: IYContainer | IYField | (IYContainer | IYField)[];\n}\n\nexport interface IStructure extends IFieldOptions {\n rules: { options: any; type: string; name: string };\n}\n\n@Injectable()\nexport class YspecService {\n private root: IYspec;\n\n set Root(yspec: IYspec) {\n this.root = yspec;\n }\n\n get Root() {\n return this.root;\n }\n\n build(rule = 'root', path: string[] = []): IYContainer | IYField {\n const { match, item, items } = this.Root[rule];\n\n switch (match) {\n case 'list':\n return this.list(item, path);\n case 'dict':\n return this.dict(items, path);\n // case 'one_of':\n // return this.one_of();\n // case 'dict_key_selection':\n // return this.dict_key_selection();\n default:\n return this.field({ type: match, path });\n }\n }\n\n field(field: { type: TNBase; path: string[] }): IYField {\n const name = field.path.reverse()[0];\n return {\n name,\n type: field.type,\n path: field.path,\n controlType: getControlType(field.type),\n validator: {\n required: this.findRule(field.path, 'required_items'),\n pattern: getPattern(field.type),\n },\n };\n }\n\n findRule(path: string[], name: string): boolean {\n const [field, parent] = path;\n const rule = this.Root[parent];\n return !!(rule && rule[name] && Array.isArray(rule[name]) && rule[name].includes(field));\n }\n\n list(item: string, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return { type: 'list', name, options: this.build(item, [...path, item]) };\n }\n\n dict(items: IRoot, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return {\n type: 'dict',\n name,\n options: Object.keys(items).map((item_name: string) => this.build(items[item_name], [...path, item_name])),\n };\n }\n\n one_of() {}\n\n dict_key_selection() {}\n}\n", - "properties": [ - { - "name": "default_item", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 40 - }, - { - "name": "item", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 37 - }, - { - "name": "items", - "deprecated": false, - "deprecationMessage": "", - "type": "IRoot", - "optional": true, - "description": "", - "line": 38 - }, - { - "name": "match", - "deprecated": false, - "deprecationMessage": "", - "type": "TMatch", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "required_items", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "optional": true, - "description": "", - "line": 39 - }, - { - "name": "selector", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 35 - }, - { - "name": "variants", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": true, - "description": "", - "line": 36 - } - ], - "indexSignatures": [], - "kind": 163, - "description": "
{\nmatch: matchType;\nselector?: string;\nvariants?: { [key: string]: string };\nitem?: string;\nitems?: IRoot;        // { [key: string]: string; }\nrequired_items?: string[];\ndefault_item?: string;\n}
", - "rawdescription": "\n\n```\n{\nmatch: matchType;\nselector?: string;\nvariants?: { [key: string]: string };\nitem?: string;\nitems?: IRoot; // { [key: string]: string; }\nrequired_items?: string[];\ndefault_item?: string;\n}\n```\n", - "methods": [] - }, - { - "name": "IYspec", - "id": "interface-IYspec-236ea186c68ad07c4fefea3b5504940f", - "file": "src/app/shared/configuration/yspec/yspec.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { IRoot } from '@app/core/types';\n\nimport { IFieldOptions, controlType, IValidator, TNBase, TNReq } from '../types';\nimport { getControlType, getPattern } from '../services/field.service';\n\nexport type TMatch = TNBase | TNReq;\n\n/**\n *```\n {\n match: matchType;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot; // { [key: string]: string; }\n required_items?: string[];\n default_item?: string;\n }\n ```\n */\ninterface IYRoot {\n match: TMatch;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot;\n required_items?: string[];\n default_item?: string;\n}\n\n/**\n *```\n {\n [key: string]: IYRoot;\n }\n ```\n */\nexport interface IYspec {\n [key: string]: IYRoot;\n}\n\n/**\n *```\n{\n name: string;\n path: string[];\n type: simpleType;\n controlType: controlType;\n validator: ValidatorInfo;\n}\n *```\n */\nexport interface IYField {\n name: string;\n path: string[];\n type: TNBase;\n controlType: controlType;\n validator: IValidator;\n}\n\n/**\n * ```\n * {\n * name: string;\n * type: reqursionType; // 'list' | 'dict'\n * options: IYContainer | IYField | (IYContainer | IYField)[];\n * }\n *```\n */\nexport interface IYContainer {\n name: string;\n type: TNReq;\n options: IYContainer | IYField | (IYContainer | IYField)[];\n}\n\nexport interface IStructure extends IFieldOptions {\n rules: { options: any; type: string; name: string };\n}\n\n@Injectable()\nexport class YspecService {\n private root: IYspec;\n\n set Root(yspec: IYspec) {\n this.root = yspec;\n }\n\n get Root() {\n return this.root;\n }\n\n build(rule = 'root', path: string[] = []): IYContainer | IYField {\n const { match, item, items } = this.Root[rule];\n\n switch (match) {\n case 'list':\n return this.list(item, path);\n case 'dict':\n return this.dict(items, path);\n // case 'one_of':\n // return this.one_of();\n // case 'dict_key_selection':\n // return this.dict_key_selection();\n default:\n return this.field({ type: match, path });\n }\n }\n\n field(field: { type: TNBase; path: string[] }): IYField {\n const name = field.path.reverse()[0];\n return {\n name,\n type: field.type,\n path: field.path,\n controlType: getControlType(field.type),\n validator: {\n required: this.findRule(field.path, 'required_items'),\n pattern: getPattern(field.type),\n },\n };\n }\n\n findRule(path: string[], name: string): boolean {\n const [field, parent] = path;\n const rule = this.Root[parent];\n return !!(rule && rule[name] && Array.isArray(rule[name]) && rule[name].includes(field));\n }\n\n list(item: string, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return { type: 'list', name, options: this.build(item, [...path, item]) };\n }\n\n dict(items: IRoot, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return {\n type: 'dict',\n name,\n options: Object.keys(items).map((item_name: string) => this.build(items[item_name], [...path, item_name])),\n };\n }\n\n one_of() {}\n\n dict_key_selection() {}\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-236ea186c68ad07c4fefea3b5504940f", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "IYRoot", - "line": 50, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "description": "
{\n[key: string]: IYRoot;\n}
", - "rawdescription": "\n\n```\n{\n[key: string]: IYRoot;\n}\n```\n", - "methods": [] - }, - { - "name": "JobAction", - "id": "interface-JobAction-a25a180383c9eab0fd04d0bffbe4860c", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { BaseEntity } from './api';\nimport { Entity } from '@adwp-ui/widgets';\n\nexport type JobStatus = 'created' | 'running' | 'failed' | 'success' | 'aborted';\n\nexport type JobType = 'component' | 'service' | 'cluster' | 'host' | 'provider';\n\nexport interface JobObject {\n id: number;\n name: string;\n type: JobType;\n url?: string[];\n}\n\ninterface TaskBase extends Entity {\n start_date: string;\n finish_date: string;\n objects: JobObject[];\n status: JobStatus;\n action: JobAction;\n terminatable: boolean;\n cancel: string;\n}\n\nexport interface JobAction {\n prototype_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n display_name: string;\n}\ninterface JobRaw extends TaskBase {\n log_files: LogFile[];\n start_date: string;\n finish_date: string;\n}\n\nexport interface TaskRaw extends TaskBase {\n jobs: Job[];\n}\n\nexport type Job = JobRaw & BaseEntity;\nexport type Task = TaskRaw & BaseEntity;\n\nexport interface LogFile {\n id: number;\n url: string;\n name: string;\n type: string;\n format: 'txt' | 'json';\n download_url: string;\n content: string | CheckLog[];\n}\n\nexport interface CheckLog {\n title: string;\n message: string;\n result: boolean;\n type: 'group' | 'check';\n content?: CheckLog[];\n}\n", - "properties": [ - { - "name": "bundle_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 39 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 40 - }, - { - "name": "prototype_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 37 - }, - { - "name": "prototype_version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 38 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "JobObject", - "id": "interface-JobObject-a25a180383c9eab0fd04d0bffbe4860c", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { BaseEntity } from './api';\nimport { Entity } from '@adwp-ui/widgets';\n\nexport type JobStatus = 'created' | 'running' | 'failed' | 'success' | 'aborted';\n\nexport type JobType = 'component' | 'service' | 'cluster' | 'host' | 'provider';\n\nexport interface JobObject {\n id: number;\n name: string;\n type: JobType;\n url?: string[];\n}\n\ninterface TaskBase extends Entity {\n start_date: string;\n finish_date: string;\n objects: JobObject[];\n status: JobStatus;\n action: JobAction;\n terminatable: boolean;\n cancel: string;\n}\n\nexport interface JobAction {\n prototype_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n display_name: string;\n}\ninterface JobRaw extends TaskBase {\n log_files: LogFile[];\n start_date: string;\n finish_date: string;\n}\n\nexport interface TaskRaw extends TaskBase {\n jobs: Job[];\n}\n\nexport type Job = JobRaw & BaseEntity;\nexport type Task = TaskRaw & BaseEntity;\n\nexport interface LogFile {\n id: number;\n url: string;\n name: string;\n type: string;\n format: 'txt' | 'json';\n download_url: string;\n content: string | CheckLog[];\n}\n\nexport interface CheckLog {\n title: string;\n message: string;\n result: boolean;\n type: 'group' | 'check';\n content?: CheckLog[];\n}\n", - "properties": [ - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 20 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 21 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "JobType", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "optional": true, - "description": "", - "line": 23 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "JobRaw", - "id": "interface-JobRaw-a25a180383c9eab0fd04d0bffbe4860c", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { BaseEntity } from './api';\nimport { Entity } from '@adwp-ui/widgets';\n\nexport type JobStatus = 'created' | 'running' | 'failed' | 'success' | 'aborted';\n\nexport type JobType = 'component' | 'service' | 'cluster' | 'host' | 'provider';\n\nexport interface JobObject {\n id: number;\n name: string;\n type: JobType;\n url?: string[];\n}\n\ninterface TaskBase extends Entity {\n start_date: string;\n finish_date: string;\n objects: JobObject[];\n status: JobStatus;\n action: JobAction;\n terminatable: boolean;\n cancel: string;\n}\n\nexport interface JobAction {\n prototype_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n display_name: string;\n}\ninterface JobRaw extends TaskBase {\n log_files: LogFile[];\n start_date: string;\n finish_date: string;\n}\n\nexport interface TaskRaw extends TaskBase {\n jobs: Job[];\n}\n\nexport type Job = JobRaw & BaseEntity;\nexport type Task = TaskRaw & BaseEntity;\n\nexport interface LogFile {\n id: number;\n url: string;\n name: string;\n type: string;\n format: 'txt' | 'json';\n download_url: string;\n content: string | CheckLog[];\n}\n\nexport interface CheckLog {\n title: string;\n message: string;\n result: boolean;\n type: 'group' | 'check';\n content?: CheckLog[];\n}\n", - "properties": [ - { - "name": "finish_date", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "log_files", - "deprecated": false, - "deprecationMessage": "", - "type": "LogFile[]", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "start_date", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 44 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "TaskBase" - }, - { - "name": "LastViewedTask", - "id": "interface-LastViewedTask-c3fd6c62e5104c98cb26311a52248a16", - "file": "src/app/core/store/profile/profile.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { HttpClient } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { environment } from '@env/environment';\nimport { Observable, throwError } from 'rxjs';\nimport { map, tap } from 'rxjs/operators';\n\nimport { AuthService } from '@app/core/auth/auth.service';\n\nconst PROFILE_LINK = `${environment.apiRoot}profile/`;\n\nexport interface LastViewedTask {\n id: number;\n}\n\nexport interface IProfile {\n textarea: { [key: string]: number };\n settingsSaved: boolean;\n lastViewedTask?: LastViewedTask;\n}\n\nexport interface IUser {\n username: string;\n change_password: string;\n profile: IProfile;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class ProfileService {\n private user: IUser;\n\n constructor(private http: HttpClient, private auth: AuthService) {}\n\n public getProfile(): Observable {\n const source$ = this.http.get(`${PROFILE_LINK}${this.auth.auth.login}/`).pipe(\n map(user => (!user.profile ? { ...user, profile: this.emptyProfile() } : user)),\n tap(user => (this.user = user))\n );\n return this.auth.auth.login ? source$ : throwError('Not authorized!');\n }\n\n emptyProfile() {\n return { textarea: {}, settingsSaved: false };\n }\n\n setUser(key: string, value: string | boolean | { [key: string]: number }) {\n const profile = { ...this.user.profile };\n profile[key] = value;\n this.user = { ...this.user, profile };\n }\n\n setProfile(): Observable {\n const { username, profile } = { ...this.user };\n return this.http.patch(`${PROFILE_LINK}${this.user.username}/`, { username, profile });\n }\n\n setTextareaProfile(data: { key: string; value: number }): Observable {\n const textarea = { ...this.user.profile.textarea };\n textarea[data.key] = data.value;\n this.setUser('textarea', textarea);\n return this.setProfile();\n }\n\n setLastViewedTask(id: number): Observable {\n this.setUser('lastViewedTask', { id });\n return this.setProfile();\n }\n\n addUser(user: { username: string; profile: string }): Observable {\n return this.http.post(`${PROFILE_LINK}`, user);\n }\n\n setPassword(password: string) {\n return this.http.patch(this.user.change_password, { password });\n }\n}\n", - "properties": [ - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 23 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "LeftMenuItem", - "id": "interface-LeftMenuItem-3efccba74ac1719d45f4a3d82ada60e7", - "file": "src/app/shared/details/left-menu/left-menu.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, ComponentFactoryResolver, ComponentRef, Input, Type, ViewChild, ViewContainerRef } from '@angular/core';\n\nimport { AdcmEntity } from '@app/models/entity';\nimport { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive';\n\nexport interface LeftMenuItem {\n link: string;\n label: string;\n data?: any;\n component: Type;\n}\n\n@Component({\n selector: 'app-left-menu',\n template: `\n \n \n \n `,\n styleUrls: ['./left-menu.component.scss']\n})\nexport class LeftMenuComponent {\n\n @ViewChild('menu', { read: ViewContainerRef }) menuRef: ViewContainerRef;\n\n private _leftMenu: LeftMenuItem[] = [];\n @Input() set leftMenu(leftMenu: LeftMenuItem[]) {\n this._leftMenu = leftMenu;\n this.rebuildComponents();\n }\n get leftMenu(): LeftMenuItem[] {\n return this._leftMenu;\n }\n\n @Input() set entity(entity: AdcmEntity) {\n this._entity = entity;\n this.componentsRef.forEach((componentRef) => componentRef.instance.entity = entity);\n }\n get entity(): AdcmEntity {\n return this._entity;\n }\n\n private componentsRef: Array> = [];\n private _entity: AdcmEntity;\n\n constructor(\n protected componentFactoryResolver: ComponentFactoryResolver,\n ) {}\n\n rebuildComponents() {\n setTimeout(() => {\n this.componentsRef = [];\n this.menuRef.clear();\n this.leftMenu.forEach((item) => {\n const componentFactory =\n this.componentFactoryResolver.resolveComponentFactory(item.component);\n const componentRef = this.menuRef.createComponent(componentFactory);\n componentRef.instance.label = item.label;\n componentRef.instance.link = item.link;\n if (item.data) {\n componentRef.instance.data = item.data;\n }\n if (this.entity !== undefined) {\n componentRef.instance.entity = this.entity;\n }\n this.componentsRef.push(componentRef);\n });\n });\n }\n\n}\n", - "properties": [ - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "type": "Type", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": true, - "description": "", - "line": 9 - }, - { - "name": "label", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "link", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 7 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "License", - "id": "interface-License-0cbb246102564bc134c66dc61b2dabe6", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IAction } from './actions';\nimport { IComponent } from './host-component';\nimport { Job, Task } from './task-job';\nimport { AdcmEntity } from '@app/models/entity';\nimport { IIssues } from '@app/models/issue';\nimport { ICluster } from '@app/models/cluster';\nimport { Concern } from '@app/models/concern/concern';\n\nexport type TypeName =\n 'bundle' |\n 'cluster' |\n 'host' |\n 'provider' |\n 'service' |\n 'job' |\n 'task' |\n 'user' |\n 'profile' |\n 'adcm' |\n 'stats' |\n 'hostcomponent' |\n 'service2cluster' |\n 'host2cluster' |\n 'servicecomponent' |\n 'component' |\n 'group_config' |\n 'group_config_hosts';\nexport type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle;\n\n/**\n *```\n {\n [key: string]: string;\n }\n ```\n */\nexport interface IRoot {\n [key: string]: string;\n}\n\nexport interface BaseEntity extends AdcmEntity {\n typeName: TypeName;\n description?: string;\n url: string;\n state?: string;\n config: string;\n action?: string;\n actions?: IAction[];\n issue?: IIssues;\n prototype_id?: number;\n prototype_name?: string;\n prototype_display_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n status?: number | string;\n concerns: Concern[];\n locked: boolean;\n}\n\nexport interface ApiFlat {\n id: number;\n object_id: number;\n object_type: TypeName;\n url: string;\n}\n\nexport interface Provider extends BaseEntity {\n host: string;\n}\n\nexport interface Host extends BaseEntity {\n fqdn: string;\n provider_id: number;\n cluster: string;\n cluster_id?: number;\n cluster_name?: string;\n}\n\nexport interface Service extends BaseEntity {\n components: IComponent[];\n status: number;\n hostcomponent: string;\n display_name: string;\n cluster_id?: number;\n group_config: string;\n}\n\nexport interface CanLicensed {\n license: 'unaccepted' | 'accepted' | 'absent';\n license_url: string;\n}\n\nexport interface License {\n accept: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n text: string;\n}\n\nexport interface Bundle extends BaseEntity, CanLicensed {\n [key: string]: any;\n}\n", - "properties": [ - { - "name": "accept", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 106 - }, - { - "name": "license", - "deprecated": false, - "deprecationMessage": "", - "type": "\"unaccepted\" | \"accepted\" | \"absent\"", - "optional": false, - "description": "", - "line": 107 - }, - { - "name": "text", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 108 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ListInstance", - "id": "interface-ListInstance-3c12cd1c1b7e9c952df7e5ee215ece55", - "file": "src/app/shared/components/list/list-service-token.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { InjectionToken } from '@angular/core';\nimport { TypeName } from '@app/core/types';\nimport { ParamMap } from '@angular/router';\nimport { Observable } from 'rxjs';\nimport { ListResult } from '@app/models/list-result';\n\nexport const LIST_SERVICE_PROVIDER = new InjectionToken>('ListService');\n\nexport interface ListInstance {\n typeName: TypeName;\n columns: string[];\n}\n\nexport interface IListService {\n current: ListInstance;\n\n initInstance(typeName?: TypeName): ListInstance;\n\n getList(p: ParamMap, typeName?: string): Observable>\n\n delete(row: T): Observable;\n}\n", - "properties": [ - { - "name": "columns", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "optional": false, - "description": "", - "line": 11 - }, - { - "name": "typeName", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 10 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "ListResult", - "id": "interface-ListResult-90aae971ca3fcc1d40b149a6b8f759d3", - "file": "src/app/models/list-result.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface ListResult {\n count: number;\n next?: string;\n previous?: string;\n results: T[];\n}\n", - "properties": [ - { - "name": "count", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 2 - }, - { - "name": "next", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 3 - }, - { - "name": "previous", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 4 - }, - { - "name": "results", - "deprecated": false, - "deprecationMessage": "", - "type": "T[]", - "optional": false, - "description": "", - "line": 5 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "LogFile", - "id": "interface-LogFile-a25a180383c9eab0fd04d0bffbe4860c", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { BaseEntity } from './api';\nimport { Entity } from '@adwp-ui/widgets';\n\nexport type JobStatus = 'created' | 'running' | 'failed' | 'success' | 'aborted';\n\nexport type JobType = 'component' | 'service' | 'cluster' | 'host' | 'provider';\n\nexport interface JobObject {\n id: number;\n name: string;\n type: JobType;\n url?: string[];\n}\n\ninterface TaskBase extends Entity {\n start_date: string;\n finish_date: string;\n objects: JobObject[];\n status: JobStatus;\n action: JobAction;\n terminatable: boolean;\n cancel: string;\n}\n\nexport interface JobAction {\n prototype_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n display_name: string;\n}\ninterface JobRaw extends TaskBase {\n log_files: LogFile[];\n start_date: string;\n finish_date: string;\n}\n\nexport interface TaskRaw extends TaskBase {\n jobs: Job[];\n}\n\nexport type Job = JobRaw & BaseEntity;\nexport type Task = TaskRaw & BaseEntity;\n\nexport interface LogFile {\n id: number;\n url: string;\n name: string;\n type: string;\n format: 'txt' | 'json';\n download_url: string;\n content: string | CheckLog[];\n}\n\nexport interface CheckLog {\n title: string;\n message: string;\n result: boolean;\n type: 'group' | 'check';\n content?: CheckLog[];\n}\n", - "properties": [ - { - "name": "content", - "deprecated": false, - "deprecationMessage": "", - "type": "string | CheckLog[]", - "optional": false, - "description": "", - "line": 62 - }, - { - "name": "download_url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 61 - }, - { - "name": "format", - "deprecated": false, - "deprecationMessage": "", - "type": "\"txt\" | \"json\"", - "optional": false, - "description": "", - "line": 60 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 56 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 58 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 59 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 57 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "NavigationState", - "id": "interface-NavigationState-2ffa191f386016a5cf13a354c908f2d0", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import {\n Action,\n createAction,\n createFeatureSelector,\n createReducer,\n createSelector,\n on,\n props,\n} from '@ngrx/store';\nimport { ParamMap } from '@angular/router';\nimport { map } from 'rxjs/operators';\nimport { Observable, zip } from 'rxjs';\n\nimport { AdcmTypedEntity } from '@app/models/entity';\nimport { TypeName } from '@app/core/types';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n\nexport const setPath = createAction('[Navigation] Set path', props<{ path: AdcmTypedEntity[] }>());\nexport const setPathOfRoute = createAction('[Navigation] Set path', props<{ params: ParamMap }>());\n\nexport interface NavigationState {\n path: AdcmTypedEntity[];\n}\n\nconst initialState: NavigationState = {\n path: [],\n};\n\nconst reducer = createReducer(\n initialState,\n on(setPath, (state, { path }) => ({ path })),\n);\n\nexport function navigationReducer(state: NavigationState, action: Action) {\n return reducer(state, action);\n}\n\nexport const getNavigationState = createFeatureSelector('navigation');\nexport const getNavigationPath = createSelector(\n getNavigationState,\n state => state.path\n);\n\nexport function getEventEntityType(type: string): TypeName {\n switch (type) {\n case 'component':\n return 'servicecomponent';\n case ConcernEventType.Cluster:\n return 'cluster';\n case ConcernEventType.Service:\n return 'service';\n case ConcernEventType.ServiceComponent:\n return 'servicecomponent';\n case ConcernEventType.Host:\n return 'host';\n case ConcernEventType.HostProvider:\n return 'provider';\n }\n}\n\nexport function getPath(getters: Observable[]): Observable {\n return zip(...getters).pipe(\n map((path: AdcmTypedEntity[]) => setPath({ path })),\n );\n}\n\n", - "properties": [ - { - "name": "path", - "deprecated": false, - "deprecationMessage": "", - "type": "AdcmTypedEntity[]", - "optional": false, - "description": "", - "line": 23 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "NotificationsData", - "id": "interface-NotificationsData-391bc2abd632d574b4523b00c2426438", - "file": "src/app/components/bell/bell.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { AfterViewInit, Component, ElementRef, Renderer2, ViewChild } from '@angular/core';\nimport { BaseDirective } from '@adwp-ui/widgets';\nimport { BehaviorSubject, combineLatest, interval, Observable, zip } from 'rxjs';\nimport { filter, map, mergeMap, take, takeWhile } from 'rxjs/operators';\n\nimport { TaskService } from '@app/services/task.service';\nimport { ACKNOWLEDGE_EVENT, NotificationsComponent } from '@app/components/notifications/notifications.component';\nimport { JobStatus, Task, TaskRaw } from '@app/core/types';\nimport { EventMessage, ProfileService } from '@app/core/store';\nimport { Stats, StatsService } from '@app/services/stats.service';\n\nconst RUNNING_COLOR = '#FFEA00';\nconst SUCCESS_COLOR = '#1EE564';\nconst FAILED_COLOR = '#FF8A80';\n\nexport interface NotificationsData {\n runningCount: number;\n successCount: number;\n failedCount: number;\n}\n\n@Component({\n selector: 'app-bell',\n template: `\n \n \n
\n
\n notifications\n
\n \n \n `,\n styleUrls: ['./bell.component.scss']\n})\nexport class BellComponent extends BaseDirective implements AfterViewInit {\n\n NotificationsComponent = NotificationsComponent;\n\n @ViewChild('animation', { static: false }) animationRef: ElementRef;\n\n runningCount = new BehaviorSubject(0);\n successCount = new BehaviorSubject(0);\n failedCount = new BehaviorSubject(0);\n\n bellGradient = '';\n\n isAnimationRunning = new BehaviorSubject(false);\n animationElem = new BehaviorSubject(null);\n\n counts = new BehaviorSubject(null);\n tasks = new BehaviorSubject([]);\n\n readonly bindedPopoverEvent = this.popoverEvent.bind(this);\n\n constructor(\n private taskService: TaskService,\n private renderer: Renderer2,\n private profileService: ProfileService,\n private statsService: StatsService,\n ) {\n super();\n }\n\n popoverEvent(event: any) {\n if (event === ACKNOWLEDGE_EVENT) {\n const lastTaskId = this.tasks.value[0]?.id;\n if (lastTaskId) {\n this.profileService.setLastViewedTask(lastTaskId).subscribe();\n }\n this.tasks.next([]);\n this.successCount.next(0);\n this.runningCount.next(0);\n this.failedCount.next(0);\n this.afterCountChanged(false);\n }\n }\n\n onAnimationStart() {\n this.isAnimationRunning.next(true);\n }\n\n onAnimationEnd() {\n this.isAnimationRunning.next(false);\n }\n\n startAnimation() {\n if (this.animationElem.value && !this.isAnimationRunning.value) {\n this.renderer.removeClass(this.animationElem.value, 'hide');\n this.renderer.addClass(this.animationElem.value, 'animated');\n }\n }\n\n endAnimation() {\n if (this.animationElem.value) {\n this.renderer.addClass(this.animationElem.value, 'hide');\n this.renderer.removeClass(this.animationElem.value, 'animated');\n }\n }\n\n afterCountChanged(animationNeeds = true) {\n const total = this.runningCount.value + this.successCount.value + this.failedCount.value;\n if (total > 0) {\n const degOne = 360 / total;\n const degRunning = this.runningCount.value * degOne;\n const degSuccess = this.successCount.value * degOne;\n this.bellGradient =\n `conic-gradient(`\n + `${RUNNING_COLOR} 0deg ${degRunning}deg,`\n + `${SUCCESS_COLOR} ${degRunning}deg ${degRunning + degSuccess}deg,`\n + `${FAILED_COLOR} ${degRunning + degSuccess}deg 360deg)`;\n } else {\n this.bellGradient = 'transparent';\n }\n if (animationNeeds) {\n this.startAnimation();\n }\n }\n\n getChangeTaskObservable(): Observable {\n return this.taskService.events({ events: ['change_job_status'] }).pipe(this.takeUntil());\n }\n\n decRunningCount() {\n const runningCount = this.runningCount.value - 1;\n this.runningCount.next(runningCount < 0 ? 0 : runningCount);\n }\n\n updateTask(updatedTaskId: number, task: TaskRaw, status: JobStatus) {\n const tasks: TaskRaw[] = this.tasks.value.slice();\n const index = tasks.findIndex(item => item.id === updatedTaskId);\n task.status = status;\n tasks.splice(index, 1, task);\n this.tasks.next(tasks);\n }\n\n listenToJobs() {\n this.getChangeTaskObservable().subscribe((event) => {\n const status = event.object.details.value;\n if (status === 'running') {\n this.runningCount.next(this.runningCount.value + 1);\n this.afterCountChanged();\n } else if (status === 'success') {\n this.successCount.next(this.successCount.value + 1);\n this.decRunningCount();\n this.afterCountChanged();\n } else if (status === 'failed') {\n this.failedCount.next(this.failedCount.value + 1);\n this.decRunningCount();\n this.afterCountChanged();\n }\n });\n\n this.getChangeTaskObservable().pipe(\n filter(event => event.object.details.type === 'status'),\n filter(event => event.object.details.value !== 'created'),\n ).subscribe((event) => {\n const tasks: TaskRaw[] = this.tasks.value.slice();\n const updatedTaskId = event.object.id;\n const index = tasks.findIndex(item => item.id === updatedTaskId);\n if (index >= 0) {\n const task: TaskRaw = Object.assign({}, tasks[index]);\n this.taskService.get(updatedTaskId).subscribe((updatedTask) => this.updateTask(updatedTaskId, updatedTask, event.object.details.value));\n tasks.splice(index, 1, task);\n this.tasks.next(tasks);\n } else {\n this.taskService.get(event.object.id).subscribe((task) => {\n task.status = event.object.details.value;\n tasks.unshift(task);\n this.tasks.next(tasks.slice(0, 5));\n });\n }\n });\n }\n\n getCurrentCounts(): Observable {\n return this.profileService.getProfile().pipe(\n take(1),\n mergeMap((user) => this.statsService.tasks(user.profile?.lastViewedTask?.id)),\n );\n }\n\n getLastTasks(): Observable {\n return zip(\n this.taskService.list({ ordering: '-finish_date', status: 'failed', limit: '5' }),\n this.taskService.list({ ordering: '-finish_date', status: 'success', limit: '5' }),\n this.taskService.list({ ordering: '-start_date', status: 'running', limit: '5' }),\n this.profileService.getProfile(),\n ).pipe(map(([failed, succeed, running, user]) => {\n let tasks = [...failed.results, ...succeed.results, ...running.results].sort((a, b) => {\n const getDateField = (task: Task) => task.status === 'failed' || task.status === 'success' ? task.finish_date : task.start_date;\n const aDate = new Date(getDateField(a));\n const bDate = new Date(getDateField(b));\n return aDate.getDate() - bDate.getDate();\n }).slice(0, 5);\n\n if (user.profile?.lastViewedTask?.id) {\n tasks = tasks.filter(task => task.id > user.profile.lastViewedTask.id);\n }\n\n return tasks;\n }));\n }\n\n ngAfterViewInit(): void {\n interval(200).pipe(\n this.takeUntil(),\n takeWhile(() => !this.animationElem.value),\n ).subscribe(() => {\n this.animationElem.next(this.animationRef ? this.animationRef.nativeElement : null);\n });\n\n this.animationElem.pipe(\n this.takeUntil(),\n filter((elem) => !!elem),\n take(1),\n ).subscribe(() => {\n zip(this.getCurrentCounts(), this.getLastTasks())\n .subscribe(([stats, tasks]) => {\n this.runningCount.next(stats.running);\n this.successCount.next(stats.success);\n this.failedCount.next(stats.failed);\n this.afterCountChanged(!!(stats.running || stats.success || stats.failed));\n this.tasks.next(tasks);\n this.listenToJobs();\n });\n });\n\n this.isAnimationRunning.pipe(\n this.takeUntil(),\n filter(isRunning => !isRunning),\n ).subscribe(() => this.endAnimation());\n\n combineLatest(this.runningCount, this.successCount, this.failedCount)\n .pipe(this.takeUntil())\n .subscribe(\n ([runningCount, successCount, failedCount]) => this.counts.next({\n runningCount,\n successCount,\n failedCount,\n })\n );\n }\n\n}\n", - "properties": [ - { - "name": "failedCount", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "runningCount", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 17 - }, - { - "name": "successCount", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 18 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "PopoverInput", - "id": "interface-PopoverInput-828cf763235e75cd27e094ca706187a9", - "file": "src/app/directives/popover.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { ComponentFactory, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Renderer2, Type, ViewContainerRef, } from '@angular/core';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { PopoverComponent } from '@app/components/popover/popover.component';\nimport { PopoverContentDirective, PopoverEventFunc } from '@app/abstract-directives/popover-content.directive';\n\nexport interface PopoverInput { [inputKey: string]: any; }\n\n@Directive({\n selector: '[appPopover]'\n})\nexport class PopoverDirective extends BaseDirective implements OnInit, OnDestroy {\n\n containerRef: ComponentRef;\n factory: ComponentFactory;\n leaveListener: () => void;\n\n shown = false;\n timeoutId: any;\n\n @Input() component: Type;\n @Input() data: PopoverInput = {};\n @Input() event: PopoverEventFunc;\n @Input() hideTimeout = 0;\n\n constructor(\n private elementRef: ElementRef,\n public viewContainer: ViewContainerRef,\n public componentFactoryResolver: ComponentFactoryResolver,\n public renderer: Renderer2,\n ) {\n super();\n }\n\n ngOnInit() {\n this.factory = this.componentFactoryResolver.resolveComponentFactory(PopoverComponent);\n }\n\n hideComponent() {\n if (!this.timeoutId) {\n this.timeoutId = setTimeout(() => {\n this.clear();\n this.shown = false;\n this.timeoutId = undefined;\n }, this.hideTimeout);\n }\n }\n\n checkReEnter() {\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n this.timeoutId = undefined;\n }\n }\n\n @HostListener('mouseenter') mouseEnter() {\n this.checkReEnter();\n if (this.component && !this.shown) {\n this.containerRef = this.viewContainer.createComponent(this.factory);\n this.containerRef.instance.component = this.component;\n this.containerRef.instance.data = this.data;\n this.containerRef.instance.event = this.event;\n\n this.leaveListener = this.renderer.listen(\n this.elementRef.nativeElement.parentElement,\n 'mouseleave',\n () => this.hideComponent(),\n );\n\n this.renderer.listen(\n this.containerRef.location.nativeElement,\n 'mouseenter',\n () => this.checkReEnter(),\n );\n\n this.shown = true;\n }\n }\n\n clear() {\n if (this.containerRef) {\n this.containerRef.destroy();\n }\n\n this.viewContainer.clear();\n\n if (this.leaveListener) {\n this.elementRef.nativeElement.parentElement.removeEventListener('mouseleave', this.leaveListener);\n }\n }\n\n ngOnDestroy() {\n super.ngOnDestroy();\n this.clear();\n }\n\n}\n", - "properties": [], - "indexSignatures": [ - { - "id": "index-declaration-828cf763235e75cd27e094ca706187a9", - "args": [ - { - "name": "inputKey", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "any", - "line": 7, - "deprecated": false, - "deprecationMessage": "" - } - ], - "kind": 172, - "methods": [] - }, - { - "name": "Provider", - "id": "interface-Provider-0cbb246102564bc134c66dc61b2dabe6", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IAction } from './actions';\nimport { IComponent } from './host-component';\nimport { Job, Task } from './task-job';\nimport { AdcmEntity } from '@app/models/entity';\nimport { IIssues } from '@app/models/issue';\nimport { ICluster } from '@app/models/cluster';\nimport { Concern } from '@app/models/concern/concern';\n\nexport type TypeName =\n 'bundle' |\n 'cluster' |\n 'host' |\n 'provider' |\n 'service' |\n 'job' |\n 'task' |\n 'user' |\n 'profile' |\n 'adcm' |\n 'stats' |\n 'hostcomponent' |\n 'service2cluster' |\n 'host2cluster' |\n 'servicecomponent' |\n 'component' |\n 'group_config' |\n 'group_config_hosts';\nexport type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle;\n\n/**\n *```\n {\n [key: string]: string;\n }\n ```\n */\nexport interface IRoot {\n [key: string]: string;\n}\n\nexport interface BaseEntity extends AdcmEntity {\n typeName: TypeName;\n description?: string;\n url: string;\n state?: string;\n config: string;\n action?: string;\n actions?: IAction[];\n issue?: IIssues;\n prototype_id?: number;\n prototype_name?: string;\n prototype_display_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n status?: number | string;\n concerns: Concern[];\n locked: boolean;\n}\n\nexport interface ApiFlat {\n id: number;\n object_id: number;\n object_type: TypeName;\n url: string;\n}\n\nexport interface Provider extends BaseEntity {\n host: string;\n}\n\nexport interface Host extends BaseEntity {\n fqdn: string;\n provider_id: number;\n cluster: string;\n cluster_id?: number;\n cluster_name?: string;\n}\n\nexport interface Service extends BaseEntity {\n components: IComponent[];\n status: number;\n hostcomponent: string;\n display_name: string;\n cluster_id?: number;\n group_config: string;\n}\n\nexport interface CanLicensed {\n license: 'unaccepted' | 'accepted' | 'absent';\n license_url: string;\n}\n\nexport interface License {\n accept: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n text: string;\n}\n\nexport interface Bundle extends BaseEntity, CanLicensed {\n [key: string]: any;\n}\n", - "properties": [ - { - "name": "host", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 80 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "BaseEntity" - }, - { - "name": "RequestCacheEntry", - "id": "interface-RequestCacheEntry-8a514e04e9e3c150b655bc69be645c5e", - "file": "src/app/core/http-interseptors/request-cache.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { HttpRequest, HttpResponse } from '@angular/common/http';\n\nconst maxAge = Number.MAX_VALUE; // maximum cache age (ms)\n\ninterface RequestCacheEntry {\n url: string;\n response: HttpResponse;\n lastRead: number;\n}\n\nexport abstract class RequestCache {\n abstract get(req: HttpRequest): HttpResponse | undefined;\n abstract put(req: HttpRequest, response: HttpResponse): void;\n}\n\n@Injectable()\nexport class RequestCacheService implements RequestCache {\n cache = new Map();\n\n constructor() {}\n\n get(req: HttpRequest): HttpResponse | undefined {\n const url = req.urlWithParams;\n const cached = this.cache.get(url);\n\n if (!cached) return undefined;\n\n const isExpired = cached.lastRead < Date.now() - maxAge;\n\n const expired = isExpired ? 'Expired ' : '';\n // this.messanger.add(new Message(`${expired}cached response for \"${url}\".`));\n\n return isExpired ? undefined : cached.response;\n }\n\n put(req: HttpRequest, response: HttpResponse): void {\n const url = req.urlWithParams;\n // this.messanger.add(new Message(`Caching response from \"${url}\".` ));\n\n const entry = { url, response, lastRead: Date.now() };\n this.cache.set(url, entry);\n\n const expired = Date.now() - maxAge;\n\n this.cache.forEach(c => {\n if (c.lastRead < expired) this.cache.delete(c.url);\n });\n\n // this.messanger.add(new Message(`Request cache size: ${this.cache.size}.`));\n }\n}\n", - "properties": [ - { - "name": "lastRead", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 20 - }, - { - "name": "response", - "deprecated": false, - "deprecationMessage": "", - "type": "HttpResponse", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 18 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "RouterStateUrl", - "id": "interface-RouterStateUrl-8dd1bd3a3ce3f8be4547bb2e68025ad1", - "file": "src/app/core/store/router/route-serializer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { RouterStateSerializer } from '@ngrx/router-store';\nimport { RouterStateSnapshot, Params } from '@angular/router';\n\nexport interface RouterStateUrl {\n url: string;\n params: Params;\n queryParams: Params;\n}\n\nexport class RouteSerializer implements RouterStateSerializer {\n serialize(routerState: RouterStateSnapshot): RouterStateUrl {\n let route = routerState.root;\n\n while (route.firstChild) {\n route = route.firstChild;\n }\n\n const {\n url,\n root: { queryParams },\n } = routerState;\n const { params } = route;\n\n // Only return an object including the URL, params and query params\n // instead of the entire snapshot\n return { url, params, queryParams };\n }\n}\n", - "properties": [ - { - "name": "params", - "deprecated": false, - "deprecationMessage": "", - "type": "Params", - "optional": false, - "description": "", - "line": 17 - }, - { - "name": "queryParams", - "deprecated": false, - "deprecationMessage": "", - "type": "Params", - "optional": false, - "description": "", - "line": 18 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 16 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "SelectOption", - "id": "interface-SelectOption-48bdc39db9b8bb2237d76b204a2e01dc", - "file": "src/app/core/types/utils.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface EmmitRow {\n cmd: string;\n row: any;\n item?: any;\n}\n\nexport interface SelectOption {\n id: number | string;\n name: string;\n}\n\nexport interface IError {\n code: string;\n desc: string;\n level: string;\n}\n", - "properties": [ - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number | string", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 27 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "Service", - "id": "interface-Service-0cbb246102564bc134c66dc61b2dabe6", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { IAction } from './actions';\nimport { IComponent } from './host-component';\nimport { Job, Task } from './task-job';\nimport { AdcmEntity } from '@app/models/entity';\nimport { IIssues } from '@app/models/issue';\nimport { ICluster } from '@app/models/cluster';\nimport { Concern } from '@app/models/concern/concern';\n\nexport type TypeName =\n 'bundle' |\n 'cluster' |\n 'host' |\n 'provider' |\n 'service' |\n 'job' |\n 'task' |\n 'user' |\n 'profile' |\n 'adcm' |\n 'stats' |\n 'hostcomponent' |\n 'service2cluster' |\n 'host2cluster' |\n 'servicecomponent' |\n 'component' |\n 'group_config' |\n 'group_config_hosts';\nexport type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle;\n\n/**\n *```\n {\n [key: string]: string;\n }\n ```\n */\nexport interface IRoot {\n [key: string]: string;\n}\n\nexport interface BaseEntity extends AdcmEntity {\n typeName: TypeName;\n description?: string;\n url: string;\n state?: string;\n config: string;\n action?: string;\n actions?: IAction[];\n issue?: IIssues;\n prototype_id?: number;\n prototype_name?: string;\n prototype_display_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n status?: number | string;\n concerns: Concern[];\n locked: boolean;\n}\n\nexport interface ApiFlat {\n id: number;\n object_id: number;\n object_type: TypeName;\n url: string;\n}\n\nexport interface Provider extends BaseEntity {\n host: string;\n}\n\nexport interface Host extends BaseEntity {\n fqdn: string;\n provider_id: number;\n cluster: string;\n cluster_id?: number;\n cluster_name?: string;\n}\n\nexport interface Service extends BaseEntity {\n components: IComponent[];\n status: number;\n hostcomponent: string;\n display_name: string;\n cluster_id?: number;\n group_config: string;\n}\n\nexport interface CanLicensed {\n license: 'unaccepted' | 'accepted' | 'absent';\n license_url: string;\n}\n\nexport interface License {\n accept: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n text: string;\n}\n\nexport interface Bundle extends BaseEntity, CanLicensed {\n [key: string]: any;\n}\n", - "properties": [ - { - "name": "cluster_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 96 - }, - { - "name": "components", - "deprecated": false, - "deprecationMessage": "", - "type": "IComponent[]", - "optional": false, - "description": "", - "line": 92 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 95 - }, - { - "name": "group_config", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 97 - }, - { - "name": "hostcomponent", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 94 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 93 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "BaseEntity" - }, - { - "name": "ServiceStatusTree", - "id": "interface-ServiceStatusTree-c0578eccc6c0f17562e0f3175dee1006", - "file": "src/app/models/status-tree.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export type StatusTreeLinkFunc = (id: number, tree: StatusTree[]) => string[];\n\nexport interface StatusTreeSubject {\n id?: number;\n name: string;\n status?: number;\n link?: StatusTreeLinkFunc;\n}\n\nexport interface StatusTree {\n subject: StatusTreeSubject;\n children: StatusTree[];\n}\n\nexport interface ClusterStatusTree extends StatusTreeSubject {\n chilren: {\n hosts: StatusTreeSubject[];\n services: ServiceStatusTree[];\n };\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n\nexport interface HostComponentStatusTree extends StatusTreeSubject {\n hosts: StatusTreeSubject[];\n}\n\nexport interface HostStatusTree extends StatusTreeSubject {\n hc: StatusTreeSubject[];\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n", - "properties": [ - { - "name": "hc", - "deprecated": false, - "deprecationMessage": "", - "type": "HostComponentStatusTree[]", - "optional": false, - "description": "", - "line": 23 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "StatusTreeSubject" - }, - { - "name": "ServiceStatusTree", - "id": "interface-ServiceStatusTree-c0578eccc6c0f17562e0f3175dee1006-1", - "file": "src/app/models/status-tree.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export type StatusTreeLinkFunc = (id: number, tree: StatusTree[]) => string[];\n\nexport interface StatusTreeSubject {\n id?: number;\n name: string;\n status?: number;\n link?: StatusTreeLinkFunc;\n}\n\nexport interface StatusTree {\n subject: StatusTreeSubject;\n children: StatusTree[];\n}\n\nexport interface ClusterStatusTree extends StatusTreeSubject {\n chilren: {\n hosts: StatusTreeSubject[];\n services: ServiceStatusTree[];\n };\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n\nexport interface HostComponentStatusTree extends StatusTreeSubject {\n hosts: StatusTreeSubject[];\n}\n\nexport interface HostStatusTree extends StatusTreeSubject {\n hc: StatusTreeSubject[];\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n", - "properties": [ - { - "name": "hc", - "deprecated": false, - "deprecationMessage": "", - "type": "HostComponentStatusTree[]", - "optional": false, - "description": "", - "line": 35 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "StatusTreeSubject", - "isDuplicate": true, - "duplicateId": 1, - "duplicateName": "ServiceStatusTree-1" - }, - { - "name": "SocketState", - "id": "interface-SocketState-ca14b9fd2a8ab6897860f58a705daf52", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { TypeName } from '@app/core/types';\nimport {\n Action,\n createAction,\n createFeatureSelector,\n createReducer,\n createSelector,\n on,\n props,\n select\n} from '@ngrx/store';\nimport { pipe } from 'rxjs';\nimport { skip } from 'rxjs/operators';\n\n/**\n * Event Message Object dispatched from socket\n */\nexport interface IEMObject {\n type: TypeName;\n id: number;\n details: {\n id?: number;\n type: string;\n value: any;\n };\n}\n\nexport type EntityEvent =\n | 'add'\n | 'add_job_log'\n | 'create'\n | 'delete'\n | 'remove'\n | 'change_config'\n | 'change_state'\n | 'change_status'\n | 'change_job_status'\n | 'change_hostcomponentmap'\n | 'upgrade'\n | 'concern';\n\nexport interface EventMessage {\n event: EntityEvent;\n object?: IEMObject;\n}\n\nexport type StatusType = 'open' | 'close' | 're-open';\n\nexport const socketInit = createAction('[Socket] Init');\nexport const socketOpen = createAction('[Socket] Open', props<{ status: StatusType }>());\nexport const socketClose = createAction('[Socket] Close', props<{ status: StatusType }>());\nexport const socketResponse = createAction('[Socket] Response', props<{ message: EventMessage }>());\nexport const clearMessages = createAction('[Socket] Clear messages');\n\nexport interface SocketState {\n status: StatusType;\n message: EventMessage;\n}\n\nconst initialState: SocketState = {\n status: null,\n message: null,\n};\n\nconst reducer = createReducer(\n initialState,\n on(socketInit, (state) => ({ ...state })),\n on(socketOpen, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketClose, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketResponse, (state, { message }) => ({\n ...state,\n message,\n })),\n on(clearMessages, (state) => ({ ...state, message: null }))\n);\n\nexport function socketReducer(state: SocketState, action: Action) {\n return reducer(state, action);\n}\n\nexport const getSocketState = createFeatureSelector('socket');\nexport const getConnectStatus = createSelector(getSocketState, (state: SocketState) => state.status);\nexport const getMessage = createSelector(getSocketState, (state) => state.message);\nexport const selectMessage = pipe(\n select(getMessage),\n skip(1),\n);\n", - "properties": [ - { - "name": "message", - "deprecated": false, - "deprecationMessage": "", - "type": "EventMessage", - "optional": false, - "description": "", - "line": 68 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "StatusType", - "optional": false, - "description": "", - "line": 67 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "StackBase", - "id": "interface-StackBase-a295d56b2f4977d66fa39a2d212c69c7", - "file": "src/app/core/types/stack.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface StackBase {\n id: number;\n name: string;\n url: string;\n version: string;\n edition: string;\n description: string;\n display_name: string;\n license: 'unaccepted' | 'accepted' | 'absent';\n bundle_id: number;\n bundle_edition: string;\n}\n\nexport type Prototype = StackBase & {bundle_id: number};\nexport type ServicePrototype = StackBase & {selected: boolean};\n", - "properties": [ - { - "name": "bundle_edition", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "bundle_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 21 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 18 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "edition", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 17 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 13 - }, - { - "name": "license", - "deprecated": false, - "deprecationMessage": "", - "type": "\"unaccepted\" | \"accepted\" | \"absent\"", - "optional": false, - "description": "", - "line": 20 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 14 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 15 - }, - { - "name": "version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 16 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "State", - "id": "interface-State-078c8935e83aa026b394f99fed46eff2", - "file": "src/app/core/store/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { environment } from '@env/environment';\nimport { ActionReducerMap, MetaReducer } from '@ngrx/store';\n\nimport { ApiEffects } from '../api/api.effects';\nimport { apiReducer, ApiState } from '../api/api.reducer';\nimport { AuthEffects, authReducer, AuthState } from '../auth/auth.store';\nimport { IssueEffect, issueReducer, IssueState } from './issue';\nimport { ProfileEffects, profileReducer, ProfileState } from './profile';\nimport { SocketEffect } from './sockets/socket.effect';\nimport { socketReducer, SocketState } from './sockets/socket.reducer';\nimport { navigationReducer, NavigationState } from '@app/store/navigation/navigation.store';\nimport { NavigationEffects } from '@app/store/navigation/navigation-effects';\n\nexport interface State {\n auth: AuthState;\n socket: SocketState;\n api: ApiState;\n profile: ProfileState;\n issue: IssueState;\n navigation: NavigationState,\n}\n\nexport const reducers: ActionReducerMap = {\n auth: authReducer,\n socket: socketReducer,\n api: apiReducer,\n profile: profileReducer,\n issue: issueReducer,\n navigation: navigationReducer,\n};\n\nexport const metaReducers: MetaReducer[] = !environment.production ? [] : [];\n\nexport const StoreEffects = [AuthEffects, ApiEffects, ProfileEffects, IssueEffect, SocketEffect, NavigationEffects];\n\nexport * from '../api/api.reducer';\nexport * from '../auth/auth.store';\nexport * from './profile';\nexport * from './profile/profile.service';\nexport * from './issue';\nexport * from './sockets/socket.service';\nexport * from './sockets/socket.reducer';\nexport * from '@app/store/navigation/navigation.store';\n", - "properties": [ - { - "name": "api", - "deprecated": false, - "deprecationMessage": "", - "type": "ApiState", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "auth", - "deprecated": false, - "deprecationMessage": "", - "type": "AuthState", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "issue", - "deprecated": false, - "deprecationMessage": "", - "type": "IssueState", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "navigation", - "deprecated": false, - "deprecationMessage": "", - "type": "NavigationState", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "profile", - "deprecated": false, - "deprecationMessage": "", - "type": "ProfileState", - "optional": false, - "description": "", - "line": 29 - }, - { - "name": "socket", - "deprecated": false, - "deprecationMessage": "", - "type": "SocketState", - "optional": false, - "description": "", - "line": 27 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "Stats", - "id": "interface-Stats-4f4a6bd7d5a030ff0f14e7faff1e5be6", - "file": "src/app/services/stats.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Observable } from 'rxjs';\n\nimport { environment } from '@env/environment';\n\nexport interface Stats {\n failed: number;\n success: number;\n running: number;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class StatsService {\n\n constructor(\n private http: HttpClient,\n ) { }\n\n tasks(lastTaskId?: number): Observable {\n return this.http.get(`${environment.apiRoot}/stats/task/${lastTaskId || 1}/`);\n }\n\n}\n", - "properties": [ - { - "name": "failed", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 8 - }, - { - "name": "running", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 10 - }, - { - "name": "success", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 9 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "StatusData", - "id": "interface-StatusData-afb8a8911522db45a368173e82024384", - "file": "src/app/components/columns/status-column/status-column.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, Input, Output, EventEmitter } from '@angular/core';\nimport { AdwpCellComponent } from '@adwp-ui/widgets';\n\nexport interface StatusData {\n event: MouseEvent;\n action: string;\n row: T;\n}\n\n@Component({\n selector: 'app-status-column',\n templateUrl: './status-column.component.html',\n styleUrls: ['./status-column.component.scss']\n})\nexport class StatusColumnComponent implements AdwpCellComponent {\n\n @Input() row: T;\n\n @Output() onClick = new EventEmitter>();\n\n clickCell(event: MouseEvent, action: string, row: T): void {\n this.onClick.emit({ event, action, row });\n }\n\n}\n", - "properties": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 6 - }, - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "type": "MouseEvent", - "optional": false, - "description": "", - "line": 5 - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "type": "T", - "optional": false, - "description": "", - "line": 7 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "StatusTree", - "id": "interface-StatusTree-c0578eccc6c0f17562e0f3175dee1006", - "file": "src/app/models/status-tree.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export type StatusTreeLinkFunc = (id: number, tree: StatusTree[]) => string[];\n\nexport interface StatusTreeSubject {\n id?: number;\n name: string;\n status?: number;\n link?: StatusTreeLinkFunc;\n}\n\nexport interface StatusTree {\n subject: StatusTreeSubject;\n children: StatusTree[];\n}\n\nexport interface ClusterStatusTree extends StatusTreeSubject {\n chilren: {\n hosts: StatusTreeSubject[];\n services: ServiceStatusTree[];\n };\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n\nexport interface HostComponentStatusTree extends StatusTreeSubject {\n hosts: StatusTreeSubject[];\n}\n\nexport interface HostStatusTree extends StatusTreeSubject {\n hc: StatusTreeSubject[];\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n", - "properties": [ - { - "name": "children", - "deprecated": false, - "deprecationMessage": "", - "type": "StatusTree[]", - "optional": false, - "description": "", - "line": 12 - }, - { - "name": "subject", - "deprecated": false, - "deprecationMessage": "", - "type": "StatusTreeSubject", - "optional": false, - "description": "", - "line": 11 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "StatusTreeSubject", - "id": "interface-StatusTreeSubject-c0578eccc6c0f17562e0f3175dee1006", - "file": "src/app/models/status-tree.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export type StatusTreeLinkFunc = (id: number, tree: StatusTree[]) => string[];\n\nexport interface StatusTreeSubject {\n id?: number;\n name: string;\n status?: number;\n link?: StatusTreeLinkFunc;\n}\n\nexport interface StatusTree {\n subject: StatusTreeSubject;\n children: StatusTree[];\n}\n\nexport interface ClusterStatusTree extends StatusTreeSubject {\n chilren: {\n hosts: StatusTreeSubject[];\n services: ServiceStatusTree[];\n };\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n\nexport interface HostComponentStatusTree extends StatusTreeSubject {\n hosts: StatusTreeSubject[];\n}\n\nexport interface HostStatusTree extends StatusTreeSubject {\n hc: StatusTreeSubject[];\n}\n\nexport interface ServiceStatusTree extends StatusTreeSubject {\n hc: HostComponentStatusTree[];\n}\n", - "properties": [ - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 4 - }, - { - "name": "link", - "deprecated": false, - "deprecationMessage": "", - "type": "StatusTreeLinkFunc", - "optional": true, - "description": "", - "line": 7 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 5 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 6 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "TaskBase", - "id": "interface-TaskBase-a25a180383c9eab0fd04d0bffbe4860c", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { BaseEntity } from './api';\nimport { Entity } from '@adwp-ui/widgets';\n\nexport type JobStatus = 'created' | 'running' | 'failed' | 'success' | 'aborted';\n\nexport type JobType = 'component' | 'service' | 'cluster' | 'host' | 'provider';\n\nexport interface JobObject {\n id: number;\n name: string;\n type: JobType;\n url?: string[];\n}\n\ninterface TaskBase extends Entity {\n start_date: string;\n finish_date: string;\n objects: JobObject[];\n status: JobStatus;\n action: JobAction;\n terminatable: boolean;\n cancel: string;\n}\n\nexport interface JobAction {\n prototype_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n display_name: string;\n}\ninterface JobRaw extends TaskBase {\n log_files: LogFile[];\n start_date: string;\n finish_date: string;\n}\n\nexport interface TaskRaw extends TaskBase {\n jobs: Job[];\n}\n\nexport type Job = JobRaw & BaseEntity;\nexport type Task = TaskRaw & BaseEntity;\n\nexport interface LogFile {\n id: number;\n url: string;\n name: string;\n type: string;\n format: 'txt' | 'json';\n download_url: string;\n content: string | CheckLog[];\n}\n\nexport interface CheckLog {\n title: string;\n message: string;\n result: boolean;\n type: 'group' | 'check';\n content?: CheckLog[];\n}\n", - "properties": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "JobAction", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "cancel", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 33 - }, - { - "name": "finish_date", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "objects", - "deprecated": false, - "deprecationMessage": "", - "type": "JobObject[]", - "optional": false, - "description": "", - "line": 29 - }, - { - "name": "start_date", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "JobStatus", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "terminatable", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 32 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "Entity" - }, - { - "name": "TaskRaw", - "id": "interface-TaskRaw-a25a180383c9eab0fd04d0bffbe4860c", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { BaseEntity } from './api';\nimport { Entity } from '@adwp-ui/widgets';\n\nexport type JobStatus = 'created' | 'running' | 'failed' | 'success' | 'aborted';\n\nexport type JobType = 'component' | 'service' | 'cluster' | 'host' | 'provider';\n\nexport interface JobObject {\n id: number;\n name: string;\n type: JobType;\n url?: string[];\n}\n\ninterface TaskBase extends Entity {\n start_date: string;\n finish_date: string;\n objects: JobObject[];\n status: JobStatus;\n action: JobAction;\n terminatable: boolean;\n cancel: string;\n}\n\nexport interface JobAction {\n prototype_name?: string;\n prototype_version?: string;\n bundle_id?: number;\n display_name: string;\n}\ninterface JobRaw extends TaskBase {\n log_files: LogFile[];\n start_date: string;\n finish_date: string;\n}\n\nexport interface TaskRaw extends TaskBase {\n jobs: Job[];\n}\n\nexport type Job = JobRaw & BaseEntity;\nexport type Task = TaskRaw & BaseEntity;\n\nexport interface LogFile {\n id: number;\n url: string;\n name: string;\n type: string;\n format: 'txt' | 'json';\n download_url: string;\n content: string | CheckLog[];\n}\n\nexport interface CheckLog {\n title: string;\n message: string;\n result: boolean;\n type: 'group' | 'check';\n content?: CheckLog[];\n}\n", - "properties": [ - { - "name": "jobs", - "deprecated": false, - "deprecationMessage": "", - "type": "Job[]", - "optional": false, - "description": "", - "line": 49 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [], - "extends": "TaskBase" - }, - { - "name": "TooltipDisplayOptions", - "id": "interface-TooltipDisplayOptions-0aa6c34b3edfef5dfe8a28653d0685f0", - "file": "src/app/shared/components/tooltip/tooltip.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { EventEmitter, Injectable } from '@angular/core';\nimport { BaseEntity } from '@app/core/types/api';\nimport { Subject } from 'rxjs';\n\nexport type ComponentName = 'issue' | 'status' | undefined;\nexport type PositionType = 'top' | 'right' | 'bottom' | 'left';\nexport interface TooltipOptions {\n event: MouseEvent;\n source: HTMLElement;\n options: TooltipDisplayOptions;\n}\n\nexport interface TooltipDisplayOptions {\n content: string | BaseEntity;\n componentName: ComponentName;\n position: PositionType;\n condition: boolean;\n}\n\n@Injectable()\nexport class ComponentData {\n path: string;\n current: any;\n emitter: EventEmitter;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class TooltipService {\n private positionSource = new Subject();\n position$ = this.positionSource.asObservable();\n timeOut: any;\n\n /**\n * TODO: show a tooltip if there is a condition\n *\n * @returns\n * @memberof TooltipComponent\n */\n isShow(source: HTMLElement, options: TooltipDisplayOptions) {\n if (options.condition) {\n return source.offsetWidth !== source.scrollWidth;\n }\n return true;\n }\n\n show(event: MouseEvent, source: HTMLElement, options: TooltipDisplayOptions) {\n this.positionSource.next();\n clearTimeout(this.timeOut);\n if (this.isShow(source, options)) {\n this.positionSource.next({ event, source, options });\n }\n }\n\n hide(withoutTimout = false, timeout = 500) {\n if (withoutTimout) {\n this.positionSource.next();\n return;\n }\n\n this.timeOut = setTimeout(() => this.positionSource.next(), timeout);\n }\n\n mouseEnterTooltip() {\n clearTimeout(this.timeOut);\n }\n\n mouseLeaveTooltip() {\n this.hide();\n }\n}\n", - "properties": [ - { - "name": "componentName", - "deprecated": false, - "deprecationMessage": "", - "type": "ComponentName", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "condition", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "content", - "deprecated": false, - "deprecationMessage": "", - "type": "string | BaseEntity", - "optional": false, - "description": "", - "line": 25 - }, - { - "name": "position", - "deprecated": false, - "deprecationMessage": "", - "type": "PositionType", - "optional": false, - "description": "", - "line": 27 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "TooltipOptions", - "id": "interface-TooltipOptions-0aa6c34b3edfef5dfe8a28653d0685f0", - "file": "src/app/shared/components/tooltip/tooltip.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { EventEmitter, Injectable } from '@angular/core';\nimport { BaseEntity } from '@app/core/types/api';\nimport { Subject } from 'rxjs';\n\nexport type ComponentName = 'issue' | 'status' | undefined;\nexport type PositionType = 'top' | 'right' | 'bottom' | 'left';\nexport interface TooltipOptions {\n event: MouseEvent;\n source: HTMLElement;\n options: TooltipDisplayOptions;\n}\n\nexport interface TooltipDisplayOptions {\n content: string | BaseEntity;\n componentName: ComponentName;\n position: PositionType;\n condition: boolean;\n}\n\n@Injectable()\nexport class ComponentData {\n path: string;\n current: any;\n emitter: EventEmitter;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class TooltipService {\n private positionSource = new Subject();\n position$ = this.positionSource.asObservable();\n timeOut: any;\n\n /**\n * TODO: show a tooltip if there is a condition\n *\n * @returns\n * @memberof TooltipComponent\n */\n isShow(source: HTMLElement, options: TooltipDisplayOptions) {\n if (options.condition) {\n return source.offsetWidth !== source.scrollWidth;\n }\n return true;\n }\n\n show(event: MouseEvent, source: HTMLElement, options: TooltipDisplayOptions) {\n this.positionSource.next();\n clearTimeout(this.timeOut);\n if (this.isShow(source, options)) {\n this.positionSource.next({ event, source, options });\n }\n }\n\n hide(withoutTimout = false, timeout = 500) {\n if (withoutTimout) {\n this.positionSource.next();\n return;\n }\n\n this.timeOut = setTimeout(() => this.positionSource.next(), timeout);\n }\n\n mouseEnterTooltip() {\n clearTimeout(this.timeOut);\n }\n\n mouseLeaveTooltip() {\n this.hide();\n }\n}\n", - "properties": [ - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "type": "MouseEvent", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "options", - "deprecated": false, - "deprecationMessage": "", - "type": "TooltipDisplayOptions", - "optional": false, - "description": "", - "line": 21 - }, - { - "name": "source", - "deprecated": false, - "deprecationMessage": "", - "type": "HTMLElement", - "optional": false, - "description": "", - "line": 20 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "UniversalAdcmEventData", - "id": "interface-UniversalAdcmEventData-8f67aea206864c943b34fb66a214d7b0", - "file": "src/app/models/universal-adcm-event-data.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "export interface UniversalAdcmEventData {\n event: MouseEvent;\n action: 'getNextPageCluster' | 'getClusters' | 'addCluster';\n row: T;\n}\n", - "properties": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "\"getNextPageCluster\" | \"getClusters\" | \"addCluster\"", - "optional": false, - "description": "", - "line": 3 - }, - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "type": "MouseEvent", - "optional": false, - "description": "", - "line": 2 - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "type": "T", - "optional": false, - "description": "", - "line": 4 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "Upgrade", - "id": "interface-Upgrade-34c36605396243e8465a70ce623de60b", - "file": "src/app/shared/components/upgrade.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { MatDialog } from '@angular/material/dialog';\nimport { ApiService } from '@app/core/api';\nimport { EmmitRow } from '@app/core/types';\nimport { concat, Observable, of } from 'rxjs';\nimport { filter, map, switchMap } from 'rxjs/operators';\nimport { EventHelper } from '@adwp-ui/widgets';\n\nimport { BaseDirective } from '../directives';\nimport { DialogComponent } from './dialog.component';\nimport { IIssues } from '@app/models/issue';\nimport { IssueHelper } from '@app/helpers/issue-helper';\n\nexport interface UpgradeItem {\n upgradable: boolean;\n upgrade: string;\n issue: IIssues;\n}\n\nexport interface Upgrade {\n id: number;\n bundle_id: number;\n name: string;\n description: string;\n do: string;\n upgradable: boolean;\n from_edition: string[];\n license: 'unaccepted' | 'absent';\n license_url: string;\n max_strict: boolean;\n max_version: string;\n min_strict: boolean;\n min_version: string;\n state_available: string;\n state_on_success: string;\n url: string;\n}\n\n@Component({\n selector: 'app-upgrade',\n template: `\n \n \n \n \n \n \n `\n})\nexport class UpgradeComponent extends BaseDirective {\n EventHelper = EventHelper;\n\n list$: Observable;\n pRow: UpgradeItem = { upgradable: false, upgrade: '', issue: null };\n\n @Input() xPosition = 'before';\n\n @Input()\n set row(row: UpgradeItem) {\n this.pRow = row;\n this.list$ = this.getUpgrades(this.pRow.upgrade);\n }\n\n @Output()\n refresh: EventEmitter = new EventEmitter();\n\n constructor(private api: ApiService, private dialog: MatDialog) {\n super();\n }\n\n checkIssue() {\n return this.pRow.upgradable && !IssueHelper.isIssue(this.pRow.issue);\n }\n\n runUpgrade(item: Upgrade) {\n const license$ = item.license === 'unaccepted' ? this.api.put(`${item.license_url}accept/`, {}) : of();\n const do$ = this.api.post<{ id: number }>(item.do, {});\n this.fork(item)\n .pipe(\n switchMap(text =>\n this.dialog\n .open(DialogComponent, {\n data: {\n title: 'Are you sure you want to upgrade?',\n text,\n disabled: !item.upgradable,\n controls: item.license === 'unaccepted' ? {\n label: 'Do you accept the license agreement?',\n buttons: ['Yes', 'No']\n } : ['Yes', 'No']\n }\n })\n .beforeClosed()\n .pipe(\n this.takeUntil(),\n filter(yes => yes),\n switchMap(() => concat(license$, do$))\n )\n )\n )\n .subscribe(row => this.refresh.emit({ cmd: 'refresh', row }));\n }\n\n fork(item: Upgrade) {\n const flag = item.license === 'unaccepted';\n return flag ? this.api.get<{ text: string }>(item.license_url).pipe(map(a => a.text)) : of(item.description);\n }\n\n getUpgrades(upgrade: string): Observable {\n return this.api.get(`${upgrade}?ordering=-name`).pipe(\n filter((list: Upgrade[]) => !!list.length)\n );\n }\n}\n", - "properties": [ - { - "name": "bundle_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 33 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "do", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 36 - }, - { - "name": "from_edition", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "optional": false, - "description": "", - "line": 38 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "license", - "deprecated": false, - "deprecationMessage": "", - "type": "\"unaccepted\" | \"absent\"", - "optional": false, - "description": "", - "line": 39 - }, - { - "name": "license_url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 40 - }, - { - "name": "max_strict", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "max_version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "min_strict", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "min_version", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 44 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "state_available", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "state_on_success", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 46 - }, - { - "name": "upgradable", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 37 - }, - { - "name": "url", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 47 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "UpgradeItem", - "id": "interface-UpgradeItem-34c36605396243e8465a70ce623de60b", - "file": "src/app/shared/components/upgrade.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { MatDialog } from '@angular/material/dialog';\nimport { ApiService } from '@app/core/api';\nimport { EmmitRow } from '@app/core/types';\nimport { concat, Observable, of } from 'rxjs';\nimport { filter, map, switchMap } from 'rxjs/operators';\nimport { EventHelper } from '@adwp-ui/widgets';\n\nimport { BaseDirective } from '../directives';\nimport { DialogComponent } from './dialog.component';\nimport { IIssues } from '@app/models/issue';\nimport { IssueHelper } from '@app/helpers/issue-helper';\n\nexport interface UpgradeItem {\n upgradable: boolean;\n upgrade: string;\n issue: IIssues;\n}\n\nexport interface Upgrade {\n id: number;\n bundle_id: number;\n name: string;\n description: string;\n do: string;\n upgradable: boolean;\n from_edition: string[];\n license: 'unaccepted' | 'absent';\n license_url: string;\n max_strict: boolean;\n max_version: string;\n min_strict: boolean;\n min_version: string;\n state_available: string;\n state_on_success: string;\n url: string;\n}\n\n@Component({\n selector: 'app-upgrade',\n template: `\n \n \n \n \n \n \n `\n})\nexport class UpgradeComponent extends BaseDirective {\n EventHelper = EventHelper;\n\n list$: Observable;\n pRow: UpgradeItem = { upgradable: false, upgrade: '', issue: null };\n\n @Input() xPosition = 'before';\n\n @Input()\n set row(row: UpgradeItem) {\n this.pRow = row;\n this.list$ = this.getUpgrades(this.pRow.upgrade);\n }\n\n @Output()\n refresh: EventEmitter = new EventEmitter();\n\n constructor(private api: ApiService, private dialog: MatDialog) {\n super();\n }\n\n checkIssue() {\n return this.pRow.upgradable && !IssueHelper.isIssue(this.pRow.issue);\n }\n\n runUpgrade(item: Upgrade) {\n const license$ = item.license === 'unaccepted' ? this.api.put(`${item.license_url}accept/`, {}) : of();\n const do$ = this.api.post<{ id: number }>(item.do, {});\n this.fork(item)\n .pipe(\n switchMap(text =>\n this.dialog\n .open(DialogComponent, {\n data: {\n title: 'Are you sure you want to upgrade?',\n text,\n disabled: !item.upgradable,\n controls: item.license === 'unaccepted' ? {\n label: 'Do you accept the license agreement?',\n buttons: ['Yes', 'No']\n } : ['Yes', 'No']\n }\n })\n .beforeClosed()\n .pipe(\n this.takeUntil(),\n filter(yes => yes),\n switchMap(() => concat(license$, do$))\n )\n )\n )\n .subscribe(row => this.refresh.emit({ cmd: 'refresh', row }));\n }\n\n fork(item: Upgrade) {\n const flag = item.license === 'unaccepted';\n return flag ? this.api.get<{ text: string }>(item.license_url).pipe(map(a => a.text)) : of(item.description);\n }\n\n getUpgrades(upgrade: string): Observable {\n return this.api.get(`${upgrade}?ordering=-name`).pipe(\n filter((list: Upgrade[]) => !!list.length)\n );\n }\n}\n", - "properties": [ - { - "name": "issue", - "deprecated": false, - "deprecationMessage": "", - "type": "IIssues", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "upgradable", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "upgrade", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 27 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "User", - "id": "interface-User-f509a3802cb60762fa3f0173645f0df6", - "file": "src/app/admin/users/users.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\n\nimport { environment } from '@env/environment';\nimport { Observable } from 'rxjs';\n\nexport interface User {\n username: string;\n password: string;\n confirm: string;\n change_password: string;\n}\n\nconst USER_LINK = `${environment.apiRoot}user/`;\n\n@Injectable()\nexport class UsersService {\n constructor(private http: HttpClient) {}\n\n public getUsers(): Observable {\n return this.http.get(USER_LINK);\n }\n\n public addUser(username: string, password: string): Observable {\n return this.http.post(USER_LINK, { username, password });\n }\n\n public clearUser(user: User): Observable {\n return this.http.delete(`${USER_LINK}${user.username}/`);\n }\n\n public changePassword(value: string, link: string): Observable {\n return this.http.patch(link, { 'password': value });\n }\n}\n", - "properties": [ - { - "name": "change_password", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "confirm", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 21 - }, - { - "name": "password", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 20 - }, - { - "name": "username", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 19 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - }, - { - "name": "WorkerInstance", - "id": "interface-WorkerInstance-15046e581cc73dfa1357124a078aabc3", - "file": "src/app/core/services/cluster.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { ParamMap } from '@angular/router';\nimport { ApiService } from '@app/core/api';\nimport { BehaviorSubject, EMPTY, forkJoin, Observable, of, throwError } from 'rxjs';\nimport { catchError, filter, map, switchMap, tap } from 'rxjs/operators';\nimport { Store } from '@ngrx/store';\n\nimport {\n Bundle,\n Entities,\n Host,\n IAction,\n IImport,\n Job,\n License,\n LogFile,\n Provider,\n Service\n} from '@app/core/types';\nimport { environment } from '@env/environment';\nimport { ServiceComponentService } from '@app/services/service-component.service';\nimport { EntityNames } from '@app/models/entity-names';\nimport { HttpResponseBase } from '@angular/common/http';\nimport { setPathOfRoute } from '@app/store/navigation/navigation.store';\nimport { EntityService } from '@app/abstract/entity-service';\nimport { ICluster } from '@app/models/cluster';\n\nexport interface WorkerInstance {\n current: Entities;\n cluster: ICluster | null;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ClusterService {\n private worker: WorkerInstance | null;\n private workerSubject = new BehaviorSubject(null);\n public worker$ = this.workerSubject.asObservable();\n\n get Cluster() {\n return this.worker ? this.worker.cluster : null;\n }\n\n set Cluster(cluster: ICluster) {\n if (cluster) cluster.typeName = 'cluster';\n if (this.worker) this.worker.cluster = cluster;\n else this.worker = { current: cluster, cluster: cluster };\n }\n\n get Current(): Entities {\n return this.worker ? this.worker.current : null;\n }\n\n constructor(\n protected api: ApiService,\n protected serviceComponentService: ServiceComponentService,\n protected store: Store,\n ) {}\n\n clearWorker() {\n this.worker = null;\n }\n\n one_cluster(id: number): Observable {\n return this.Cluster ? of(this.Cluster) : this.api.getOne('cluster', id);\n }\n\n one_service(id: number): Observable {\n return this.api.get(`${this.worker.cluster.service}${id}/`);\n }\n\n one_host(id: number): Observable {\n return this.api.getOne('host', id).pipe(map((host: Host) => ({ ...host, name: host.fqdn })));\n }\n\n one_provider(id: number): Observable {\n return this.api.getOne('provider', id);\n }\n\n one_job(id: number): Observable {\n return this.api.getOne('job', id).pipe(\n map((j: Job) => ({\n ...j,\n prototype_name: j.action ? j.action.prototype_name : '',\n prototype_version: j.action ? j.action.prototype_version : '',\n bundle_id: j.action ? j.action.bundle_id : null,\n name: j.action ? `${j.action.display_name}` : 'Object has been deleted',\n }))\n );\n }\n\n one_bundle(id: number): Observable {\n return this.api.get(`${environment.apiRoot}stack/bundle/${id}/`);\n }\n\n getContext(param: ParamMap, service?: EntityService): Observable {\n this.store.dispatch(setPathOfRoute({ params: param }));\n\n const typeName = EntityNames.find((a) => param.keys.some((b) => a === b));\n const id = +param.get(typeName);\n const cluster$ = param.has('cluster') ? this.api.getOne('cluster', +param.get('cluster')) : of(null);\n return cluster$\n .pipe(\n tap((cluster) => (this.Cluster = cluster)),\n switchMap((cluster) => {\n if (typeName === 'group_config') {\n return service.get(id);\n } else if (cluster && (typeName === 'servicecomponent' || typeName === 'component')) {\n return this.serviceComponentService.get(id);\n } else if (cluster && typeName !== 'cluster') {\n return this.api.get(`${cluster[typeName]}${id}/`);\n } else {\n return this[`one_${typeName}`](id);\n }\n }),\n )\n .pipe(\n map((a: any) => {\n this.worker.current = { ...a, name: (a?.display_name || a?.name || (a as Host)?.fqdn) ?? '', typeName };\n this.workerSubject.next(this.worker);\n return this.worker;\n })\n );\n }\n\n getLog(url: string): Observable {\n return this.api.get(url);\n }\n\n getActions(): Observable {\n return typeof this.worker.current.action === 'string' ? this.api.get(this.worker.current.action) : of([]);\n }\n\n getServices(p: ParamMap) {\n return this.api.getList(this.Cluster.service, p).pipe(\n map((r) => {\n r.results = r.results.map((a) => ({ ...a, cluster: this.Cluster }));\n return r;\n })\n );\n }\n\n addServices(output: { prototype_id: number }[]) {\n return forkJoin(output.map((o) => this.api.post(this.Cluster.service, o)));\n }\n\n getHosts(p: ParamMap) {\n return this.api.getList(this.Cluster.host, p);\n }\n\n addHost(host_id: number) {\n return this.api.post(this.Cluster.host, { host_id });\n }\n\n reset(): Observable {\n if (!this.Current) return EMPTY;\n const typeName = this.Current.typeName;\n return this.api.get(this.Current.url).pipe(\n filter((_) => !!this.worker),\n map((a) => {\n if (typeName === 'cluster') this.worker.cluster = { ...(a as ICluster), typeName };\n this.worker.current = { ...a, typeName, name: a.display_name || a.name || (a as Host).fqdn };\n return this.worker;\n })\n );\n }\n\n getMainInfo() {\n return this.api.get(`${this.Current.config}current/`).pipe(\n map((a: any) => a.config.find((b: { name: string }) => b.name === '__main_info')),\n filter((a) => a),\n map((a) => a.value),\n catchError((e: HttpResponseBase) => {\n if (e.status === 404) {\n return of('Nothing to display');\n } else {\n return throwError(e);\n }\n }),\n );\n }\n\n getBundleLicenseText(): Observable {\n const { license_url, license } = (this.Current as Bundle);\n\n return this.api.get(license_url).pipe(\n map(({ text }) => license !== 'absent' ? text : 'No license required'),\n );\n }\n\n /**\n * Import / Export data for `Cluster`\n */\n getImportData() {\n return 'imports' in this.Current ? this.api.get(this.Current.imports) : EMPTY;\n }\n\n bindImport(bind: any) {\n return 'imports' in this.Current ? this.api.post(this.Current.imports, bind) : EMPTY;\n }\n\n /**\n * For `Job` and `Task` operating time data\n */\n getOperationTimeData(job: Job) {\n const { start_date, finish_date, status } = job;\n const sdn = Date.parse(start_date),\n fdn = Date.parse(finish_date),\n ttm = fdn - sdn,\n sec = Math.floor(ttm / 1000),\n min = Math.floor(sec / 60),\n time = status !== 'running' ? `${min}m. ${sec - min * 60}s.` : '';\n const a = new Date(sdn);\n const b = new Date(fdn);\n return { start: a.toLocaleTimeString(), end: status !== 'running' ? b.toLocaleTimeString() : '', time };\n }\n}\n", - "properties": [ - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "ICluster | null", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "Entities", - "optional": false, - "description": "", - "line": 40 - } - ], - "indexSignatures": [], - "kind": 163, - "methods": [] - } - ], - "injectables": [ - { - "name": "ActionsService", - "id": "injectable-ActionsService-6336ecef0c3a0e1478a498fbb3e3ca89", - "file": "src/app/shared/components/actions/actions.service.ts", - "properties": [], - "methods": [ - { - "name": "getActions", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 54, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { ApiService } from '@app/core/api';\n\n// export const fruit = {\n// display_name: 'Fruit',\n// desctiption: 'fruit description',\n// children: [\n// { display_name: 'Apple', description: 'description or some description about this action description or some description about this action' },\n// { display_name: 'Banana', description: 'description or some description about this action bannana' },\n// { display_name: 'Fruit loops', description: '' },\n// ],\n// };\n\n// export const vegetable = {\n// display_name: 'Vegetables',\n// desctiption: 'description or some description about this action some description about this action Vegetables',\n// children: [\n// {\n// display_name: 'Green',\n// description: 'description or some description about this action description or some description about this action',\n// children: [\n// { display_name: 'Broccoli', description: 'description or some description about this action description or some description about this action' },\n// { display_name: 'Brussels sprouts', description: 'description or some description about this action bannana' },\n// ],\n// },\n// {\n// display_name: 'Orange',\n// description: 'description or some description about this action bannana',\n// children: [\n// { display_name: 'Pumpkins', description: 'description or some description about this action description or some description about this action' },\n// { display_name: 'Carrots', description: 'description or some description about this action bannana' },\n// ],\n// },\n// ],\n// };\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ActionsService {\n constructor(private api: ApiService) {}\n\n getActions(url: string) {\n return this.api.get(url); //.pipe(map((a) => [fruit, vegetable, ...a]));\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 51, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "AddService", - "id": "injectable-AddService-3ef9727fae7ca66330a93148e4dcac79", - "file": "src/app/shared/add-component/add.service.ts", - "properties": [ - { - "name": "_currentPrototype", - "deprecated": false, - "deprecationMessage": "", - "type": "StackBase", - "optional": false, - "description": "", - "line": 68, - "modifierKind": [ - 120 - ] - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 80, - "modifierKind": [ - 122 - ] - } - ], - "methods": [ - { - "name": "add", - "args": [ - { - "name": "data", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "name", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "prototype", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [ - "T" - ], - "line": 106, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "name", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "prototype", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "addHost", - "args": [ - { - "name": "host", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 135, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "host", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "addHostInCluster", - "args": [ - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 143, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "addService", - "args": [ - { - "name": "data", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 147, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "genName", - "args": [ - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 96, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getHostListForCurrentCluster", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 181, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getList", - "args": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 156, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getListResults", - "args": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [ - "T" - ], - "line": 151, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getProtoServiceForCurrentCluster", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 164, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getPrototype", - "args": [ - { - "name": "name", - "type": "StackInfo", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "param", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 160, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "StackInfo", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "param", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "model", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "upload", - "args": [ - { - "name": "data", - "type": "FormData[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 177, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "FormData[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { FormControl, FormGroup, Validators } from '@angular/forms';\nimport { MatDialog } from '@angular/material/dialog';\nimport { convertToParamMap, Params } from '@angular/router';\nimport { environment } from '@env/environment';\nimport { forkJoin, Observable, of, throwError } from 'rxjs';\nimport { catchError, concatAll, filter, map, switchMap } from 'rxjs/operators';\n\nimport { StackInfo, StackService } from '@app/core/services';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ApiService } from '@app/core/api';\nimport { Host, Prototype, ServicePrototype, StackBase, TypeName } from '@app/core/types';\nimport { DialogComponent } from '@app/shared/components/dialog.component';\nimport { GenName } from './naming';\nimport { MainService } from '@app/shared/configuration/main/main.service';\nimport { FormModel, IAddService } from '@app/shared/add-component/add-service-model';\n\n\nconst fromBundle = () =>\n new FormGroup({\n prototype_id: new FormControl('', Validators.required),\n name: new FormControl('', Validators.required),\n description: new FormControl(),\n });\n\nconst MODELS: { [key: string]: FormModel } = {\n provider: {\n name: 'provider',\n form: fromBundle(),\n },\n host: {\n name: 'host',\n form: new FormGroup({\n fqdn: new FormControl('', [Validators.required, Validators.pattern(new RegExp(/^[A-Za-z0-9_\\.\\-]+$/))]),\n cluster_id: new FormControl(),\n provider_id: new FormControl('', Validators.required),\n }),\n },\n cluster: {\n name: 'cluster',\n form: fromBundle(),\n },\n service: {\n name: 'service',\n title: 'services'\n },\n host2cluster: {\n name: 'host2cluster',\n title: 'hosts',\n },\n};\n\n@Injectable({\n providedIn: 'root',\n})\nexport class AddService implements IAddService {\n private _currentPrototype: StackBase;\n set currentPrototype(a: StackBase) {\n this._currentPrototype = a;\n }\n\n get currentPrototype(): StackBase {\n return this._currentPrototype;\n }\n\n constructor(private api: ApiService,\n private stack: StackService,\n private cluster: ClusterService,\n public dialog: MatDialog,\n private main: MainService,\n ) {}\n\n model(name: string) {\n return MODELS[name];\n }\n\n get Cluster() {\n return this.cluster.Cluster;\n }\n\n get Current() {\n return this.main.Current;\n }\n\n genName(form: FormGroup) {\n return form\n .get('prototype_id')\n .valueChanges.pipe(filter((v) => !!v))\n .subscribe(() => {\n const field = form.get('name');\n if (!field.value) field.setValue(GenName.do());\n });\n }\n\n add(data: Partial, name: TypeName, prototype?: StackBase) {\n const currentPrototype = prototype || this.currentPrototype;\n if (currentPrototype?.license === 'unaccepted') {\n return this.api.root.pipe(\n switchMap((root) =>\n this.api.get<{ text: string }>(`${root.stack}bundle/${currentPrototype.bundle_id}/license/`).pipe(\n switchMap((info) =>\n this.dialog\n .open(DialogComponent, {\n data: {\n title: `Accept license agreement`,\n text: info.text,\n controls: { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] },\n },\n })\n .beforeClosed()\n .pipe(\n filter((yes) => yes),\n switchMap(() =>\n this.api.put(`${root.stack}bundle/${currentPrototype.bundle_id}/license/accept/`, {}).pipe(switchMap(() => this.api.post(root[name], data)))\n )\n )\n )\n )\n )\n );\n } else return this.api.root.pipe(switchMap((root) => this.api.post(root[name], data)));\n }\n\n addHost(host: Partial): Observable {\n const a$ = this.api.post(`${environment.apiRoot}provider/${host.provider_id}/host/`, { fqdn: host.fqdn });\n const b$ = a$.pipe(\n map((h) => (host.cluster_id ? this.api.post(`${environment.apiRoot}cluster/${host.cluster_id}/host/`, { host_id: h.id }) : of(h)))\n );\n return b$.pipe(concatAll());\n }\n\n addHostInCluster(ids: number[]) {\n return forkJoin([...ids.map(id => this.cluster.addHost(id))]);\n }\n\n addService(data: { prototype_id: number }[]) {\n return this.cluster.addServices(data);\n }\n\n getListResults(type: TypeName, param: Params = {}) {\n const paramMap = convertToParamMap(param);\n return this.api.root.pipe(switchMap((root) => this.api.getList(root[type], paramMap)));\n }\n\n getList(type: TypeName, param: Params = {}): Observable {\n return this.getListResults(type, param).pipe(map((list) => list.results));\n }\n\n getPrototype(name: StackInfo, param: { [key: string]: string | number }): Observable {\n return this.stack.fromStack(name, param);\n }\n\n getProtoServiceForCurrentCluster() {\n return this.api.get(this.cluster.Cluster.serviceprototype).pipe(\n map((a: ServicePrototype[]) =>\n a\n .filter((b) => !b.selected)\n .map((b) => ({\n ...b,\n name: `${b.display_name} - ${b.version}`,\n }))\n )\n );\n }\n\n upload(data: FormData[]) {\n return this.stack.upload(data).pipe(catchError((e) => throwError(e)));\n }\n\n getHostListForCurrentCluster() {\n return this.api.get(this.cluster.Cluster.host).pipe(\n map((hosts) =>\n hosts\n .map((host) => ({\n ...host,\n name: host.fqdn,\n }))\n )\n );\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "stack", - "type": "StackService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "main", - "type": "MainService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 75, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "stack", - "type": "StackService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "main", - "type": "MainService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "currentPrototype": { - "name": "currentPrototype", - "setSignature": { - "name": "currentPrototype", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "a", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 69, - "jsdoctags": [ - { - "name": "a", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "currentPrototype", - "type": "", - "returnType": "StackBase", - "line": 73 - } - }, - "Cluster": { - "name": "Cluster", - "getSignature": { - "name": "Cluster", - "type": "", - "returnType": "", - "line": 88 - } - }, - "Current": { - "name": "Current", - "getSignature": { - "name": "Current", - "type": "", - "returnType": "", - "line": 92 - } - } - }, - "type": "injectable" - }, - { - "name": "ApiEffects", - "id": "injectable-ApiEffects-9fc30922f74708781225b00333cce55b", - "file": "src/app/core/api/api.effects.ts", - "properties": [ - { - "name": "retry$", - "defaultValue": "createEffect(() =>\n this.actions$.pipe(\n ofType(rootError),\n delay(3000),\n switchMap(() =>\n this.api.get(environment.apiRoot).pipe(\n map(root => rootSuccess({ root })),\n catchError(() => of(rootError()))\n )\n )\n )\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 38 - }, - { - "name": "root$", - "defaultValue": "createEffect(() =>\n this.actions$.pipe(\n ofType(loadRoot),\n exhaustMap(() =>\n this.api.get(environment.apiRoot).pipe(\n map(root => rootSuccess({ root })),\n catchError(() => of(rootError()))\n )\n )\n )\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "stack$", - "defaultValue": "createEffect(() =>\n this.actions$.pipe(\n ofType(loadStack),\n withLatestFrom(this.store, (actions, store) => store.api),\n filter(api => api.root && !api.stack),\n exhaustMap(api => this.api.get(api.root.stack).pipe(map(stack => stackSuccess({ stack }))))\n )\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 51 - } - ], - "methods": [], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { IRoot } from '@app/core/types/api';\nimport { environment } from '@env/environment';\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\nimport { Store } from '@ngrx/store';\nimport { of } from 'rxjs';\nimport { catchError, delay, exhaustMap, filter, map, switchMap, withLatestFrom } from 'rxjs/operators';\n\nimport { State } from '../store';\nimport { loadRoot, loadStack, rootError, rootSuccess, stackSuccess } from './api.reducer';\nimport { ApiService } from './api.service';\n\n@Injectable()\nexport class ApiEffects {\n root$ = createEffect(() =>\n this.actions$.pipe(\n ofType(loadRoot),\n exhaustMap(() =>\n this.api.get(environment.apiRoot).pipe(\n map(root => rootSuccess({ root })),\n catchError(() => of(rootError()))\n )\n )\n )\n );\n\n retry$ = createEffect(() =>\n this.actions$.pipe(\n ofType(rootError),\n delay(3000),\n switchMap(() =>\n this.api.get(environment.apiRoot).pipe(\n map(root => rootSuccess({ root })),\n catchError(() => of(rootError()))\n )\n )\n )\n );\n\n stack$ = createEffect(() =>\n this.actions$.pipe(\n ofType(loadStack),\n withLatestFrom(this.store, (actions, store) => store.api),\n filter(api => api.root && !api.stack),\n exhaustMap(api => this.api.get(api.root.stack).pipe(map(stack => stackSuccess({ stack }))))\n )\n );\n\n constructor(private actions$: Actions, private api: ApiService, private store: Store) {}\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 58, - "jsdoctags": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "ApiService", - "id": "injectable-ApiService-c4a1dd344dfe5a2c435fa29e712883f6", - "file": "src/app/core/api/api.service.ts", - "properties": [], - "methods": [ - { - "name": "delete", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 75, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "get", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 40, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getList", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable>", - "typeParameters": [ - "T" - ], - "line": 44, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getOne", - "args": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [ - "T" - ], - "line": 36, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getPure", - "args": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "list", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type | null", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [ - "T" - ], - "line": 56, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type | null", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "patch", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "item", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "item", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "post", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "item", - "type": "Object | FormData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 63, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "item", - "type": "Object | FormData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "put", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "item", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 67, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "item", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { HttpClient } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { ParamMap } from '@angular/router';\nimport { IRoot, TypeName } from '@app/core/types/api';\nimport { ListResult } from '@app/models/list-result';\nimport { select, Store } from '@ngrx/store';\nimport { EMPTY, Observable } from 'rxjs';\nimport { catchError, filter, switchMap } from 'rxjs/operators';\n\nimport { State } from '../store';\nimport { getRoot } from './api.reducer';\n\n@Injectable()\nexport class ApiService {\n constructor(private http: HttpClient, private store: Store) {}\n\n get root(): Observable {\n return this.store.pipe(select(getRoot)).pipe(filter((root) => !!root));\n }\n\n getPure(typeName: TypeName, params: { [key: string]: string } = {}): Observable {\n return this.root.pipe(switchMap((root) => this.get(root[typeName], params))).pipe(catchError(() => EMPTY));\n }\n\n getOne(typeName: TypeName, id: number, params: { [key: string]: string } = {}) {\n return this.root.pipe(switchMap((root) => this.get(`${root[typeName]}${id}/`, params))).pipe(catchError(() => EMPTY));\n }\n\n get(url: string, params: { [key: string]: string } = {}): Observable {\n return this.http.get(url, { params });\n }\n\n getList(url: string, p: ParamMap): Observable> {\n const params = p?.keys.reduce((pr, c) => ({ ...pr, [c]: p.get(c) }), {});\n if (p) {\n const limit = p.get('limit') ? +p.get('limit') : +localStorage.getItem('limit'),\n offset = (p.get('page') ? +p.get('page') : 0) * limit;\n params['limit'] = limit.toString();\n params['offset'] = offset.toString();\n params['status'] = p.get('filter') || '';\n }\n return this.get>(url, params);\n }\n\n list(url: string, params: { limit: string; offset: string; ordering?: string } | null) {\n if (!params) {\n params = { limit: localStorage.getItem('limit'), offset: '0' };\n }\n return this.get>(url, params);\n }\n\n post(url: string, item: Object | FormData): Observable {\n return this.http.post(url, item);\n }\n\n put(url: string, item: any): Observable {\n return this.http.put(url, item).pipe(catchError(() => EMPTY));\n }\n\n patch(url: string, item: any): Observable {\n return this.http.patch(url, item).pipe(catchError(() => EMPTY));\n }\n\n delete(url: string) {\n return this.http.delete(url).pipe(catchError(() => EMPTY));\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 25, - "jsdoctags": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "root": { - "name": "root", - "getSignature": { - "name": "root", - "type": "", - "returnType": "Observable", - "line": 28 - } - } - }, - "type": "injectable" - }, - { - "name": "AppService", - "id": "injectable-AppService-b94c005ca6e31012de3308c5aad8b5c1", - "file": "src/app/core/services/app/app.service.ts", - "properties": [ - { - "name": "snackBar", - "deprecated": false, - "deprecationMessage": "", - "type": "MatSnackBar", - "optional": false, - "description": "", - "line": 32, - "modifierKind": [ - 122 - ] - } - ], - "methods": [ - { - "name": "checkUserProfile", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "checkWSconnectStatus", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 55, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getRootAndCheckAuth", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getVersion", - "args": [ - { - "name": "versionData", - "type": "IVersionInfo", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IVersionInfo", - "typeParameters": [], - "line": 76, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "versionData", - "type": "IVersionInfo", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "initListeners", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 80, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { MatDialog } from '@angular/material/dialog';\nimport { MatSnackBar } from '@angular/material/snack-bar';\nimport { NavigationStart, Router } from '@angular/router';\nimport { getConnectStatus, getFirstAdminLogin, getProfile, getRoot, isAuthenticated, loadProfile, loadRoot, loadStack, rootError, socketInit, State } from '@app/core/store';\nimport { select, Store } from '@ngrx/store';\nimport { combineLatest } from 'rxjs';\nimport { filter, switchMap, tap } from 'rxjs/operators';\n\nimport { ChannelService, keyChannelStrim } from '../channel.service';\nimport { ConfigService, IVersionInfo } from '../config.service';\n\n@Injectable()\nexport class AppService {\n constructor(\n private store: Store,\n private config: ConfigService,\n private router: Router,\n private dialog: MatDialog,\n private channel: ChannelService,\n public snackBar: MatSnackBar\n ) {}\n\n getRootAndCheckAuth() {\n this.store.dispatch(loadRoot());\n const b$ = this.store.pipe(select(getRoot));\n const a$ = this.store.pipe(select(isAuthenticated));\n return combineLatest([a$, b$]).pipe(\n filter((a) => a[0] && !!a[1]),\n switchMap((_) => this.config.load()),\n tap((c) => {\n if (!c) {\n this.channel.next(keyChannelStrim.notifying, 'New version available. Page has been refreshed.');\n setTimeout(() => location.reload(), 2000);\n } else {\n this.store.dispatch(socketInit());\n this.store.dispatch(loadStack());\n this.store.dispatch(loadProfile());\n }\n })\n );\n }\n\n checkWSconnectStatus() {\n return this.store.pipe(\n select(getConnectStatus),\n filter((a) => !!a),\n tap((status) => {\n if (status === 'open') this.channel.next(keyChannelStrim.notifying, 'Connection established.');\n if (status === 'close') {\n this.channel.next(keyChannelStrim.notifying, 'Connection lost. Recovery attempt.::error');\n this.store.dispatch(rootError());\n }\n })\n );\n }\n\n checkUserProfile() {\n return this.store.pipe(\n select(getProfile),\n filter((u) => u.settingsSaved)\n );\n }\n\n getVersion(versionData: IVersionInfo): IVersionInfo {\n return this.config.version.split('-').reduce((p, c, i) => ({ ...p, [Object.keys(versionData)[i]]: c }), {} as IVersionInfo);\n }\n\n initListeners() {\n // check user profile settings - this is the first entry\n this.store\n .pipe(\n select(getFirstAdminLogin),\n filter((u) => u)\n )\n .subscribe(() => this.router.navigate(['admin']));\n\n // close dialog\n this.router.events.pipe(filter((e) => e instanceof NavigationStart)).subscribe(() => this.dialog.closeAll());\n\n // notification\n this.channel.on(keyChannelStrim.notifying).subscribe((m) => {\n const astr = m.split('::');\n const data = astr[1]\n ? { panelClass: 'snack-bar-error' }\n : {\n duration: 5000,\n panelClass: 'snack-bar-notify',\n };\n this.snackBar.open(astr[0], 'Hide', data);\n });\n\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "config", - "type": "ConfigService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "snackBar", - "type": "MatSnackBar", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 25, - "jsdoctags": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "config", - "type": "ConfigService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "snackBar", - "type": "MatSnackBar", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "AttributeService", - "id": "injectable-AttributeService-651cfdba3f000923bbee8d3d05505de6", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "properties": [ - { - "name": "_activeAttributes", - "defaultValue": "[\n ConfigAttributeNames.GROUP_KEYS,\n ConfigAttributeNames.CUSTOM_GROUP_KEYS\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "Partial[]", - "optional": false, - "description": "", - "line": 50, - "modifierKind": [ - 120, - 142 - ] - }, - { - "name": "_attributes", - "deprecated": false, - "deprecationMessage": "", - "type": "Attributes", - "optional": false, - "description": "", - "line": 59, - "modifierKind": [ - 120 - ] - } - ], - "methods": [ - { - "name": "_createAttributes", - "args": [ - { - "name": "_activeAttributes", - "type": "Partial[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "configs", - "type": "AttributesOptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Attributes", - "typeParameters": [], - "line": 72, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ], - "jsdoctags": [ - { - "name": "_activeAttributes", - "type": "Partial[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "configs", - "type": "AttributesOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getByName", - "args": [ - { - "name": "name", - "type": "ConfigAttributeNames", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "ConfigAttribute", - "typeParameters": [], - "line": 68, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "ConfigAttributeNames", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "init", - "args": [ - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 64, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "rawAttributes", - "args": [], - "optional": false, - "returnType": "{}", - "typeParameters": [], - "line": 86, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Inject, Injectable, InjectionToken, TemplateRef, Type } from '@angular/core';\nimport { FormBuilder, FormGroup } from '@angular/forms';\nimport { IFieldOptions } from '@app/shared/configuration/types';\nimport { isBoolean, isEmptyObject } from '@app/core/types';\nimport { FieldComponent } from '@app/shared/configuration/field/field.component';\n\nexport const ATTRIBUTES_OPTIONS = new InjectionToken('Attributes options');\n\nexport interface AttributeOptions {\n name: ConfigAttributeNames;\n wrapper?: Type;\n options?: ConfigAttributeOptions;\n}\n\nexport type AttributesOptions = Record\n\nexport interface AttributeWrapper {\n fieldTemplate: TemplateRef;\n wrapperOptions: ConfigAttributeOptions;\n fieldOptions: IFieldOptions;\n attributeForm: FormGroup;\n parametersForm: FormGroup;\n field: FieldComponent;\n}\n\nexport enum ConfigAttributeNames {\n // an attribute for adding config parameters to group\n GROUP_KEYS = 'group_keys',\n // an attribute for config parameters that determines whether this parameter can be added to the config group\n CUSTOM_GROUP_KEYS = 'custom_group_keys'\n}\n\nexport interface ConfigAttributesJSON {\n [key: string]: any;\n}\n\nexport interface ConfigAttributeOptions {\n tooltipText?: string;\n\n [key: string]: any;\n}\n\nexport type ConfigAttribute = AttributeOptions & { value: ConfigAttributesJSON, form: FormGroup };\n\nexport type Attributes = Map;\n\n@Injectable()\nexport class AttributeService {\n\n private readonly _activeAttributes: Partial[] = [\n ConfigAttributeNames.GROUP_KEYS,\n ConfigAttributeNames.CUSTOM_GROUP_KEYS\n ];\n\n get attributes(): Attributes {\n return this._attributes;\n }\n\n private _attributes: Attributes;\n\n constructor(@Inject(ATTRIBUTES_OPTIONS) private _configs: AttributesOptions, private _fb: FormBuilder) {\n }\n\n init(json: ConfigAttributesJSON): void {\n this._attributes = this._createAttributes(this._activeAttributes, json, this._configs);\n }\n\n getByName(name: ConfigAttributeNames): ConfigAttribute {\n return this._attributes.has(name) ? this._attributes.get(name) : undefined;\n }\n\n private _createAttributes(_activeAttributes: Partial[], json: ConfigAttributesJSON, configs: AttributesOptions): Attributes {\n const isEmptyAttrs = !Object.keys(json || {}).length;\n const isActiveAttrsPresent = !!Object.keys(json || {}).filter((x: ConfigAttributeNames) => this._activeAttributes.includes(x)).length;\n if (isEmptyAttrs || !isActiveAttrsPresent) {\n return;\n }\n\n return new Map(this._activeAttributes.map((attr) => [\n attr,\n new ConfigAttributeFactory(this._fb).create(attr, json[attr], configs[attr], json),\n ]));\n }\n\n\n rawAttributes() {\n let json = {};\n if (this._attributes) {\n for (const [key, value] of this._attributes.entries()) {\n json = {\n ...json,\n [key]: value.form.value\n };\n }\n }\n\n return json;\n }\n}\n\nexport const createFormForAttribute = (fb: FormBuilder, json: ConfigAttributesJSON, attr: ConfigAttributeNames, disabled: boolean = false): FormGroup => {\n const buildFormGroup = (json: boolean | ConfigAttributesJSON) => {\n const data = Object.entries(json).map(([key, value]) => [key, value]).reduce((acc, [key, value]: [string, boolean | ConfigAttributesJSON]) => {\n\n if (isBoolean(value) || isEmptyObject(value)) {\n return {\n ...acc,\n [key]: { value, disabled }\n };\n } else if (!isEmptyObject(value)) {\n return { ...acc, [key]: buildFormGroup(value) };\n }\n\n }, {});\n\n return fb.group(data);\n };\n\n return buildFormGroup(json[attr]);\n};\n\n\nexport class ConfigAttributeFactory {\n\n constructor(private fb: FormBuilder) {}\n\n create(name: ConfigAttributeNames, value: ConfigAttributesJSON, options: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n if (!this[name]) {\n return;\n }\n\n return this[name](value, options, json);\n }\n\n [ConfigAttributeNames.GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options,\n wrapper\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return {\n name,\n value,\n wrapper,\n options,\n form\n };\n }\n\n [ConfigAttributeNames.CUSTOM_GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return { name, value, options, form };\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "_configs", - "type": "AttributesOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "_fb", - "type": "FormBuilder", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 59, - "jsdoctags": [ - { - "name": "_configs", - "type": "AttributesOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "_fb", - "type": "FormBuilder", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "attributes": { - "name": "attributes", - "getSignature": { - "name": "attributes", - "type": "", - "returnType": "Attributes", - "line": 55 - } - } - }, - "type": "injectable" - }, - { - "name": "AuthEffects", - "id": "injectable-AuthEffects-c93cd801beead75ee8f3180f3314d660", - "file": "src/app/core/auth/auth.store.ts", - "properties": [ - { - "name": "auth$", - "defaultValue": "createEffect(\n () =>\n this.actions$.pipe(\n ofType(authLogin),\n switchMap(a =>\n this.authService.login(a.login, a.password).pipe(\n map(() => authSuccess({ login: a.login })),\n catchError(() => of(authFaled({ message: 'Incorrect password or user.' })))\n )\n )\n ),\n { useEffectsErrorHandler: true }\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 66 - }, - { - "name": "check$", - "defaultValue": "createEffect(() =>\n this.actions$.pipe(\n ofType(authCheck),\n map(() =>\n this.authService.auth.token\n ? authSuccess({ login: this.authService.auth.login })\n : authFaled({ message: 'User is not authorized!' })\n )\n )\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 55 - }, - { - "name": "logout$", - "defaultValue": "createEffect(\n () =>\n this.actions$.pipe(\n ofType(authLogout),\n tap(() => this.authService.logout())\n ),\n { dispatch: false }\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 80 - } - ], - "methods": [], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\nimport { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props } from '@ngrx/store';\nimport { of } from 'rxjs';\nimport { catchError, map, switchMap, tap } from 'rxjs/operators';\n\nimport { AuthService } from './auth.service';\n\nexport const authCheck = createAction('[Auth] Check');\nexport const authLogin = createAction('[Auth] Login', props<{ login: string; password: string }>());\nexport const authSuccess = createAction('[Auth] LoginSuccess', props<{ login: string }>());\nexport const authFaled = createAction('[Auth] LoginFaled', props<{ message: string }>());\nexport const authLogout = createAction('[Auth] Logout');\n\nexport interface AuthState {\n isValid: boolean;\n message: string;\n}\n\nconst initialState: AuthState = {\n isValid: false,\n message: '',\n};\n\nconst reducer = createReducer(\n initialState,\n on(authSuccess, state => ({ isValid: true, message: 'Auth is success.' })),\n on(authFaled, (state, { message }) => ({ isValid: false, message })),\n on(authLogout, state => ({ isValid: false, message: '' }))\n);\n\nexport function authReducer(state: AuthState, action: Action) {\n return reducer(state, action);\n}\n\nexport const getAuthState = createFeatureSelector('auth');\nexport const isAuthenticated = createSelector(\n getAuthState,\n state => state.isValid\n);\n\n@Injectable()\nexport class AuthEffects {\n check$ = createEffect(() =>\n this.actions$.pipe(\n ofType(authCheck),\n map(() =>\n this.authService.auth.token\n ? authSuccess({ login: this.authService.auth.login })\n : authFaled({ message: 'User is not authorized!' })\n )\n )\n );\n\n auth$ = createEffect(\n () =>\n this.actions$.pipe(\n ofType(authLogin),\n switchMap(a =>\n this.authService.login(a.login, a.password).pipe(\n map(() => authSuccess({ login: a.login })),\n catchError(() => of(authFaled({ message: 'Incorrect password or user.' })))\n )\n )\n ),\n { useEffectsErrorHandler: true }\n );\n\n logout$ = createEffect(\n () =>\n this.actions$.pipe(\n ofType(authLogout),\n tap(() => this.authService.logout())\n ),\n { dispatch: false }\n );\n\n constructor(private actions$: Actions, private authService: AuthService) {}\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "authService", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 87, - "jsdoctags": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "authService", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "AuthService", - "id": "injectable-AuthService-1a73d8404c4a8783a33220a1f6cf89e8", - "file": "src/app/core/auth/auth.service.ts", - "properties": [ - { - "name": "redirectUrl", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 35, - "modifierKind": [ - 122 - ] - } - ], - "methods": [ - { - "name": "checkGoogle", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "login", - "args": [ - { - "name": "login", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "password", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 43, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "login", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "password", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "logout", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 58, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Observable } from 'rxjs';\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { Injectable } from '@angular/core';\nimport { environment } from '@env/environment';\nimport { throwError } from 'rxjs';\nimport { catchError, map, tap } from 'rxjs/operators';\n\nimport { ApiService } from '../api';\n\n@Injectable()\nexport class AuthService {\n public get token(): string {\n return this.auth.token;\n }\n\n public get auth() {\n const auth = localStorage.getItem('auth') || '';\n return auth ? JSON.parse(auth) : { login: '', token: '' };\n }\n\n public set auth(value: { login: string; token: string }) {\n localStorage.setItem('auth', JSON.stringify(value));\n }\n\n public redirectUrl: string;\n\n constructor(private api: ApiService) {}\n\n checkGoogle() {\n return this.api.get<{google_oauth: boolean}>(`${environment.apiRoot}info/`).pipe(map(a => a.google_oauth));\n }\n\n login(login: string, password: string): Observable<{ token: string }> {\n return this.api.post(`${environment.apiRoot}token/`, { username: login, password }).pipe(\n tap((response: { token: string }) => {\n let token = response && response.token;\n if (token) {\n this.auth = { login, token };\n }\n }),\n catchError(err => {\n this.auth = { login: '', token: '' };\n return throwError(err);\n })\n );\n }\n\n logout() {\n this.auth = { login: '', token: '' };\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 35, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "token": { - "name": "token", - "getSignature": { - "name": "token", - "type": "string", - "returnType": "string", - "line": 22 - } - }, - "auth": { - "name": "auth", - "setSignature": { - "name": "auth", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "value", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 31, - "jsdoctags": [ - { - "name": "value", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "auth", - "type": "", - "returnType": "", - "line": 26 - } - } - }, - "type": "injectable" - }, - { - "name": "BundleService", - "id": "injectable-BundleService-a15c3c1fbdf22d493fdb9dc9c1f1e710", - "file": "src/app/services/bundle.service.ts", - "properties": [], - "methods": [ - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { EntityService } from '../abstract/entity-service';\nimport { Bundle } from '../core/types';\nimport { ApiService } from '../core/api';\nimport { environment } from '@env/environment';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class BundleService extends EntityService {\n\n constructor(\n protected api: ApiService,\n ) {\n super(api);\n }\n\n get(\n id: number,\n params: { [key: string]: string } = {},\n ): Observable {\n return this.api.get(`${environment.apiRoot}stack/bundle/${id}/`, params);\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 12, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "EntityService", - "type": "injectable" - }, - { - "name": "ChannelService", - "id": "injectable-ChannelService-74d64d1aba32ec1d01c0f425b85ec663", - "file": "src/app/core/services/channel.service.ts", - "properties": [ - { - "name": "event", - "defaultValue": "new Subject>()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 31, - "modifierKind": [ - 120 - ] - } - ], - "methods": [ - { - "name": "next", - "args": [ - { - "name": "key", - "type": "TKey", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "T", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [ - "T" - ], - "line": 33, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "key", - "type": "TKey", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "T", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "on", - "args": [ - { - "name": "key", - "type": "TKey", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 37, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "key", - "type": "TKey", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\nimport { filter, map } from 'rxjs/operators';\n\nexport enum keyChannelStrim {\n 'scroll',\n 'notifying',\n 'load_complete'\n}\n\nexport interface IBroadcast {\n key: TKey;\n value: any;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ChannelService {\n private event = new Subject>();\n\n next(key: TKey, value: T) {\n this.event.next({ key, value });\n }\n\n on(key: TKey): Observable {\n return this.event.asObservable().pipe(\n filter((e) => e.key === key),\n map, T>((a) => a.value)\n );\n }\n}\n", - "type": "injectable" - }, - { - "name": "ClusterEntityService", - "id": "injectable-ClusterEntityService-1762ae86ddfb98493c8cae3cd01d63f8", - "file": "src/app/services/cluster-entity.service.ts", - "properties": [], - "methods": [ - { - "name": "entityStatusTreeToStatusTree", - "args": [ - { - "name": "input", - "type": "ClusterStatusTree", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "StatusTree[]", - "typeParameters": [], - "line": 33, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "input", - "type": "ClusterStatusTree", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 22, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - }, - { - "name": "getStatusTree", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { EntityService } from '@app/abstract/entity-service';\nimport { environment } from '@env/environment';\nimport { ApiService } from '@app/core/api';\nimport { ICluster } from '@app/models/cluster';\nimport { ClusterStatusTree, StatusTree } from '@app/models/status-tree';\nimport { HavingStatusTreeAbstractService } from '@app/abstract/having-status-tree.abstract.service';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ClusterEntityService extends EntityService implements HavingStatusTreeAbstractService {\n\n constructor(\n protected api: ApiService,\n ) {\n super(api);\n }\n\n get(\n id: number,\n params: { [key: string]: string } = {},\n ): Observable {\n return this.api.get(`${environment.apiRoot}cluster/${id}/`, params);\n }\n\n getStatusTree(id: number): Observable {\n return this.api.get(`${environment.apiRoot}cluster/${id}/status/`);\n }\n\n entityStatusTreeToStatusTree(input: ClusterStatusTree): StatusTree[] {\n let hostsStatus;\n let servicesStatus;\n\n const hosts = input.chilren.hosts.map((host) => {\n hostsStatus = host.status;\n\n return {\n subject: {\n id: host.id,\n status: host.status,\n name: host.name,\n link: (id) => ['/cluster', input.id.toString(), 'host', id.toString(), 'status'],\n },\n children: [],\n };\n });\n\n const services = input.chilren.services.map((service) => {\n servicesStatus = service.status;\n\n return {\n subject: {\n id: service.id,\n status: service.status,\n name: service.name,\n },\n children: service.hc.map(component => ({\n subject: {\n id: component.id,\n name: component.name,\n status: component.status,\n },\n children: component.hosts.map(host => ({\n subject: {\n id: host.id,\n status: host.status,\n name: host.name,\n link: (id) => ['/cluster', input.id.toString(), 'host', id.toString(), 'status'],\n },\n children: [],\n })),\n })),\n };\n });\n\n return [{\n subject: {\n id: input.id,\n status: input.status,\n name: input.name,\n },\n children: [\n {\n subject: {\n name: 'Hosts',\n status: hostsStatus\n },\n children: hosts,\n },\n {\n subject: {\n name: 'Services',\n status: servicesStatus\n },\n children: services,\n }\n ],\n }];\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 14, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "EntityService", - "type": "injectable" - }, - { - "name": "ClusterService", - "id": "injectable-ClusterService-15046e581cc73dfa1357124a078aabc3", - "file": "src/app/core/services/cluster.service.ts", - "properties": [ - { - "name": "worker", - "deprecated": false, - "deprecationMessage": "", - "type": "WorkerInstance | null", - "optional": false, - "description": "", - "line": 48, - "modifierKind": [ - 120 - ] - }, - { - "name": "worker$", - "defaultValue": "this.workerSubject.asObservable()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 50, - "modifierKind": [ - 122 - ] - }, - { - "name": "workerSubject", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 49, - "modifierKind": [ - 120 - ] - } - ], - "methods": [ - { - "name": "addHost", - "args": [ - { - "name": "host_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 163, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "host_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "addServices", - "args": [ - { - "name": "output", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 155, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "output", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "bindImport", - "args": [ - { - "name": "bind", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 210, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "bind", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clearWorker", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 72, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getActions", - "args": [], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 142, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getBundleLicenseText", - "args": [], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 195, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getContext", - "args": [ - { - "name": "param", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "EntityService", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 108, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "param", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "EntityService", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getHosts", - "args": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 159, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getImportData", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 206, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nImport / Export data for `Cluster`\n", - "description": "

Import / Export data for Cluster

\n" - }, - { - "name": "getLog", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 138, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getMainInfo", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 180, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getOperationTimeData", - "args": [ - { - "name": "job", - "type": "Job", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "{ start: any; end: any; time: string; }", - "typeParameters": [], - "line": 217, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nFor `Job` and `Task` operating time data\n", - "description": "

For Job and Task operating time data

\n", - "jsdoctags": [ - { - "name": "job", - "type": "Job", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getServices", - "args": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 146, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "one_bundle", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 104, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "one_cluster", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 76, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "one_host", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "one_job", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 92, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "one_provider", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 88, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "one_service", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 80, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "reset", - "args": [], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 167, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { ParamMap } from '@angular/router';\nimport { ApiService } from '@app/core/api';\nimport { BehaviorSubject, EMPTY, forkJoin, Observable, of, throwError } from 'rxjs';\nimport { catchError, filter, map, switchMap, tap } from 'rxjs/operators';\nimport { Store } from '@ngrx/store';\n\nimport {\n Bundle,\n Entities,\n Host,\n IAction,\n IImport,\n Job,\n License,\n LogFile,\n Provider,\n Service\n} from '@app/core/types';\nimport { environment } from '@env/environment';\nimport { ServiceComponentService } from '@app/services/service-component.service';\nimport { EntityNames } from '@app/models/entity-names';\nimport { HttpResponseBase } from '@angular/common/http';\nimport { setPathOfRoute } from '@app/store/navigation/navigation.store';\nimport { EntityService } from '@app/abstract/entity-service';\nimport { ICluster } from '@app/models/cluster';\n\nexport interface WorkerInstance {\n current: Entities;\n cluster: ICluster | null;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ClusterService {\n private worker: WorkerInstance | null;\n private workerSubject = new BehaviorSubject(null);\n public worker$ = this.workerSubject.asObservable();\n\n get Cluster() {\n return this.worker ? this.worker.cluster : null;\n }\n\n set Cluster(cluster: ICluster) {\n if (cluster) cluster.typeName = 'cluster';\n if (this.worker) this.worker.cluster = cluster;\n else this.worker = { current: cluster, cluster: cluster };\n }\n\n get Current(): Entities {\n return this.worker ? this.worker.current : null;\n }\n\n constructor(\n protected api: ApiService,\n protected serviceComponentService: ServiceComponentService,\n protected store: Store,\n ) {}\n\n clearWorker() {\n this.worker = null;\n }\n\n one_cluster(id: number): Observable {\n return this.Cluster ? of(this.Cluster) : this.api.getOne('cluster', id);\n }\n\n one_service(id: number): Observable {\n return this.api.get(`${this.worker.cluster.service}${id}/`);\n }\n\n one_host(id: number): Observable {\n return this.api.getOne('host', id).pipe(map((host: Host) => ({ ...host, name: host.fqdn })));\n }\n\n one_provider(id: number): Observable {\n return this.api.getOne('provider', id);\n }\n\n one_job(id: number): Observable {\n return this.api.getOne('job', id).pipe(\n map((j: Job) => ({\n ...j,\n prototype_name: j.action ? j.action.prototype_name : '',\n prototype_version: j.action ? j.action.prototype_version : '',\n bundle_id: j.action ? j.action.bundle_id : null,\n name: j.action ? `${j.action.display_name}` : 'Object has been deleted',\n }))\n );\n }\n\n one_bundle(id: number): Observable {\n return this.api.get(`${environment.apiRoot}stack/bundle/${id}/`);\n }\n\n getContext(param: ParamMap, service?: EntityService): Observable {\n this.store.dispatch(setPathOfRoute({ params: param }));\n\n const typeName = EntityNames.find((a) => param.keys.some((b) => a === b));\n const id = +param.get(typeName);\n const cluster$ = param.has('cluster') ? this.api.getOne('cluster', +param.get('cluster')) : of(null);\n return cluster$\n .pipe(\n tap((cluster) => (this.Cluster = cluster)),\n switchMap((cluster) => {\n if (typeName === 'group_config') {\n return service.get(id);\n } else if (cluster && (typeName === 'servicecomponent' || typeName === 'component')) {\n return this.serviceComponentService.get(id);\n } else if (cluster && typeName !== 'cluster') {\n return this.api.get(`${cluster[typeName]}${id}/`);\n } else {\n return this[`one_${typeName}`](id);\n }\n }),\n )\n .pipe(\n map((a: any) => {\n this.worker.current = { ...a, name: (a?.display_name || a?.name || (a as Host)?.fqdn) ?? '', typeName };\n this.workerSubject.next(this.worker);\n return this.worker;\n })\n );\n }\n\n getLog(url: string): Observable {\n return this.api.get(url);\n }\n\n getActions(): Observable {\n return typeof this.worker.current.action === 'string' ? this.api.get(this.worker.current.action) : of([]);\n }\n\n getServices(p: ParamMap) {\n return this.api.getList(this.Cluster.service, p).pipe(\n map((r) => {\n r.results = r.results.map((a) => ({ ...a, cluster: this.Cluster }));\n return r;\n })\n );\n }\n\n addServices(output: { prototype_id: number }[]) {\n return forkJoin(output.map((o) => this.api.post(this.Cluster.service, o)));\n }\n\n getHosts(p: ParamMap) {\n return this.api.getList(this.Cluster.host, p);\n }\n\n addHost(host_id: number) {\n return this.api.post(this.Cluster.host, { host_id });\n }\n\n reset(): Observable {\n if (!this.Current) return EMPTY;\n const typeName = this.Current.typeName;\n return this.api.get(this.Current.url).pipe(\n filter((_) => !!this.worker),\n map((a) => {\n if (typeName === 'cluster') this.worker.cluster = { ...(a as ICluster), typeName };\n this.worker.current = { ...a, typeName, name: a.display_name || a.name || (a as Host).fqdn };\n return this.worker;\n })\n );\n }\n\n getMainInfo() {\n return this.api.get(`${this.Current.config}current/`).pipe(\n map((a: any) => a.config.find((b: { name: string }) => b.name === '__main_info')),\n filter((a) => a),\n map((a) => a.value),\n catchError((e: HttpResponseBase) => {\n if (e.status === 404) {\n return of('Nothing to display');\n } else {\n return throwError(e);\n }\n }),\n );\n }\n\n getBundleLicenseText(): Observable {\n const { license_url, license } = (this.Current as Bundle);\n\n return this.api.get(license_url).pipe(\n map(({ text }) => license !== 'absent' ? text : 'No license required'),\n );\n }\n\n /**\n * Import / Export data for `Cluster`\n */\n getImportData() {\n return 'imports' in this.Current ? this.api.get(this.Current.imports) : EMPTY;\n }\n\n bindImport(bind: any) {\n return 'imports' in this.Current ? this.api.post(this.Current.imports, bind) : EMPTY;\n }\n\n /**\n * For `Job` and `Task` operating time data\n */\n getOperationTimeData(job: Job) {\n const { start_date, finish_date, status } = job;\n const sdn = Date.parse(start_date),\n fdn = Date.parse(finish_date),\n ttm = fdn - sdn,\n sec = Math.floor(ttm / 1000),\n min = Math.floor(sec / 60),\n time = status !== 'running' ? `${min}m. ${sec - min * 60}s.` : '';\n const a = new Date(sdn);\n const b = new Date(fdn);\n return { start: a.toLocaleTimeString(), end: status !== 'running' ? b.toLocaleTimeString() : '', time };\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "serviceComponentService", - "type": "ServiceComponentService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 64, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "serviceComponentService", - "type": "ServiceComponentService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "Cluster": { - "name": "Cluster", - "setSignature": { - "name": "Cluster", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "cluster", - "type": "ICluster", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 56, - "jsdoctags": [ - { - "name": "cluster", - "type": "ICluster", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "Cluster", - "type": "", - "returnType": "", - "line": 52 - } - }, - "Current": { - "name": "Current", - "getSignature": { - "name": "Current", - "type": "", - "returnType": "Entities", - "line": 62 - } - } - }, - "type": "injectable" - }, - { - "name": "ComponentData", - "id": "injectable-ComponentData-0aa6c34b3edfef5dfe8a28653d0685f0", - "file": "src/app/shared/components/tooltip/tooltip.service.ts", - "properties": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "emitter", - "deprecated": false, - "deprecationMessage": "", - "type": "EventEmitter", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "path", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 33 - } - ], - "methods": [], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { EventEmitter, Injectable } from '@angular/core';\nimport { BaseEntity } from '@app/core/types/api';\nimport { Subject } from 'rxjs';\n\nexport type ComponentName = 'issue' | 'status' | undefined;\nexport type PositionType = 'top' | 'right' | 'bottom' | 'left';\nexport interface TooltipOptions {\n event: MouseEvent;\n source: HTMLElement;\n options: TooltipDisplayOptions;\n}\n\nexport interface TooltipDisplayOptions {\n content: string | BaseEntity;\n componentName: ComponentName;\n position: PositionType;\n condition: boolean;\n}\n\n@Injectable()\nexport class ComponentData {\n path: string;\n current: any;\n emitter: EventEmitter;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class TooltipService {\n private positionSource = new Subject();\n position$ = this.positionSource.asObservable();\n timeOut: any;\n\n /**\n * TODO: show a tooltip if there is a condition\n *\n * @returns\n * @memberof TooltipComponent\n */\n isShow(source: HTMLElement, options: TooltipDisplayOptions) {\n if (options.condition) {\n return source.offsetWidth !== source.scrollWidth;\n }\n return true;\n }\n\n show(event: MouseEvent, source: HTMLElement, options: TooltipDisplayOptions) {\n this.positionSource.next();\n clearTimeout(this.timeOut);\n if (this.isShow(source, options)) {\n this.positionSource.next({ event, source, options });\n }\n }\n\n hide(withoutTimout = false, timeout = 500) {\n if (withoutTimout) {\n this.positionSource.next();\n return;\n }\n\n this.timeOut = setTimeout(() => this.positionSource.next(), timeout);\n }\n\n mouseEnterTooltip() {\n clearTimeout(this.timeOut);\n }\n\n mouseLeaveTooltip() {\n this.hide();\n }\n}\n", - "type": "injectable" - }, - { - "name": "ConcernService", - "id": "injectable-ConcernService-742d732e4654358d603998bf0d04fa22", - "file": "src/app/services/concern.service.ts", - "properties": [], - "methods": [ - { - "name": "events", - "args": [ - { - "name": "eventFilter", - "type": "ConcernEventFilter", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "eventFilter", - "type": "ConcernEventFilter", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "parse", - "args": [ - { - "name": "issueMessage", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string[]", - "typeParameters": [], - "line": 16, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "issueMessage", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Store } from '@ngrx/store';\nimport { Observable } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\nimport { ConcernEventFilter, EventableService } from '@app/models/eventable-service';\nimport { EventMessage, selectMessage, SocketState } from '@app/core/store';\n\n@Injectable()\nexport class ConcernService implements EventableService {\n\n constructor(\n private store: Store,\n ) { }\n\n parse(issueMessage: string): string[] {\n let result = [];\n for (const item of issueMessage.matchAll(/(.*?)(\\$\\{.+?\\})|(.+$)/g)) {\n if (item.length) {\n result = [ ...result, ...item.slice(1, item.length) ];\n }\n }\n\n return result.filter(item => !!item);\n }\n\n events(eventFilter?: ConcernEventFilter): Observable {\n return this.store.pipe(\n selectMessage,\n filter(event => !!event),\n filter(event => !eventFilter?.events || eventFilter.events.includes(event.event)),\n filter(event => !eventFilter?.types || eventFilter.types.includes(event.object?.type as any)),\n );\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 10, - "jsdoctags": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "ConfigGroupAddService", - "id": "injectable-ConfigGroupAddService-6163991ecb0b5e96a90755db1ba74393", - "file": "src/app/config-groups/service/config-group-add.service.ts", - "properties": [], - "methods": [ - { - "name": "add", - "args": [ - { - "name": "group", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "group", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "model", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "FormModel", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { FormModel, IAddService } from '@app/shared/add-component/add-service-model';\nimport { FormControl, FormGroup, Validators } from '@angular/forms';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { Observable } from 'rxjs';\nimport { ApiService } from '@app/core/api';\nimport { ConfigGroup } from '../model';\nimport { environment } from '@env/environment';\n\nconst newConfigGroupForm = (): FormGroup =>\n new FormGroup({\n name: new FormControl('', [Validators.required, Validators.maxLength(30)]),\n description: new FormControl(),\n });\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigGroupAddService implements IAddService {\n\n get Cluster() {\n return this.service.Cluster;\n }\n\n get Current() {\n return this.service.Current;\n }\n\n constructor(private service: ClusterService, protected api: ApiService) {}\n\n model(name?: string): FormModel {\n return {\n name: 'group_config',\n title: 'Config group',\n form: newConfigGroupForm()\n };\n }\n\n add(group: Partial): Observable {\n const params = { ...group };\n params.object_type = this.service.Current.typeName === 'servicecomponent' ? 'component' : this.service.Current.typeName;\n params.object_id = this.service.Current.id;\n return this.api.post(`${environment.apiRoot}group-config/`, params);\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 27, - "jsdoctags": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "Cluster": { - "name": "Cluster", - "getSignature": { - "name": "Cluster", - "type": "", - "returnType": "", - "line": 21 - } - }, - "Current": { - "name": "Current", - "getSignature": { - "name": "Current", - "type": "", - "returnType": "", - "line": 25 - } - } - }, - "type": "injectable" - }, - { - "name": "ConfigGroupHostAddService", - "id": "injectable-ConfigGroupHostAddService-588e650f4bcd0cf38165a01eee86feed", - "file": "src/app/config-groups/service/config-group-host-add.service.ts", - "properties": [], - "methods": [ - { - "name": "add", - "args": [ - { - "name": "data", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 42, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getListResults", - "args": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable>", - "typeParameters": [ - "T" - ], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "model", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "FormModel", - "typeParameters": [], - "line": 34, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { FormModel, IAddService } from '@app/shared/add-component/add-service-model';\nimport { FormControl, FormGroup, Validators } from '@angular/forms';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { TypeName } from '@app/core/types';\nimport { convertToParamMap, Params } from '@angular/router';\nimport { forkJoin, Observable } from 'rxjs';\nimport { ApiService } from '@app/core/api';\nimport { environment } from '@env/environment';\nimport { ConfigGroup } from '@app/config-groups';\nimport { ListResult } from '@app/models/list-result';\n\nconst newConfigGroupHostForm = () =>\n new FormGroup({\n name: new FormControl('', Validators.required),\n description: new FormControl(),\n });\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigGroupHostAddService implements IAddService {\n\n get Cluster() {\n return this.service.Cluster;\n }\n\n get Current() {\n return this.service.Current;\n }\n\n constructor(private service: ClusterService, protected api: ApiService) {}\n\n model(name?: string): FormModel {\n return {\n name: 'host2configgroup',\n title: 'Config group hosts',\n form: newConfigGroupHostForm()\n };\n }\n\n add(data: { host: number, group: number }[]): Observable {\n return forkJoin(data.map((o) => this.api.post(`${environment.apiRoot}group-config/${o.group}/host/`, { id: o.host })));\n }\n\n getListResults(type: TypeName, param: Params = {}): Observable> {\n const paramMap = convertToParamMap(param);\n const current = this.Current as unknown as ConfigGroup;\n\n return this.api.getList(current.host_candidate, paramMap);\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 30, - "jsdoctags": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "Cluster": { - "name": "Cluster", - "getSignature": { - "name": "Cluster", - "type": "", - "returnType": "", - "line": 24 - } - }, - "Current": { - "name": "Current", - "getSignature": { - "name": "Current", - "type": "", - "returnType": "", - "line": 28 - } - } - }, - "type": "injectable" - }, - { - "name": "ConfigGroupHostListService", - "id": "injectable-ConfigGroupHostListService-01265bf1ce5dda49ff701abdaa93cc95", - "file": "src/app/config-groups/service/config-group-host-list.service.ts", - "properties": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "ListInstance", - "optional": false, - "description": "", - "line": 17 - } - ], - "methods": [ - { - "name": "delete", - "args": [ - { - "name": "row", - "type": "Host", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "Host", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getList", - "args": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable>", - "typeParameters": [], - "line": 26, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "initInstance", - "args": [], - "optional": false, - "returnType": "ListInstance", - "typeParameters": [], - "line": 44, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { ApiService } from '@app/core/api';\nimport { ParamMap } from '@angular/router';\nimport { IListService, ListInstance } from '@app/shared/components/list/list-service-token';\nimport { ListResult } from '@app/models/list-result';\nimport { ApiFlat, Host } from '@app/core/types';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { environment } from '@env/environment';\n\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigGroupHostListService implements IListService {\n\n current: ListInstance;\n\n constructor(\n protected api: ApiService,\n protected cluster: ClusterService\n ) {\n }\n\n\n getList(p: ParamMap): Observable> {\n const current = this.cluster.Current as unknown as ApiFlat;\n\n const listParamStr = localStorage.getItem('list:param');\n if (p?.keys.length) {\n const param = p.keys.reduce((a, c) => ({ ...a, [c]: p.get(c) }), {});\n if (listParamStr) {\n const json = JSON.parse(listParamStr);\n json[`group_config_host_${current.object_type}`] = param;\n localStorage.setItem('list:param', JSON.stringify(json));\n } else localStorage.setItem('list:param', JSON.stringify({ [`group_config_host_${current.object_type}`]: param }));\n }\n\n const configGroupId = this.cluster.Current.id;\n\n return this.api.getList(`${environment.apiRoot}group-config/${configGroupId}/host/`, p);\n }\n\n initInstance(): ListInstance {\n this.current = { typeName: 'group_config_hosts', columns: ['name', 'remove'] };\n return this.current;\n }\n\n delete(row: Host): Observable {\n return this.api.delete(row.url);\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 17, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "ConfigGroupListService", - "id": "injectable-ConfigGroupListService-c4c94ea035d031b77561543aa237c3c8", - "file": "src/app/config-groups/service/config-group-list.service.ts", - "properties": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "ListInstance", - "optional": false, - "description": "", - "line": 23 - } - ], - "methods": [ - { - "name": "delete", - "args": [ - { - "name": "row", - "type": "ConfigGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "ConfigGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 53, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - }, - { - "name": "getList", - "args": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable>", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "initInstance", - "args": [], - "optional": false, - "returnType": "ListInstance", - "typeParameters": [], - "line": 48, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable, InjectionToken } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { ParamMap } from '@angular/router';\n\nimport { EntityService } from '@app/abstract/entity-service';\nimport { ApiService } from '@app/core/api';\nimport { environment } from '@env/environment';\nimport { ConfigGroup } from '@app/config-groups/model/config-group.model';\nimport { IListService, ListInstance } from '@app/shared/components/list/list-service-token';\nimport { ListResult } from '@app/models/list-result';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { Service } from '@app/core/types';\nimport { ICluster } from '@app/models/cluster';\n\nexport const CONFIG_GROUP_LIST_SERVICE = new InjectionToken>('EntityService');\n\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigGroupListService extends EntityService implements IListService {\n\n current: ListInstance;\n\n constructor(\n protected api: ApiService,\n private cluster: ClusterService\n ) {\n super(api);\n }\n\n getList(p: ParamMap): Observable> {\n const current = this.cluster.Current as ICluster | Service;\n\n const listParamStr = localStorage.getItem('list:param');\n if (p?.keys.length) {\n const param = p.keys.reduce((a, c) => ({ ...a, [c]: p.get(c) }), {});\n if (listParamStr) {\n const json = JSON.parse(listParamStr);\n json[`group_config_${current.typeName}`] = param;\n localStorage.setItem('list:param', JSON.stringify(json));\n } else localStorage.setItem('list:param', JSON.stringify({ [`group_config_${current.typeName}`]: param }));\n }\n\n return this.api.getList(current.group_config, p);\n }\n\n initInstance(): ListInstance {\n this.current = { typeName: 'group_config', columns: ['name', 'description', 'remove'] };\n return this.current;\n }\n\n get(\n id: number,\n params: { [key: string]: string } = {},\n ): Observable {\n return this.api.get(`${environment.apiRoot}group-config/${id}/`, params);\n }\n\n delete(row: ConfigGroup): Observable {\n return this.api.delete(row.url);\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 23, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "EntityService", - "type": "injectable" - }, - { - "name": "ConfigGroupService", - "id": "injectable-ConfigGroupService-dd1cba81c2063ee3f25be0cdd10f9061", - "file": "src/app/config-groups/service/config-group.service.ts", - "properties": [], - "methods": [ - { - "name": "changeVersion", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 21, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getConfig", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getHistoryList", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "currentVersionId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "currentVersionId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "send", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport {\n IConfigListResponse,\n IConfigResponse,\n IConfigService\n} from '@app/shared/configuration/services/config.service';\nimport { ApiService } from '@app/core/api';\nimport { CompareConfig, IConfig } from '@app/shared/configuration/types';\nimport { map, switchMap } from 'rxjs/operators';\nimport { getRandomColor } from '@app/core/types';\nimport { environment } from '@env/environment';\n\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigGroupService implements IConfigService {\n constructor(private api: ApiService) { }\n\n changeVersion(id: number): Observable {\n return this.api.get(`${environment.apiRoot}config-log/${id}`);\n }\n\n getConfig(url: string): Observable {\n return this.api.get(url).pipe(\n switchMap((config) => this.api.get(config.current))\n );\n }\n\n getHistoryList(url: string, currentVersionId: number): Observable {\n return this.api.get(url).pipe(\n switchMap((config) => this.api.get(config.history)),\n map((value) => value.results),\n map((h) => h.filter((a) => a.id !== currentVersionId).map((b) => ({\n ...b,\n color: getRandomColor()\n }))));\n }\n\n send(url: string, data: any): Observable {\n return this.api.get(url).pipe(\n switchMap((config) => this.api.post(config.history, data)),\n );\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 18, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "ConfigService", - "id": "injectable-ConfigService-7ae880838369c63d70d654bd977c19c3", - "file": "src/app/core/services/config.service.ts", - "properties": [ - { - "name": "appConfig$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 27 - } - ], - "methods": [ - { - "name": "checkVersion", - "args": [ - { - "name": "c", - "type": "IVersionInfo", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IVersionInfo", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "c", - "type": "IVersionInfo", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "load", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { HttpClient } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nconst CONFIG_URL = '/assets/config.json';\nexport interface IVersionInfo {\n version: string;\n commit_id: string;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ConfigService {\n appConfig$: Observable;\n\n constructor(private http: HttpClient) {}\n\n get version() {\n return localStorage.getItem('adcm:version') || '';\n }\n\n set version(version: string) {\n localStorage.setItem('adcm:version', version);\n }\n\n checkVersion(c: IVersionInfo): IVersionInfo {\n const version = `${c.version}-${c.commit_id}`;\n if (!this.version) this.version = version;\n else if (this.version !== version) {\n this.version = version;\n return null;\n }\n return c;\n }\n\n load() {\n return this.http.get(`${CONFIG_URL}?nocache=${Date.now()}`).pipe(map((c) => this.checkVersion(c)));\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 27, - "jsdoctags": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "version": { - "name": "version", - "setSignature": { - "name": "version", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "version", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 35, - "jsdoctags": [ - { - "name": "version", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "version", - "type": "", - "returnType": "", - "line": 31 - } - } - }, - "type": "injectable" - }, - { - "name": "ConfigService", - "id": "injectable-ConfigService-22030f6a941975f09576eee3ff38c576-1", - "file": "src/app/shared/configuration/services/config.service.ts", - "properties": [], - "methods": [ - { - "name": "changeVersion", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 38, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getConfig", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 42, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getHistoryList", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "currentVersionId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "currentVersionId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "send", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 57, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { CompareConfig, IConfig } from '../types';\nimport { map, switchMap } from 'rxjs/operators';\nimport { getRandomColor } from '@app/core/types';\nimport { ApiService } from '@app/core/api';\n\nexport interface IConfigResponse {\n current: string;\n history: string;\n previous: string;\n}\n\nexport interface IConfigListResponse {\n count: 1;\n next: null;\n previous: null;\n results: IConfig[];\n}\n\n\nexport interface IConfigService {\n getConfig(url: string): Observable;\n\n getHistoryList(url: string, currentVersionId: number): Observable;\n\n send(url: string, data: any): Observable;\n\n changeVersion(id: number, url?: string): Observable;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ConfigService implements IConfigService {\n constructor(private api: ApiService) { }\n\n changeVersion(id: number, url: string): Observable {\n return this.api.get(`${url}history/${id}/`);\n }\n\n getConfig(url: string): Observable {\n return this.api.get(`${url}current/`);\n }\n\n getHistoryList(url: string, currentVersionId: number): Observable {\n return this.api.get(url).pipe(\n switchMap((config) => this.api.get(config.history)),\n // ToDo remove it when API will be consistent\n map((value) => Array.isArray(value) ? value as IConfig[] : value.results),\n map((h) => h.filter((a) => a.id !== currentVersionId).map((b) => ({\n ...b,\n color: getRandomColor()\n }))));\n }\n\n send(url: string, data: any): Observable {\n return this.api.post(`${url}history/`, data);\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 35, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable", - "isDuplicate": true, - "duplicateId": 1, - "duplicateName": "ConfigService-1" - }, - { - "name": "DomService", - "id": "injectable-DomService-4c918521cd94dab3a5b9086cadd56624", - "file": "src/app/core/services/dom.service.ts", - "properties": [], - "methods": [ - { - "name": "appendComponentToBody", - "args": [ - { - "name": "component", - "type": "Type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [ - "T" - ], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "component", - "type": "Type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { ApplicationRef, ComponentFactoryResolver, EmbeddedViewRef, Injectable, Injector, Type } from '@angular/core';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class DomService {\n constructor(\n private componentFactoryResolver: ComponentFactoryResolver,\n private appRef: ApplicationRef,\n private injector: Injector\n ) {}\n\n appendComponentToBody(component: Type) {\n const componentRef = this.componentFactoryResolver.resolveComponentFactory(component).create(this.injector);\n\n this.appRef.attachView(componentRef.hostView);\n\n const domElem = (componentRef.hostView as EmbeddedViewRef).rootNodes[0] as HTMLElement;\n\n document.body.appendChild(domElem);\n\n /** TODO: remove component, need to add variable where keep links to componentRef */\n // this.appRef.detachView(componentRef.hostView);\n // componentRef.destroy();\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "appRef", - "type": "ApplicationRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 18, - "jsdoctags": [ - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "appRef", - "type": "ApplicationRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "FieldService", - "id": "injectable-FieldService-d78cb6aa832432b3e07848b2b3bbd66d", - "file": "src/app/shared/configuration/services/field.service.ts", - "properties": [ - { - "name": "attributesService", - "deprecated": false, - "deprecationMessage": "", - "type": "AttributeService | undefined", - "optional": false, - "description": "", - "line": 155 - }, - { - "name": "fb", - "deprecated": false, - "deprecationMessage": "", - "type": "FormBuilder", - "optional": false, - "description": "", - "line": 157, - "modifierKind": [ - 122 - ] - } - ], - "methods": [ - { - "name": "checkValue", - "args": [ - { - "name": "value", - "type": "resultTypes", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "type", - "type": "TNForm", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "resultTypes", - "typeParameters": [], - "line": 319, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "resultTypes", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "type", - "type": "TNForm", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "fillForm", - "args": [ - { - "name": "field", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "controls", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "{}", - "typeParameters": [], - "line": 210, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ], - "jsdoctags": [ - { - "name": "field", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "controls", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "filterApply", - "args": [ - { - "name": "options", - "type": "TFormOptions[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "c", - "type": "ISearchParam", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "TFormOptions[]", - "typeParameters": [], - "line": 265, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nFilter by group and all fields\n", - "description": "

Filter by group and all fields

\n", - "modifierKind": [ - 122 - ], - "jsdoctags": [ - { - "name": "options", - "type": "TFormOptions[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "c", - "type": "ISearchParam", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getPanels", - "args": [ - { - "name": "data", - "type": "IConfig", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "TFormOptions[]", - "typeParameters": [], - "line": 162, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nParse and prepare source data from backend\n", - "description": "

Parse and prepare source data from backend

\n", - "modifierKind": [ - 122 - ], - "jsdoctags": [ - { - "name": "data", - "type": "IConfig", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "parseValue", - "args": [ - { - "name": "output", - "type": "IOutput", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "source", - "type": "ISource[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IOutput", - "typeParameters": [], - "line": 272, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nOutput form, cast to source type\n", - "description": "

Output form, cast to source type

\n", - "modifierKind": [ - 122 - ], - "jsdoctags": [ - { - "name": "output", - "type": "IOutput", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "source", - "type": "ISource[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "runByTree", - "args": [ - { - "name": "field", - "type": "TFormOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "controls", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "literal type", - "typeParameters": [], - "line": 195, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ], - "jsdoctags": [ - { - "name": "field", - "type": "TFormOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "controls", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "runYspec", - "args": [ - { - "name": "value", - "type": "resultTypes", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "rules", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 301, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ], - "jsdoctags": [ - { - "name": "value", - "type": "resultTypes", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "rules", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "setValidator", - "args": [ - { - "name": "field", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "controlToCompare", - "type": "AbstractControl", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "{}", - "typeParameters": [], - "line": 221, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nExternal use (scheme.service) to set validator for FormControl by type\n", - "description": "

External use (scheme.service) to set validator for FormControl by type

\n", - "modifierKind": [ - 122 - ], - "jsdoctags": [ - { - "name": { - "pos": 7171, - "end": 7176, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "field" - }, - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "pos": 7165, - "end": 7170, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "

Partial{ ValidatorInfo, controlType }

\n" - }, - { - "name": { - "pos": 7241, - "end": 7257, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "controlToCompare" - }, - "type": "AbstractControl", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "pos": 7235, - "end": 7240, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "" - } - ] - }, - { - "name": "toFormGroup", - "args": [ - { - "name": "options", - "type": "TFormOptions[]", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "[]" - } - ], - "optional": false, - "returnType": "FormGroup", - "typeParameters": [], - "line": 176, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nGenerate FormGroup\n", - "description": "

Generate FormGroup

\n", - "modifierKind": [ - 122 - ], - "jsdoctags": [ - { - "name": { - "pos": 5695, - "end": 5702, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "options" - }, - "type": "TFormOptions[]", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "[]", - "tagName": { - "pos": 5689, - "end": 5694, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "" - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms';\nimport { isEmptyObject } from '@app/core/types';\n\nimport { ISearchParam } from '../main/main.service';\nimport {\n controlType,\n IConfig,\n IConfigAttr,\n IFieldOptions,\n IFieldStack,\n ILimits,\n IPanelOptions,\n IValidator,\n resultTypes,\n TNBase,\n TNForm\n} from '../types';\nimport { AttributeService } from '@app/shared/configuration/attributes/attribute.service';\n\nexport type TFormOptions = IFieldOptions | IPanelOptions;\n\nexport interface IOutput {\n [key: string]: resultTypes;\n}\n\nexport interface ISource {\n name: string;\n subname: string;\n type: TNForm;\n read_only: boolean;\n limits?: ILimits;\n value: any;\n}\n\nexport interface IToolsEvent {\n name: string;\n conditions?: { advanced: boolean; search: string } | boolean;\n}\n\nconst isVisibleField = (a: TFormOptions) => !a.ui_options?.invisible;\nconst isAdvancedField = (a: TFormOptions) => isVisibleField(a) && a.ui_options?.advanced;\nconst isHidden = (a: IFieldStack) => !!(a.ui_options?.invisible || a.ui_options?.advanced);\n\nconst typeToControl: Partial<{ [key in TNForm | controlType]: controlType }> = {\n bool: 'boolean',\n int: 'textbox',\n integer: 'textbox',\n float: 'textbox',\n string: 'textbox',\n file: 'textarea',\n text: 'textarea',\n};\n\nexport const getControlType = (t: TNForm): controlType => typeToControl[t] || (t as controlType);\n\nconst intPattern = () => new RegExp(/^[-]?\\d+$/);\nconst patternFn = {\n integer: intPattern,\n int: intPattern,\n float: () => new RegExp(/^[-]?[0-9]+(\\.[0-9]+)?$/),\n};\n\nexport const getPattern = (t: TNForm): RegExp => (patternFn[t] ? patternFn[t]() : null);\n\nconst fn = {\n boolean: (v: boolean | null, d: boolean | null, r: boolean): boolean | null => (String(v) === 'true' || String(v) === 'false' || String(v) === 'null' ? v : r ? d : null),\n json: (v: string): string => (v === null ? '' : JSON.stringify(v, undefined, 4)),\n map: (v: object, d: object): object => (!v ? d : v),\n list: (v: string[], d: string[]): string[] => (!v ? d : v),\n structure: (v: any): any => v,\n};\n\nexport const getValue = (t: TNForm) => {\n const def = (value: number | string) => (value === null || value === undefined ? '' : String(value));\n return fn[t] ? fn[t] : def;\n};\n\nexport const getKey = (name: string, subname: string): string => (subname ? `${subname}/${name}` : name);\n\nexport const getValidator = (required: boolean, min: number, max: number, type: TNForm) => ({\n required,\n min,\n max,\n pattern: getPattern(type),\n});\n\nconst getField = (item: IFieldStack): IFieldOptions => {\n return {\n ...item,\n key: getKey(item.name, item.subname),\n value: getValue(item.type)(item.value, item.default, item.required),\n validator: getValidator(item.required, item.limits?.min, item.limits?.max, item.type),\n controlType: getControlType(item.type),\n hidden: item.name === '__main_info' || isHidden(item),\n compare: []\n };\n};\n\nconst fo = (n: string) => (b: IFieldStack) => b.type !== 'group' && b.subname && b.name === n;\nconst isActive = (a: IConfigAttr, n: string) => a[n]?.active;\nexport const getOptions = (a: IFieldStack, d: IConfig) =>\n d.config\n .filter(fo(a.name))\n .map((f) => getField(f))\n // switch off validation for field if !(activatable: true && active: false) - line: 146\n .map((c) => ({ ...c, name: c.subname, activatable: a.activatable && !isActive(d.attr, a.name) }));\n\nconst getPanel = (a: IFieldStack, d: IConfig): IPanelOptions => ({\n ...a,\n hidden: isHidden(a),\n active: a.activatable ? isActive(d.attr, a.name) : true,\n options: getOptions(a, d),\n});\n\nconst handleTree = (c: ISearchParam): ((a: TFormOptions) => TFormOptions) => (a: TFormOptions): TFormOptions => {\n if ('options' in a) {\n a.options = a.options.map(handleTree(c));\n if (c.search) a.hidden = a.options.filter((b) => !b.hidden).length === 0;\n else a.hidden = isAdvancedField(a) ? !c.advanced : false;\n } else if (isVisibleField(a)) {\n a.hidden = !(a.display_name.toLowerCase().includes(c.search.toLowerCase()) || String(a.value).toLocaleLowerCase().includes(c.search.toLocaleLowerCase()));\n if (!a.hidden && isAdvancedField(a)) a.hidden = !c.advanced;\n }\n return a;\n};\n\nconst findAttrValue = (obj: T, key: string): boolean => {\n let value;\n for (let i in obj) {\n if (!obj.hasOwnProperty(i)) continue;\n if (typeof obj[i] === 'object') {\n value = findAttrValue(obj[i], key);\n } else if (i === key) {\n value = obj[i];\n }\n }\n return value;\n};\n\n@Injectable()\nexport class FieldService {\n attributesService: AttributeService | undefined;\n\n constructor(public fb: FormBuilder) {}\n\n /**\n * Parse and prepare source data from backend\n */\n public getPanels(data: IConfig): TFormOptions[] {\n return data?.config\n ?.filter((a) => a.name !== '__main_info')\n .reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, getField(c)];\n else return [...p, getPanel(c, data)];\n }, []);\n }\n\n /**\n * Generate FormGroup\n * @param options\n */\n public toFormGroup(options: TFormOptions[] = []): FormGroup {\n const check = (a: TFormOptions): boolean =>\n 'options' in a\n ? a.activatable\n ? isVisibleField(a) // if group.activatable - only visible\n : isVisibleField(a) && !a.read_only // else visible an not read_only\n ? a.options.some((b) => check(b)) // check inner fields\n : false\n : isVisibleField(a) && !a.read_only; // for fields in group\n\n return this.fb.group(\n options.reduce((p, c) => this.runByTree(c, p), {}),\n {\n validator: () => (options.filter(check).length === 0 ? { error: 'Form is empty' } : null),\n }\n );\n }\n\n // TODO:\n private runByTree(field: TFormOptions, controls: { [key: string]: {} }): { [key: string]: {} } {\n if ('options' in field) {\n controls[field.name] = this.fb.group(\n field.options.reduce((p, a) => {\n if ('options' in a) this.fb.group(this.runByTree(a, p));\n else this.fillForm(a, p);\n return p;\n }, {})\n );\n return controls;\n } else {\n return this.fillForm(field, controls);\n }\n }\n\n private fillForm(field: IFieldOptions, controls: {}) {\n const name = field.subname || field.name;\n controls[name] = this.fb.control(field.value, field.activatable ? [] : this.setValidator(field));\n return controls;\n }\n\n /**\n * External use (scheme.service) to set validator for FormControl by type\n * @param field Partial{ ValidatorInfo, controlType }\n * @param controlToCompare\n */\n public setValidator(field: { validator: IValidator; controlType: controlType }, controlToCompare?: AbstractControl) {\n const v: ValidatorFn[] = [];\n\n if (field.validator.required) v.push(Validators.required);\n if (field.validator.pattern) v.push(Validators.pattern(field.validator.pattern));\n //if (field.validator.max !== null)\n v.push(Validators.max(field.validator.max));\n //if (field.validator.min !== null)\n v.push(Validators.min(field.validator.min));\n\n if (field.controlType === 'password') {\n const passwordConfirm = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => {\n if (controlToCompare && controlToCompare.value !== control.value) return { notEqual: true };\n return null;\n };\n v.push(passwordConfirm());\n }\n\n if (field.controlType === 'json') {\n const jsonParse = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => {\n if (control.value) {\n try {\n JSON.parse(control.value);\n return null;\n } catch (e) {\n return { jsonParseError: { value: control.value } };\n }\n } else return null;\n };\n\n v.push(jsonParse());\n }\n\n if (field.controlType === 'map') {\n const parseKey = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null =>\n control.value && Object.keys(control.value).length && Object.keys(control.value).some((a) => !a) ? { parseKey: true } : null;\n v.push(parseKey());\n }\n return v;\n }\n\n /**\n * Filter by group and all fields\n */\n public filterApply(options: TFormOptions[], c: ISearchParam): TFormOptions[] {\n return options.filter((a) => isVisibleField(a)).map(handleTree(c));\n }\n\n /**\n * Output form, cast to source type\n */\n public parseValue(output: IOutput, source: ISource[]): IOutput {\n const findField = (name: string, p?: string): Partial => source.find((a) => (p ? a.name === p && a.subname === name : a.name === name));\n\n const runYspecParse = (v: any, f: Partial) => ((!v || !Object.keys(v).length) && !f.value ? f.value : this.runYspec(v, f.limits.rules));\n\n const runParse = (v: IOutput, parentName?: string): IOutput => {\n const runByValue = (p: IOutput, c: string) => {\n const checkType = (data: resultTypes | IOutput, field: Partial): resultTypes => {\n const { type } = field;\n if (type === 'structure') return runYspecParse(data, field);\n else if (type === 'group') return this.checkValue(runParse(data as IOutput, field.name), type);\n else return this.checkValue(data, type);\n };\n\n const f = findField(c, parentName);\n if (f) {\n const result = checkType(v[c], f);\n return f.type !== 'group' || result ? { ...p, [c]: result } : p;\n }\n return p;\n };\n\n return Object.keys(v).reduce(runByValue, {});\n };\n\n const __main_info = findField('__main_info');\n return runParse(__main_info?.required ? { ...output, __main_info: __main_info.value } : { ...output });\n }\n\n private runYspec(value: resultTypes, rules: any) {\n switch (rules?.type) {\n case 'list': {\n return (value as Array).filter((a) => !!a).map((a) => this.runYspec(a, rules.options));\n }\n case 'dict': {\n return Object.keys(value).reduce((p, c) => {\n const r = rules.options.find((b: any) => b.name === c);\n const v = r ? this.runYspec(value[c], r) : null;\n return v !== null ? { ...p, [c]: v } : { ...p };\n }, {});\n }\n default: {\n return this.checkValue(value, rules?.type);\n }\n }\n }\n\n checkValue(value: resultTypes, type: TNForm): resultTypes {\n if ((value === '' || isEmptyObject(value)) && type === 'map') return {};\n\n if ((value === '' || isEmptyObject(value)) && type === 'list') return [];\n\n if (value === '' || value === null || isEmptyObject(value)) return null;\n\n if (typeof value === 'boolean') return value;\n else if (typeof value === 'string')\n switch (type) {\n case 'option':\n return !isNaN(+value) ? parseInt(value, 10) : value;\n case 'integer':\n case 'int':\n return parseInt(value, 10);\n case 'float':\n return parseFloat(value);\n case 'json':\n return JSON.parse(value);\n }\n else\n switch (type) {\n case 'map':\n return Object.keys(value)\n .filter((a) => !!a)\n .reduce((p, c) => ({ ...p, [c]: value[c] }), {});\n\n case 'list':\n return Array.isArray(value) ? (value as Array).filter((a) => !!a) : null;\n }\n\n return value;\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "fb", - "type": "FormBuilder", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 155, - "jsdoctags": [ - { - "name": "fb", - "type": "FormBuilder", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "FullyRenderedService", - "id": "injectable-FullyRenderedService-ca65161cb3b7e03bec7a3ee145dfd56f", - "file": "src/app/core/services/fully-rendered.service.ts", - "properties": [ - { - "name": "navStart$", - "defaultValue": "this.router.events\n .pipe(\n filter((event) => event instanceof NavigationStart),\n startWith(null as string), // Start with something, because the app doesn't fire this on appload, only on subsequent route changes\n tap((event) => {\n /* Place code to track NavigationStart here */\n })\n )\n .subscribe()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21 - } - ], - "methods": [ - { - "name": "stableView", - "args": [ - { - "name": "callback", - "type": "function", - "deprecated": false, - "deprecationMessage": "", - "function": [] - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\n\n\n", - "description": "", - "jsdoctags": [ - { - "name": { - "pos": 1323, - "end": 1331, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "callback" - }, - "type": "function", - "deprecated": false, - "deprecationMessage": "", - "function": [], - "tagName": { - "pos": 1304, - "end": 1309, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "", - "typeExpression": { - "pos": 1310, - "end": 1322, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 302, - "type": { - "pos": 1311, - "end": 1321, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 175, - "parameters": [], - "type": { - "pos": 1316, - "end": 1321, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 113 - } - } - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable, NgZone } from '@angular/core';\nimport { NavigationStart, Router } from '@angular/router';\nimport { interval } from 'rxjs';\nimport { distinctUntilChanged, filter, map, startWith, take, tap } from 'rxjs/operators';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class FullyRenderedService {\n navStart$ = this.router.events\n .pipe(\n filter((event) => event instanceof NavigationStart),\n startWith(null as string), // Start with something, because the app doesn't fire this on appload, only on subsequent route changes\n tap((event) => {\n /* Place code to track NavigationStart here */\n })\n )\n .subscribe();\n\n constructor(private router: Router, private zone: NgZone) {}\n\n /**\n *\n *\n * @param {() => void} callback\n * @memberof FullyRenderedService\n */\n stableView(callback: () => void) {\n this.zone.runOutsideAngular(() => {\n interval(10)\n .pipe(\n startWith(0),\n // To prevent a memory leak on two closely times route changes, take until the next nav start\n //takeUntil(this.navigationStart$),\n // Turn the interval number into the current state of the zone\n map(() => !this.zone.hasPendingMacrotasks),\n // Don't emit until the zone state actually flips from `false` to `true`\n distinctUntilChanged(),\n // Filter out unstable event. Only emit once the state is stable again\n filter((stateStable) => stateStable === true),\n // Complete the observable after it emits the first result\n take(1),\n tap((stateStable) => {\n callback();\n })\n )\n .subscribe();\n });\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "zone", - "type": "NgZone", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 29, - "jsdoctags": [ - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "zone", - "type": "NgZone", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "HostService", - "id": "injectable-HostService-d46c66649d2436b6a7fe0d0d3b3eb137", - "file": "src/app/services/host.service.ts", - "properties": [], - "methods": [ - { - "name": "addToCluster", - "args": [ - { - "name": "hostId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "clusterId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "hostId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "clusterId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "entityStatusTreeToStatusTree", - "args": [ - { - "name": "input", - "type": "HostStatusTree", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "StatusTree[]", - "typeParameters": [], - "line": 38, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "input", - "type": "HostStatusTree", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - }, - { - "name": "getStatusTree", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 34, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { EntityService } from '../abstract/entity-service';\nimport { IHost } from '../models/host';\nimport { Host } from '../core/types';\nimport { environment } from '@env/environment';\nimport { ApiService } from '@app/core/api';\nimport { HostStatusTree, StatusTree } from '@app/models/status-tree';\nimport { HavingStatusTreeAbstractService } from '@app/abstract/having-status-tree.abstract.service';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class HostService extends EntityService implements HavingStatusTreeAbstractService {\n\n constructor(\n protected api: ApiService,\n ) {\n super(api);\n }\n\n get(\n id: number,\n params: { [key: string]: string } = {},\n ): Observable {\n return this.api.get(`${environment.apiRoot}host/${id}/`, params);\n }\n\n addToCluster(hostId: number, clusterId: number): Observable {\n return this.api.post(`${environment.apiRoot}cluster/${clusterId}/host/`, { host_id: hostId });\n }\n\n getStatusTree(id: number): Observable {\n return this.api.get(`${environment.apiRoot}host/${id}/status/`);\n }\n\n entityStatusTreeToStatusTree(input: HostStatusTree): StatusTree[] {\n return [{\n subject: {\n id: input.id,\n status: input.status,\n name: input.name,\n },\n children: input.hc.map((hc) => ({\n subject: {\n id: hc.id,\n status: hc.status,\n name: hc.name,\n },\n children: [],\n })),\n }];\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 15, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "EntityService", - "type": "injectable" - }, - { - "name": "IssueEffect", - "id": "injectable-IssueEffect-a6605e20804c67a3c80aae8f5f6181fc", - "file": "src/app/core/store/issue.ts", - "properties": [ - { - "name": "load$", - "defaultValue": "createEffect(() =>\n this.actions$.pipe(\n ofType(loadIssue),\n withLatestFrom(this.store, (action, state) => state.issue.url),\n filter(url => !!url),\n exhaustMap(url => this.api.get(url).pipe(map(o => fillIssue({ value: o.issue, url: o.url }))))\n )\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 43 - } - ], - "methods": [], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\nimport { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props, Store } from '@ngrx/store';\nimport { exhaustMap, filter, map, withLatestFrom } from 'rxjs/operators';\n\nimport { ApiService } from '../api';\nimport { State } from '../store';\nimport { BaseEntity } from '../types';\nimport { IIssues } from '@app/models/issue';\n\nexport interface IssueState {\n value: IIssues;\n url: string;\n}\n\nconst InitState = {\n value: null,\n url: '',\n};\n\nexport const loadIssue = createAction('[Issue] LoadIssue');\nexport const fillIssue = createAction('[Issue] FillIssue', props<{ value: IIssues; url: string }>());\n\nconst reducer = createReducer(InitState, on(loadIssue, state => ({ ...state })), on(fillIssue, (state, { value, url }) => ({ value, url })));\n\nexport function issueReducer(state: IssueState, action: Action) {\n return reducer(state, action);\n}\n\n@Injectable()\nexport class IssueEffect {\n load$ = createEffect(() =>\n this.actions$.pipe(\n ofType(loadIssue),\n withLatestFrom(this.store, (action, state) => state.issue.url),\n filter(url => !!url),\n exhaustMap(url => this.api.get(url).pipe(map(o => fillIssue({ value: o.issue, url: o.url }))))\n )\n );\n\n constructor(private actions$: Actions, private api: ApiService, private store: Store) {}\n}\n\nexport const getIssueSelector = createFeatureSelector('issue');\n\nexport const checkIssue = createSelector(\n getIssueSelector,\n state => state\n);\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 50, - "jsdoctags": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "JobService", - "id": "injectable-JobService-fb5cf4b4669cbd3b3a0034f5446a4b7c", - "file": "src/app/services/job.service.ts", - "properties": [], - "methods": [ - { - "name": "events", - "args": [ - { - "name": "eventFilter", - "type": "EventFilter", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "eventFilter", - "type": "EventFilter", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { filter } from 'rxjs/operators';\nimport { Store } from '@ngrx/store';\n\nimport { EventableService, EventFilter } from '@app/models/eventable-service';\nimport { EventMessage, selectMessage, SocketState } from '@app/core/store';\nimport { EntityService } from '@app/abstract/entity-service';\nimport { Job } from '@app/core/types';\nimport { ApiService } from '@app/core/api';\nimport { environment } from '@env/environment';\n\n@Injectable()\nexport class JobService extends EntityService implements EventableService {\n\n constructor(\n private store: Store,\n protected api: ApiService,\n ) {\n super(api);\n }\n\n get(id: number, params: { [key: string]: string } = {}): Observable {\n return this.api.get(`${environment.apiRoot}job/${id}/`, params);\n }\n\n events(eventFilter?: EventFilter): Observable {\n return this.store.pipe(\n selectMessage,\n filter(event => event?.object?.type === 'job'),\n filter(event => !eventFilter?.events || eventFilter.events.includes(event?.event)),\n );\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 14, - "jsdoctags": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "EntityService", - "type": "injectable" - }, - { - "name": "ListService", - "id": "injectable-ListService-cacb1e16b90fc26c0f8b1c0f88811ebe", - "file": "src/app/shared/components/list/list.service.ts", - "properties": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "ListInstance", - "optional": false, - "description": "", - "line": 40 - } - ], - "methods": [ - { - "name": "acceptLicense", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 100, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "checkItem", - "args": [ - { - "name": "item", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [ - "T" - ], - "line": 96, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "delete", - "args": [ - { - "name": "row", - "type": "Entities", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 85, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "Entities", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getActions", - "args": [ - { - "name": "row", - "type": "Entities", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 78, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "Entities", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getClustersForHost", - "args": [ - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 90, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "param", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getCrumbs", - "args": [], - "optional": false, - "returnType": "{}", - "typeParameters": [], - "line": 74, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getLicenseInfo", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 104, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getList", - "args": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable>", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "initInstance", - "args": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "ListInstance", - "typeParameters": [], - "line": 44, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "typeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { convertToParamMap, ParamMap, Params } from '@angular/router';\nimport { map, switchMap, tap } from 'rxjs/operators';\nimport { Observable } from 'rxjs';\n\nimport { environment } from '@env/environment';\nimport { ApiService } from '@app/core/api';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { BaseEntity, Bundle, Entities, IAction, Service, TypeName } from '@app/core/types';\nimport { IListService, ListInstance } from '@app/shared/components/list/list-service-token';\nimport { ListResult } from '@app/models/list-result';\nimport { ICluster } from '@app/models/cluster';\n\nconst COLUMNS_SET = {\n cluster: ['name', 'prototype_version', 'description', 'state', 'status', 'actions', 'import', 'upgrade', 'config', 'controls'],\n host2cluster: ['fqdn', 'provider_name', 'state', 'status', 'actions', 'config', 'remove'],\n service2cluster: ['display_name', 'version_no_sort', 'state', 'status', 'actions', 'import', 'config'],\n host: ['fqdn', 'provider_name', 'host2cluster', 'state', 'status', 'actions', 'config', 'controls'],\n provider: ['name', 'prototype_version', 'state', 'actions', 'upgrade', 'config', 'controls'],\n job: ['action', 'objects', 'start_date', 'finish_date', 'status'],\n task: ['id', 'start_date', 'finish_date', 'status'],\n bundle: ['name', 'version', 'edition', 'description', 'controls'],\n};\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ListService implements IListService {\n current: ListInstance;\n\n constructor(private api: ApiService, private detail: ClusterService) {}\n\n initInstance(typeName: TypeName): ListInstance {\n this.current = { typeName, columns: COLUMNS_SET[typeName] };\n return this.current;\n }\n\n getList(p: ParamMap, typeName: string): Observable> {\n const listParamStr = localStorage.getItem('list:param');\n if (p?.keys.length) {\n const param = p.keys.reduce((a, c) => ({ ...a, [c]: p.get(c) }), {});\n if (listParamStr) {\n const json = JSON.parse(listParamStr);\n json[typeName] = param;\n localStorage.setItem('list:param', JSON.stringify(json));\n } else localStorage.setItem('list:param', JSON.stringify({ [typeName]: param }));\n }\n\n switch (typeName) {\n case 'host2cluster':\n return this.detail.getHosts(p);\n case 'service2cluster':\n return this.detail.getServices(p);\n case 'bundle':\n return this.api.getList(`${environment.apiRoot}stack/bundle/`, p);\n case 'servicecomponent':\n return this.api.getList(`${environment.apiRoot}cluster/${(this.detail.Current as Service).cluster_id}/service/${this.detail.Current.id}/component`, p);\n default:\n return this.api.root.pipe(switchMap((root) => this.api.getList(root[this.current.typeName], p)));\n }\n }\n\n getCrumbs() {\n return [{ path: '/cluster', name: 'clusters' }];\n }\n\n getActions(row: Entities) {\n this.api\n .get(row.action)\n .pipe(tap((actions) => (row.actions = actions)))\n .subscribe();\n }\n\n delete(row: Entities) {\n return this.api.delete(row.url);\n }\n\n // host\n getClustersForHost(param: Params): Observable<{ id: number; title: string }[]> {\n return this.api.root\n .pipe(switchMap((root) => this.api.getList(root.cluster, convertToParamMap(param))))\n .pipe(map((res) => res.results.map((a) => ({ id: a.id, title: a.name }))));\n }\n\n checkItem(item: BaseEntity) {\n return this.api.get(item.url);\n }\n\n acceptLicense(url: string) {\n return this.api.put(url, {});\n }\n\n getLicenseInfo(url: string) {\n return this.api.get<{ text: string }>(url);\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "detail", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 40, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "detail", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "MainService", - "id": "injectable-MainService-bfe1187b2f621020ae1b5f2e70d5b6f1", - "file": "src/app/shared/configuration/main/main.service.ts", - "properties": [ - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "ClusterService", - "optional": false, - "description": "", - "line": 51, - "modifierKind": [ - 122 - ] - }, - { - "name": "configService", - "deprecated": false, - "deprecationMessage": "", - "type": "IConfigService", - "optional": false, - "description": "", - "line": 48 - } - ], - "methods": [ - { - "name": "changeVersion", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 73, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "checkField", - "args": [ - { - "name": "a", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "configs", - "type": "CompareConfig[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 111, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "a", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "configs", - "type": "CompareConfig[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "compareConfig", - "args": [ - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dataOptions", - "type": "TFormOptions[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "compareConfig", - "type": "CompareConfig[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 93, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dataOptions", - "type": "TFormOptions[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "compareConfig", - "type": "CompareConfig[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "filterApply", - "args": [ - { - "name": "options", - "type": "TFormOptions[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "search", - "type": "ISearchParam", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 77, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "options", - "type": "TFormOptions[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "search", - "type": "ISearchParam", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "findFieldiCompare", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cc", - "type": "CompareConfig", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "{ id: any; date: any; color: any; value: any; }", - "typeParameters": [], - "line": 142, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cc", - "type": "CompareConfig", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getConfig", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getHistoryList", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "currentVersionId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 89, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "currentVersionId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "parseValue", - "args": [ - { - "name": "output", - "type": "IOutput", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "source", - "type": "IFieldStack[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 81, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "output", - "type": "IOutput", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "source", - "type": "IFieldStack[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "runCheck", - "args": [ - { - "name": "a", - "type": "TFormOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "configs", - "type": "CompareConfig[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 105, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "a", - "type": "TFormOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "configs", - "type": "CompareConfig[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "runClear", - "args": [ - { - "name": "a", - "type": "TFormOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 99, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "a", - "type": "TFormOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "send", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 85, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "data", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { animate, state, style, transition, trigger } from '@angular/animations';\nimport { Injectable, InjectionToken, Injector } from '@angular/core';\nimport { isObject, TypeName } from '@app/core/types';\nimport { FieldService, IOutput, TFormOptions } from '../services/field.service';\nimport { CompareConfig, IFieldOptions, IFieldStack } from '../types';\nimport { ConfigService, IConfigService } from '@app/shared/configuration/services/config.service';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ConfigGroupService } from '@app/config-groups/service/config-group.service';\n\n/**\n *```\n advanced: boolean;\n search: string;\n ```\n */\nexport interface ISearchParam {\n advanced: boolean;\n search: string;\n}\n\nexport const historyAnime = [\n trigger('history', [\n state('hide', style({ top: '70px' })),\n state('show', style({ top: '134px' })),\n state('hideTools', style({ opacity: 0 })),\n state('showTools', style({ opacity: 0.8 })),\n transition('hideTools => showTools', animate('.5s .3s ease-in')),\n transition('showTools => hideTools', animate('.2s ease-out')),\n transition('hide <=> show', animate('.3s')),\n ]),\n];\n\n@Injectable({\n providedIn: 'root'\n})\nexport class MainService {\n configService: IConfigService;\n\n constructor(private fields: FieldService,\n public cluster: ClusterService,\n injector: Injector) {\n const current: TypeName | undefined = cluster.Current?.typeName;\n if (current === 'group_config') {\n this.configService = injector.get(ConfigGroupService);\n } else {\n this.configService = injector.get(ConfigService);\n }\n }\n\n get worker$() {\n return this.cluster.worker$;\n }\n\n get Current() {\n return this.cluster.Current;\n }\n\n getConfig(url: string) {\n return this.configService.getConfig(url);\n }\n\n changeVersion(url: string, id: number) {\n return this.configService.changeVersion(id, url);\n }\n\n filterApply(options: TFormOptions[], search: ISearchParam) {\n this.fields.filterApply(options, search);\n }\n\n parseValue(output: IOutput, source: IFieldStack[]) {\n return this.fields.parseValue(output, source);\n }\n\n send(url: string, data: any) {\n return this.configService.send(url, data);\n }\n\n getHistoryList(url: string, currentVersionId: number) {\n return this.configService.getHistoryList(url, currentVersionId);\n }\n\n compareConfig(ids: number[], dataOptions: TFormOptions[], compareConfig: CompareConfig[]) {\n dataOptions.map((a) => this.runClear(a, ids));\n const cc = ids.map((id) => compareConfig.find((a) => a.id === id));\n dataOptions.map((a) => this.runCheck(a, cc));\n }\n\n runClear(a: TFormOptions, ids: number[]) {\n if ('options' in a) a.options.map((b) => this.runClear(b, ids));\n else if (a.compare.length) a.compare = a.compare.filter((b) => ids.includes(b.id));\n return a;\n }\n\n runCheck(a: TFormOptions, configs: CompareConfig[]) {\n if ('options' in a) a.options.map((b) => this.runCheck(b, configs));\n else this.checkField(a, configs);\n return a;\n }\n\n checkField(a: IFieldOptions, configs: CompareConfig[]) {\n configs\n .filter((b) => a.compare.every((e) => e.id !== b.id))\n .map((c) => {\n const co = this.findFieldiCompare(a.key, c);\n if (!co) {\n if (String(a.value) && String(a.value) !== 'null') a.compare.push({\n id: c.id,\n date: c.date,\n color: c.color,\n value: 'null'\n });\n } else {\n if (isObject(co.value)) {\n if (isObject(a.value)) {\n if (JSON.stringify(a.value) !== JSON.stringify(co.value)) a.compare.push({\n ...co,\n value: JSON.stringify(co.value)\n });\n } else if (typeof a.value === 'string') {\n if (JSON.stringify(JSON.parse(a.value)) !== JSON.stringify(co.value)) a.compare.push({\n ...co,\n value: JSON.stringify(co.value)\n });\n }\n } else if (String(co.value) !== String(a.value)) a.compare.push(co);\n }\n });\n return a;\n }\n\n findFieldiCompare(key: string, cc: CompareConfig) {\n const value = key\n .split('/')\n .reverse()\n .reduce((p, c) => p[c], cc.config);\n if (value !== null && value !== undefined && String(value)) {\n const { id, date, color } = { ...cc };\n return { id, date, color, value };\n }\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "fields", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 48, - "jsdoctags": [ - { - "name": "fields", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "worker$": { - "name": "worker$", - "getSignature": { - "name": "worker$", - "type": "", - "returnType": "", - "line": 61 - } - }, - "Current": { - "name": "Current", - "getSignature": { - "name": "Current", - "type": "", - "returnType": "", - "line": 65 - } - } - }, - "type": "injectable" - }, - { - "name": "MasterService", - "id": "injectable-MasterService-4cd1f32b2d3db5ce944b66105c7f592e", - "file": "src/app/shared/components/actions/master/master.service.ts", - "properties": [], - "methods": [ - { - "name": "parseData", - "args": [ - { - "name": "v", - "type": "IValue", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IMasterData", - "typeParameters": [], - "line": 51, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "v", - "type": "IValue", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "send", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "spotShow", - "args": [ - { - "name": "action", - "type": "IAction", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "whatShow", - "typeParameters": [], - "line": 45, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "action", - "type": "IAction", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { ApiService } from '@app/core/api';\nimport { IAction } from '@app/core/types';\nimport { FieldService } from '@app/shared/configuration/services/field.service';\nimport { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component';\nimport { ServiceHostComponent } from '@app/shared/host-components-map/services2hosts/service-host.component';\nimport { Post } from '@app/shared/host-components-map/types';\nimport { IConfigAttr } from '@app/shared/configuration/types';\nimport { IOutput } from '@app/shared/configuration/services/field.service';\n\nexport interface IValue {\n config?: ConfigFieldsComponent;\n hostmap?: ServiceHostComponent;\n}\n\nexport enum whatShow {\n none = 'none',\n config = 'config',\n hostMap = 'hostmap',\n stepper = 'stepper',\n}\n\nexport interface IMasterData {\n attr: IConfigAttr;\n config: IOutput;\n hc: Post[];\n verbose?: boolean;\n}\n\n@Injectable()\nexport class MasterService {\n constructor(private api: ApiService, private configService: FieldService) {}\n\n spotShow(action: IAction): whatShow {\n const config = action.config?.config?.length;\n const hm = action.hostcomponentmap?.length;\n return config ? (hm ? whatShow.stepper : whatShow.config) : hm ? whatShow.hostMap : whatShow.none;\n }\n\n parseData(v: IValue): IMasterData {\n const getData = (attr: IConfigAttr, c: ConfigFieldsComponent, h: ServiceHostComponent) => {\n const config = c ? this.configService.parseValue(c.form.value, c.rawConfig.config) : undefined;\n const hc = h?.statePost.data;\n return { attr, config, hc };\n };\n return v ? getData(v.config?.attr, v.config, v.hostmap) : undefined;\n }\n\n send(url: string, value: { config: any; hc: Post[] }) {\n return this.api.post(url, value);\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "configService", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 42, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "configService", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "NavigationEffects", - "id": "injectable-NavigationEffects-add285eeee99d0c1741f5de7e8bcc764", - "file": "src/app/store/navigation/navigation-effects.ts", - "properties": [ - { - "name": "changePathOfEvent$", - "defaultValue": "createEffect(() => this.actions$.pipe(\n ofType(socketResponse),\n filter(action =>\n [ConcernEventType.Service, ConcernEventType.Cluster, ConcernEventType.Host, ConcernEventType.HostProvider, ConcernEventType.ServiceComponent].includes(action.message.object.type as any)\n ),\n concatMap((event: { message: EventMessage }) => {\n return new Observable(subscriber => {\n this.store.select(getNavigationPath).pipe(take(1)).subscribe((path) => {\n if (path.some(item => item.typeName === getEventEntityType(event.message.object.type) && event.message.object.id === item.id)) {\n this.entityGetter(getEventEntityType(event.message.object.type), event.message.object.id)\n .subscribe((entity) => {\n subscriber.next(setPath({\n path: path.reduce((acc, item) =>\n acc.concat(getEventEntityType(event.message.object.type) === item.typeName && item.id === event.message.object.id ? entity : item), []),\n }));\n subscriber.complete();\n }, () => subscriber.complete());\n } else {\n subscriber.complete();\n }\n }, () => subscriber.complete());\n });\n }),\n ))", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 47 - }, - { - "name": "setPathOfRoute$", - "defaultValue": "createEffect(\n () =>\n this.actions$.pipe(\n ofType(setPathOfRoute),\n filter(action => !!action.params),\n switchMap(action => {\n const getters: Observable[] = action.params.keys.reduce((acc, param) => {\n const getter = this.entityGetter(param as TypeName, +action.params.get(param));\n if (getter) {\n acc.push(getter);\n }\n\n return acc;\n }, []);\n return getPath(getters);\n }),\n ),\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 28 - } - ], - "methods": [ - { - "name": "entityGetter", - "args": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 81, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\nimport { concatMap, filter, map, switchMap, take } from 'rxjs/operators';\nimport { Observable } from 'rxjs';\nimport { AdcmEntity, AdcmTypedEntity } from '@app/models/entity';\nimport { TypeName } from '@app/core/types';\nimport { Action, Store } from '@ngrx/store';\n\nimport { ApiService } from '@app/core/api';\nimport { ServiceComponentService } from '@app/services/service-component.service';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { EntityNames } from '@app/models/entity-names';\nimport {\n getEventEntityType,\n getNavigationPath,\n getPath,\n setPath,\n setPathOfRoute\n} from '@app/store/navigation/navigation.store';\nimport { EventMessage, socketResponse } from '@app/core/store/sockets/socket.reducer';\nimport { IClusterService } from '@app/models/cluster-service';\nimport { ConfigGroupListService } from '@app/config-groups/service/config-group-list.service';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n@Injectable()\nexport class NavigationEffects {\n\n setPathOfRoute$ = createEffect(\n () =>\n this.actions$.pipe(\n ofType(setPathOfRoute),\n filter(action => !!action.params),\n switchMap(action => {\n const getters: Observable[] = action.params.keys.reduce((acc, param) => {\n const getter = this.entityGetter(param as TypeName, +action.params.get(param));\n if (getter) {\n acc.push(getter);\n }\n\n return acc;\n }, []);\n return getPath(getters);\n }),\n ),\n );\n\n changePathOfEvent$ = createEffect(() => this.actions$.pipe(\n ofType(socketResponse),\n filter(action =>\n [ConcernEventType.Service, ConcernEventType.Cluster, ConcernEventType.Host, ConcernEventType.HostProvider, ConcernEventType.ServiceComponent].includes(action.message.object.type as any)\n ),\n concatMap((event: { message: EventMessage }) => {\n return new Observable(subscriber => {\n this.store.select(getNavigationPath).pipe(take(1)).subscribe((path) => {\n if (path.some(item => item.typeName === getEventEntityType(event.message.object.type) && event.message.object.id === item.id)) {\n this.entityGetter(getEventEntityType(event.message.object.type), event.message.object.id)\n .subscribe((entity) => {\n subscriber.next(setPath({\n path: path.reduce((acc, item) =>\n acc.concat(getEventEntityType(event.message.object.type) === item.typeName && item.id === event.message.object.id ? entity : item), []),\n }));\n subscriber.complete();\n }, () => subscriber.complete());\n } else {\n subscriber.complete();\n }\n }, () => subscriber.complete());\n });\n }),\n ));\n\n constructor(\n private actions$: Actions,\n private api: ApiService,\n private serviceComponentService: ServiceComponentService,\n private store: Store,\n private clusterService: ClusterService,\n private configGroupService: ConfigGroupListService\n ) {}\n\n entityGetter(type: TypeName, id: number): Observable {\n const entityToTypedEntity = (getter: Observable, typeName: TypeName) => getter.pipe(\n map(entity => ({\n ...entity,\n typeName,\n } as AdcmTypedEntity))\n );\n\n if (EntityNames.includes(type)) {\n if (type === 'bundle') {\n return entityToTypedEntity(\n this.clusterService.one_bundle(id),\n type,\n );\n } else if (type === 'servicecomponent' || type === 'component') {\n return entityToTypedEntity(\n this.serviceComponentService.get(id),\n type,\n );\n }\n if (type === 'service') {\n return entityToTypedEntity(\n this.api.getOne(type, id),\n type,\n ).pipe(switchMap((entity) => {\n return this.api.getOne('cluster', (entity as any as IClusterService).cluster_id)\n .pipe(map(cluster => ({ ...entity, cluster })));\n }));\n } else if (type === 'group_config') {\n return entityToTypedEntity(\n this.configGroupService.get(id),\n type,\n );\n } else {\n return entityToTypedEntity(\n this.api.getOne(type, id),\n type,\n );\n }\n }\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "serviceComponentService", - "type": "ServiceComponentService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "clusterService", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "configGroupService", - "type": "ConfigGroupListService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 70, - "jsdoctags": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "serviceComponentService", - "type": "ServiceComponentService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "clusterService", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "configGroupService", - "type": "ConfigGroupListService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "PreloaderService", - "id": "injectable-PreloaderService-1100441504f027363be0b0f2acc72e5b", - "file": "src/app/core/services/preloader.service.ts", - "properties": [ - { - "name": "_counter", - "defaultValue": "0", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 19, - "modifierKind": [ - 120 - ] - }, - { - "name": "active$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "Subject", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "isFreese", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 20, - "modifierKind": [ - 120 - ] - } - ], - "methods": [ - { - "name": "end", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 34, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "freeze", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "start", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 28, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Subject } from 'rxjs';\nimport { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class PreloaderService {\n private _counter = 0;\n private isFreese = false;\n\n active$: Subject = new Subject();\n\n get counter(): number {\n return this._counter;\n }\n\n start(): void {\n this._counter++;\n if (!this.isFreese) this.active$.next(this._counter > 0);\n this.isFreese = false;\n }\n\n end(): void {\n this._counter--;\n this.active$.next(this._counter > 0);\n }\n\n freeze(): void {\n this.isFreese = true;\n }\n}\n", - "accessors": { - "counter": { - "name": "counter", - "getSignature": { - "name": "counter", - "type": "number", - "returnType": "number", - "line": 24 - } - } - }, - "type": "injectable" - }, - { - "name": "ProfileEffects", - "id": "injectable-ProfileEffects-23b89f0ddded9ef4d31a5b89bdac5d47", - "file": "src/app/core/store/profile/index.ts", - "properties": [ - { - "name": "load$", - "defaultValue": "createEffect(() =>\n this.actions$.pipe(\n ofType(loadProfile),\n exhaustMap(() => this.service.getProfile().pipe(map(user => loadProfileSuccess({ profile: user }))))\n )\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 50 - }, - { - "name": "saveSettings$", - "defaultValue": "createEffect(() =>\n this.actions$.pipe(\n ofType(settingsSave),\n map(a => this.service.setUser('settingsSaved', a.isSet)),\n exhaustMap(() => this.service.setProfile().pipe(map(user => loadProfileSuccess({ profile: user }))))\n )\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 66 - }, - { - "name": "saveTextarea$", - "defaultValue": "createEffect(() =>\n this.actions$.pipe(\n ofType(setTextareaHeight),\n exhaustMap(a =>\n this.service.setTextareaProfile(a).pipe(map(user => loadProfileSuccess({ profile: user })))\n )\n )\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 57 - } - ], - "methods": [], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\nimport { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props } from '@ngrx/store';\nimport { exhaustMap, map } from 'rxjs/operators';\n\nimport { IUser, ProfileService } from './profile.service';\n\nexport type ProfileState = IUser;\n\nconst InitState = {\n username: '',\n change_password: '',\n profile: {\n textarea: {},\n settingsSaved: false,\n },\n};\n\nexport const loadProfile = createAction('[Profile] Load');\nexport const clearProfile = createAction('[Profile] ClearProfile');\nexport const loadProfileSuccess = createAction('[Profile] LoadSuccess', props<{ profile: IUser }>());\nexport const setTextareaHeight = createAction('[Profile] SetTextareaHeight', props<{ key: string; value: number }>());\nexport const settingsSave = createAction('[Profile] SettingsSave', props<{ isSet: boolean }>());\n\nconst reducer = createReducer(\n InitState,\n on(loadProfileSuccess, (state, { profile }) => ({ ...profile })),\n on(setTextareaHeight, state => ({ ...state })),\n on(settingsSave, (state, { isSet }) => ({ ...state, isSet })),\n on(clearProfile, () => InitState)\n);\n\nexport function profileReducer(state: ProfileState, action: Action) {\n return reducer(state, action);\n}\n\n@Injectable()\nexport class ProfileEffects {\n load$ = createEffect(() =>\n this.actions$.pipe(\n ofType(loadProfile),\n exhaustMap(() => this.service.getProfile().pipe(map(user => loadProfileSuccess({ profile: user }))))\n )\n );\n\n saveTextarea$ = createEffect(() =>\n this.actions$.pipe(\n ofType(setTextareaHeight),\n exhaustMap(a =>\n this.service.setTextareaProfile(a).pipe(map(user => loadProfileSuccess({ profile: user })))\n )\n )\n );\n\n saveSettings$ = createEffect(() =>\n this.actions$.pipe(\n ofType(settingsSave),\n map(a => this.service.setUser('settingsSaved', a.isSet)),\n exhaustMap(() => this.service.setProfile().pipe(map(user => loadProfileSuccess({ profile: user }))))\n )\n );\n\n constructor(private actions$: Actions, private service: ProfileService) {}\n}\n\nexport const getProfileSelector = createFeatureSelector('profile');\n\nexport const getProfile = createSelector(\n getProfileSelector,\n state => state.profile\n);\n\nexport const getFirstAdminLogin = createSelector(\n getProfileSelector,\n state => state.username === 'admin' && !state.profile.settingsSaved\n);\n\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ProfileService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 72, - "jsdoctags": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ProfileService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "ProfileService", - "id": "injectable-ProfileService-c3fd6c62e5104c98cb26311a52248a16", - "file": "src/app/core/store/profile/profile.service.ts", - "properties": [ - { - "name": "user", - "deprecated": false, - "deprecationMessage": "", - "type": "IUser", - "optional": false, - "description": "", - "line": 40, - "modifierKind": [ - 120 - ] - } - ], - "methods": [ - { - "name": "addUser", - "args": [ - { - "name": "user", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 79, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "user", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "emptyProfile", - "args": [], - "optional": false, - "returnType": "{ textarea: {}; settingsSaved: boolean; }", - "typeParameters": [], - "line": 52, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getProfile", - "args": [], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 44, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 122 - ] - }, - { - "name": "setLastViewedTask", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 74, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "setPassword", - "args": [ - { - "name": "password", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 83, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "password", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "setProfile", - "args": [], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 62, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "setTextareaProfile", - "args": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 67, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "setUser", - "args": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "string | boolean | literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 56, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "key", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "string | boolean | literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { HttpClient } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { environment } from '@env/environment';\nimport { Observable, throwError } from 'rxjs';\nimport { map, tap } from 'rxjs/operators';\n\nimport { AuthService } from '@app/core/auth/auth.service';\n\nconst PROFILE_LINK = `${environment.apiRoot}profile/`;\n\nexport interface LastViewedTask {\n id: number;\n}\n\nexport interface IProfile {\n textarea: { [key: string]: number };\n settingsSaved: boolean;\n lastViewedTask?: LastViewedTask;\n}\n\nexport interface IUser {\n username: string;\n change_password: string;\n profile: IProfile;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class ProfileService {\n private user: IUser;\n\n constructor(private http: HttpClient, private auth: AuthService) {}\n\n public getProfile(): Observable {\n const source$ = this.http.get(`${PROFILE_LINK}${this.auth.auth.login}/`).pipe(\n map(user => (!user.profile ? { ...user, profile: this.emptyProfile() } : user)),\n tap(user => (this.user = user))\n );\n return this.auth.auth.login ? source$ : throwError('Not authorized!');\n }\n\n emptyProfile() {\n return { textarea: {}, settingsSaved: false };\n }\n\n setUser(key: string, value: string | boolean | { [key: string]: number }) {\n const profile = { ...this.user.profile };\n profile[key] = value;\n this.user = { ...this.user, profile };\n }\n\n setProfile(): Observable {\n const { username, profile } = { ...this.user };\n return this.http.patch(`${PROFILE_LINK}${this.user.username}/`, { username, profile });\n }\n\n setTextareaProfile(data: { key: string; value: number }): Observable {\n const textarea = { ...this.user.profile.textarea };\n textarea[data.key] = data.value;\n this.setUser('textarea', textarea);\n return this.setProfile();\n }\n\n setLastViewedTask(id: number): Observable {\n this.setUser('lastViewedTask', { id });\n return this.setProfile();\n }\n\n addUser(user: { username: string; profile: string }): Observable {\n return this.http.post(`${PROFILE_LINK}`, user);\n }\n\n setPassword(password: string) {\n return this.http.patch(this.user.change_password, { password });\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "auth", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 40, - "jsdoctags": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "auth", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "ProviderService", - "id": "injectable-ProviderService-34845259b186f3eef0ef70c10ef515d3", - "file": "src/app/services/provider.service.ts", - "properties": [], - "methods": [ - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { EntityService } from '../abstract/entity-service';\nimport { Provider } from '../core/types';\nimport { environment } from '../../environments/environment';\nimport { ApiService } from '../core/api';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ProviderService extends EntityService {\n\n constructor(\n protected api: ApiService,\n ) {\n super(api);\n }\n\n get(\n id: number,\n params: { [key: string]: string } = {},\n ): Observable {\n return this.api.get(`${environment.apiRoot}provider/${id}/`, params);\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 12, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "EntityService", - "type": "injectable" - }, - { - "name": "RequestCacheService", - "id": "injectable-RequestCacheService-8a514e04e9e3c150b655bc69be645c5e", - "file": "src/app/core/http-interseptors/request-cache.service.ts", - "properties": [ - { - "name": "cache", - "defaultValue": "new Map()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 30 - } - ], - "methods": [ - { - "name": "get", - "args": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "HttpResponse | undefined", - "typeParameters": [], - "line": 34, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "put", - "args": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "response", - "type": "HttpResponse", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 48, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "response", - "type": "HttpResponse", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { HttpRequest, HttpResponse } from '@angular/common/http';\n\nconst maxAge = Number.MAX_VALUE; // maximum cache age (ms)\n\ninterface RequestCacheEntry {\n url: string;\n response: HttpResponse;\n lastRead: number;\n}\n\nexport abstract class RequestCache {\n abstract get(req: HttpRequest): HttpResponse | undefined;\n abstract put(req: HttpRequest, response: HttpResponse): void;\n}\n\n@Injectable()\nexport class RequestCacheService implements RequestCache {\n cache = new Map();\n\n constructor() {}\n\n get(req: HttpRequest): HttpResponse | undefined {\n const url = req.urlWithParams;\n const cached = this.cache.get(url);\n\n if (!cached) return undefined;\n\n const isExpired = cached.lastRead < Date.now() - maxAge;\n\n const expired = isExpired ? 'Expired ' : '';\n // this.messanger.add(new Message(`${expired}cached response for \"${url}\".`));\n\n return isExpired ? undefined : cached.response;\n }\n\n put(req: HttpRequest, response: HttpResponse): void {\n const url = req.urlWithParams;\n // this.messanger.add(new Message(`Caching response from \"${url}\".` ));\n\n const entry = { url, response, lastRead: Date.now() };\n this.cache.set(url, entry);\n\n const expired = Date.now() - maxAge;\n\n this.cache.forEach(c => {\n if (c.lastRead < expired) this.cache.delete(c.url);\n });\n\n // this.messanger.add(new Message(`Request cache size: ${this.cache.size}.`));\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [], - "line": 30 - }, - "type": "injectable" - }, - { - "name": "RouterEffects", - "id": "injectable-RouterEffects-304a79a3d828dbedba7025d23e3e563e", - "file": "src/app/core/store/router/router.effects.ts", - "properties": [ - { - "name": "navigate$", - "defaultValue": "this.actions$.pipe(\n ofType(RouterActions.GO),\n map((action: RouterActions.Go) => action.payload),\n tap(({ path, query: queryParams, extras }) => this.router.navigate(path, { queryParams, ...extras }))\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 22, - "decorators": [ - { - "name": "Effect", - "stringifiedArguments": "{dispatch: false}" - } - ] - }, - { - "name": "navigateBack$", - "defaultValue": "this.actions$.pipe(ofType(RouterActions.BACK), tap(() => this.location.back()))", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 29, - "decorators": [ - { - "name": "Effect", - "stringifiedArguments": "{dispatch: false}" - } - ] - }, - { - "name": "navigateForward$", - "defaultValue": "this.actions$.pipe(ofType(RouterActions.FORWARD), tap(() => this.location.forward()))", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 32, - "decorators": [ - { - "name": "Effect", - "stringifiedArguments": "{dispatch: false}" - } - ] - } - ], - "methods": [], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { Location } from '@angular/common';\nimport { Effect, Actions, ofType } from '@ngrx/effects';\nimport { map, tap } from 'rxjs/operators';\nimport * as RouterActions from './router.actions';\n\n@Injectable()\nexport class RouterEffects {\n @Effect({ dispatch: false })\n navigate$ = this.actions$.pipe(\n ofType(RouterActions.GO),\n map((action: RouterActions.Go) => action.payload),\n tap(({ path, query: queryParams, extras }) => this.router.navigate(path, { queryParams, ...extras }))\n );\n\n @Effect({ dispatch: false })\n navigateBack$ = this.actions$.pipe(ofType(RouterActions.BACK), tap(() => this.location.back()));\n\n @Effect({ dispatch: false })\n navigateForward$ = this.actions$.pipe(ofType(RouterActions.FORWARD), tap(() => this.location.forward()));\n\n constructor(private actions$: Actions, private router: Router, private location: Location) {}\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "location", - "type": "Location", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 32, - "jsdoctags": [ - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "location", - "type": "Location", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "SchemeService", - "id": "injectable-SchemeService-19b19308484527efdbe79aeeb38c9a3d", - "file": "src/app/shared/configuration/scheme/scheme.service.ts", - "properties": [], - "methods": [ - { - "name": "addControls", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "TValue | IValue", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "currentForm", - "type": "FormGroup | FormArray", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "opt", - "type": "IYContainer | IYField | (IYContainer | IYField)[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "type", - "type": "TNReq", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IControl", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "TValue | IValue", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "currentForm", - "type": "FormGroup | FormArray", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "opt", - "type": "IYContainer | IYField | (IYContainer | IYField)[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "type", - "type": "TNReq", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "addControlsDict", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "source", - "type": "TValue | IValue", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "currentForm", - "type": "FormArray", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "rules", - "type": "IYContainer[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IControl", - "typeParameters": [], - "line": 51, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "source", - "type": "TValue | IValue", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "currentForm", - "type": "FormArray", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "rules", - "type": "IYContainer[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "emptyValidator", - "args": [], - "optional": false, - "returnType": "() => any", - "typeParameters": [], - "line": 37, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "setCurrentForm", - "args": [ - { - "name": "type", - "type": "TNForm", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "parent", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "field", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 44, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "type", - "type": "TNForm", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "parent", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "field", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { AbstractControl, FormArray, FormControl, FormGroup, ValidatorFn } from '@angular/forms';\nimport { isObject } from '@app/core/types/func';\n\nimport { FieldService } from '../services/field.service';\nimport { IFieldOptions, TNForm, TNReq, TValue } from '../types';\nimport { IYContainer, IYField } from '../yspec/yspec.service';\n\nexport interface IValue {\n [key: string]: TValue;\n}\n\nexport interface IControl {\n name: string;\n type: TNForm;\n rules: IYField | IYContainer | (IYField | IYContainer)[];\n form: FormGroup | FormArray;\n value: IValue | TValue;\n parent: TNReq;\n}\n\n@Injectable()\nexport class SchemeService {\n constructor(private service: FieldService) {}\n\n emptyValidator() {\n // const isEmptyArray = (v: any) => (Array.isArray(v) && v.length ? v.some((a) => isEmptyValue(a)) : false);\n // const isEmptyObj = (v: any) => (isObject(v) && Object.keys(v).length ? Object.keys(v).some((a) => isEmptyValue(v[a])) : false);\n const isEmptyValue = (v: any) => !v || (Array.isArray(v) && !v.length) || (isObject(v) && !Object.keys(v).length);\n return (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (isEmptyValue(control.value) ? { isEmpty: true } : null);\n }\n\n setCurrentForm(type: TNForm, parent: FormGroup, field: IFieldOptions) {\n const v = field.required ? this.emptyValidator()() : null;\n const current = type === 'list' || type === 'dict' ? (type === 'list' ? new FormArray([], v) : new FormGroup({}, v)) : new FormControl('', v);\n parent.setControl(field.name, current);\n return current;\n }\n\n addControlsDict(name: string, source: TValue | IValue, currentForm: FormArray, rules: IYContainer[]): IControl {\n const value = !source ? rules.reduce((p, c) => ({ ...p, [c.name]: '' }), {}) : source;\n\n const checkValue = () => {\n if (Array.isArray(rules)) {\n if (Array.isArray(value)) {\n return rules.some((a) => a.name === value[0]);\n } else if (typeof value === 'object') {\n return Object.keys(value).every((x) => rules.some((a) => a.name === x));\n }\n }\n };\n\n if (checkValue()) {\n const form = new FormGroup({});\n currentForm.push(form);\n return { name, value, type: 'dict', rules, form, parent: 'list' };\n }\n }\n\n addControls(name: string, value: TValue | IValue, currentForm: FormGroup | FormArray, opt: IYContainer | IYField | (IYContainer | IYField)[], type: TNReq): IControl {\n const rules = Array.isArray(opt) ? opt.find((a) => a.name === name) : opt;\n if (!rules) return;\n let form = currentForm;\n if (rules.type !== 'list' && rules.type !== 'dict') {\n const { validator, controlType } = rules as IYField;\n if (Array.isArray(currentForm.controls)) {\n name = currentForm.controls.length.toString();\n (currentForm as FormArray).push(new FormControl(value || '', this.service.setValidator({ validator, controlType })));\n } else (currentForm as FormGroup).addControl(rules.name, new FormControl(rules.type !== 'bool' ? value || '' : value, this.service.setValidator({ validator, controlType })));\n } else {\n form = rules.type === 'list' ? new FormArray([]) : new FormGroup({});\n (currentForm as FormGroup).addControl(rules.name, form);\n }\n\n return { name, value, type: rules.type, rules, form, parent: type };\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 34, - "jsdoctags": [ - { - "name": "service", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "ServiceComponentService", - "id": "injectable-ServiceComponentService-372f8ea265a388d8827460f255dd4970", - "file": "src/app/services/service-component.service.ts", - "properties": [], - "methods": [ - { - "name": "entityStatusTreeToStatusTree", - "args": [ - { - "name": "input", - "type": "HostComponentStatusTree", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "clusterId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "StatusTree[]", - "typeParameters": [], - "line": 33, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "input", - "type": "HostComponentStatusTree", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "clusterId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 22, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - }, - { - "name": "getStatusTree", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { ApiService } from '@app/core/api';\nimport { IServiceComponent } from '@app/models/service-component';\nimport { EntityService } from '@app/abstract/entity-service';\nimport { environment } from '@env/environment';\nimport { HavingStatusTreeAbstractService } from '@app/abstract/having-status-tree.abstract.service';\nimport { HostComponentStatusTree, StatusTree } from '@app/models/status-tree';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ServiceComponentService extends EntityService implements HavingStatusTreeAbstractService {\n\n constructor(\n protected api: ApiService,\n ) {\n super(api);\n }\n\n get(\n id: number,\n params: { [key: string]: string } = {},\n ): Observable {\n return this.api.get(`${environment.apiRoot}component/${id}`, params);\n }\n\n getStatusTree(id: number): Observable {\n return this.api.get(`${environment.apiRoot}component/${id}/status/`);\n }\n\n entityStatusTreeToStatusTree(input: HostComponentStatusTree, clusterId: number): StatusTree[] {\n return [{\n subject: {\n id: input.id,\n name: input.name,\n status: input.status,\n },\n children: input.hosts.map(host => ({\n subject: {\n id: host.id,\n name: host.name,\n status: host.status,\n link: (id) => ['/cluster', clusterId.toString(), 'host', id.toString(), 'status'],\n },\n children: [],\n })),\n }];\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 14, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "EntityService", - "type": "injectable" - }, - { - "name": "ServiceService", - "id": "injectable-ServiceService-3ae1355d8fa3a8fddd7e8d65fa884fea", - "file": "src/app/services/service.service.ts", - "properties": [], - "methods": [ - { - "name": "entityStatusTreeToStatusTree", - "args": [ - { - "name": "input", - "type": "ServiceStatusTree", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "clusterId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "StatusTree[]", - "typeParameters": [], - "line": 33, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "input", - "type": "ServiceStatusTree", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "clusterId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 22, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - }, - { - "name": "getStatusTree", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { ApiService } from '@app/core/api';\nimport { EntityService } from '@app/abstract/entity-service';\nimport { environment } from '@env/environment';\nimport { Service } from '@app/core/types';\nimport { HavingStatusTreeAbstractService } from '@app/abstract/having-status-tree.abstract.service';\nimport { ServiceStatusTree, StatusTree } from '@app/models/status-tree';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ServiceService extends EntityService implements HavingStatusTreeAbstractService {\n\n constructor(\n protected api: ApiService,\n ) {\n super(api);\n }\n\n get(\n id: number,\n params: { [key: string]: string } = {},\n ): Observable {\n return this.api.get(`${environment.apiRoot}service/${id}/`, params);\n }\n\n getStatusTree(id: number): Observable {\n return this.api.get(`${environment.apiRoot}service/${id}/status/`);\n }\n\n entityStatusTreeToStatusTree(input: ServiceStatusTree, clusterId: number): StatusTree[] {\n return [{\n subject: {\n id: input.id,\n name: input.name,\n status: input.status,\n },\n children: input.hc.map(hc => ({\n subject: {\n id: hc.id,\n name: hc.name,\n status: hc.status,\n },\n children: hc.hosts.map(host => ({\n subject: {\n id: host.id,\n name: host.name,\n status: host.status,\n link: (id) => ['/cluster', clusterId.toString(), 'host', id.toString(), 'status'],\n },\n children: [],\n })),\n })),\n }];\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 14, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "EntityService", - "type": "injectable" - }, - { - "name": "SocketEffect", - "id": "injectable-SocketEffect-37d1cce6522c6f026fb9f5ca47d930ea", - "file": "src/app/core/store/sockets/socket.effect.ts", - "properties": [ - { - "name": "init$", - "defaultValue": "createEffect(\n () =>\n this.actions$.pipe(\n ofType(socketInit),\n exhaustMap(() => this.service.init())\n ),\n { dispatch: false }\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21 - } - ], - "methods": [], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\nimport { exhaustMap } from 'rxjs/operators';\n\nimport { socketInit } from './socket.reducer';\nimport { SocketService } from './socket.service';\n\n@Injectable()\nexport class SocketEffect {\n init$ = createEffect(\n () =>\n this.actions$.pipe(\n ofType(socketInit),\n exhaustMap(() => this.service.init())\n ),\n { dispatch: false }\n );\n \n constructor(private service: SocketService, private actions$: Actions) {}\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "SocketService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 28, - "jsdoctags": [ - { - "name": "service", - "type": "SocketService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "actions$", - "type": "Actions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "SocketListenerDirective", - "id": "injectable-SocketListenerDirective-fa0c54661488f8a796fa76d8835736e4", - "file": "src/app/shared/directives/socketListener.directive.ts", - "properties": [ - { - "name": "socket$", - "defaultValue": "this.socket.pipe(this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object))", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 24 - } - ], - "methods": [ - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "socketListener", - "args": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "startListenSocket", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Injectable, OnDestroy } from '@angular/core';\nimport { select, Store } from '@ngrx/store';\nimport { filter, tap } from 'rxjs/operators';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { EventMessage, getMessage, SocketState, clearMessages } from '@app/core/store';\n\n@Directive({\n selector: '[appBase]',\n})\n@Injectable()\nexport class SocketListenerDirective extends BaseDirective implements OnDestroy {\n socket$ = this.socket.pipe(this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object));\n\n constructor(private socket: Store) {\n super();\n }\n\n ngOnDestroy() {\n super.ngOnDestroy();\n this.socket.dispatch(clearMessages());\n }\n\n startListenSocket(): void {\n this.socket$.pipe(\n tap(m => this.socketListener(m))\n ).subscribe();\n }\n\n socketListener(m: EventMessage) {\n console.warn('No implemented socketListener method', m);\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 24, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "type": "injectable" - }, - { - "name": "SocketService", - "id": "injectable-SocketService-15d0ac49cf76acd9a282626b5dc0899d", - "file": "src/app/core/store/sockets/socket.service.ts", - "properties": [ - { - "name": "connectUrl", - "defaultValue": "environment.SERVER_URL_EVENT", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 24 - }, - { - "name": "socket", - "deprecated": false, - "deprecationMessage": "", - "type": "WebSocket", - "optional": false, - "description": "", - "line": 25 - } - ], - "methods": [ - { - "name": "init", - "args": [ - { - "name": "openStatus", - "type": "StatusType", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "'open'" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "openStatus", - "type": "StatusType", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "'open'", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { AuthService } from '@app/core/auth/auth.service';\nimport { environment } from '@env/environment';\nimport { Store } from '@ngrx/store';\nimport { EMPTY, of } from 'rxjs';\n\nimport { socketClose, socketOpen, socketResponse, SocketState, StatusType } from './socket.reducer';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class SocketService {\n connectUrl = environment.SERVER_URL_EVENT;\n socket: WebSocket;\n\n constructor(private store: Store, private auth: AuthService) {}\n\n init(openStatus: StatusType = 'open') {\n if (!this.auth.token) {\n console.warn('Socket can not connect. Token is failed.');\n return EMPTY;\n }\n\n this.socket = new WebSocket(this.connectUrl, ['adcm', `${this.auth.token}`]);\n\n this.socket.onopen = () => this.store.dispatch(socketOpen({ status: openStatus }));\n this.socket.onclose = () => this.store.dispatch(socketClose({ status: 'close' }));\n this.socket.onmessage = (response: { data: string }) => this.store.dispatch(socketResponse({ message: JSON.parse(response.data) }));\n\n return of(this.socket);\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "auth", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 25, - "jsdoctags": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "auth", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "StackService", - "id": "injectable-StackService-5876b67a9b79a70b8902021989c10a47", - "file": "src/app/core/services/stack.service.ts", - "properties": [], - "methods": [ - { - "name": "fromStack", - "args": [ - { - "name": "name", - "type": "StackInfo", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "param", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [ - "T" - ], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "StackInfo", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "param", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "upload", - "args": [ - { - "name": "output", - "type": "FormData[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 40, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "output", - "type": "FormData[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { ApiService } from '@app/core/api';\nimport { ApiState, getStack } from '@app/core/store';\nimport { Bundle } from '@app/core/types';\nimport { environment } from '@env/environment';\nimport { select, Store } from '@ngrx/store';\nimport { combineLatest, Observable } from 'rxjs';\nimport { filter, map, mergeMap, switchMap } from 'rxjs/operators';\nimport { ListResult } from '@app/models/list-result';\n\nexport type StackInfo = 'cluster' | 'host' | 'provider' | 'service' | 'bundle';\n\nconst UPLOAD_URL = `${environment.apiRoot}stack/upload/`,\n LOAD_URL = `${environment.apiRoot}stack/load/`;\n\n@Injectable({ providedIn: 'root' })\nexport class StackService {\n constructor(private api: ApiService, private store: Store) {}\n\n fromStack(name: StackInfo, param?: { [key: string]: string | number }): Observable {\n const params = Object.keys(param).reduce((p, c) => ({ ...p, [c]: param[c] }), {});\n return this.store.pipe(\n select(getStack),\n filter((a) => a && !!Object.keys(a).length),\n switchMap((s) => this.api.get>(s[name], params).pipe(map((a) => a.results)))\n );\n }\n\n upload(output: FormData[]) {\n const item = (form: FormData) => {\n return this.api.post(UPLOAD_URL, form).pipe(\n mergeMap(() => this.api.post(LOAD_URL, { bundle_file: (form.get('file') as File).name }))\n );\n };\n return combineLatest(output.map((o) => item(o)));\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 28, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "StatsService", - "id": "injectable-StatsService-4f4a6bd7d5a030ff0f14e7faff1e5be6", - "file": "src/app/services/stats.service.ts", - "properties": [], - "methods": [ - { - "name": "tasks", - "args": [ - { - "name": "lastTaskId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 22, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "lastTaskId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Observable } from 'rxjs';\n\nimport { environment } from '@env/environment';\n\nexport interface Stats {\n failed: number;\n success: number;\n running: number;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class StatsService {\n\n constructor(\n private http: HttpClient,\n ) { }\n\n tasks(lastTaskId?: number): Observable {\n return this.http.get(`${environment.apiRoot}/stats/task/${lastTaskId || 1}/`);\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 16, - "jsdoctags": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "StatusService", - "id": "injectable-StatusService-f4479ba0b2419eab84b2be3a638f7417", - "file": "src/app/shared/components/status/status.service.ts", - "properties": [], - "methods": [ - { - "name": "getAllClusterStatus", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 72, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getClusterById", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 68, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getComponentsOnly", - "args": [ - { - "name": "a", - "type": "[IAllStatus, HostComponent[]]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "host_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 58, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "a", - "type": "[IAllStatus, HostComponent[]]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "host_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getHostComponents", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 43, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getHostcomponentStatus", - "args": [ - { - "name": "k", - "type": "HostComponent", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "all", - "type": "IAllStatus", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 53, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "k", - "type": "HostComponent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "all", - "type": "IAllStatus", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getServiceComponentsByCluster", - "args": [ - { - "name": "cluster", - "type": "ICluster", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "cluster", - "type": "ICluster", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getStatusInfo", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hostcomponent_link", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 37, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hostcomponent_link", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { combineLatest, Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { ApiService } from '@app/core/api';\nimport { IComponent, Host, HostComponent } from '@app/core/types';\nimport { ICluster } from '@app/models/cluster';\n\ninterface IStatus {\n [key: number]: { status: number };\n}\n\nexport interface IAllStatus {\n hosts: IStatus;\n services: { details: [{ host: string | number; component: string | number; status: number }]; status: number }[];\n components: IStatus;\n status: number;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class StatusService {\n constructor(private api: ApiService) { }\n\n getStatusInfo(id: number, hostcomponent_link: string) {\n const statuses$ = this.getAllClusterStatus(id),\n host_components$ = this.getHostComponents(hostcomponent_link);\n return combineLatest([statuses$, host_components$]);\n }\n\n getHostComponents(url: string): Observable {\n return this.api\n .get<{ host: Host[]; hc: HostComponent[]; component: IComponent[] }>(url)\n .pipe(map((a) => a.hc.map((hc) => ({ ...hc, monitoring: a.component.find((b) => b.id === hc.component_id).monitoring }))));\n }\n\n getServiceComponentsByCluster(cluster: ICluster, service_id?: number): Observable {\n return this.api.get(cluster.status_url).pipe(map((s) => s.filter((se) => (service_id ? se.service_id === service_id : true))));\n }\n\n getHostcomponentStatus(k: HostComponent, all: IAllStatus) {\n const c = all.services[k.service_id]?.details.find((e) => +e.host === k.host_id && +e.component === k.component_id);\n return c ? c.status : null;\n }\n\n getComponentsOnly(a: [IAllStatus, HostComponent[]], host_id?: number) {\n const all: IAllStatus = a[0],\n hc: HostComponent[] = a[1];\n return hc\n .filter((h) => (host_id ? host_id === h.host_id : true))\n .reduce((acc, cur) => (!acc.some((c) => c.host_id === cur.host_id && c.service_id === cur.service_id) ? [...acc, cur] : acc), [])\n .map((k) => ({ ...k, status: this.getHostcomponentStatus(k, all) }))\n .filter((b) => b.status !== 0);\n }\n\n getClusterById(id: number) {\n return this.api.getOne('cluster', id);\n }\n\n getAllClusterStatus(id: number) {\n return this.api.get(`/status/api/v1/cluster/${id}/`);\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 34, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "TakeService", - "id": "injectable-TakeService-ad30c16a88a98b3abb08b9a62424a5ed", - "file": "src/app/shared/host-components-map/take.service.ts", - "properties": [], - "methods": [ - { - "name": "clearDependencies", - "args": [ - { - "name": "comp", - "type": "CompTile", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "state", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 210, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "comp", - "type": "CompTile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "state", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "dialog4Requires", - "args": [ - { - "name": "model", - "type": "IRequires[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 304, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "model", - "type": "IRequires[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "divorce", - "args": [ - { - "name": "both", - "type": "[CompTile, HostTile]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "state", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 233, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "both", - "type": "[CompTile, HostTile]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "state", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "fillComponent", - "args": [ - { - "name": "pc", - "type": "IComponent[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ap", - "type": "IActionParameter[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 100, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "pc", - "type": "IComponent[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "ap", - "type": "IActionParameter[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "fillHost", - "args": [ - { - "name": "hosts", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ap", - "type": "IActionParameter[]", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "HostTile[]", - "typeParameters": [], - "line": 96, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nMapping backend source hosts to detect `disabled` properties based on action parameters, if present\n", - "description": "

Mapping backend source hosts to detect disabled properties based on action parameters, if present

\n", - "jsdoctags": [ - { - "name": "hosts", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "ap", - "type": "IActionParameter[]", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "formFill", - "args": [ - { - "name": "components", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hosts", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 130, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "components", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hosts", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "handleLink", - "args": [ - { - "name": "link", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "target", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "state", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "load", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 267, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "link", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "target", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "state", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "load", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "load", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 81, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "next", - "args": [ - { - "name": "target", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "stream", - "type": "IStream", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "state", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "load", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 246, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "target", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "stream", - "type": "IStream", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "state", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "load", - "type": "StatePost", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "save", - "args": [ - { - "name": "cluster_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hostcomponent", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hc", - "type": "Post[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 85, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "cluster_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hostcomponent", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hc", - "type": "Post[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "setFormValue", - "args": [ - { - "name": "c", - "type": "CompTile", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 202, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "c", - "type": "CompTile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "form", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "setRelations", - "args": [ - { - "name": "rel", - "type": "Post[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ap", - "type": "IActionParameter[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 110, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "rel", - "type": "Post[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cs", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hs", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "ap", - "type": "IActionParameter[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "validateConstraints", - "args": [ - { - "name": "component", - "type": "CompTile", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hostLength", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "() => any", - "typeParameters": [], - "line": 153, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\n```\nhttps://docs.arenadata.io/adcm/sdk/config.html#components\n[1] – exactly once component shoud be installed;\n[0,1] – one or zero component shoud be installed;\n[1,2] – one or two component shoud be installed;\n[0,+] – zero or any more component shoud be installed (default value);\n[1,odd] – one or more component shoud be installed; total amount should be odd\n[0,odd] – zero or more component shoud be installed; if more than zero, total amount should be odd\n[odd] – the same as [1,odd]\n[1,+] – one or any more component shoud be installed;\n[+] – component shoud be installed on all hosts of cluster.\n```\n", - "description": "
https://docs.arenadata.io/adcm/sdk/config.html#components\n[1] – exactly once component shoud be installed;\n[0,1] – one or zero component shoud be installed;\n[1,2] – one or two component shoud be installed;\n[0,+] – zero or any more component shoud be installed (default value);\n[1,odd] – one or more component shoud be installed; total amount should be odd\n[0,odd] – zero or more component shoud be installed; if more than zero, total amount should be odd\n[odd] – the same as [1,odd]\n[1,+] – one or any more component shoud be installed;\n[+] – component shoud be installed on all hosts of cluster.
", - "jsdoctags": [ - { - "name": "component", - "type": "CompTile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hostLength", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { FormControl, FormGroup, ValidationErrors } from '@angular/forms';\nimport { MatDialog } from '@angular/material/dialog';\nimport { ApiService } from '@app/core/api';\nimport { IComponent, IActionParameter, IRequires } from '@app/core/types';\nimport { filter, map, switchMap, take } from 'rxjs/operators';\n\nimport { AddService } from '../add-component/add.service';\nimport { DialogComponent } from '../components';\nimport { DependenciesComponent } from './dependencies.component';\nimport { CompTile, TConstraint, HostTile, IRawHosComponent, IStream, Post, StatePost, Tile } from './types';\n\nexport const getSelected = (from: Tile[]): Tile => from.find((a) => a.isSelected);\n\nconst isShrink = (ap: IActionParameter[]): boolean => ap.every((a) => a.action === 'remove');\n\nconst isExpand = (ap: IActionParameter[]): boolean => ap.every((a) => a.action === 'add');\n\nconst accord = (a: IActionParameter): ((b: CompTile) => boolean) => (b: CompTile): boolean =>\n b.component === `${a.service}/${a.component}`;\n\nexport const isExist = (rel: CompTile[], ap: IActionParameter[]): boolean =>\n isShrink(ap) ? ap.some((a) => rel.some(accord(a))) : ap.every((a) => rel.some(accord(a)));\n\nexport const disableHost = (h: HostTile, ap: IActionParameter[]): boolean =>\n ap ? (isExist(h.relations as CompTile[], ap) ? isExpand(ap) : isShrink(ap)) : false;\n\n//#region user click\n\nconst checkConstraint = (c: TConstraint, r: number): boolean => {\n if (!c?.length) return true;\n const v = c[c.length - 1];\n return v === '+' || v === 'odd' || v > r || v === 'depend';\n};\n\nconst flag = (host_id: number, com: CompTile, load: StatePost): boolean =>\n load.data.some((a) => a.component_id === com.id && a.service_id === com.service_id && a.host_id === host_id);\n\nconst checkActions = (host_id: number, com: CompTile, action: 'add' | 'remove', load: StatePost): boolean => {\n if (com.actions?.length) {\n if (action === 'remove') return flag(host_id, com, load) ? com.actions.some((a) => a === 'remove') : true;\n if (action === 'add') return flag(host_id, com, load) ? true : com.actions.some((a) => a === 'add');\n } else return true;\n};\n\nconst findDependencies = (c: CompTile, cs: CompTile[]): CompTile[] => {\n const r =\n c.requires?.reduce<{ prototype_id: number }[]>(\n (p, a) => [...p, ...a.components.map((b) => ({ prototype_id: b.prototype_id }))],\n []\n ) || [];\n return cs.filter((a) => r.some((b) => b.prototype_id === a.prototype_id));\n};\n\nconst checkDependencies = (c: CompTile, cs: CompTile[]): void =>\n findDependencies(c, cs).forEach((a) => (a.limit = a.limit ? [...a.limit, 'depend'] : ['depend']));\n\nconst checkRequires = (component: CompTile, cs: CompTile[]): IRequires[] =>\n component.requires.reduce(\n (p, c) => (c.components.every((a) => cs.some((b) => b.prototype_id === a.prototype_id)) ? p : [...p, c]),\n []\n );\n\n//#endregion\n@Injectable()\nexport class TakeService {\n constructor(private api: ApiService, private dialog: MatDialog, private add: AddService) {}\n\n //#region ----- HttpClient ------\n load(url: string) {\n return this.api.get(url);\n }\n\n save(cluster_id: number, hostcomponent: string, hc: Post[]) {\n const send = { cluster_id, hc };\n return this.api.post(hostcomponent, send).pipe(take(1));\n }\n //#endregion\n\n //#region after a successful download, run and fill in\n\n /**\n * Mapping backend source hosts to detect `disabled` properties based on action parameters, if present\n */\n fillHost(hosts: HostTile[], ap?: IActionParameter[]): HostTile[] {\n return hosts.map((h) => ({ ...h, disabled: disableHost(h, ap) }));\n }\n\n fillComponent(pc: IComponent[], ap: IActionParameter[]) {\n return pc.map(\n (c) =>\n new CompTile(\n c,\n ap ? ap.filter((a) => a.service === c.service_name && a.component === c.name).map((b) => b.action) : null\n )\n );\n }\n\n setRelations(rel: Post[], cs: CompTile[], hs: HostTile[], ap: IActionParameter[]) {\n rel.forEach((p) => {\n const host = hs.find((h) => h.id === p.host_id),\n component = cs.find((s) => s.id === p.component_id);\n if (host && component) {\n if (ap) {\n component.relations = [...component.relations, host];\n const clone_component = { ...component };\n clone_component.disabled = component.actions.every((k) => k !== 'remove');\n host.relations = [...host.relations, clone_component];\n } else {\n host.relations = [...host.relations, component];\n component.relations = [...component.relations, host];\n }\n }\n });\n }\n //#endregion\n\n //#region FormGrop and validation for Components\n formFill(components: CompTile[], hosts: HostTile[], form: FormGroup) {\n components.map((a) =>\n form.addControl(\n `${a.service_id}/${a.id}`,\n new FormControl(a.relations.length, this.validateConstraints(a, hosts.length))\n )\n );\n }\n\n /**\n * ```\n https://docs.arenadata.io/adcm/sdk/config.html#components\n [1] – exactly once component shoud be installed;\n [0,1] – one or zero component shoud be installed;\n [1,2] – one or two component shoud be installed;\n [0,+] – zero or any more component shoud be installed (default value);\n [1,odd] – one or more component shoud be installed; total amount should be odd\n [0,odd] – zero or more component shoud be installed; if more than zero, total amount should be odd\n [odd] – the same as [1,odd]\n [1,+] – one or any more component shoud be installed;\n [+] – component shoud be installed on all hosts of cluster.\n ```\n */\n validateConstraints(component: CompTile, hostLength: number) {\n const getError = (constraint: TConstraint, relations: HostTile[]) => {\n if (!constraint?.length) return null;\n const [a1, a2, a3] = constraint;\n const countRelations = relations.length;\n const depend = () =>\n relations.some((a) => a.relations.some((b) => b.id === component.id))\n ? null\n : 'Must be installed because it is a dependency of another component';\n if (a3 && a3 === 'depend') return depend();\n else if (a2) {\n switch (a2) {\n case 'depend':\n return depend();\n case 'odd':\n return countRelations % 2 && countRelations >= a1\n ? null\n : a1 === 0\n ? 'Total amount should be odd.'\n : `Must be installed at least ${a1} components. Total amount should be odd.`;\n case '+':\n default:\n return countRelations < a1 ? `Must be installed at least ${a1} components.` : null;\n }\n } else {\n switch (a1) {\n case 0:\n return null;\n case 'depend':\n return depend();\n case '+':\n return countRelations < hostLength ? 'Component should be installed on all hosts of cluster.' : null;\n case 'odd':\n return countRelations % 2 ? null : 'One or more component should be installed. Total amount should be odd.';\n default:\n return countRelations !== a1 ? `Exactly ${a1} component should be installed` : null;\n }\n }\n };\n return (): ValidationErrors => {\n const { limit, relations } = component;\n if (limit) {\n const error = getError(limit, relations);\n return error ? { error } : null;\n }\n return null;\n };\n }\n\n setFormValue(c: CompTile, form: FormGroup) {\n form.controls[`${c.service_id}/${c.id}`].setValue(c.relations);\n }\n\n //#endregion\n\n //#region Removing links and dependencies\n\n clearDependencies(comp: CompTile, state: StatePost, cs: CompTile[], hs: HostTile[], form: FormGroup) {\n const getLimitsFromState = (prototype_id: number) => cs.find((b) => b.prototype_id === prototype_id).limit;\n if (comp.requires?.length) {\n findDependencies(comp, cs).forEach((a) => {\n a.limit = getLimitsFromState(a.prototype_id);\n a.notification = '';\n });\n\n state.data.map((a) =>\n checkDependencies(\n cs.find((b) => b.id === a.component_id),\n cs\n )\n );\n\n form.reset();\n this.formFill(cs, hs, form);\n }\n }\n\n //#endregion\n\n //#region handler user events\n divorce(both: [CompTile, HostTile], cs: CompTile[], hs: HostTile[], state: StatePost, form: FormGroup) {\n const [component, host] = both;\n\n component.isLink = false;\n component.relations = component.relations.filter((r) => r.id !== host.id);\n host.isLink = false;\n host.relations = host.relations.filter((r) => r.id !== component.id);\n\n state.delete(new Post(host.id, component.service_id, component.id));\n this.clearDependencies(component, state, cs, hs, form);\n this.setFormValue(component, form);\n }\n\n next(\n target: Tile,\n stream: IStream,\n cs: CompTile[],\n hs: HostTile[],\n state: StatePost,\n load: StatePost,\n form: FormGroup\n ) {\n stream.linkSource.forEach((s) => (s.isLink = false));\n if (stream.selected) stream.selected.isSelected = false;\n\n if (stream.link) this.handleLink(stream.link, target, state, cs, hs, load, form);\n else if (stream.selected !== target) {\n target.isSelected = true;\n target.relations.forEach(\n (e) => (stream.linkSource.find((s) => s.name === e.name && s.id === e.id).isLink = true)\n );\n }\n }\n\n handleLink(\n link: Tile,\n target: Tile,\n state: StatePost,\n cs: CompTile[],\n hs: HostTile[],\n load: StatePost,\n form: FormGroup\n ) {\n const isComp = target instanceof CompTile;\n const component = (isComp ? target : link) as CompTile;\n const host = isComp ? link : target;\n\n if (link.relations.find((e) => e.id === target.id)) {\n if (checkActions(host.id, component, 'remove', load)) this.divorce([component, host], cs, hs, state, form);\n return;\n } else if (checkConstraint(component.limit, component.relations.length)) {\n if (!checkActions(host.id, component, 'add', load)) return;\n if (component.requires?.length) {\n const requires = checkRequires(component, cs);\n if (requires.length) {\n this.dialog4Requires(requires);\n return;\n } else {\n checkDependencies(component, cs);\n form.reset();\n this.formFill(cs, hs, form);\n }\n }\n link.relations.push(target);\n target.relations.push(link);\n target.isLink = true;\n state.add(new Post(host.id, component.service_id, component.id));\n }\n this.setFormValue(component, form);\n }\n\n dialog4Requires(model: IRequires[]) {\n this.dialog\n .open(DialogComponent, {\n data: {\n title: 'This component cannot be installed without the following dependencies.',\n component: DependenciesComponent,\n model,\n controls: ['Install All', 'It is clear'],\n },\n })\n .beforeClosed()\n .pipe(\n filter((a) => a),\n map((_) => model.map((a) => ({ prototype_id: a.prototype_id }))),\n switchMap((result) => this.add.addService(result))\n )\n .subscribe();\n }\n //#endregion\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "add", - "type": "AddService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 77, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "add", - "type": "AddService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "TaskService", - "id": "injectable-TaskService-b0c22a173b4aa743a242886bef8a0b1b", - "file": "src/app/services/task.service.ts", - "properties": [], - "methods": [ - { - "name": "events", - "args": [ - { - "name": "eventFilter", - "type": "EventFilter", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "eventFilter", - "type": "EventFilter", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - }, - { - "name": "list", - "args": [ - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "Observable>", - "typeParameters": [], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { Store } from '@ngrx/store';\nimport { filter } from 'rxjs/operators';\nimport { Observable } from 'rxjs';\nimport { IListResult } from '@adwp-ui/widgets';\n\nimport { EventMessage, selectMessage, SocketState } from '@app/core/store';\nimport { EventableService, EventFilter } from '@app/models/eventable-service';\nimport { Task } from '@app/core/types';\nimport { ApiService } from '@app/core/api';\nimport { EntityService } from '@app/abstract/entity-service';\nimport { environment } from '@env/environment';\n\n@Injectable()\nexport class TaskService extends EntityService implements EventableService {\n\n constructor(\n private store: Store,\n protected api: ApiService,\n ) {\n super(api);\n }\n\n get(id: number, params: { [key: string]: string } = {}): Observable {\n return this.api.get(`${environment.apiRoot}task/${id}/`, params);\n }\n\n list(params: { [key: string]: string } = {}): Observable> {\n return this.api.get(`${environment.apiRoot}task/`, params);\n }\n\n events(eventFilter?: EventFilter): Observable {\n return this.store.pipe(\n selectMessage,\n filter(event => event?.object?.type === 'task'),\n filter(event => !eventFilter?.events || eventFilter.events.includes(event?.event)),\n );\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 15, - "jsdoctags": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "EntityService", - "type": "injectable" - }, - { - "name": "TooltipService", - "id": "injectable-TooltipService-0aa6c34b3edfef5dfe8a28653d0685f0", - "file": "src/app/shared/components/tooltip/tooltip.service.ts", - "properties": [ - { - "name": "position$", - "defaultValue": "this.positionSource.asObservable()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "positionSource", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 42, - "modifierKind": [ - 120 - ] - }, - { - "name": "timeOut", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 44 - } - ], - "methods": [ - { - "name": "hide", - "args": [ - { - "name": "withoutTimout", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "false" - }, - { - "name": "timeout", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "500" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 67, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "withoutTimout", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "false", - "tagName": { - "text": "param" - } - }, - { - "name": "timeout", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "500", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "isShow", - "args": [ - { - "name": "source", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "options", - "type": "TooltipDisplayOptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 52, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nTODO: show a tooltip if there is a condition\n\n", - "description": "

TODO: show a tooltip if there is a condition

\n", - "jsdoctags": [ - { - "name": "source", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "options", - "type": "TooltipDisplayOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "tagName": { - "pos": 1460, - "end": 1467, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "returns" - }, - "comment": "" - } - ] - }, - { - "name": "mouseEnterTooltip", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 76, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "mouseLeaveTooltip", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 80, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "show", - "args": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "source", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "options", - "type": "TooltipDisplayOptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 59, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "source", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "options", - "type": "TooltipDisplayOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { EventEmitter, Injectable } from '@angular/core';\nimport { BaseEntity } from '@app/core/types/api';\nimport { Subject } from 'rxjs';\n\nexport type ComponentName = 'issue' | 'status' | undefined;\nexport type PositionType = 'top' | 'right' | 'bottom' | 'left';\nexport interface TooltipOptions {\n event: MouseEvent;\n source: HTMLElement;\n options: TooltipDisplayOptions;\n}\n\nexport interface TooltipDisplayOptions {\n content: string | BaseEntity;\n componentName: ComponentName;\n position: PositionType;\n condition: boolean;\n}\n\n@Injectable()\nexport class ComponentData {\n path: string;\n current: any;\n emitter: EventEmitter;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class TooltipService {\n private positionSource = new Subject();\n position$ = this.positionSource.asObservable();\n timeOut: any;\n\n /**\n * TODO: show a tooltip if there is a condition\n *\n * @returns\n * @memberof TooltipComponent\n */\n isShow(source: HTMLElement, options: TooltipDisplayOptions) {\n if (options.condition) {\n return source.offsetWidth !== source.scrollWidth;\n }\n return true;\n }\n\n show(event: MouseEvent, source: HTMLElement, options: TooltipDisplayOptions) {\n this.positionSource.next();\n clearTimeout(this.timeOut);\n if (this.isShow(source, options)) {\n this.positionSource.next({ event, source, options });\n }\n }\n\n hide(withoutTimout = false, timeout = 500) {\n if (withoutTimout) {\n this.positionSource.next();\n return;\n }\n\n this.timeOut = setTimeout(() => this.positionSource.next(), timeout);\n }\n\n mouseEnterTooltip() {\n clearTimeout(this.timeOut);\n }\n\n mouseLeaveTooltip() {\n this.hide();\n }\n}\n", - "type": "injectable" - }, - { - "name": "UsersService", - "id": "injectable-UsersService-f509a3802cb60762fa3f0173645f0df6", - "file": "src/app/admin/users/users.service.ts", - "properties": [], - "methods": [ - { - "name": "addUser", - "args": [ - { - "name": "username", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "password", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 122 - ], - "jsdoctags": [ - { - "name": "username", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "password", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "changePassword", - "args": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 43, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 122 - ], - "jsdoctags": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clearUser", - "args": [ - { - "name": "user", - "type": "User", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 122 - ], - "jsdoctags": [ - { - "name": "user", - "type": "User", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getUsers", - "args": [], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 122 - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\n\nimport { environment } from '@env/environment';\nimport { Observable } from 'rxjs';\n\nexport interface User {\n username: string;\n password: string;\n confirm: string;\n change_password: string;\n}\n\nconst USER_LINK = `${environment.apiRoot}user/`;\n\n@Injectable()\nexport class UsersService {\n constructor(private http: HttpClient) {}\n\n public getUsers(): Observable {\n return this.http.get(USER_LINK);\n }\n\n public addUser(username: string, password: string): Observable {\n return this.http.post(USER_LINK, { username, password });\n }\n\n public clearUser(user: User): Observable {\n return this.http.delete(`${USER_LINK}${user.username}/`);\n }\n\n public changePassword(value: string, link: string): Observable {\n return this.http.patch(link, { 'password': value });\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 28, - "jsdoctags": [ - { - "name": "http", - "type": "HttpClient", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "injectable" - }, - { - "name": "YspecService", - "id": "injectable-YspecService-236ea186c68ad07c4fefea3b5504940f", - "file": "src/app/shared/configuration/yspec/yspec.service.ts", - "properties": [ - { - "name": "root", - "deprecated": false, - "deprecationMessage": "", - "type": "IYspec", - "optional": false, - "description": "", - "line": 94, - "modifierKind": [ - 120 - ] - } - ], - "methods": [ - { - "name": "build", - "args": [ - { - "name": "rule", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "'root'" - }, - { - "name": "path", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "[]" - } - ], - "optional": false, - "returnType": "IYContainer | IYField", - "typeParameters": [], - "line": 104, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "rule", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "'root'", - "tagName": { - "text": "param" - } - }, - { - "name": "path", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "[]", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "dict", - "args": [ - { - "name": "items", - "type": "IRoot", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "path", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IYContainer", - "typeParameters": [], - "line": 146, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "items", - "type": "IRoot", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "path", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "dict_key_selection", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 157, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "field", - "args": [ - { - "name": "field", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IYField", - "typeParameters": [], - "line": 121, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "field", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "findRule", - "args": [ - { - "name": "path", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 135, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "path", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "list", - "args": [ - { - "name": "item", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "path", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IYContainer", - "typeParameters": [], - "line": 141, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "path", - "type": "string[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "one_of", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 155, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { IRoot } from '@app/core/types';\n\nimport { IFieldOptions, controlType, IValidator, TNBase, TNReq } from '../types';\nimport { getControlType, getPattern } from '../services/field.service';\n\nexport type TMatch = TNBase | TNReq;\n\n/**\n *```\n {\n match: matchType;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot; // { [key: string]: string; }\n required_items?: string[];\n default_item?: string;\n }\n ```\n */\ninterface IYRoot {\n match: TMatch;\n selector?: string;\n variants?: { [key: string]: string };\n item?: string;\n items?: IRoot;\n required_items?: string[];\n default_item?: string;\n}\n\n/**\n *```\n {\n [key: string]: IYRoot;\n }\n ```\n */\nexport interface IYspec {\n [key: string]: IYRoot;\n}\n\n/**\n *```\n{\n name: string;\n path: string[];\n type: simpleType;\n controlType: controlType;\n validator: ValidatorInfo;\n}\n *```\n */\nexport interface IYField {\n name: string;\n path: string[];\n type: TNBase;\n controlType: controlType;\n validator: IValidator;\n}\n\n/**\n * ```\n * {\n * name: string;\n * type: reqursionType; // 'list' | 'dict'\n * options: IYContainer | IYField | (IYContainer | IYField)[];\n * }\n *```\n */\nexport interface IYContainer {\n name: string;\n type: TNReq;\n options: IYContainer | IYField | (IYContainer | IYField)[];\n}\n\nexport interface IStructure extends IFieldOptions {\n rules: { options: any; type: string; name: string };\n}\n\n@Injectable()\nexport class YspecService {\n private root: IYspec;\n\n set Root(yspec: IYspec) {\n this.root = yspec;\n }\n\n get Root() {\n return this.root;\n }\n\n build(rule = 'root', path: string[] = []): IYContainer | IYField {\n const { match, item, items } = this.Root[rule];\n\n switch (match) {\n case 'list':\n return this.list(item, path);\n case 'dict':\n return this.dict(items, path);\n // case 'one_of':\n // return this.one_of();\n // case 'dict_key_selection':\n // return this.dict_key_selection();\n default:\n return this.field({ type: match, path });\n }\n }\n\n field(field: { type: TNBase; path: string[] }): IYField {\n const name = field.path.reverse()[0];\n return {\n name,\n type: field.type,\n path: field.path,\n controlType: getControlType(field.type),\n validator: {\n required: this.findRule(field.path, 'required_items'),\n pattern: getPattern(field.type),\n },\n };\n }\n\n findRule(path: string[], name: string): boolean {\n const [field, parent] = path;\n const rule = this.Root[parent];\n return !!(rule && rule[name] && Array.isArray(rule[name]) && rule[name].includes(field));\n }\n\n list(item: string, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return { type: 'list', name, options: this.build(item, [...path, item]) };\n }\n\n dict(items: IRoot, path: string[]): IYContainer {\n const name = [...path].reverse()[0] || 'root';\n return {\n type: 'dict',\n name,\n options: Object.keys(items).map((item_name: string) => this.build(items[item_name], [...path, item_name])),\n };\n }\n\n one_of() {}\n\n dict_key_selection() {}\n}\n", - "accessors": { - "Root": { - "name": "Root", - "setSignature": { - "name": "Root", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "yspec", - "type": "IYspec", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 96, - "jsdoctags": [ - { - "name": "yspec", - "type": "IYspec", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "Root", - "type": "", - "returnType": "", - "line": 100 - } - } - }, - "type": "injectable" - } - ], - "guards": [ - { - "name": "AuthGuard", - "id": "injectable-AuthGuard-6aa37ec183c4f94a4c0c050edcaa66c0", - "file": "src/app/core/auth/auth.guard.ts", - "properties": [], - "methods": [ - { - "name": "canActivate", - "args": [ - { - "name": "route", - "type": "ActivatedRouteSnapshot", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "state", - "type": "RouterStateSnapshot", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "route", - "type": "ActivatedRouteSnapshot", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "state", - "type": "RouterStateSnapshot", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "canActivateChild", - "args": [ - { - "name": "route", - "type": "ActivatedRouteSnapshot", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "state", - "type": "RouterStateSnapshot", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 40, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "route", - "type": "ActivatedRouteSnapshot", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "state", - "type": "RouterStateSnapshot", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router';\nimport { select, Store } from '@ngrx/store';\nimport { Observable } from 'rxjs';\nimport { filter, tap } from 'rxjs/operators';\n\nimport { AuthService } from './auth.service';\nimport { authCheck, AuthState, isAuthenticated } from './auth.store';\n\n@Injectable()\nexport class AuthGuard implements CanActivate, CanActivateChild {\n constructor(private store: Store, private authService: AuthService, private router: Router) {}\n\n canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {\n this.store.dispatch(authCheck());\n const a$ = this.store.pipe(select(isAuthenticated));\n\n a$.pipe(\n filter(a => !a),\n tap(() => {\n this.authService.redirectUrl = state.url;\n this.router.navigate(['/login']);\n })\n ).subscribe();\n\n return a$;\n }\n\n canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {\n return this.canActivate(route, state);\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "authService", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 22, - "jsdoctags": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "authService", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "guard" - } - ], - "interceptors": [ - { - "name": "AuthInterceptor", - "id": "injectable-AuthInterceptor-8b2b2f6267e7f95cbf755655ac303c24", - "file": "src/app/core/http-interseptors/auth-interseptor.ts", - "properties": [], - "methods": [ - { - "name": "addAuthHeader", - "args": [ - { - "name": "request", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "HttpRequest", - "typeParameters": [], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "request", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "intercept", - "args": [ - { - "name": "request", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "next", - "type": "HttpHandler", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 37, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "request", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "next", - "type": "HttpHandler", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { HttpErrorResponse, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { Observable, throwError } from 'rxjs';\nimport { catchError, finalize } from 'rxjs/operators';\n\nimport { AuthService } from '@app/core/auth/auth.service';\nimport { ChannelService, keyChannelStrim, PreloaderService } from '../services';\n\nconst EXCLUDE_URLS = ['/api/v1/token/', '/assets/config.json'];\n\n@Injectable()\nexport class AuthInterceptor implements HttpInterceptor {\n constructor(private authService: AuthService, private preloader: PreloaderService, private router: Router, private channel: ChannelService) {}\n\n addAuthHeader(request: HttpRequest): HttpRequest {\n const token = this.authService.token;\n if (token && !EXCLUDE_URLS.includes(request.url)) {\n const setParams = request.url.split('?').find((a, i) => i === 1 && a.includes('noview')) ? {} : { view: 'interface' };\n request = request.clone({ setHeaders: { Authorization: `Token ${token}` }, setParams });\n }\n\n return request;\n }\n\n intercept(request: HttpRequest, next: HttpHandler): Observable {\n this.preloader.start();\n request = this.addAuthHeader(request);\n return next.handle(request).pipe(\n catchError((res: HttpErrorResponse) => {\n if (res.status === 401 || res.status === 403) {\n this.authService.redirectUrl = this.router.url;\n this.router.navigate(['/login']);\n }\n\n if (res.status === 500) this.router.navigate(['/500']);\n\n /** no need to show notification because error handling on landing page */\n const exclude = ['USER_NOT_FOUND', 'AUTH_ERROR', 'CONFIG_NOT_FOUND'];\n\n if (!exclude.includes(res.error.code)) {\n const message =\n res.statusText === 'Unknown Error' || res.statusText === 'Gateway Timeout'\n ? 'No connection to back-end. Check your internet connection.'\n : `[ ${res.statusText.toUpperCase()} ] ${res.error.code ? ` ${res.error.code} -- ${res.error.desc}` : res.error?.detail || ''}`;\n this.channel.next(keyChannelStrim.notifying, `${message}::error`);\n }\n\n return throwError(res);\n }),\n finalize(() => this.preloader.end())\n );\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "authService", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "preloader", - "type": "PreloaderService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 24, - "jsdoctags": [ - { - "name": "authService", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "preloader", - "type": "PreloaderService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "interceptor" - }, - { - "name": "CachingInterseptor", - "id": "injectable-CachingInterseptor-33c7f2d8238c74f2deb2b16860d97790", - "file": "src/app/core/http-interseptors/caching-interseptor.ts", - "properties": [], - "methods": [ - { - "name": "intercept", - "args": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "next", - "type": "HttpHandler", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 22, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "next", - "type": "HttpHandler", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { HttpInterceptor, HttpRequest, HttpResponse, HttpHandler, HttpHeaders, HttpEvent } from '@angular/common/http';\nimport { RequestCache } from './request-cache.service';\nimport { of, Observable } from 'rxjs';\nimport { startWith, tap } from 'rxjs/operators';\n\n@Injectable()\nexport class CachingInterseptor implements HttpInterceptor {\n constructor(private cache: RequestCache) {}\n\n intercept(req: HttpRequest, next: HttpHandler) {\n if (!isCachable(req)) return next.handle(req);\n\n const cachedResponse = this.cache.get(req);\n\n // cache-then-refresh\n if (req.headers.get('x-refresh')) {\n const results$ = sendRequest(req, next, this.cache);\n return cachedResponse ? results$.pipe(startWith(cachedResponse)) : results$;\n }\n\n return cachedResponse ? of(cachedResponse) : sendRequest(req, next, this.cache);\n }\n}\n\nfunction isCachable(req: HttpRequest) {\n const method = req.method,\n url = req.url;\n return req.params.get('c') ? true : false;\n}\n\nfunction sendRequest(req: HttpRequest, next: HttpHandler, cache: RequestCache): Observable> {\n const noHeaderClone = req.clone({ headers: new HttpHeaders() });\n\n return next.handle(noHeaderClone).pipe(\n tap(event => {\n if (event instanceof HttpResponse) cache.put(req, event);\n })\n );\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "cache", - "type": "RequestCache", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 19, - "jsdoctags": [ - { - "name": "cache", - "type": "RequestCache", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "type": "interceptor" - } - ], - "classes": [ - { - "name": "AdwpBaseListDirective", - "id": "class-AdwpBaseListDirective-4b89898f1052fa2db6eb6d952db555cf", - "file": "src/app/abstract-directives/adwp-base-list.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { BehaviorSubject } from 'rxjs';\nimport { Paging } from '@adwp-ui/widgets';\nimport { Sort } from '@angular/material/sort';\nimport { ParamMap } from '@angular/router';\nimport { Store } from '@ngrx/store';\n\nimport { BaseListDirective } from '@app/shared/components/list/base-list.directive';\nimport { TypeName } from '@app/core/types';\nimport { ListDirective } from '@app/abstract-directives/list.directive';\nimport { ListService } from '@app/shared/components/list/list.service';\nimport { SocketState } from '@app/core/store';\n\nexport class AdwpBaseListDirective extends BaseListDirective {\n\n paging: BehaviorSubject;\n sorting: BehaviorSubject = new BehaviorSubject(null);\n\n constructor(\n protected parent: ListDirective,\n protected service: ListService,\n protected store: Store,\n ) {\n super(parent, service, store);\n }\n\n checkType(typeName: string, referenceTypeName: TypeName): boolean {\n if (referenceTypeName === 'servicecomponent') {\n return typeName === 'component';\n }\n\n return (referenceTypeName ? referenceTypeName.split('2')[0] : referenceTypeName) === typeName;\n }\n\n routeListener(limit: number, page: number, ordering: string, params: ParamMap) {\n this.paging.next({ pageIndex: page + 1, pageSize: limit });\n if (ordering) {\n const direction = ordering[0] === '-' ? 'desc' : 'asc';\n const active = ordering[0] === '-' ? ordering.substr(1) : ordering;\n this.sorting.next({ direction, active });\n }\n\n this.listParams = params;\n this.refresh();\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "parent", - "type": "ListDirective", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 16, - "jsdoctags": [ - { - "name": "parent", - "type": "ListDirective", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "paging", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 15 - }, - { - "name": "sorting", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 16 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 46, - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "limit", - "defaultValue": "10", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 50, - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "listParams", - "deprecated": false, - "deprecationMessage": "", - "type": "ParamMap", - "optional": false, - "description": "", - "line": 49, - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "reload", - "deprecated": false, - "deprecationMessage": "", - "type": "function", - "optional": false, - "description": "", - "line": 53, - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "type": "Entities", - "optional": false, - "description": "", - "line": 48, - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "socket$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 45, - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "typeName", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 51, - "inheritance": { - "file": "BaseListDirective" - } - } - ], - "methods": [ - { - "name": "checkType", - "args": [ - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "referenceTypeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 26, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "referenceTypeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "routeListener", - "args": [ - { - "name": "limit", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "page", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ordering", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 34, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "limit", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "page", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "ordering", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "calcSort", - "args": [ - { - "name": "ordering", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Sort", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "ordering", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "checkParam", - "args": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 140, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "delete", - "args": [ - { - "name": "item", - "type": "Entities", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 238, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "Entities", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "destroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 131, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "getClusters", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 246, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "getNextPageCluster", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 257, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "init", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 123, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "initColumns", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 74, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "initListItemEvent", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 78, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "initRouteListener", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 114, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "initSocket", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "license", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 215, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "listEvents", - "args": [ - { - "name": "event", - "type": "EmmitRow", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 196, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EmmitRow", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "onLoad", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 213, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "refresh", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 186, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "socketListener", - "args": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 156, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "startListenSocket", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 65, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [ - "T" - ], - "line": 61, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseListDirective" - } - } - ], - "indexSignatures": [], - "extends": "BaseListDirective", - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "AppPage", - "id": "class-AppPage-44fb262d2bcd410bff4ac18f6ada327a", - "file": "e2e/app.po.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { browser } from 'protractor';\n\nexport class AppPage { \n navigateTo() {\n return browser.get('/');\n }\n}\n", - "properties": [], - "methods": [ - { - "name": "navigateTo", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 15, - "deprecated": false, - "deprecationMessage": "" - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "Back", - "id": "class-Back-a77f96cd644e5211741a053e7028f0c2", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { Action } from '@ngrx/store';\nimport { NavigationExtras } from '@angular/router';\n\nexport const GO = '[Router] Go';\nexport const BACK = '[Router] Back';\nexport const FORWARD = '[Router] Forward';\n\nexport class Go implements Action {\n readonly type = GO;\n\n constructor(\n public payload: {\n path: any[];\n query?: object;\n extras?: NavigationExtras;\n }\n ) {}\n}\n\nexport class Back implements Action {\n readonly type = BACK;\n}\n\nexport class Forward implements Action {\n readonly type = FORWARD;\n}\n\nexport type RouterActionsUnion = Go | Back | Forward;\n", - "properties": [ - { - "name": "type", - "defaultValue": "BACK", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 32, - "modifierKind": [ - 142 - ] - } - ], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [], - "implements": [ - "Action" - ] - }, - { - "name": "BaseListDirective", - "id": "class-BaseListDirective-8686b2996dc23fd6b135de183a41f1f3", - "file": "src/app/shared/components/list/base-list.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { MatDialog } from '@angular/material/dialog';\nimport { ParamMap } from '@angular/router';\nimport { select, Store } from '@ngrx/store';\nimport { filter, mergeMap, switchMap, takeUntil, tap } from 'rxjs/operators';\nimport { IListResult } from '@adwp-ui/widgets';\nimport { Sort } from '@angular/material/sort';\nimport { Observable, Subject } from 'rxjs';\n\nimport { clearMessages, EventMessage, getMessage, SocketState } from '@app/core/store';\nimport { Bundle, EmmitRow, Entities, Host as AdcmHost, TypeName } from '@app/core/types';\nimport { DialogComponent } from '@app/shared/components';\nimport { ListResult } from '@app/models/list-result';\nimport { ListService } from './list.service';\nimport { ListDirective } from '@app/abstract-directives/list.directive';\nimport { ICluster } from '@app/models/cluster';\n\n\nconst TemporaryEntityNameConverter = (currentName: Partial): string => {\n\n if (currentName === 'group_config') return 'group-config';\n if (currentName === 'group_config_hosts') return 'group-config-hosts';\n\n return currentName;\n};\n\ninterface IRowHost extends AdcmHost {\n clusters: Partial[];\n page: number;\n}\n\nexport class BaseListDirective {\n\n socket$: Observable;\n destroy$ = new Subject();\n\n row: Entities;\n listParams: ParamMap;\n limit = 10;\n typeName: TypeName;\n\n reload: (result: ListResult) => void;\n\n constructor(\n protected parent: ListDirective,\n protected service: ListService,\n protected store: Store,\n ) {}\n\n takeUntil() {\n return takeUntil(this.destroy$);\n }\n\n startListenSocket(): void {\n this.socket$.pipe(tap(m => this.socketListener(m))).subscribe();\n }\n\n initSocket() {\n this.socket$ = this.store.pipe(\n this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object));\n }\n\n initColumns() {\n this.parent.columns = this.service.initInstance(this.typeName).columns;\n }\n\n initListItemEvent() {\n this.parent.listItemEvt\n .pipe(this.takeUntil())\n .subscribe({ next: (event: EmmitRow) => this.listEvents(event) });\n }\n\n calcSort(ordering: string): Sort {\n let sort: Sort;\n if (ordering) {\n sort = {\n direction: ordering[0] === '-' ? 'desc' : 'asc',\n active: ordering[0] === '-' ? ordering.substr(1) : ordering,\n };\n }\n\n return sort;\n }\n\n routeListener(limit: number, page: number, ordering: string, params: ParamMap) {\n\n this.parent.paginator.pageSize = limit;\n if (page === 0) {\n this.parent.paginator.firstPage();\n } else {\n this.parent.paginator.pageIndex = page;\n }\n if (ordering && !this.parent.sort.active) {\n this.parent.sort.direction = ordering[0] === '-' ? 'desc' : 'asc';\n this.parent.sort.active = ordering[0] === '-' ? ordering.substr(1) : ordering;\n this.parent.sortParam = ordering;\n }\n\n this.listParams = params;\n this.refresh();\n }\n\n initRouteListener() {\n this.parent.route.paramMap\n .pipe(\n this.takeUntil(),\n filter((p) => this.checkParam(p))\n )\n .subscribe((p) => this.routeListener(+p.get('limit') || 10, +p.get('page'), p.get('ordering'), p));\n }\n\n init(): void {\n this.initSocket();\n this.initColumns();\n this.initListItemEvent();\n this.initRouteListener();\n this.startListenSocket();\n }\n\n destroy() {\n this.parent.listItemEvt.complete();\n\n this.destroy$.next();\n this.destroy$.complete();\n\n this.store.dispatch(clearMessages());\n }\n\n checkParam(p: ParamMap): boolean {\n const listParamStr = localStorage.getItem('list:param');\n if (!p.keys.length && listParamStr) {\n const json = JSON.parse(listParamStr);\n if (json[this.typeName]) {\n this.parent.router.navigate(['./', json[this.typeName]], { relativeTo: this.parent.route });\n return false;\n }\n }\n return true;\n }\n\n checkType(typeName: string, referenceTypeName: TypeName): boolean {\n return (referenceTypeName ? referenceTypeName.split('2')[0] : referenceTypeName) === typeName;\n }\n\n socketListener(m: EventMessage): void {\n const stype = (x: string) => `${m.object.type}${m.object.details.type ? `2${m.object.details.type}` : ''}` === x;\n\n const checkUpgradable = () => (m.event === 'create' || m.event === 'delete') && m.object.type === 'bundle' && this.typeName === 'cluster';\n const changeList = (name?: string) => stype(name ?? this.typeName) && (m.event === 'create' || m.event === 'delete' || m.event === 'add' || m.event === 'remove');\n const createHostPro = () => stype('host2provider') && m.event === 'create';\n const jobComplete = () => (m.event === 'change_job_status') && m.object.type === 'task' && m.object.details.value === 'success';\n const rewriteRow = (row: Entities) => this.service.checkItem(row).subscribe((item) => Object.keys(row).map((a) => (row[a] = item[a])));\n\n if (checkUpgradable() || changeList(TemporaryEntityNameConverter(this.typeName)) || createHostPro() || jobComplete()) {\n this.refresh(m.object.id);\n return;\n }\n\n // events for the row of list\n if (this.parent.data.data.length) {\n const row = this.parent.data.data.find((a) => a.id === m.object.id);\n if (!row) return;\n\n if (m.event === 'add' && stype('host2cluster')) rewriteRow(row);\n\n if (this.checkType(m.object.type, this.typeName)) {\n if (m.event === 'change_state') row.state = m.object.details.value;\n if (m.event === 'change_status') row.status = +m.object.details.value;\n if (m.event === 'change_job_status') row.status = m.object.details.value;\n if (m.event === 'upgrade') rewriteRow(row);\n }\n }\n }\n\n refresh(id?: number) {\n if (id) this.parent.current = { id };\n this.service.getList(this.listParams, this.typeName).subscribe((list: IListResult) => {\n if (this.reload) {\n this.reload(list);\n }\n this.parent.dataSource = list;\n });\n }\n\n listEvents(event: EmmitRow) {\n const createUrl = (a: string[]) => this.parent.router.createUrlTree(['./', this.row.id, ...a], { relativeTo: this.parent.route });\n const nav = (a: string[]) => this.parent.router.navigateByUrl(createUrl(a));\n\n this.row = event.row;\n const { cmd, row, item } = event;\n\n if (['title', 'status', 'config', 'import'].includes(cmd)) {\n nav(cmd === 'title' ? [] : [cmd]);\n } else if (cmd === 'new-tab') {\n const url = this.parent.router.serializeUrl(createUrl([]));\n window.open(url, '_blank');\n } else {\n this[cmd](row || item);\n }\n }\n\n onLoad() {}\n\n license() {\n const row = this.row as Bundle;\n\n const closedDialog$ = (text: string, dialog: MatDialog) =>\n dialog\n .open(DialogComponent, {\n data: {\n title: `Accept license agreement`,\n text,\n controls: { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] },\n },\n })\n .beforeClosed();\n\n const showDialog = (info: { text: string }) =>\n closedDialog$(info.text, this.parent.dialog).pipe(\n filter((yes) => yes),\n switchMap(() => this.service.acceptLicense(`${row.license_url}accept/`).pipe(tap((_) => (row.license = 'accepted'))))\n );\n\n this.service.getLicenseInfo(row.license_url).pipe(this.takeUntil(), mergeMap(showDialog)).subscribe();\n }\n\n delete(item?: Entities) {\n this.service\n .delete(item ?? this.row)\n .pipe(this.takeUntil())\n .subscribe(() => (this.parent.current = null));\n }\n\n // host\n getClusters() {\n const row = this.row as IRowHost;\n if (!row.clusters) {\n row.page = 0;\n this.service\n .getClustersForHost({ limit: this.limit, page: 0 })\n .pipe(this.takeUntil())\n .subscribe((list) => (row.clusters = list));\n }\n }\n\n getNextPageCluster() {\n const row = this.row as IRowHost;\n const count = row.clusters.length;\n if (count === (row.page + 1) * this.limit) {\n row.page++;\n this.service\n .getClustersForHost({ limit: this.limit, page: row.page })\n .pipe(this.takeUntil())\n .subscribe((list) => (row.clusters = [...row.clusters, ...list]));\n }\n }\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "parent", - "type": "ListDirective", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 53, - "jsdoctags": [ - { - "name": "parent", - "type": "ListDirective", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 46 - }, - { - "name": "limit", - "defaultValue": "10", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 50 - }, - { - "name": "listParams", - "deprecated": false, - "deprecationMessage": "", - "type": "ParamMap", - "optional": false, - "description": "", - "line": 49 - }, - { - "name": "reload", - "deprecated": false, - "deprecationMessage": "", - "type": "function", - "optional": false, - "description": "", - "line": 53 - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "type": "Entities", - "optional": false, - "description": "", - "line": 48 - }, - { - "name": "socket$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "typeName", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 51 - } - ], - "methods": [ - { - "name": "calcSort", - "args": [ - { - "name": "ordering", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Sort", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "ordering", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "checkParam", - "args": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 140, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "p", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "checkType", - "args": [ - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "referenceTypeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 152, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "referenceTypeName", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "delete", - "args": [ - { - "name": "item", - "type": "Entities", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 238, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "Entities", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "destroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 131, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getClusters", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 246, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getNextPageCluster", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 257, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "init", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 123, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "initColumns", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 74, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "initListItemEvent", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 78, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "initRouteListener", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 114, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "initSocket", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "license", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 215, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "listEvents", - "args": [ - { - "name": "event", - "type": "EmmitRow", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 196, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EmmitRow", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "onLoad", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 213, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "refresh", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 186, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "routeListener", - "args": [ - { - "name": "limit", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "page", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ordering", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 96, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "limit", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "page", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "ordering", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "socketListener", - "args": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 156, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "startListenSocket", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 65, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [ - "T" - ], - "line": 61, - "deprecated": false, - "deprecationMessage": "" - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "CompTile", - "id": "class-CompTile-a875bd9ec8a9450bd7b364337c366dfb", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IComponent, Host, IRequires } from '@app/core/types';\n\nexport type ActionParam = 'add' | 'remove';\nexport type TConstraintValue = number | '+' | 'odd' | 'depend';\nexport type TConstraint = TConstraintValue[];\n\nexport interface IRawHosComponent {\n component: IComponent[];\n host: Partial[];\n hc: Post[];\n}\n\nexport interface Post {\n id?: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class Post implements Post {\n constructor(public host_id: number, public service_id: number, public component_id: number, public id?: number) {}\n}\n\n/**\n *```\n {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: Constraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n }\n ```\n * @class Tile\n */\nexport class Tile {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: TConstraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n}\n\nexport class HostTile extends Tile {\n constructor(rawHost: Partial) {\n super();\n this.id = rawHost.id;\n this.name = rawHost.fqdn;\n }\n}\n\nexport class CompTile extends Tile {\n prototype_id: number;\n service_id: number;\n component: string;\n requires: IRequires[];\n constructor(rawComponent: IComponent, public actions?: ActionParam[]) {\n super();\n this.id = rawComponent.id;\n this.service_id = rawComponent.service_id;\n this.component = `${rawComponent.service_name}/${rawComponent.name}`;\n this.name = rawComponent.display_name;\n this.disabled = rawComponent.service_state !== 'created';\n this.limit = rawComponent.constraint;\n this.requires = rawComponent.requires;\n this.prototype_id = rawComponent.prototype_id;\n }\n}\n\n/**\n * State user selection\n *\n * @class StatePost\n */\nexport class StatePost {\n private _data: Post[];\n\n constructor() {\n this._data = [];\n }\n\n private _compare(a: Post, b: Post) {\n return a.host_id === b.host_id && a.service_id === b.service_id && a.component_id === b.component_id;\n }\n\n get data() {\n return this._data;\n }\n\n add(post: Post) {\n const f = this._data.find((p) => this._compare(p, post));\n if (!f) this._data.push(post);\n else if (!f.id) f.id = post.id;\n }\n\n delete(post: Post) {\n this._data = this._data.filter((p) => !this._compare(p, post));\n }\n\n clear() {\n this._data = [];\n }\n\n update(data: Post[]) {\n data.forEach((a) => this.add(new Post(a.host_id, a.service_id, a.component_id, a.id)));\n }\n}\n/**\n *```\n {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n }\n *```\n */\nexport interface IStream {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "rawComponent", - "type": "IComponent", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "actions", - "type": "ActionParam[]", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "line": 77, - "jsdoctags": [ - { - "name": "rawComponent", - "type": "IComponent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "actions", - "type": "ActionParam[]", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "actions", - "deprecated": false, - "deprecationMessage": "", - "type": "ActionParam[]", - "optional": true, - "description": "", - "line": 78, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "Tile" - } - }, - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 76 - }, - { - "name": "prototype_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 74 - }, - { - "name": "requires", - "deprecated": false, - "deprecationMessage": "", - "type": "IRequires[]", - "optional": false, - "description": "", - "line": 77 - }, - { - "name": "service_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 75 - }, - { - "name": "color", - "deprecated": false, - "deprecationMessage": "", - "type": "\"none\" | \"white\" | \"gray\" | \"yellow\"", - "optional": true, - "description": "", - "line": 61, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "disabled", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 59, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 53, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "isLink", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 57, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "isSelected", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 56, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "limit", - "deprecated": false, - "deprecationMessage": "", - "type": "TConstraint", - "optional": true, - "description": "", - "line": 58, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 54, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "notification", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 62, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "relations", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "Tile[]", - "optional": false, - "description": "", - "line": 55, - "inheritance": { - "file": "Tile" - } - } - ], - "methods": [], - "indexSignatures": [], - "extends": "Tile", - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "ConfigAttributeFactory", - "id": "class-ConfigAttributeFactory-651cfdba3f000923bbee8d3d05505de6", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { Inject, Injectable, InjectionToken, TemplateRef, Type } from '@angular/core';\nimport { FormBuilder, FormGroup } from '@angular/forms';\nimport { IFieldOptions } from '@app/shared/configuration/types';\nimport { isBoolean, isEmptyObject } from '@app/core/types';\nimport { FieldComponent } from '@app/shared/configuration/field/field.component';\n\nexport const ATTRIBUTES_OPTIONS = new InjectionToken('Attributes options');\n\nexport interface AttributeOptions {\n name: ConfigAttributeNames;\n wrapper?: Type;\n options?: ConfigAttributeOptions;\n}\n\nexport type AttributesOptions = Record\n\nexport interface AttributeWrapper {\n fieldTemplate: TemplateRef;\n wrapperOptions: ConfigAttributeOptions;\n fieldOptions: IFieldOptions;\n attributeForm: FormGroup;\n parametersForm: FormGroup;\n field: FieldComponent;\n}\n\nexport enum ConfigAttributeNames {\n // an attribute for adding config parameters to group\n GROUP_KEYS = 'group_keys',\n // an attribute for config parameters that determines whether this parameter can be added to the config group\n CUSTOM_GROUP_KEYS = 'custom_group_keys'\n}\n\nexport interface ConfigAttributesJSON {\n [key: string]: any;\n}\n\nexport interface ConfigAttributeOptions {\n tooltipText?: string;\n\n [key: string]: any;\n}\n\nexport type ConfigAttribute = AttributeOptions & { value: ConfigAttributesJSON, form: FormGroup };\n\nexport type Attributes = Map;\n\n@Injectable()\nexport class AttributeService {\n\n private readonly _activeAttributes: Partial[] = [\n ConfigAttributeNames.GROUP_KEYS,\n ConfigAttributeNames.CUSTOM_GROUP_KEYS\n ];\n\n get attributes(): Attributes {\n return this._attributes;\n }\n\n private _attributes: Attributes;\n\n constructor(@Inject(ATTRIBUTES_OPTIONS) private _configs: AttributesOptions, private _fb: FormBuilder) {\n }\n\n init(json: ConfigAttributesJSON): void {\n this._attributes = this._createAttributes(this._activeAttributes, json, this._configs);\n }\n\n getByName(name: ConfigAttributeNames): ConfigAttribute {\n return this._attributes.has(name) ? this._attributes.get(name) : undefined;\n }\n\n private _createAttributes(_activeAttributes: Partial[], json: ConfigAttributesJSON, configs: AttributesOptions): Attributes {\n const isEmptyAttrs = !Object.keys(json || {}).length;\n const isActiveAttrsPresent = !!Object.keys(json || {}).filter((x: ConfigAttributeNames) => this._activeAttributes.includes(x)).length;\n if (isEmptyAttrs || !isActiveAttrsPresent) {\n return;\n }\n\n return new Map(this._activeAttributes.map((attr) => [\n attr,\n new ConfigAttributeFactory(this._fb).create(attr, json[attr], configs[attr], json),\n ]));\n }\n\n\n rawAttributes() {\n let json = {};\n if (this._attributes) {\n for (const [key, value] of this._attributes.entries()) {\n json = {\n ...json,\n [key]: value.form.value\n };\n }\n }\n\n return json;\n }\n}\n\nexport const createFormForAttribute = (fb: FormBuilder, json: ConfigAttributesJSON, attr: ConfigAttributeNames, disabled: boolean = false): FormGroup => {\n const buildFormGroup = (json: boolean | ConfigAttributesJSON) => {\n const data = Object.entries(json).map(([key, value]) => [key, value]).reduce((acc, [key, value]: [string, boolean | ConfigAttributesJSON]) => {\n\n if (isBoolean(value) || isEmptyObject(value)) {\n return {\n ...acc,\n [key]: { value, disabled }\n };\n } else if (!isEmptyObject(value)) {\n return { ...acc, [key]: buildFormGroup(value) };\n }\n\n }, {});\n\n return fb.group(data);\n };\n\n return buildFormGroup(json[attr]);\n};\n\n\nexport class ConfigAttributeFactory {\n\n constructor(private fb: FormBuilder) {}\n\n create(name: ConfigAttributeNames, value: ConfigAttributesJSON, options: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n if (!this[name]) {\n return;\n }\n\n return this[name](value, options, json);\n }\n\n [ConfigAttributeNames.GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options,\n wrapper\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return {\n name,\n value,\n wrapper,\n options,\n form\n };\n }\n\n [ConfigAttributeNames.CUSTOM_GROUP_KEYS](value: ConfigAttributesJSON, {\n name,\n options\n }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute {\n\n const form = createFormForAttribute(this.fb, json, name);\n\n return { name, value, options, form };\n }\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "fb", - "type": "FormBuilder", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 123, - "jsdoctags": [ - { - "name": "fb", - "type": "FormBuilder", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [], - "methods": [ - { - "name": "create", - "args": [ - { - "name": "name", - "type": "ConfigAttributeNames", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "options", - "type": "AttributeOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "ConfigAttribute", - "typeParameters": [], - "line": 127, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "ConfigAttributeNames", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "options", - "type": "AttributeOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "args": [ - { - "name": "value", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "" - }, - { - "type": "AttributeOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "ConfigAttribute", - "typeParameters": [], - "line": 135, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "type": "AttributeOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "args": [ - { - "name": "value", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "" - }, - { - "type": "AttributeOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "ConfigAttribute", - "typeParameters": [], - "line": 152, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "type": "AttributeOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "json", - "type": "ConfigAttributesJSON", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "Configuration", - "id": "class-Configuration-e7cc495d69a4fedb6c84456abf0fbd99", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IFieldOptions } from './../types';\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { getControlType, getKey, getOptions, getValidator, getValue, TFormOptions, IOutput } from '../services/field.service';\n\nimport { IConfig, IConfigAttr, IFieldStack, ILimits, IPanelOptions, IUIoptions, stateType, TNForm, TValue } from '../types';\nimport { IYContainer, IYField, IYspec } from '../yspec/yspec.service';\n\nexport class YContainer {}\n\nexport class YField {}\n\nexport class Yspec {\n constructor() {}\n}\n\nexport class UIOptions implements IUIoptions {}\n\nexport class Limits {\n min: number;\n max: number;\n option: any;\n read_only: stateType[];\n active: boolean;\n rules: IYField | IYContainer;\n constructor(public yspec: IYspec) {}\n set Rules(rules: IYField | IYContainer) {\n this.rules = rules;\n }\n}\n\nexport class FieldStack implements IFieldStack {\n subname: string;\n display_name: string;\n default: TValue = null;\n description?: string;\n limits: ILimits;\n ui_options: IUIoptions;\n\n constructor(\n id: number,\n public type: TNForm,\n public name: string = null,\n public value = null,\n public required = true,\n public read_only = false,\n public activatable = false\n ) {\n const dn = `field_${type}_${id}`;\n this.name = !this.name ? dn : this.name;\n this.subname = this.name === dn ? '' : `subname_${type}_${id}`;\n this.display_name = `display_${this.name}_${this.subname}`;\n this.value = getValue(this.type)(this.value, this.default, this.required);\n }\n\n set Limits(limits: ILimits) {\n this.limits = limits;\n }\n set UIOptions(options: IUIoptions) {\n this.ui_options = options;\n }\n}\n\nexport class Configuration implements IConfig {\n id?: number;\n date?: string;\n description?: string;\n attr?: IConfigAttr;\n constructor(public config: IFieldStack[]) {}\n}\n\nexport class FieldFactory {\n public static addGroup(id: number, params: TNForm[]): IFieldStack[] {\n const group = new FieldStack(id, 'group');\n return params.reduce((p, c, i) => [...p, new FieldStack(i, c, group.name)], [group]);\n }\n\n /**\n * return group if params as array\n */\n public static add(params: (TNForm | TNForm[])[]) {\n return params.reduce(\n (p, c, i) => [...p, ...(Array.isArray(c) ? this.addGroup(i, c) : [new FieldStack(i, c)])],\n []\n );\n }\n}\n\nconst toPanel = (a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n});\n\nconst toField = (a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n});\n\nexport const toFormOptions = (data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n};\n\nexport const setValue = (data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n );\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "config", - "type": "IFieldStack[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 77, - "jsdoctags": [ - { - "name": "config", - "type": "IFieldStack[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "attr", - "deprecated": false, - "deprecationMessage": "", - "type": "IConfigAttr", - "optional": true, - "description": "", - "line": 77 - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "type": "IFieldStack[]", - "optional": false, - "description": "", - "line": 78, - "modifierKind": [ - 122 - ] - }, - { - "name": "date", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 75 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 76 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": true, - "description": "", - "line": 74 - } - ], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [], - "implements": [ - "IConfig" - ] - }, - { - "name": "ContextManager", - "id": "class-ContextManager-ed3a3a7c183131d19d99b08e7c8de4e0", - "file": "src/app/core/types/context-manager.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "export class ContextManager {\n constructor(typeName: string) {}\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 12, - "jsdoctags": [ - { - "name": "typeName", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "DateHelper", - "id": "class-DateHelper-0378511aedd8526bea7730dba4a4a240", - "file": "src/app/helpers/date-helper.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { DateTime } from 'luxon';\n\nexport class DateHelper {\n\n static short(date: string) {\n return DateTime.fromISO(date).setLocale('en').toFormat('FF');\n }\n\n}\n", - "properties": [], - "methods": [ - { - "name": "short", - "args": [ - { - "name": "date", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 5, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "date", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "DetailsFactory", - "id": "class-DetailsFactory-5922a056325c58af02a41603676764e9", - "file": "src/app/factories/details.factory.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { LeftMenuItem } from '../shared/details/left-menu/left-menu.component';\nimport { LabelMenuItemComponent } from '../shared/details/left-menu-items/label-menu-item/label-menu-item.component';\nimport { StatusMenuItemComponent } from '@app/shared/details/left-menu-items/status-menu-item/status-menu-item.component';\nimport { LogMenuItemComponent } from '@app/shared/details/left-menu-items/log-menu-item/log-menu-item.component';\nimport { TypeName } from '@app/core/types';\nimport { ConcernMenuItemComponent } from '@app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.component';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\nexport class DetailsFactory {\n\n static labelMenuItem(label: string, link: string): LeftMenuItem {\n return {\n label,\n link,\n component: LabelMenuItemComponent,\n };\n }\n\n static concernMenuItem(label: string, link: string, cause: string, type: ConcernEventType, owner_type: TypeName): LeftMenuItem {\n return {\n label,\n link,\n data: { cause, type, owner_type },\n component: ConcernMenuItemComponent,\n };\n }\n\n static statusMenuItem(label: string, link: string, entityType: TypeName): LeftMenuItem {\n return {\n label,\n link,\n data: { entityType },\n component: StatusMenuItemComponent,\n };\n }\n\n static logMenuItem(label: string, link: string, logId: number): LeftMenuItem {\n return {\n label,\n link,\n data: { logId },\n component: LogMenuItemComponent,\n };\n }\n\n}\n", - "properties": [], - "methods": [ - { - "name": "concernMenuItem", - "args": [ - { - "name": "label", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cause", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "type", - "type": "ConcernEventType", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "owner_type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "LeftMenuItem", - "typeParameters": [], - "line": 19, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "label", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cause", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "type", - "type": "ConcernEventType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "owner_type", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "labelMenuItem", - "args": [ - { - "name": "label", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "LeftMenuItem", - "typeParameters": [], - "line": 11, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "label", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "logMenuItem", - "args": [ - { - "name": "label", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "logId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "LeftMenuItem", - "typeParameters": [], - "line": 37, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "label", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "logId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "statusMenuItem", - "args": [ - { - "name": "label", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "entityType", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "LeftMenuItem", - "typeParameters": [], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "label", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "link", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "entityType", - "type": "TypeName", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "EntityService", - "id": "class-EntityService-cf44d7994264b717b6a3ad4e6000bbb4", - "file": "src/app/abstract/entity-service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { Observable } from 'rxjs';\n\nimport { ApiService } from '@app/core/api';\n\nexport abstract class EntityService {\n\n constructor(\n protected api: ApiService,\n ) {\n }\n\n abstract get(id: number, params?: { [key: string]: string }): Observable;\n\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 5, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [], - "methods": [ - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 12, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 125 - ], - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "FieldFactory", - "id": "class-FieldFactory-e7cc495d69a4fedb6c84456abf0fbd99", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IFieldOptions } from './../types';\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { getControlType, getKey, getOptions, getValidator, getValue, TFormOptions, IOutput } from '../services/field.service';\n\nimport { IConfig, IConfigAttr, IFieldStack, ILimits, IPanelOptions, IUIoptions, stateType, TNForm, TValue } from '../types';\nimport { IYContainer, IYField, IYspec } from '../yspec/yspec.service';\n\nexport class YContainer {}\n\nexport class YField {}\n\nexport class Yspec {\n constructor() {}\n}\n\nexport class UIOptions implements IUIoptions {}\n\nexport class Limits {\n min: number;\n max: number;\n option: any;\n read_only: stateType[];\n active: boolean;\n rules: IYField | IYContainer;\n constructor(public yspec: IYspec) {}\n set Rules(rules: IYField | IYContainer) {\n this.rules = rules;\n }\n}\n\nexport class FieldStack implements IFieldStack {\n subname: string;\n display_name: string;\n default: TValue = null;\n description?: string;\n limits: ILimits;\n ui_options: IUIoptions;\n\n constructor(\n id: number,\n public type: TNForm,\n public name: string = null,\n public value = null,\n public required = true,\n public read_only = false,\n public activatable = false\n ) {\n const dn = `field_${type}_${id}`;\n this.name = !this.name ? dn : this.name;\n this.subname = this.name === dn ? '' : `subname_${type}_${id}`;\n this.display_name = `display_${this.name}_${this.subname}`;\n this.value = getValue(this.type)(this.value, this.default, this.required);\n }\n\n set Limits(limits: ILimits) {\n this.limits = limits;\n }\n set UIOptions(options: IUIoptions) {\n this.ui_options = options;\n }\n}\n\nexport class Configuration implements IConfig {\n id?: number;\n date?: string;\n description?: string;\n attr?: IConfigAttr;\n constructor(public config: IFieldStack[]) {}\n}\n\nexport class FieldFactory {\n public static addGroup(id: number, params: TNForm[]): IFieldStack[] {\n const group = new FieldStack(id, 'group');\n return params.reduce((p, c, i) => [...p, new FieldStack(i, c, group.name)], [group]);\n }\n\n /**\n * return group if params as array\n */\n public static add(params: (TNForm | TNForm[])[]) {\n return params.reduce(\n (p, c, i) => [...p, ...(Array.isArray(c) ? this.addGroup(i, c) : [new FieldStack(i, c)])],\n []\n );\n }\n}\n\nconst toPanel = (a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n});\n\nconst toField = (a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n});\n\nexport const toFormOptions = (data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n};\n\nexport const setValue = (data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n );\n", - "properties": [], - "methods": [ - { - "name": "add", - "args": [ - { - "name": "params", - "type": "(TNForm | TNForm[])[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 90, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nreturn group if params as array\n", - "description": "

return group if params as array

\n", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "params", - "type": "(TNForm | TNForm[])[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "addGroup", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "TNForm[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IFieldStack[]", - "typeParameters": [], - "line": 82, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "TNForm[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "FieldStack", - "id": "class-FieldStack-e7cc495d69a4fedb6c84456abf0fbd99", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IFieldOptions } from './../types';\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { getControlType, getKey, getOptions, getValidator, getValue, TFormOptions, IOutput } from '../services/field.service';\n\nimport { IConfig, IConfigAttr, IFieldStack, ILimits, IPanelOptions, IUIoptions, stateType, TNForm, TValue } from '../types';\nimport { IYContainer, IYField, IYspec } from '../yspec/yspec.service';\n\nexport class YContainer {}\n\nexport class YField {}\n\nexport class Yspec {\n constructor() {}\n}\n\nexport class UIOptions implements IUIoptions {}\n\nexport class Limits {\n min: number;\n max: number;\n option: any;\n read_only: stateType[];\n active: boolean;\n rules: IYField | IYContainer;\n constructor(public yspec: IYspec) {}\n set Rules(rules: IYField | IYContainer) {\n this.rules = rules;\n }\n}\n\nexport class FieldStack implements IFieldStack {\n subname: string;\n display_name: string;\n default: TValue = null;\n description?: string;\n limits: ILimits;\n ui_options: IUIoptions;\n\n constructor(\n id: number,\n public type: TNForm,\n public name: string = null,\n public value = null,\n public required = true,\n public read_only = false,\n public activatable = false\n ) {\n const dn = `field_${type}_${id}`;\n this.name = !this.name ? dn : this.name;\n this.subname = this.name === dn ? '' : `subname_${type}_${id}`;\n this.display_name = `display_${this.name}_${this.subname}`;\n this.value = getValue(this.type)(this.value, this.default, this.required);\n }\n\n set Limits(limits: ILimits) {\n this.limits = limits;\n }\n set UIOptions(options: IUIoptions) {\n this.ui_options = options;\n }\n}\n\nexport class Configuration implements IConfig {\n id?: number;\n date?: string;\n description?: string;\n attr?: IConfigAttr;\n constructor(public config: IFieldStack[]) {}\n}\n\nexport class FieldFactory {\n public static addGroup(id: number, params: TNForm[]): IFieldStack[] {\n const group = new FieldStack(id, 'group');\n return params.reduce((p, c, i) => [...p, new FieldStack(i, c, group.name)], [group]);\n }\n\n /**\n * return group if params as array\n */\n public static add(params: (TNForm | TNForm[])[]) {\n return params.reduce(\n (p, c, i) => [...p, ...(Array.isArray(c) ? this.addGroup(i, c) : [new FieldStack(i, c)])],\n []\n );\n }\n}\n\nconst toPanel = (a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n});\n\nconst toField = (a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n});\n\nexport const toFormOptions = (data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n};\n\nexport const setValue = (data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n );\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "type", - "type": "TNForm", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "null" - }, - { - "name": "value", - "type": "null", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "null" - }, - { - "name": "required", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "true" - }, - { - "name": "read_only", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "false" - }, - { - "name": "activatable", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "false" - } - ], - "line": 47, - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "type", - "type": "TNForm", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "null", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "null", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "null", - "tagName": { - "text": "param" - } - }, - { - "name": "required", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "true", - "tagName": { - "text": "param" - } - }, - { - "name": "read_only", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "false", - "tagName": { - "text": "param" - } - }, - { - "name": "activatable", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "false", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "activatable", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 56, - "modifierKind": [ - 122 - ] - }, - { - "name": "default", - "defaultValue": "null", - "deprecated": false, - "deprecationMessage": "", - "type": "TValue", - "optional": false, - "description": "", - "line": 44 - }, - { - "name": "description", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 45 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "limits", - "deprecated": false, - "deprecationMessage": "", - "type": "ILimits", - "optional": false, - "description": "", - "line": 46 - }, - { - "name": "name", - "defaultValue": "null", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 52, - "modifierKind": [ - 122 - ] - }, - { - "name": "read_only", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 55, - "modifierKind": [ - 122 - ] - }, - { - "name": "required", - "defaultValue": "true", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 54, - "modifierKind": [ - 122 - ] - }, - { - "name": "subname", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "type": "TNForm", - "optional": false, - "description": "", - "line": 51, - "modifierKind": [ - 122 - ] - }, - { - "name": "ui_options", - "deprecated": false, - "deprecationMessage": "", - "type": "IUIoptions", - "optional": false, - "description": "", - "line": 47 - }, - { - "name": "value", - "defaultValue": "null", - "deprecated": false, - "deprecationMessage": "", - "type": "null", - "optional": false, - "description": "", - "line": 53, - "modifierKind": [ - 122 - ] - } - ], - "methods": [], - "indexSignatures": [], - "accessors": { - "Limits": { - "name": "Limits", - "setSignature": { - "name": "Limits", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "limits", - "type": "ILimits", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 65, - "jsdoctags": [ - { - "name": "limits", - "type": "ILimits", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - "UIOptions": { - "name": "UIOptions", - "setSignature": { - "name": "UIOptions", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "options", - "type": "IUIoptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 68, - "jsdoctags": [ - { - "name": "options", - "type": "IUIoptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - }, - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [], - "implements": [ - "IFieldStack" - ] - }, - { - "name": "Forward", - "id": "class-Forward-a77f96cd644e5211741a053e7028f0c2", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { Action } from '@ngrx/store';\nimport { NavigationExtras } from '@angular/router';\n\nexport const GO = '[Router] Go';\nexport const BACK = '[Router] Back';\nexport const FORWARD = '[Router] Forward';\n\nexport class Go implements Action {\n readonly type = GO;\n\n constructor(\n public payload: {\n path: any[];\n query?: object;\n extras?: NavigationExtras;\n }\n ) {}\n}\n\nexport class Back implements Action {\n readonly type = BACK;\n}\n\nexport class Forward implements Action {\n readonly type = FORWARD;\n}\n\nexport type RouterActionsUnion = Go | Back | Forward;\n", - "properties": [ - { - "name": "type", - "defaultValue": "FORWARD", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 36, - "modifierKind": [ - 142 - ] - } - ], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [], - "implements": [ - "Action" - ] - }, - { - "name": "GenName", - "id": "class-GenName-a14c51920fb5cd299c091f6e62420ca5", - "file": "src/app/shared/add-component/naming.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { randomInteger } from '@app/core/types/func';\n\nconst rivers: string[] = [\n 'Amur',\n 'Anadyr',\n 'Angara',\n 'Colorado',\n 'Congo',\n 'Desna',\n 'Dnieper',\n 'Don',\n 'Itrysh',\n 'Kama',\n 'Limpopo',\n 'Mekong',\n 'Mississippi',\n 'Nile',\n 'Ob',\n 'Oka',\n 'Pechora',\n 'Rhine',\n 'Ural',\n 'Volga',\n 'Yangtze',\n 'Yenisei',\n 'Yukon',\n 'Zambezi',\n];\n\nconst adjectives: string[] = [\n 'Ancient',\n 'Beautiful',\n 'Big',\n 'Blue',\n 'Broad',\n 'Clear',\n 'Cold',\n 'Dark',\n 'Deep',\n 'Distant',\n 'Down',\n 'Dry',\n 'Famous',\n 'Fear',\n 'Flowing',\n 'Frozen',\n 'Great',\n 'Holy',\n 'Huge',\n 'Icy',\n 'Large',\n 'Latter',\n 'Longest',\n 'Lovely',\n 'Lower',\n 'Mad',\n 'Magnificent',\n 'Majestic',\n 'Middle',\n 'Mighty',\n 'Muddy',\n 'Narrow',\n 'Noble',\n 'North',\n 'Placid',\n 'Polluted',\n 'Quiet',\n 'Rapid',\n 'Sacred',\n 'Shallow',\n 'Slow',\n 'Sluggish',\n 'Small',\n 'Swift',\n 'Tidal',\n 'Tributary',\n 'Turbulent',\n 'Wide',\n 'Wild',\n];\n\nexport class GenName {\n public static do(prefix: string = '') {\n return `${adjectives[randomInteger(adjectives.length - 1)]} ${rivers[randomInteger(rivers.length - 1)]}${prefix}`;\n }\n}\n", - "properties": [], - "methods": [ - { - "name": "do", - "args": [ - { - "name": "prefix", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "''" - } - ], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 94, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "prefix", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "''", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "Go", - "id": "class-Go-a77f96cd644e5211741a053e7028f0c2", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { Action } from '@ngrx/store';\nimport { NavigationExtras } from '@angular/router';\n\nexport const GO = '[Router] Go';\nexport const BACK = '[Router] Back';\nexport const FORWARD = '[Router] Forward';\n\nexport class Go implements Action {\n readonly type = GO;\n\n constructor(\n public payload: {\n path: any[];\n query?: object;\n extras?: NavigationExtras;\n }\n ) {}\n}\n\nexport class Back implements Action {\n readonly type = BACK;\n}\n\nexport class Forward implements Action {\n readonly type = FORWARD;\n}\n\nexport type RouterActionsUnion = Go | Back | Forward;\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "payload", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 20, - "jsdoctags": [ - { - "name": "payload", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "payload", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 23, - "modifierKind": [ - 122 - ] - }, - { - "name": "type", - "defaultValue": "GO", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 20, - "modifierKind": [ - 142 - ] - } - ], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [], - "implements": [ - "Action" - ] - }, - { - "name": "HavingStatusTreeAbstractService", - "id": "class-HavingStatusTreeAbstractService-ac4a211ede81d2fdb53aad014397edf4", - "file": "src/app/abstract/having-status-tree.abstract.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { Observable } from 'rxjs';\n\nimport { StatusTree, StatusTreeSubject } from '../models/status-tree';\nimport { EntityService } from '@app/abstract/entity-service';\nimport { AdcmEntity } from '@app/models/entity';\n\nexport abstract class HavingStatusTreeAbstractService extends EntityService {\n\n abstract getStatusTree(id: number): Observable;\n abstract entityStatusTreeToStatusTree(input: StatusTreeType, ...args): StatusTree[];\n\n}\n", - "properties": [], - "methods": [ - { - "name": "entityStatusTreeToStatusTree", - "args": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "args", - "type": "any[]", - "deprecated": false, - "deprecationMessage": "", - "dotDotDotToken": true - } - ], - "optional": false, - "returnType": "StatusTree[]", - "typeParameters": [], - "line": 10, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 125 - ], - "jsdoctags": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "args", - "type": "any[]", - "deprecated": false, - "deprecationMessage": "", - "dotDotDotToken": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getStatusTree", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 9, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 125 - ], - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "get", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 12, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 125 - ], - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "params", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "EntityService" - } - } - ], - "indexSignatures": [], - "extends": "EntityService", - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "HCmComponent", - "id": "class-HCmComponent-b54e687297e8b02797d55193fc2ec35c", - "file": "src/app/shared/host-components-map/test/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IComponent, IRequires } from '@app/core/types';\nimport { newArray } from '@app/core/types/func';\n\nimport { Post, TConstraint } from '../types';\n\nexport class HCmRequires implements IRequires {\n name: string;\n display_name: string;\n components?: IRequires[];\n constructor(public prototype_id: number) {\n this.name = `name_${prototype_id}`;\n this.display_name = `component_display_name_${prototype_id}`;\n }\n}\n\nexport class HostComponent {\n id: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class HcmHost {\n constructor(public fqdn: string, public id: number) {}\n}\n\nexport class HCmComponent {\n name: string;\n display_name: string;\n service_name: string;\n service_state = 'created';\n prototype_id: number;\n constraint: TConstraint = null;\n requires: HCmRequires[];\n constructor(public id: number, public service_id: number) {\n this.prototype_id = id;\n this.name = `component_${id}`;\n this.display_name = `component_display_name_${id}`;\n this.service_name = `service_${service_id}`;\n }\n}\n\n/**\n * Array with specific service id and components with id by index [1, count]\n * see: class HCmComponent\n*/\nexport const ComponentFactory = (count: number, service_id: number): IComponent[] =>\n newArray(count, (_, i) => new HCmComponent(i + 1, service_id) as IComponent);\n\nexport const HCFactory = (host_id: number, service_id: number, components: number): Post[] =>\n newArray(components, (_, i) => new Post(host_id, service_id, i + 1, i + 1));\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 45, - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "constraint", - "defaultValue": "null", - "deprecated": false, - "deprecationMessage": "", - "type": "TConstraint", - "optional": false, - "description": "", - "line": 44 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 40 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 46, - "modifierKind": [ - 122 - ] - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 39 - }, - { - "name": "prototype_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "requires", - "deprecated": false, - "deprecationMessage": "", - "type": "HCmRequires[]", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "service_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 46, - "modifierKind": [ - 122 - ] - }, - { - "name": "service_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "service_state", - "defaultValue": "'created'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 42 - } - ], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "HcmHost", - "id": "class-HcmHost-b54e687297e8b02797d55193fc2ec35c", - "file": "src/app/shared/host-components-map/test/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IComponent, IRequires } from '@app/core/types';\nimport { newArray } from '@app/core/types/func';\n\nimport { Post, TConstraint } from '../types';\n\nexport class HCmRequires implements IRequires {\n name: string;\n display_name: string;\n components?: IRequires[];\n constructor(public prototype_id: number) {\n this.name = `name_${prototype_id}`;\n this.display_name = `component_display_name_${prototype_id}`;\n }\n}\n\nexport class HostComponent {\n id: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class HcmHost {\n constructor(public fqdn: string, public id: number) {}\n}\n\nexport class HCmComponent {\n name: string;\n display_name: string;\n service_name: string;\n service_state = 'created';\n prototype_id: number;\n constraint: TConstraint = null;\n requires: HCmRequires[];\n constructor(public id: number, public service_id: number) {\n this.prototype_id = id;\n this.name = `component_${id}`;\n this.display_name = `component_display_name_${id}`;\n this.service_name = `service_${service_id}`;\n }\n}\n\n/**\n * Array with specific service id and components with id by index [1, count]\n * see: class HCmComponent\n*/\nexport const ComponentFactory = (count: number, service_id: number): IComponent[] =>\n newArray(count, (_, i) => new HCmComponent(i + 1, service_id) as IComponent);\n\nexport const HCFactory = (host_id: number, service_id: number, components: number): Post[] =>\n newArray(components, (_, i) => new Post(host_id, service_id, i + 1, i + 1));\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "fqdn", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 34, - "jsdoctags": [ - { - "name": "fqdn", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "fqdn", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 35, - "modifierKind": [ - 122 - ] - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 35, - "modifierKind": [ - 122 - ] - } - ], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "HCmRequires", - "id": "class-HCmRequires-b54e687297e8b02797d55193fc2ec35c", - "file": "src/app/shared/host-components-map/test/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IComponent, IRequires } from '@app/core/types';\nimport { newArray } from '@app/core/types/func';\n\nimport { Post, TConstraint } from '../types';\n\nexport class HCmRequires implements IRequires {\n name: string;\n display_name: string;\n components?: IRequires[];\n constructor(public prototype_id: number) {\n this.name = `name_${prototype_id}`;\n this.display_name = `component_display_name_${prototype_id}`;\n }\n}\n\nexport class HostComponent {\n id: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class HcmHost {\n constructor(public fqdn: string, public id: number) {}\n}\n\nexport class HCmComponent {\n name: string;\n display_name: string;\n service_name: string;\n service_state = 'created';\n prototype_id: number;\n constraint: TConstraint = null;\n requires: HCmRequires[];\n constructor(public id: number, public service_id: number) {\n this.prototype_id = id;\n this.name = `component_${id}`;\n this.display_name = `component_display_name_${id}`;\n this.service_name = `service_${service_id}`;\n }\n}\n\n/**\n * Array with specific service id and components with id by index [1, count]\n * see: class HCmComponent\n*/\nexport const ComponentFactory = (count: number, service_id: number): IComponent[] =>\n newArray(count, (_, i) => new HCmComponent(i + 1, service_id) as IComponent);\n\nexport const HCFactory = (host_id: number, service_id: number, components: number): Post[] =>\n newArray(components, (_, i) => new Post(host_id, service_id, i + 1, i + 1));\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "prototype_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 20, - "jsdoctags": [ - { - "name": "prototype_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "components", - "deprecated": false, - "deprecationMessage": "", - "type": "IRequires[]", - "optional": true, - "description": "", - "line": 20 - }, - { - "name": "display_name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 18 - }, - { - "name": "prototype_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 21, - "modifierKind": [ - 122 - ] - } - ], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [], - "implements": [ - "IRequires" - ] - }, - { - "name": "HostComponent", - "id": "class-HostComponent-b54e687297e8b02797d55193fc2ec35c", - "file": "src/app/shared/host-components-map/test/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IComponent, IRequires } from '@app/core/types';\nimport { newArray } from '@app/core/types/func';\n\nimport { Post, TConstraint } from '../types';\n\nexport class HCmRequires implements IRequires {\n name: string;\n display_name: string;\n components?: IRequires[];\n constructor(public prototype_id: number) {\n this.name = `name_${prototype_id}`;\n this.display_name = `component_display_name_${prototype_id}`;\n }\n}\n\nexport class HostComponent {\n id: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class HcmHost {\n constructor(public fqdn: string, public id: number) {}\n}\n\nexport class HCmComponent {\n name: string;\n display_name: string;\n service_name: string;\n service_state = 'created';\n prototype_id: number;\n constraint: TConstraint = null;\n requires: HCmRequires[];\n constructor(public id: number, public service_id: number) {\n this.prototype_id = id;\n this.name = `component_${id}`;\n this.display_name = `component_display_name_${id}`;\n this.service_name = `service_${service_id}`;\n }\n}\n\n/**\n * Array with specific service id and components with id by index [1, count]\n * see: class HCmComponent\n*/\nexport const ComponentFactory = (count: number, service_id: number): IComponent[] =>\n newArray(count, (_, i) => new HCmComponent(i + 1, service_id) as IComponent);\n\nexport const HCFactory = (host_id: number, service_id: number, components: number): Post[] =>\n newArray(components, (_, i) => new Post(host_id, service_id, i + 1, i + 1));\n", - "properties": [ - { - "name": "component_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "host_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 29 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "service_id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 30 - } - ], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "HostTile", - "id": "class-HostTile-a875bd9ec8a9450bd7b364337c366dfb", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IComponent, Host, IRequires } from '@app/core/types';\n\nexport type ActionParam = 'add' | 'remove';\nexport type TConstraintValue = number | '+' | 'odd' | 'depend';\nexport type TConstraint = TConstraintValue[];\n\nexport interface IRawHosComponent {\n component: IComponent[];\n host: Partial[];\n hc: Post[];\n}\n\nexport interface Post {\n id?: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class Post implements Post {\n constructor(public host_id: number, public service_id: number, public component_id: number, public id?: number) {}\n}\n\n/**\n *```\n {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: Constraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n }\n ```\n * @class Tile\n */\nexport class Tile {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: TConstraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n}\n\nexport class HostTile extends Tile {\n constructor(rawHost: Partial) {\n super();\n this.id = rawHost.id;\n this.name = rawHost.fqdn;\n }\n}\n\nexport class CompTile extends Tile {\n prototype_id: number;\n service_id: number;\n component: string;\n requires: IRequires[];\n constructor(rawComponent: IComponent, public actions?: ActionParam[]) {\n super();\n this.id = rawComponent.id;\n this.service_id = rawComponent.service_id;\n this.component = `${rawComponent.service_name}/${rawComponent.name}`;\n this.name = rawComponent.display_name;\n this.disabled = rawComponent.service_state !== 'created';\n this.limit = rawComponent.constraint;\n this.requires = rawComponent.requires;\n this.prototype_id = rawComponent.prototype_id;\n }\n}\n\n/**\n * State user selection\n *\n * @class StatePost\n */\nexport class StatePost {\n private _data: Post[];\n\n constructor() {\n this._data = [];\n }\n\n private _compare(a: Post, b: Post) {\n return a.host_id === b.host_id && a.service_id === b.service_id && a.component_id === b.component_id;\n }\n\n get data() {\n return this._data;\n }\n\n add(post: Post) {\n const f = this._data.find((p) => this._compare(p, post));\n if (!f) this._data.push(post);\n else if (!f.id) f.id = post.id;\n }\n\n delete(post: Post) {\n this._data = this._data.filter((p) => !this._compare(p, post));\n }\n\n clear() {\n this._data = [];\n }\n\n update(data: Post[]) {\n data.forEach((a) => this.add(new Post(a.host_id, a.service_id, a.component_id, a.id)));\n }\n}\n/**\n *```\n {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n }\n *```\n */\nexport interface IStream {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "rawHost", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 65, - "jsdoctags": [ - { - "name": "rawHost", - "type": "Partial", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "actions", - "deprecated": false, - "deprecationMessage": "", - "type": "ActionParam[]", - "optional": true, - "description": "", - "line": 60, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "color", - "deprecated": false, - "deprecationMessage": "", - "type": "\"none\" | \"white\" | \"gray\" | \"yellow\"", - "optional": true, - "description": "", - "line": 61, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "disabled", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 59, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 53, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "isLink", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 57, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "isSelected", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 56, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "limit", - "deprecated": false, - "deprecationMessage": "", - "type": "TConstraint", - "optional": true, - "description": "", - "line": 58, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 54, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "notification", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 62, - "inheritance": { - "file": "Tile" - } - }, - { - "name": "relations", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "Tile[]", - "optional": false, - "description": "", - "line": 55, - "inheritance": { - "file": "Tile" - } - } - ], - "methods": [], - "indexSignatures": [], - "extends": "Tile", - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "IssueHelper", - "id": "class-IssueHelper-dc8aa95f7949659a3f7b85c169ab436c", - "file": "src/app/helpers/issue-helper.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IIssues } from '../models/issue';\n\nexport class IssueHelper {\n\n static isIssue(issue: IIssues): boolean {\n return !!(issue && Object.keys(issue).length);\n }\n\n}\n", - "properties": [], - "methods": [ - { - "name": "isIssue", - "args": [ - { - "name": "issue", - "type": "IIssues", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 17, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "issue", - "type": "IIssues", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "Limits", - "id": "class-Limits-e7cc495d69a4fedb6c84456abf0fbd99", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IFieldOptions } from './../types';\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { getControlType, getKey, getOptions, getValidator, getValue, TFormOptions, IOutput } from '../services/field.service';\n\nimport { IConfig, IConfigAttr, IFieldStack, ILimits, IPanelOptions, IUIoptions, stateType, TNForm, TValue } from '../types';\nimport { IYContainer, IYField, IYspec } from '../yspec/yspec.service';\n\nexport class YContainer {}\n\nexport class YField {}\n\nexport class Yspec {\n constructor() {}\n}\n\nexport class UIOptions implements IUIoptions {}\n\nexport class Limits {\n min: number;\n max: number;\n option: any;\n read_only: stateType[];\n active: boolean;\n rules: IYField | IYContainer;\n constructor(public yspec: IYspec) {}\n set Rules(rules: IYField | IYContainer) {\n this.rules = rules;\n }\n}\n\nexport class FieldStack implements IFieldStack {\n subname: string;\n display_name: string;\n default: TValue = null;\n description?: string;\n limits: ILimits;\n ui_options: IUIoptions;\n\n constructor(\n id: number,\n public type: TNForm,\n public name: string = null,\n public value = null,\n public required = true,\n public read_only = false,\n public activatable = false\n ) {\n const dn = `field_${type}_${id}`;\n this.name = !this.name ? dn : this.name;\n this.subname = this.name === dn ? '' : `subname_${type}_${id}`;\n this.display_name = `display_${this.name}_${this.subname}`;\n this.value = getValue(this.type)(this.value, this.default, this.required);\n }\n\n set Limits(limits: ILimits) {\n this.limits = limits;\n }\n set UIOptions(options: IUIoptions) {\n this.ui_options = options;\n }\n}\n\nexport class Configuration implements IConfig {\n id?: number;\n date?: string;\n description?: string;\n attr?: IConfigAttr;\n constructor(public config: IFieldStack[]) {}\n}\n\nexport class FieldFactory {\n public static addGroup(id: number, params: TNForm[]): IFieldStack[] {\n const group = new FieldStack(id, 'group');\n return params.reduce((p, c, i) => [...p, new FieldStack(i, c, group.name)], [group]);\n }\n\n /**\n * return group if params as array\n */\n public static add(params: (TNForm | TNForm[])[]) {\n return params.reduce(\n (p, c, i) => [...p, ...(Array.isArray(c) ? this.addGroup(i, c) : [new FieldStack(i, c)])],\n []\n );\n }\n}\n\nconst toPanel = (a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n});\n\nconst toField = (a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n});\n\nexport const toFormOptions = (data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n};\n\nexport const setValue = (data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n );\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "yspec", - "type": "IYspec", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 34, - "jsdoctags": [ - { - "name": "yspec", - "type": "IYspec", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "properties": [ - { - "name": "active", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 33 - }, - { - "name": "max", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "min", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 29 - }, - { - "name": "option", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "read_only", - "deprecated": false, - "deprecationMessage": "", - "type": "stateType[]", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "rules", - "deprecated": false, - "deprecationMessage": "", - "type": "IYField | IYContainer", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "yspec", - "deprecated": false, - "deprecationMessage": "", - "type": "IYspec", - "optional": false, - "description": "", - "line": 35, - "modifierKind": [ - 122 - ] - } - ], - "methods": [], - "indexSignatures": [], - "accessors": { - "Rules": { - "name": "Rules", - "setSignature": { - "name": "Rules", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "rules", - "type": "IYField | IYContainer", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 36, - "jsdoctags": [ - { - "name": "rules", - "type": "IYField | IYContainer", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - }, - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "ListFactory", - "id": "class-ListFactory-505028d528229bf4882d10af2d9da1f6", - "file": "src/app/factories/list.factory.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IComponentColumn, IValueColumn, IButtonsColumn, ILinkColumn } from '@adwp-ui/widgets';\nimport { ComponentRef } from '@angular/core';\n\nimport { StateColumnComponent } from '@app/components/columns/state-column/state-column.component';\nimport { StatusColumnComponent, StatusData } from '@app/components/columns/status-column/status-column.component';\nimport { AdwpListDirective } from '@app/abstract-directives/adwp-list.directive';\nimport { UpgradeComponent } from '@app/shared/components';\nimport { ActionsButtonComponent } from '@app/components/actions-button/actions-button.component';\nimport { BaseEntity } from '@app/core/types';\nimport { ConcernListDirective } from '@app/abstract-directives/concern-list.directive';\n\nexport class ListFactory {\n\n static nameColumn(sort: string = 'name'): IValueColumn {\n return {\n label: 'Name',\n sort,\n value: (row) => row.display_name || row.name,\n };\n }\n\n static fqdnColumn(): IValueColumn {\n return {\n label: 'FQDN',\n sort: 'fqdn',\n className: 'width30pr',\n headerClassName: 'width30pr',\n value: row => row.fqdn,\n };\n }\n\n static descriptionColumn(): IValueColumn {\n return {\n label: 'Description',\n value: (row) => row.description,\n };\n }\n\n static stateColumn(): IComponentColumn {\n return {\n label: 'State',\n sort: 'state',\n type: 'component',\n className: 'width100',\n headerClassName: 'width100',\n component: StateColumnComponent,\n };\n }\n\n static statusColumn(listDirective: AdwpListDirective): IComponentColumn {\n return {\n label: 'Status',\n sort: 'status',\n type: 'component',\n className: 'list-control',\n headerClassName: 'list-control',\n component: StatusColumnComponent,\n instanceTaken: (componentRef: ComponentRef>) => {\n componentRef.instance.onClick\n .pipe(listDirective.takeUntil())\n .subscribe((data: StatusData) => listDirective.gotoStatus(data));\n }\n };\n }\n\n static actionsButton(listDirective: ConcernListDirective): IComponentColumn {\n return {\n label: 'Actions',\n type: 'component',\n className: 'list-control',\n headerClassName: 'list-control',\n component: ActionsButtonComponent,\n instanceTaken: (componentRef: ComponentRef>) => {\n componentRef.instance.onMouseenter\n .pipe(listDirective.takeUntil())\n .subscribe((row: T) => {\n listDirective.rewriteRow(row);\n });\n },\n };\n }\n\n static importColumn(listDirective: AdwpListDirective): IButtonsColumn {\n return {\n label: 'Import',\n type: 'buttons',\n className: 'list-control',\n headerClassName: 'list-control',\n buttons: [{\n icon: 'import_export',\n callback: (row) => listDirective.baseListDirective.listEvents({ cmd: 'import', row }),\n }]\n };\n }\n\n static configColumn(listDirective: AdwpListDirective): IButtonsColumn {\n return {\n label: 'Config',\n type: 'buttons',\n className: 'list-control',\n headerClassName: 'list-control',\n buttons: [{\n icon: 'settings',\n callback: (row) => listDirective.baseListDirective.listEvents({ cmd: 'config', row }),\n }]\n };\n }\n\n static bundleColumn(): IValueColumn {\n return {\n label: 'Bundle',\n sort: 'prototype_display_name',\n value: (row) => [row.prototype_display_name || row.prototype_name, row.prototype_version, row.edition].join(' '),\n };\n }\n\n static updateColumn(): IComponentColumn {\n return {\n label: 'Upgrade',\n type: 'component',\n className: 'list-control',\n headerClassName: 'list-control',\n component: UpgradeComponent,\n };\n }\n\n static deleteColumn(listDirective: AdwpListDirective): IButtonsColumn {\n return {\n type: 'buttons',\n className: 'list-control',\n headerClassName: 'list-control',\n buttons: [{\n icon: 'delete',\n callback: (row, event) => listDirective.delete(event, row),\n }]\n };\n }\n\n static providerColumn(): ILinkColumn {\n return {\n type: 'link',\n label: 'Provider',\n sort: 'provider_name',\n value: row => row.provider_name,\n url: row => `/provider/${row.provider_id}`,\n };\n }\n\n static keyColumn(): IValueColumn {\n return {\n label: 'Parameter',\n value: (row) => row.key,\n };\n }\n\n static valueColumn(): IValueColumn {\n return {\n label: 'Value',\n className: 'width30pr',\n headerClassName: 'width30pr',\n value: (row) => row.value,\n };\n }\n\n}\n", - "properties": [], - "methods": [ - { - "name": "actionsButton", - "args": [ - { - "name": "listDirective", - "type": "ConcernListDirective", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IComponentColumn", - "typeParameters": [ - "T" - ], - "line": 66, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "listDirective", - "type": "ConcernListDirective", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "bundleColumn", - "args": [], - "optional": false, - "returnType": "IValueColumn", - "typeParameters": [], - "line": 109, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ] - }, - { - "name": "configColumn", - "args": [ - { - "name": "listDirective", - "type": "AdwpListDirective", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IButtonsColumn", - "typeParameters": [ - "T" - ], - "line": 96, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "listDirective", - "type": "AdwpListDirective", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "deleteColumn", - "args": [ - { - "name": "listDirective", - "type": "AdwpListDirective", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IButtonsColumn", - "typeParameters": [ - "T" - ], - "line": 127, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "listDirective", - "type": "AdwpListDirective", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "descriptionColumn", - "args": [], - "optional": false, - "returnType": "IValueColumn", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ] - }, - { - "name": "fqdnColumn", - "args": [], - "optional": false, - "returnType": "IValueColumn", - "typeParameters": [], - "line": 22, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ] - }, - { - "name": "importColumn", - "args": [ - { - "name": "listDirective", - "type": "AdwpListDirective", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IButtonsColumn", - "typeParameters": [ - "T" - ], - "line": 83, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "listDirective", - "type": "AdwpListDirective", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "keyColumn", - "args": [], - "optional": false, - "returnType": "IValueColumn", - "typeParameters": [], - "line": 149, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ] - }, - { - "name": "nameColumn", - "args": [ - { - "name": "sort", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "'name'" - } - ], - "optional": false, - "returnType": "IValueColumn", - "typeParameters": [], - "line": 14, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "sort", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "'name'", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "providerColumn", - "args": [], - "optional": false, - "returnType": "ILinkColumn", - "typeParameters": [], - "line": 139, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ] - }, - { - "name": "stateColumn", - "args": [], - "optional": false, - "returnType": "IComponentColumn", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ] - }, - { - "name": "statusColumn", - "args": [ - { - "name": "listDirective", - "type": "AdwpListDirective", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "IComponentColumn", - "typeParameters": [ - "T" - ], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "listDirective", - "type": "AdwpListDirective", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "updateColumn", - "args": [], - "optional": false, - "returnType": "IComponentColumn", - "typeParameters": [], - "line": 117, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ] - }, - { - "name": "valueColumn", - "args": [], - "optional": false, - "returnType": "IValueColumn", - "typeParameters": [], - "line": 156, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "LoginPage", - "id": "class-LoginPage-977bf5dbdbd43649b038d4a82c6e9c87", - "file": "e2e/login/login.po.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { browser, by, element } from 'protractor';\n\nexport class LoginPage {\n private credentials = {\n username: 'admin',\n password: 'admin',\n };\n\n navigateTo() {\n return browser.get('/login');\n }\n\n fillCredentials(credentials: any = this.credentials) {\n element(by.css('[placeholder=\"Login\"]')).sendKeys(credentials.username);\n element(by.css('[placeholder=\"Password\"]')).sendKeys(credentials.password);\n this.getButton().click();\n }\n\n getErrorMessage() {\n return element(by.css('.warn')).getText();\n }\n\n getButton() {\n return element(by.tagName('button'));\n }\n}\n", - "properties": [ - { - "name": "credentials", - "defaultValue": "{\n username: 'admin',\n password: 'admin',\n }", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "optional": false, - "description": "", - "line": 15, - "modifierKind": [ - 120 - ] - } - ], - "methods": [ - { - "name": "fillCredentials", - "args": [ - { - "name": "credentials", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "this.credentials" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "credentials", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "this.credentials", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getButton", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 34, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getErrorMessage", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "navigateTo", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "" - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "ObjectsHelper", - "id": "class-ObjectsHelper-b3e1566deba281613f43dbe612ff8260", - "file": "src/app/helpers/objects-helper.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { JobObject, JobType } from '../core/types';\n\nexport class ObjectsHelper {\n\n static getObject(objects: JobObject[], type: JobType): JobObject {\n return objects.find(object => object.type === type);\n }\n\n static getObjectUrl(object: JobObject, objects: JobObject[]): string[] {\n if (object.type === 'cluster' || !ObjectsHelper.getCluster(objects)) {\n return ['/', object.type, `${object.id}`];\n } else if (object.type === 'component' && ObjectsHelper.getService(objects)) {\n return ['/', 'cluster', `${ObjectsHelper.getCluster(objects).id}`, 'service', `${ObjectsHelper.getService(objects).id}`, object.type, `${object.id}`];\n } else if (object.type === 'component' && !ObjectsHelper.getService(objects)) {\n return ['/', 'cluster', `${ObjectsHelper.getCluster(objects).id}`, 'host_component'];\n } else {\n return ['/', 'cluster', `${ObjectsHelper.getCluster(objects).id}`, object.type, `${object.id}`];\n }\n }\n\n static sortObjects(objects: JobObject[]): JobObject[] {\n return [\n ObjectsHelper.getObject(objects, 'cluster'),\n ObjectsHelper.getObject(objects, 'service'),\n ObjectsHelper.getObject(objects, 'component'),\n ObjectsHelper.getObject(objects, 'provider'),\n ObjectsHelper.getObject(objects, 'host'),\n ].filter(Boolean);\n }\n\n static getCluster(objects: JobObject[]): JobObject {\n return ObjectsHelper.getObject(objects, 'cluster');\n }\n\n static getService(objects: JobObject[]): JobObject {\n return ObjectsHelper.getObject(objects, 'service');\n }\n\n}\n", - "properties": [], - "methods": [ - { - "name": "getCluster", - "args": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "JobObject", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getObject", - "args": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "type", - "type": "JobType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "JobObject", - "typeParameters": [], - "line": 5, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "type", - "type": "JobType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getObjectUrl", - "args": [ - { - "name": "object", - "type": "JobObject", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string[]", - "typeParameters": [], - "line": 9, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "object", - "type": "JobObject", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getService", - "args": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "JobObject", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "sortObjects", - "args": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "JobObject[]", - "typeParameters": [], - "line": 21, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "objects", - "type": "JobObject[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "RequestCache", - "id": "class-RequestCache-8a514e04e9e3c150b655bc69be645c5e", - "file": "src/app/core/http-interseptors/request-cache.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { Injectable } from '@angular/core';\nimport { HttpRequest, HttpResponse } from '@angular/common/http';\n\nconst maxAge = Number.MAX_VALUE; // maximum cache age (ms)\n\ninterface RequestCacheEntry {\n url: string;\n response: HttpResponse;\n lastRead: number;\n}\n\nexport abstract class RequestCache {\n abstract get(req: HttpRequest): HttpResponse | undefined;\n abstract put(req: HttpRequest, response: HttpResponse): void;\n}\n\n@Injectable()\nexport class RequestCacheService implements RequestCache {\n cache = new Map();\n\n constructor() {}\n\n get(req: HttpRequest): HttpResponse | undefined {\n const url = req.urlWithParams;\n const cached = this.cache.get(url);\n\n if (!cached) return undefined;\n\n const isExpired = cached.lastRead < Date.now() - maxAge;\n\n const expired = isExpired ? 'Expired ' : '';\n // this.messanger.add(new Message(`${expired}cached response for \"${url}\".`));\n\n return isExpired ? undefined : cached.response;\n }\n\n put(req: HttpRequest, response: HttpResponse): void {\n const url = req.urlWithParams;\n // this.messanger.add(new Message(`Caching response from \"${url}\".` ));\n\n const entry = { url, response, lastRead: Date.now() };\n this.cache.set(url, entry);\n\n const expired = Date.now() - maxAge;\n\n this.cache.forEach(c => {\n if (c.lastRead < expired) this.cache.delete(c.url);\n });\n\n // this.messanger.add(new Message(`Request cache size: ${this.cache.size}.`));\n }\n}\n", - "properties": [], - "methods": [ - { - "name": "get", - "args": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "HttpResponse | undefined", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 125 - ], - "jsdoctags": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "put", - "args": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "response", - "type": "HttpResponse", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 125 - ], - "jsdoctags": [ - { - "name": "req", - "type": "HttpRequest", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "response", - "type": "HttpResponse", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "RouteSerializer", - "id": "class-RouteSerializer-8dd1bd3a3ce3f8be4547bb2e68025ad1", - "file": "src/app/core/store/router/route-serializer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { RouterStateSerializer } from '@ngrx/router-store';\nimport { RouterStateSnapshot, Params } from '@angular/router';\n\nexport interface RouterStateUrl {\n url: string;\n params: Params;\n queryParams: Params;\n}\n\nexport class RouteSerializer implements RouterStateSerializer {\n serialize(routerState: RouterStateSnapshot): RouterStateUrl {\n let route = routerState.root;\n\n while (route.firstChild) {\n route = route.firstChild;\n }\n\n const {\n url,\n root: { queryParams },\n } = routerState;\n const { params } = route;\n\n // Only return an object including the URL, params and query params\n // instead of the entire snapshot\n return { url, params, queryParams };\n }\n}\n", - "properties": [], - "methods": [ - { - "name": "serialize", - "args": [ - { - "name": "routerState", - "type": "RouterStateSnapshot", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "RouterStateUrl", - "typeParameters": [], - "line": 22, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "routerState", - "type": "RouterStateSnapshot", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [], - "implements": [ - "RouterStateSerializer" - ] - }, - { - "name": "StartPage", - "id": "class-StartPage-e4e774d0f67b20e2c020b586e5ac123b", - "file": "e2e/start/start.po.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { browser, element, by } from 'protractor';\n\nexport class StartPage {\n navigateTo() {\n return browser.get('/admin/intro');\n }\n\n getPageTitleText() {\n return element(by.css('.mat-card-title')).getText();\n }\n}\n", - "properties": [], - "methods": [ - { - "name": "getPageTitleText", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 19, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "navigateTo", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 15, - "deprecated": false, - "deprecationMessage": "" - } - ], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "StatePost", - "id": "class-StatePost-a875bd9ec8a9450bd7b364337c366dfb", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IComponent, Host, IRequires } from '@app/core/types';\n\nexport type ActionParam = 'add' | 'remove';\nexport type TConstraintValue = number | '+' | 'odd' | 'depend';\nexport type TConstraint = TConstraintValue[];\n\nexport interface IRawHosComponent {\n component: IComponent[];\n host: Partial[];\n hc: Post[];\n}\n\nexport interface Post {\n id?: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class Post implements Post {\n constructor(public host_id: number, public service_id: number, public component_id: number, public id?: number) {}\n}\n\n/**\n *```\n {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: Constraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n }\n ```\n * @class Tile\n */\nexport class Tile {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: TConstraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n}\n\nexport class HostTile extends Tile {\n constructor(rawHost: Partial) {\n super();\n this.id = rawHost.id;\n this.name = rawHost.fqdn;\n }\n}\n\nexport class CompTile extends Tile {\n prototype_id: number;\n service_id: number;\n component: string;\n requires: IRequires[];\n constructor(rawComponent: IComponent, public actions?: ActionParam[]) {\n super();\n this.id = rawComponent.id;\n this.service_id = rawComponent.service_id;\n this.component = `${rawComponent.service_name}/${rawComponent.name}`;\n this.name = rawComponent.display_name;\n this.disabled = rawComponent.service_state !== 'created';\n this.limit = rawComponent.constraint;\n this.requires = rawComponent.requires;\n this.prototype_id = rawComponent.prototype_id;\n }\n}\n\n/**\n * State user selection\n *\n * @class StatePost\n */\nexport class StatePost {\n private _data: Post[];\n\n constructor() {\n this._data = [];\n }\n\n private _compare(a: Post, b: Post) {\n return a.host_id === b.host_id && a.service_id === b.service_id && a.component_id === b.component_id;\n }\n\n get data() {\n return this._data;\n }\n\n add(post: Post) {\n const f = this._data.find((p) => this._compare(p, post));\n if (!f) this._data.push(post);\n else if (!f.id) f.id = post.id;\n }\n\n delete(post: Post) {\n this._data = this._data.filter((p) => !this._compare(p, post));\n }\n\n clear() {\n this._data = [];\n }\n\n update(data: Post[]) {\n data.forEach((a) => this.add(new Post(a.host_id, a.service_id, a.component_id, a.id)));\n }\n}\n/**\n *```\n {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n }\n *```\n */\nexport interface IStream {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [], - "line": 97 - }, - "properties": [ - { - "name": "_data", - "deprecated": false, - "deprecationMessage": "", - "type": "Post[]", - "optional": false, - "description": "", - "line": 97, - "modifierKind": [ - 120 - ] - } - ], - "description": "

State user selection

\n", - "rawdescription": "\n\nState user selection\n\n", - "methods": [ - { - "name": "_compare", - "args": [ - { - "name": "a", - "type": "Post", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "b", - "type": "Post", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 103, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ], - "jsdoctags": [ - { - "name": "a", - "type": "Post", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "b", - "type": "Post", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "add", - "args": [ - { - "name": "post", - "type": "Post", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 111, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "post", - "type": "Post", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clear", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 121, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "delete", - "args": [ - { - "name": "post", - "type": "Post", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 117, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "post", - "type": "Post", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "update", - "args": [ - { - "name": "data", - "type": "Post[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 125, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "Post[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "indexSignatures": [], - "accessors": { - "data": { - "name": "data", - "getSignature": { - "name": "data", - "type": "", - "returnType": "", - "line": 107 - } - } - }, - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "Tile", - "id": "class-Tile-a875bd9ec8a9450bd7b364337c366dfb", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IComponent, Host, IRequires } from '@app/core/types';\n\nexport type ActionParam = 'add' | 'remove';\nexport type TConstraintValue = number | '+' | 'odd' | 'depend';\nexport type TConstraint = TConstraintValue[];\n\nexport interface IRawHosComponent {\n component: IComponent[];\n host: Partial[];\n hc: Post[];\n}\n\nexport interface Post {\n id?: number;\n host_id: number;\n service_id: number;\n component_id: number;\n}\n\nexport class Post implements Post {\n constructor(public host_id: number, public service_id: number, public component_id: number, public id?: number) {}\n}\n\n/**\n *```\n {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: Constraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n }\n ```\n * @class Tile\n */\nexport class Tile {\n id: number;\n name: string;\n relations: Tile[] = [];\n isSelected?: boolean;\n isLink?: boolean;\n limit?: TConstraint;\n disabled: boolean;\n actions?: ActionParam[];\n color?: 'none' | 'white' | 'gray' | 'yellow';\n notification?: string;\n}\n\nexport class HostTile extends Tile {\n constructor(rawHost: Partial) {\n super();\n this.id = rawHost.id;\n this.name = rawHost.fqdn;\n }\n}\n\nexport class CompTile extends Tile {\n prototype_id: number;\n service_id: number;\n component: string;\n requires: IRequires[];\n constructor(rawComponent: IComponent, public actions?: ActionParam[]) {\n super();\n this.id = rawComponent.id;\n this.service_id = rawComponent.service_id;\n this.component = `${rawComponent.service_name}/${rawComponent.name}`;\n this.name = rawComponent.display_name;\n this.disabled = rawComponent.service_state !== 'created';\n this.limit = rawComponent.constraint;\n this.requires = rawComponent.requires;\n this.prototype_id = rawComponent.prototype_id;\n }\n}\n\n/**\n * State user selection\n *\n * @class StatePost\n */\nexport class StatePost {\n private _data: Post[];\n\n constructor() {\n this._data = [];\n }\n\n private _compare(a: Post, b: Post) {\n return a.host_id === b.host_id && a.service_id === b.service_id && a.component_id === b.component_id;\n }\n\n get data() {\n return this._data;\n }\n\n add(post: Post) {\n const f = this._data.find((p) => this._compare(p, post));\n if (!f) this._data.push(post);\n else if (!f.id) f.id = post.id;\n }\n\n delete(post: Post) {\n this._data = this._data.filter((p) => !this._compare(p, post));\n }\n\n clear() {\n this._data = [];\n }\n\n update(data: Post[]) {\n data.forEach((a) => this.add(new Post(a.host_id, a.service_id, a.component_id, a.id)));\n }\n}\n/**\n *```\n {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n }\n *```\n */\nexport interface IStream {\n link: Tile;\n linkSource: Tile[];\n selected: Tile;\n}\n", - "properties": [ - { - "name": "actions", - "deprecated": false, - "deprecationMessage": "", - "type": "ActionParam[]", - "optional": true, - "description": "", - "line": 60 - }, - { - "name": "color", - "deprecated": false, - "deprecationMessage": "", - "type": "\"none\" | \"white\" | \"gray\" | \"yellow\"", - "optional": true, - "description": "", - "line": 61 - }, - { - "name": "disabled", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 59 - }, - { - "name": "id", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 53 - }, - { - "name": "isLink", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 57 - }, - { - "name": "isSelected", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": true, - "description": "", - "line": 56 - }, - { - "name": "limit", - "deprecated": false, - "deprecationMessage": "", - "type": "TConstraint", - "optional": true, - "description": "", - "line": 58 - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 54 - }, - { - "name": "notification", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": true, - "description": "", - "line": 62 - }, - { - "name": "relations", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "Tile[]", - "optional": false, - "description": "", - "line": 55 - } - ], - "description": "
{\nid: number;\nname: string;\nrelations: Tile[] = [];\nisSelected?: boolean;\nisLink?: boolean;\nlimit?: Constraint;\ndisabled: boolean;\nactions?: ActionParam[];\ncolor?: 'none' | 'white' | 'gray' | 'yellow';\nnotification?: string;\n}
", - "rawdescription": "\n\n```\n{\nid: number;\nname: string;\nrelations: Tile[] = [];\nisSelected?: boolean;\nisLink?: boolean;\nlimit?: Constraint;\ndisabled: boolean;\nactions?: ActionParam[];\ncolor?: 'none' | 'white' | 'gray' | 'yellow';\nnotification?: string;\n}\n```\n", - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "UIOptions", - "id": "class-UIOptions-e7cc495d69a4fedb6c84456abf0fbd99", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IFieldOptions } from './../types';\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { getControlType, getKey, getOptions, getValidator, getValue, TFormOptions, IOutput } from '../services/field.service';\n\nimport { IConfig, IConfigAttr, IFieldStack, ILimits, IPanelOptions, IUIoptions, stateType, TNForm, TValue } from '../types';\nimport { IYContainer, IYField, IYspec } from '../yspec/yspec.service';\n\nexport class YContainer {}\n\nexport class YField {}\n\nexport class Yspec {\n constructor() {}\n}\n\nexport class UIOptions implements IUIoptions {}\n\nexport class Limits {\n min: number;\n max: number;\n option: any;\n read_only: stateType[];\n active: boolean;\n rules: IYField | IYContainer;\n constructor(public yspec: IYspec) {}\n set Rules(rules: IYField | IYContainer) {\n this.rules = rules;\n }\n}\n\nexport class FieldStack implements IFieldStack {\n subname: string;\n display_name: string;\n default: TValue = null;\n description?: string;\n limits: ILimits;\n ui_options: IUIoptions;\n\n constructor(\n id: number,\n public type: TNForm,\n public name: string = null,\n public value = null,\n public required = true,\n public read_only = false,\n public activatable = false\n ) {\n const dn = `field_${type}_${id}`;\n this.name = !this.name ? dn : this.name;\n this.subname = this.name === dn ? '' : `subname_${type}_${id}`;\n this.display_name = `display_${this.name}_${this.subname}`;\n this.value = getValue(this.type)(this.value, this.default, this.required);\n }\n\n set Limits(limits: ILimits) {\n this.limits = limits;\n }\n set UIOptions(options: IUIoptions) {\n this.ui_options = options;\n }\n}\n\nexport class Configuration implements IConfig {\n id?: number;\n date?: string;\n description?: string;\n attr?: IConfigAttr;\n constructor(public config: IFieldStack[]) {}\n}\n\nexport class FieldFactory {\n public static addGroup(id: number, params: TNForm[]): IFieldStack[] {\n const group = new FieldStack(id, 'group');\n return params.reduce((p, c, i) => [...p, new FieldStack(i, c, group.name)], [group]);\n }\n\n /**\n * return group if params as array\n */\n public static add(params: (TNForm | TNForm[])[]) {\n return params.reduce(\n (p, c, i) => [...p, ...(Array.isArray(c) ? this.addGroup(i, c) : [new FieldStack(i, c)])],\n []\n );\n }\n}\n\nconst toPanel = (a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n});\n\nconst toField = (a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n});\n\nexport const toFormOptions = (data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n};\n\nexport const setValue = (data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n );\n", - "properties": [], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [], - "implements": [ - "IUIoptions" - ] - }, - { - "name": "YContainer", - "id": "class-YContainer-e7cc495d69a4fedb6c84456abf0fbd99", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IFieldOptions } from './../types';\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { getControlType, getKey, getOptions, getValidator, getValue, TFormOptions, IOutput } from '../services/field.service';\n\nimport { IConfig, IConfigAttr, IFieldStack, ILimits, IPanelOptions, IUIoptions, stateType, TNForm, TValue } from '../types';\nimport { IYContainer, IYField, IYspec } from '../yspec/yspec.service';\n\nexport class YContainer {}\n\nexport class YField {}\n\nexport class Yspec {\n constructor() {}\n}\n\nexport class UIOptions implements IUIoptions {}\n\nexport class Limits {\n min: number;\n max: number;\n option: any;\n read_only: stateType[];\n active: boolean;\n rules: IYField | IYContainer;\n constructor(public yspec: IYspec) {}\n set Rules(rules: IYField | IYContainer) {\n this.rules = rules;\n }\n}\n\nexport class FieldStack implements IFieldStack {\n subname: string;\n display_name: string;\n default: TValue = null;\n description?: string;\n limits: ILimits;\n ui_options: IUIoptions;\n\n constructor(\n id: number,\n public type: TNForm,\n public name: string = null,\n public value = null,\n public required = true,\n public read_only = false,\n public activatable = false\n ) {\n const dn = `field_${type}_${id}`;\n this.name = !this.name ? dn : this.name;\n this.subname = this.name === dn ? '' : `subname_${type}_${id}`;\n this.display_name = `display_${this.name}_${this.subname}`;\n this.value = getValue(this.type)(this.value, this.default, this.required);\n }\n\n set Limits(limits: ILimits) {\n this.limits = limits;\n }\n set UIOptions(options: IUIoptions) {\n this.ui_options = options;\n }\n}\n\nexport class Configuration implements IConfig {\n id?: number;\n date?: string;\n description?: string;\n attr?: IConfigAttr;\n constructor(public config: IFieldStack[]) {}\n}\n\nexport class FieldFactory {\n public static addGroup(id: number, params: TNForm[]): IFieldStack[] {\n const group = new FieldStack(id, 'group');\n return params.reduce((p, c, i) => [...p, new FieldStack(i, c, group.name)], [group]);\n }\n\n /**\n * return group if params as array\n */\n public static add(params: (TNForm | TNForm[])[]) {\n return params.reduce(\n (p, c, i) => [...p, ...(Array.isArray(c) ? this.addGroup(i, c) : [new FieldStack(i, c)])],\n []\n );\n }\n}\n\nconst toPanel = (a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n});\n\nconst toField = (a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n});\n\nexport const toFormOptions = (data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n};\n\nexport const setValue = (data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n );\n", - "properties": [], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "YField", - "id": "class-YField-e7cc495d69a4fedb6c84456abf0fbd99", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IFieldOptions } from './../types';\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { getControlType, getKey, getOptions, getValidator, getValue, TFormOptions, IOutput } from '../services/field.service';\n\nimport { IConfig, IConfigAttr, IFieldStack, ILimits, IPanelOptions, IUIoptions, stateType, TNForm, TValue } from '../types';\nimport { IYContainer, IYField, IYspec } from '../yspec/yspec.service';\n\nexport class YContainer {}\n\nexport class YField {}\n\nexport class Yspec {\n constructor() {}\n}\n\nexport class UIOptions implements IUIoptions {}\n\nexport class Limits {\n min: number;\n max: number;\n option: any;\n read_only: stateType[];\n active: boolean;\n rules: IYField | IYContainer;\n constructor(public yspec: IYspec) {}\n set Rules(rules: IYField | IYContainer) {\n this.rules = rules;\n }\n}\n\nexport class FieldStack implements IFieldStack {\n subname: string;\n display_name: string;\n default: TValue = null;\n description?: string;\n limits: ILimits;\n ui_options: IUIoptions;\n\n constructor(\n id: number,\n public type: TNForm,\n public name: string = null,\n public value = null,\n public required = true,\n public read_only = false,\n public activatable = false\n ) {\n const dn = `field_${type}_${id}`;\n this.name = !this.name ? dn : this.name;\n this.subname = this.name === dn ? '' : `subname_${type}_${id}`;\n this.display_name = `display_${this.name}_${this.subname}`;\n this.value = getValue(this.type)(this.value, this.default, this.required);\n }\n\n set Limits(limits: ILimits) {\n this.limits = limits;\n }\n set UIOptions(options: IUIoptions) {\n this.ui_options = options;\n }\n}\n\nexport class Configuration implements IConfig {\n id?: number;\n date?: string;\n description?: string;\n attr?: IConfigAttr;\n constructor(public config: IFieldStack[]) {}\n}\n\nexport class FieldFactory {\n public static addGroup(id: number, params: TNForm[]): IFieldStack[] {\n const group = new FieldStack(id, 'group');\n return params.reduce((p, c, i) => [...p, new FieldStack(i, c, group.name)], [group]);\n }\n\n /**\n * return group if params as array\n */\n public static add(params: (TNForm | TNForm[])[]) {\n return params.reduce(\n (p, c, i) => [...p, ...(Array.isArray(c) ? this.addGroup(i, c) : [new FieldStack(i, c)])],\n []\n );\n }\n}\n\nconst toPanel = (a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n});\n\nconst toField = (a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n});\n\nexport const toFormOptions = (data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n};\n\nexport const setValue = (data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n );\n", - "properties": [], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - }, - { - "name": "Yspec", - "id": "class-Yspec-e7cc495d69a4fedb6c84456abf0fbd99", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "class", - "sourceCode": "import { IFieldOptions } from './../types';\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { getControlType, getKey, getOptions, getValidator, getValue, TFormOptions, IOutput } from '../services/field.service';\n\nimport { IConfig, IConfigAttr, IFieldStack, ILimits, IPanelOptions, IUIoptions, stateType, TNForm, TValue } from '../types';\nimport { IYContainer, IYField, IYspec } from '../yspec/yspec.service';\n\nexport class YContainer {}\n\nexport class YField {}\n\nexport class Yspec {\n constructor() {}\n}\n\nexport class UIOptions implements IUIoptions {}\n\nexport class Limits {\n min: number;\n max: number;\n option: any;\n read_only: stateType[];\n active: boolean;\n rules: IYField | IYContainer;\n constructor(public yspec: IYspec) {}\n set Rules(rules: IYField | IYContainer) {\n this.rules = rules;\n }\n}\n\nexport class FieldStack implements IFieldStack {\n subname: string;\n display_name: string;\n default: TValue = null;\n description?: string;\n limits: ILimits;\n ui_options: IUIoptions;\n\n constructor(\n id: number,\n public type: TNForm,\n public name: string = null,\n public value = null,\n public required = true,\n public read_only = false,\n public activatable = false\n ) {\n const dn = `field_${type}_${id}`;\n this.name = !this.name ? dn : this.name;\n this.subname = this.name === dn ? '' : `subname_${type}_${id}`;\n this.display_name = `display_${this.name}_${this.subname}`;\n this.value = getValue(this.type)(this.value, this.default, this.required);\n }\n\n set Limits(limits: ILimits) {\n this.limits = limits;\n }\n set UIOptions(options: IUIoptions) {\n this.ui_options = options;\n }\n}\n\nexport class Configuration implements IConfig {\n id?: number;\n date?: string;\n description?: string;\n attr?: IConfigAttr;\n constructor(public config: IFieldStack[]) {}\n}\n\nexport class FieldFactory {\n public static addGroup(id: number, params: TNForm[]): IFieldStack[] {\n const group = new FieldStack(id, 'group');\n return params.reduce((p, c, i) => [...p, new FieldStack(i, c, group.name)], [group]);\n }\n\n /**\n * return group if params as array\n */\n public static add(params: (TNForm | TNForm[])[]) {\n return params.reduce(\n (p, c, i) => [...p, ...(Array.isArray(c) ? this.addGroup(i, c) : [new FieldStack(i, c)])],\n []\n );\n }\n}\n\nconst toPanel = (a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n});\n\nconst toField = (a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n});\n\nexport const toFormOptions = (data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n};\n\nexport const setValue = (data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n );\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [], - "line": 22 - }, - "properties": [], - "methods": [], - "indexSignatures": [], - "inputsClass": [], - "outputsClass": [], - "hostBindings": [], - "hostListeners": [] - } - ], - "directives": [ - { - "name": "ActionsDirective", - "id": "directive-ActionsDirective-4a99492dc98d6050cef89c3777395d3d", - "file": "src/app/shared/components/actions/actions.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, HostListener, Input } from '@angular/core';\nimport { MatDialog, MatDialogConfig } from '@angular/material/dialog';\nimport { IAction } from '@app/core/types';\n\nimport { DialogComponent } from '../dialog.component';\nimport { ActionMasterComponent as component } from './master/master.component';\n\nexport interface ActionParameters {\n cluster?: {\n id: number;\n hostcomponent: string;\n };\n actions: IAction[];\n}\n\n@Directive({\n selector: '[appActions]'\n})\nexport class ActionsDirective {\n @Input('appActions') inputData: ActionParameters;\n\n constructor(private dialog: MatDialog) {}\n\n @HostListener('click')\n onClick() {\n this.dialog.closeAll();\n const dialogModel: MatDialogConfig = this.prepare();\n this.dialog.open(DialogComponent, dialogModel);\n }\n\n prepare(): MatDialogConfig {\n const maxWidth = '1400px';\n const model = this.inputData;\n\n if (!model.actions?.length) return { data: { title: 'No parameters for run the action', model: null, component: null } };\n\n const act = model.actions[0];\n const isMulty = model.actions.length > 1;\n\n const width = isMulty || act.config?.config.length || act.hostcomponentmap?.length ? '90%' : '400px';\n const title = act.ui_options?.disclaimer ? act.ui_options.disclaimer : isMulty ? 'Run an actions?' : `Run an action [ ${act.display_name} ]?`;\n\n return {\n width,\n maxWidth,\n data: {\n title,\n model,\n component,\n }\n };\n }\n}\n", - "selector": "[appActions]", - "providers": [], - "inputsClass": [ - { - "name": "appActions", - "deprecated": false, - "deprecationMessage": "", - "line": 31, - "type": "ActionParameters" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "click", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 36 - } - ], - "propertiesClass": [], - "methodsClass": [ - { - "name": "onClick", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 36, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'click'" - } - ] - }, - { - "name": "prepare", - "args": [], - "optional": false, - "returnType": "MatDialogConfig", - "typeParameters": [], - "line": 42, - "deprecated": false, - "deprecationMessage": "" - } - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 31, - "jsdoctags": [ - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "AdwpListDirective", - "id": "directive-AdwpListDirective-81b84d7ac1e15eb131c3e3aa3705da0a", - "file": "src/app/abstract-directives/adwp-list.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, OnInit } from '@angular/core';\nimport { BehaviorSubject } from 'rxjs';\nimport { IColumns, IListResult, Paging, RowEventData } from '@adwp-ui/widgets';\nimport { Sort } from '@angular/material/sort';\nimport { PageEvent } from '@angular/material/paginator';\n\nimport { ListDirective } from './list.directive';\nimport { AdwpBaseListDirective } from './adwp-base-list.directive';\nimport { BaseEntity, Entities } from '@app/core/types';\n\n@Directive({\n selector: '[appAdwpList]',\n})\nexport abstract class AdwpListDirective extends ListDirective implements OnInit {\n\n abstract listColumns: IColumns;\n\n data$: BehaviorSubject> = new BehaviorSubject(null);\n\n paging: BehaviorSubject = new BehaviorSubject(null);\n sorting: BehaviorSubject = new BehaviorSubject(null);\n\n defaultSort: Sort = { active: 'id', direction: 'desc' };\n\n reload(data: IListResult) {\n this.data$.next(data as any);\n }\n\n initBaseListDirective() {\n this.baseListDirective = new AdwpBaseListDirective(this, this.service, this.store);\n this.baseListDirective.typeName = this.type;\n this.baseListDirective.reload = this.reload.bind(this);\n (this.baseListDirective as AdwpBaseListDirective).paging = this.paging;\n (this.baseListDirective as AdwpBaseListDirective).sorting = this.sorting;\n this.baseListDirective.init();\n }\n\n ngOnInit() {\n this.initBaseListDirective();\n }\n\n clickRow(data: RowEventData) {\n this.clickCell(data.event, 'title', data.row);\n }\n\n auxclickRow(data: RowEventData) {\n this.clickCell(data.event, 'new-tab', data.row);\n }\n\n changeCount(count: number) {}\n\n getPageIndex(): number {\n return this.paging.value.pageIndex - 1;\n }\n\n getPageSize(): number {\n return this.paging.value.pageSize;\n }\n\n onChangePaging(paging: Paging): void {\n this.paging.next(paging);\n\n const pageEvent = new PageEvent();\n pageEvent.pageIndex = this.getPageIndex();\n pageEvent.length = this.data$.value.count;\n pageEvent.pageSize = this.getPageSize();\n\n this.pageHandler(pageEvent);\n }\n\n onChangeSort(sort: Sort): void {\n this.sorting.next(sort);\n this.changeSorting(sort);\n }\n\n getSort(): Sort {\n return this.sorting.value;\n }\n\n rewriteRow(row: BaseEntity) {\n this.service.checkItem(row).subscribe((item) => Object.keys(row).map((a) => (row[a] = item[a])));\n }\n\n findRow(id: number): BaseEntity {\n return this.data.data.find((item) => item.id === id);\n }\n\n}\n", - "selector": "[appAdwpList]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "data$", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject>", - "optional": false, - "description": "", - "line": 18 - }, - { - "name": "defaultSort", - "defaultValue": "{ active: 'id', direction: 'desc' }", - "deprecated": false, - "deprecationMessage": "", - "type": "Sort", - "optional": false, - "description": "", - "line": 23 - }, - { - "name": "listColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "IColumns", - "optional": false, - "description": "", - "line": 16, - "modifierKind": [ - 125 - ] - }, - { - "name": "paging", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 20 - }, - { - "name": "sorting", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 21 - } - ], - "methodsClass": [ - { - "name": "auxclickRow", - "args": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "changeCount", - "args": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clickRow", - "args": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 42, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "findRow", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "BaseEntity", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getPageIndex", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 52, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getPageSize", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 56, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getSort", - "args": [], - "optional": false, - "returnType": "Sort", - "typeParameters": [], - "line": 76, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "initBaseListDirective", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 38, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onChangePaging", - "args": [ - { - "name": "paging", - "type": "Paging", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "paging", - "type": "Paging", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "onChangeSort", - "args": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "reload", - "args": [ - { - "name": "data", - "type": "IListResult", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "IListResult", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "rewriteRow", - "args": [ - { - "name": "row", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 80, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "implements": [ - "OnInit" - ] - }, - { - "name": "BaseDetailAbstractDirective", - "id": "directive-BaseDetailAbstractDirective-dbebb9f675cf1f93860242df7c87e5b9", - "file": "src/app/abstract-directives/base-detail.abstract.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Injector, OnDestroy, OnInit } from '@angular/core';\nimport { ActivatedRoute, convertToParamMap, ParamMap } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { Observable, Subscription } from 'rxjs';\nimport { switchMap, tap } from 'rxjs/operators';\n\nimport { ChannelService, keyChannelStrim } from '../core/services';\nimport { ClusterService, WorkerInstance } from '../core/services/cluster.service';\nimport { EventMessage, getNavigationPath, setPathOfRoute, SocketState } from '../core/store';\nimport { EmmitRow, Host, IAction, Job } from '../core/types';\nimport { SocketListenerDirective } from '@app/shared/directives';\nimport { IDetails } from '@app/models/details';\nimport { AdcmEntity } from '../models/entity';\nimport { IIssues } from '../models/issue';\nimport { IssueHelper } from '../helpers/issue-helper';\nimport { ICluster } from '../models/cluster';\n\n@Directive({\n selector: '[appBaseDetailAbstract]',\n})\nexport abstract class BaseDetailAbstractDirective extends SocketListenerDirective implements OnInit, OnDestroy {\n subscription$: Subscription;\n upgradable = false;\n actions: IAction[] = [];\n status: number | string;\n issue: IIssues;\n current: IDetails;\n currentName = '';\n\n navigationPath: Observable = this.store.select(getNavigationPath).pipe(this.takeUntil());\n\n constructor(\n socket: Store,\n protected route: ActivatedRoute,\n protected service: ClusterService,\n protected channel: ChannelService,\n protected store: Store,\n injector: Injector,\n ) {\n super(socket);\n }\n\n get Current() {\n return this.service.Current;\n }\n\n initContext(param: ParamMap): Observable {\n return this.service.getContext(param);\n }\n\n ngOnInit(): void {\n this.subscription$ = this.route.paramMap.pipe(\n switchMap((param) => this.initContext(param)),\n tap((w) => this.run(w)),\n this.takeUntil(),\n ).subscribe();\n\n super.startListenSocket();\n }\n\n ngOnDestroy(): void {\n this.service.clearWorker();\n }\n\n get isIssue() {\n return IssueHelper.isIssue(this.issue);\n }\n\n run(w: WorkerInstance) {\n const {\n id,\n name,\n typeName,\n action,\n actions,\n issue,\n status,\n prototype_name,\n prototype_display_name,\n prototype_version,\n bundle_id,\n state,\n } = w.current;\n const { upgradable, upgrade, hostcomponent } = w.current as ICluster;\n const { log_files, objects } = w.current as Job;\n const { provider_id } = w.current as Host;\n\n this.currentName = name;\n this.actions = actions;\n this.upgradable = upgradable;\n this.status = status;\n\n const parent = w.current.typeName === 'cluster' ? null : w.cluster;\n this.issue = issue;\n\n this.current = {\n parent,\n id,\n name,\n typeName,\n actions,\n action,\n issue,\n upgradable,\n upgrade,\n status,\n state,\n log_files,\n objects,\n prototype_name,\n prototype_display_name,\n prototype_version,\n provider_id,\n bundle_id,\n hostcomponent,\n };\n }\n\n scroll(stop: { direct: -1 | 1 | 0; screenTop: number }) {\n this.channel.next(keyChannelStrim.scroll, stop);\n }\n\n reset() {\n if (this.subscription$) {\n this.subscription$.unsubscribe();\n }\n this.subscription$ = this.service.reset().pipe(\n this.takeUntil(),\n tap((a) => this.run(a)),\n this.takeUntil(),\n ).subscribe();\n }\n\n socketListener(m: EventMessage) {\n if ((m.event === 'create' || m.event === 'delete') && m.object.type === 'bundle') {\n this.reset();\n return;\n }\n\n const type = m.object.type === 'component' ? 'servicecomponent' : m.object.type;\n if (this.Current?.typeName === type && this.Current?.id === m.object.id) {\n if (this.service.Current.typeName === 'job' && (m.event === 'change_job_status' || m.event === 'add_job_log')) {\n this.reset();\n return;\n }\n\n if (m.event === 'change_state' || m.event === 'upgrade') {\n this.reset();\n return;\n }\n\n if (m.event === 'change_status') this.status = +m.object.details.value;\n }\n\n }\n\n refresh(event: EmmitRow): void {\n const { row } = event;\n\n const params: ParamMap = convertToParamMap({ cluster: row.id });\n this.store.dispatch(setPathOfRoute({ params }));\n\n }\n}\n", - "selector": "[appBaseDetailAbstract]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "actions", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction[]", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "IDetails", - "optional": false, - "description": "", - "line": 38 - }, - { - "name": "currentName", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 39 - }, - { - "name": "issue", - "deprecated": false, - "deprecationMessage": "", - "type": "IIssues", - "optional": false, - "description": "", - "line": 37 - }, - { - "name": "navigationPath", - "defaultValue": "this.store.select(getNavigationPath).pipe(this.takeUntil())", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "type": "number | string", - "optional": false, - "description": "", - "line": 36 - }, - { - "name": "subscription$", - "deprecated": false, - "deprecationMessage": "", - "type": "Subscription", - "optional": false, - "description": "", - "line": 33 - }, - { - "name": "upgradable", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 34 - } - ], - "methodsClass": [ - { - "name": "initContext", - "args": [ - { - "name": "param", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 58, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "param", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 72, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 62, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "refresh", - "args": [ - { - "name": "event", - "type": "EmmitRow", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 168, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EmmitRow", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "reset", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 134, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "run", - "args": [ - { - "name": "w", - "type": "WorkerInstance", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 80, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "w", - "type": "WorkerInstance", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "scroll", - "args": [ - { - "name": "stop", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 130, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "stop", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "socketListener", - "args": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 145, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "implements": [ - "OnInit", - "OnDestroy" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 41, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "Current": { - "name": "Current", - "getSignature": { - "name": "Current", - "type": "", - "returnType": "", - "line": 54 - } - }, - "isIssue": { - "name": "isIssue", - "getSignature": { - "name": "isIssue", - "type": "", - "returnType": "", - "line": 76 - } - } - } - }, - { - "name": "BaseDirective", - "id": "directive-BaseDirective-7f95d972aa2e0bf28838c5beb72bc3dc", - "file": "src/app/shared/directives/base.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, OnDestroy } from '@angular/core';\nimport { EventMessage } from '@app/core/store';\nimport { MonoTypeOperatorFunction, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\n@Directive({\n selector: '[appBase]'\n})\nexport class BaseDirective implements OnDestroy {\n destroy$ = new Subject();\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n takeUntil(): MonoTypeOperatorFunction {\n return takeUntil(this.destroy$);\n }\n}\nexport interface ISocketListener {\n socketListener: (m: EventMessage) => void;\n}\n", - "selector": "[appBase]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21 - } - ], - "methodsClass": [ - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "OnDestroy" - ] - }, - { - "name": "BaseFormDirective", - "id": "directive-BaseFormDirective-a8060909d158ae3a5edc1970e85b3bef", - "file": "src/app/shared/add-component/base-form.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Inject } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { MatDialog } from '@angular/material/dialog';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { ADD_SERVICE_PROVIDER, IAddService } from '@app/shared/add-component/add-service-model';\n\n@Directive({\n selector: '[appBaseForm]',\n})\nexport class BaseFormDirective extends BaseDirective {\n form = new FormGroup({});\n\n constructor(\n @Inject(ADD_SERVICE_PROVIDER) public service: IAddService,\n public dialog: MatDialog,\n ) {\n super();\n }\n\n onCancel(): void {\n this.form.reset();\n this.dialog.closeAll();\n }\n\n save() {}\n}\n", - "selector": "[appBaseForm]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 27, - "modifierKind": [ - 122 - ] - }, - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 23 - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "IAddService", - "optional": false, - "description": "", - "line": 26, - "decorators": [ - { - "name": "Inject", - "stringifiedArguments": "ADD_SERVICE_PROVIDER" - } - ], - "modifierKind": [ - 122 - ] - } - ], - "methodsClass": [ - { - "name": "onCancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "save", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 37, - "deprecated": false, - "deprecationMessage": "" - } - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "IAddService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 23, - "jsdoctags": [ - { - "name": "service", - "type": "IAddService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "BaseMapListDirective", - "id": "directive-BaseMapListDirective-c4849ca5fb4d9a382681ce222fff0dff", - "file": "src/app/shared/form-elements/map.component.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Component, Directive, OnInit } from '@angular/core';\nimport { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';\n\nimport { FieldDirective } from './field.directive';\n\n@Directive({\n selector: '[appBaseMapList]'\n})\nexport class BaseMapListDirective extends FieldDirective implements OnInit {\n asList: boolean;\n items = new FormArray([]);\n\n constructor(private fb: FormBuilder) {\n super();\n }\n\n ngOnInit() {\n if (!Object.keys(this.field.value || {}).length) this.control.setValue('');\n this.reload();\n this.items.valueChanges.pipe(\n this.takeUntil()\n ).subscribe((a: { key: string; value: string }[]) => this.prepare(a));\n\n this.control.statusChanges.pipe(\n this.takeUntil()\n ).subscribe((state) => {\n if (state === 'DISABLED') {\n this.items.controls.forEach((control) => {\n control.disable({ emitEvent: false });\n });\n } else {\n this.items.controls.forEach((control) => {\n control.enable({ emitEvent: false });\n });\n }\n });\n }\n\n prepare(a: { key: string; value: string }[]) {\n let value = this.asList ? a.map(b => b.value).filter(c => c) : a.length ? a.reduce((p, c) => ({\n ...p,\n [c.key]: c.value\n }), {}) : null;\n if (value && this.asList) value = (value as Array).length ? value : null;\n this.control.setValue(value);\n }\n\n reload() {\n this.items.reset([]);\n this.items.controls = [];\n const fieldValue = this.field.value ? { ...(this.field.value as Object) } : {};\n Object.keys(fieldValue).forEach(a => this.items.push(this.fb.group({\n key: [{ value: a, disabled: this.control.disabled }, Validators.required],\n value: [{ value: fieldValue[a], disabled: this.control.disabled }],\n })));\n }\n\n add() {\n const group = this.fb.group({ key: ['', Validators.required], value: '' });\n this.items.push(group);\n group.controls['key'].markAsTouched();\n }\n\n check(item: FormGroup) {\n return item.controls['key'].hasError('required');\n }\n\n clear(i: number) {\n this.items.removeAt(i);\n }\n}\n\n@Component({\n selector: 'app-fields-list',\n templateUrl: './map-list.template.html',\n styleUrls: ['./map.component.scss']\n})\nexport class FieldListComponent extends BaseMapListDirective {\n asList = true;\n}\n\n@Component({\n selector: 'app-fields-map',\n templateUrl: './map-list.template.html',\n styleUrls: ['./map.component.scss']\n})\nexport class FieldMapComponent extends BaseMapListDirective {\n asList = false;\n}\n", - "selector": "[appBaseMapList]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "asList", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 21 - }, - { - "name": "items", - "defaultValue": "new FormArray([])", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 22 - } - ], - "methodsClass": [ - { - "name": "add", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "check", - "args": [ - { - "name": "item", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 75, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clear", - "args": [ - { - "name": "i", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 79, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "i", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 28, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "prepare", - "args": [ - { - "name": "a", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "a", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "reload", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 59, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "OnInit" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "fb", - "type": "FormBuilder", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 22, - "jsdoctags": [ - { - "name": "fb", - "type": "FormBuilder", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "ColorOptionDirective", - "id": "directive-ColorOptionDirective-ca251c92bac56e96d78d6d88c07663e2", - "file": "src/app/shared/configuration/tools/color-option.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, ElementRef, Input, AfterViewInit, Renderer2 } from '@angular/core';\n\n@Directive({\n selector: '[appColorOption]'\n})\nexport class ColorOptionDirective implements AfterViewInit {\n \n @Input('appColorOption')\n colorOption: string;\n\n constructor(private el: ElementRef, private render: Renderer2) { }\n\n ngAfterViewInit(): void {\n const pchb = this.el.nativeElement.firstElementChild;\n this.render.setStyle(pchb, 'backgroundColor', this.colorOption);\n }\n}\n", - "selector": "[appColorOption]", - "providers": [], - "inputsClass": [ - { - "name": "appColorOption", - "deprecated": false, - "deprecationMessage": "", - "line": 20, - "type": "string" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "ngAfterViewInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "AfterViewInit" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "render", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 20, - "jsdoctags": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "render", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "ConcernListDirective", - "id": "directive-ConcernListDirective-97129e475fc97cc978e474980a72c99c", - "file": "src/app/abstract-directives/concern-list.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, OnInit } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { MatDialog } from '@angular/material/dialog';\nimport { Store } from '@ngrx/store';\n\nimport { AdwpListDirective } from './adwp-list.directive';\nimport { ListService } from '../shared/components/list/list.service';\nimport { SocketState } from '../core/store';\nimport { ConcernService } from '../services/concern.service';\nimport { ConcernEventType } from '../models/concern/concern-reason';\n\n@Directive({\n selector: '[appConcernList]',\n})\nexport abstract class ConcernListDirective extends AdwpListDirective implements OnInit {\n\n abstract eventTypes: ConcernEventType[];\n\n constructor(\n protected service: ListService,\n protected store: Store,\n public route: ActivatedRoute,\n public router: Router,\n public dialog: MatDialog,\n protected concernService: ConcernService,\n ) {\n super(service, store, route, router, dialog);\n }\n\n ngOnInit() {\n super.ngOnInit();\n\n this.concernService.events({ types: this.eventTypes })\n .pipe(this.takeUntil())\n .subscribe(resp => {\n const row = this.findRow(resp.object.id);\n if (row) {\n this.rewriteRow(row);\n }\n });\n }\n\n}\n", - "selector": "[appConcernList]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 24, - "modifierKind": [ - 122 - ] - }, - { - "name": "eventTypes", - "deprecated": false, - "deprecationMessage": "", - "type": "ConcernEventType[]", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 125 - ] - }, - { - "name": "route", - "deprecated": false, - "deprecationMessage": "", - "type": "ActivatedRoute", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ] - }, - { - "name": "router", - "deprecated": false, - "deprecationMessage": "", - "type": "Router", - "optional": false, - "description": "", - "line": 23, - "modifierKind": [ - 122 - ] - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "OnInit" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "concernService", - "type": "ConcernService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 17, - "jsdoctags": [ - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "concernService", - "type": "ConcernService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "ConfigFieldMarker", - "id": "directive-ConfigFieldMarker-7f8905d3248056843c8691d2f355bad7", - "file": "src/app/shared/configuration/attributes/config-field.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, TemplateRef } from '@angular/core';\n\n@Directive({\n selector: '[configField]'\n})\nexport class ConfigFieldMarker {\n constructor(public template: TemplateRef) {\n }\n\n}\n", - "selector": "[configField]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "template", - "deprecated": false, - "deprecationMessage": "", - "type": "TemplateRef", - "optional": false, - "description": "", - "line": 7, - "modifierKind": [ - 122 - ] - } - ], - "methodsClass": [], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "template", - "type": "TemplateRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 6, - "jsdoctags": [ - { - "name": "template", - "type": "TemplateRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "ConfirmEqualValidatorDirective", - "id": "directive-ConfirmEqualValidatorDirective-5ed7a95456ab0cc12447d26b365cbcd8", - "file": "src/app/shared/form-elements/confirm-equal-validator.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Input } from '@angular/core';\nimport { AbstractControl, NG_VALIDATORS, Validator } from '@angular/forms';\n\n@Directive({\n selector: '[appConfirmEqualValidator]',\n providers: [\n {\n provide: NG_VALIDATORS,\n useExisting: ConfirmEqualValidatorDirective,\n multi: true,\n },\n ],\n})\nexport class ConfirmEqualValidatorDirective implements Validator {\n @Input() appConfirmEqualValidator: string;\n\n validate(control: AbstractControl): { [key: string]: any } | null {\n const controlToCompare = control.parent.controls[this.appConfirmEqualValidator];\n if (controlToCompare && controlToCompare.value !== control.value) return { notEqual: true };\n return null;\n }\n}\n", - "selector": "[appConfirmEqualValidator]", - "providers": [ - { - "name": "{\n provide: NG_VALIDATORS, useExisting: ConfirmEqualValidatorDirective, multi: true,\n}", - "type": "directive" - } - ], - "inputsClass": [ - { - "name": "appConfirmEqualValidator", - "deprecated": false, - "deprecationMessage": "", - "line": 26, - "type": "string" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "validate", - "args": [ - { - "name": "control", - "type": "AbstractControl", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "literal type | null", - "typeParameters": [], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "control", - "type": "AbstractControl", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "implements": [ - "Validator" - ] - }, - { - "name": "DetailAbstractDirective", - "id": "directive-DetailAbstractDirective-0a1325c8cd7bd6be0aa9ca378bebb622", - "file": "src/app/abstract-directives/detail.abstract.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { switchMap } from 'rxjs/operators';\nimport { Directive, OnInit } from '@angular/core';\n\nimport { BaseDetailAbstractDirective } from './base-detail.abstract.directive';\nimport { LeftMenuItem } from '@app/shared/details/left-menu/left-menu.component';\nimport { AdcmEntity } from '@app/models/entity';\nimport { EntityService } from '@app/abstract/entity-service';\n\n@Directive({\n selector: '[appDetailAbstract]',\n})\nexport abstract class DetailAbstractDirective extends BaseDetailAbstractDirective implements OnInit {\n\n entity: EntityType;\n\n abstract leftMenu: LeftMenuItem[];\n protected abstract subjectService: EntityService;\n abstract entityParam: string;\n\n entityReceived(entity: EntityType): void {\n this.entity = entity;\n }\n\n ngOnInit() {\n super.ngOnInit();\n\n this.route.params.pipe(\n switchMap((params) => this.subjectService.get(params[this.entityParam])),\n this.takeUntil(),\n ).subscribe((entity) => this.entityReceived(entity));\n }\n\n}\n", - "selector": "[appDetailAbstract]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 14 - }, - { - "name": "entityParam", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 18, - "modifierKind": [ - 125 - ] - }, - { - "name": "leftMenu", - "deprecated": false, - "deprecationMessage": "", - "type": "LeftMenuItem[]", - "optional": false, - "description": "", - "line": 16, - "modifierKind": [ - 125 - ] - }, - { - "name": "subjectService", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityService", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 121, - 125 - ] - } - ], - "methodsClass": [ - { - "name": "entityReceived", - "args": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "OnInit" - ] - }, - { - "name": "DynamicDirective", - "id": "directive-DynamicDirective-417b7397318b007b139d072bc712681f", - "file": "src/app/shared/directives/dynamic.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, ViewContainerRef, EventEmitter } from '@angular/core';\n\n/**\n * @param name string required name action\n * @param data any\n */\nexport interface DynamicEvent {\n name: string;\n data?: any;\n}\n\nexport interface DynamicComponent {\n event?: EventEmitter;\n model?: any;\n onEnterKey?: () => void;\n}\n\n@Directive({\n selector: '[appDynamic]',\n})\nexport class DynamicDirective {\n constructor(public viewContainerRef: ViewContainerRef) {}\n}\n", - "selector": "[appDynamic]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "viewContainerRef", - "deprecated": false, - "deprecationMessage": "", - "type": "ViewContainerRef", - "optional": false, - "description": "", - "line": 33, - "modifierKind": [ - 122 - ] - } - ], - "methodsClass": [], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "viewContainerRef", - "type": "ViewContainerRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 32, - "jsdoctags": [ - { - "name": "viewContainerRef", - "type": "ViewContainerRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "FieldDirective", - "id": "directive-FieldDirective-ed712f4322fbb9bf0fca84c6dd7dec50", - "file": "src/app/shared/form-elements/field.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Input, OnInit } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\n\nimport { IFieldOptions } from '../configuration/types';\nimport { BaseDirective } from '../directives';\n\n@Directive({\n selector: '[appField]'\n})\nexport class FieldDirective extends BaseDirective implements OnInit {\n @Input() form: FormGroup;\n @Input() field: IFieldOptions;\n\n ngOnInit() {\n this.control.markAllAsTouched();\n }\n\n get control() {\n return this.form.controls[this.field.name];\n }\n\n get isValid() {\n if (this.field.read_only) return true;\n const control = this.control;\n return control.valid && (control.dirty || control.touched);\n }\n\n hasError(name: string) {\n return this.control.hasError(name);\n }\n}\n", - "selector": "[appField]", - "providers": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions" - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "OnInit" - ], - "accessors": { - "control": { - "name": "control", - "getSignature": { - "name": "control", - "type": "", - "returnType": "", - "line": 29 - } - }, - "isValid": { - "name": "isValid", - "getSignature": { - "name": "isValid", - "type": "", - "returnType": "", - "line": 33 - } - } - } - }, - { - "name": "ForTestDirective", - "id": "directive-ForTestDirective-4bddeac80fcef482d5dbd9695ebb0c2b", - "file": "src/app/shared/directives/for-test.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Input, OnInit, ElementRef } from '@angular/core';\n\n@Directive({\n selector: '[appForTest]',\n})\nexport class ForTestDirective implements OnInit {\n @Input('appForTest') attr: string;\n constructor(private el: ElementRef) {}\n\n ngOnInit() {\n // old attrname = test\n this.el.nativeElement.setAttribute('adcm_test', this.attr);\n }\n}\n", - "selector": "[appForTest]", - "providers": [], - "inputsClass": [ - { - "name": "appForTest", - "deprecated": false, - "deprecationMessage": "", - "line": 18, - "type": "string" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 21, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "OnInit" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 18, - "jsdoctags": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "HolderDirective", - "id": "directive-HolderDirective-0ac793ac5e8d784427b2a424b66c502e", - "file": "src/app/shared/host-components-map/holder.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, ElementRef, Input } from '@angular/core';\n\n@Directive({\n selector: '[appHolder]',\n})\nexport class HolderDirective {\n ps: { short: HTMLElement; long: HTMLElement };\n\n @Input('appHolder') set scroll(data: { direct: -1 | 1 | 0; scrollTop: number }) {\n if (data) {\n if (!this.ps) this.getPs();\n else if (this.ps.short.clientHeight + data.scrollTop < this.ps.long.clientHeight) this.ps.short.style.marginTop = `${Math.floor(data.scrollTop)}px`;\n }\n }\n\n constructor(private el: ElementRef) {}\n\n getPs() {\n const els: HTMLElement[] = [...this.el.nativeElement.children];\n if (els.length) {\n const a = els[0].querySelector('.wrapper'),\n b = els[1].querySelector('.wrapper');\n this.ps = a.clientHeight < b.clientHeight ? { short: a, long: b } : { short: b, long: a };\n }\n }\n}\n", - "selector": "[appHolder]", - "providers": [], - "inputsClass": [ - { - "name": "appHolder", - "deprecated": false, - "deprecationMessage": "", - "line": 20, - "type": "literal type" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "ps", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 18 - } - ], - "methodsClass": [ - { - "name": "getPs", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "" - } - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 25, - "jsdoctags": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "scroll": { - "name": "scroll", - "setSignature": { - "name": "scroll", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 20, - "jsdoctags": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "HoverDirective", - "id": "directive-HoverDirective-b5eb8ecc9a72e8fcaeb28fd53316e59b", - "file": "src/app/entry/task/hover.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, HostListener, ContentChild, Renderer2 } from '@angular/core';\nimport { MatIcon } from '@angular/material/icon';\n\n@Directive({\n selector: '[appHoverStatusTask]'\n})\nexport class HoverDirective {\n @ContentChild('taskIcon') icon: MatIcon;\n @HostListener('mouseover') onHover() {\n const icon = this.icon._elementRef.nativeElement;\n this.re.removeClass(icon, 'icon-locked');\n icon.innerText = 'block';\n }\n @HostListener('mouseout') onOut() {\n const icon = this.icon._elementRef.nativeElement;\n this.re.addClass(icon, 'icon-locked');\n icon.innerText = 'autorenew';\n }\n constructor(private re: Renderer2) {}\n}\n", - "selector": "[appHoverStatusTask]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "mouseout", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 25 - }, - { - "name": "mouseover", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 20 - } - ], - "propertiesClass": [ - { - "name": "icon", - "deprecated": false, - "deprecationMessage": "", - "type": "MatIcon", - "optional": false, - "description": "", - "line": 19, - "decorators": [ - { - "name": "ContentChild", - "stringifiedArguments": "'taskIcon'" - } - ] - } - ], - "methodsClass": [ - { - "name": "onHover", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseover'" - } - ] - }, - { - "name": "onOut", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseout'" - } - ] - } - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "re", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 29, - "jsdoctags": [ - { - "name": "re", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "HoverDirective", - "id": "directive-HoverDirective-ec340ca11b388c9173e1d8d44335b611-1", - "file": "src/app/shared/directives/hover.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, HostListener, ElementRef } from '@angular/core';\n\n@Directive({\n selector: '[appHover]',\n})\nexport class HoverDirective {\n constructor(private el: ElementRef) {}\n\n @HostListener('mouseenter')\n onmouseenter() {\n this.el.nativeElement.style.backgroundColor = 'rgba(255, 255, 255, 0.12)';\n this.el.nativeElement.style.cursor = 'pointer';\n }\n\n @HostListener('mouseleave')\n onmouseleave() {\n this.el.nativeElement.style.backgroundColor = 'transparent';\n this.el.nativeElement.style.cursor = 'defautl';\n }\n}\n", - "selector": "[appHover]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "mouseenter", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 21 - }, - { - "name": "mouseleave", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 27 - } - ], - "propertiesClass": [], - "methodsClass": [ - { - "name": "onmouseenter", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 21, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseenter'" - } - ] - }, - { - "name": "onmouseleave", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseleave'" - } - ] - } - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 17, - "jsdoctags": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "isDuplicate": true, - "duplicateId": 1, - "duplicateName": "HoverDirective-1" - }, - { - "name": "InfinityScrollDirective", - "id": "directive-InfinityScrollDirective-b6ddac5ac67b6dfcc2a9f719cbc4112c", - "file": "src/app/shared/directives/infinity-scroll.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Renderer2, Host, OnInit, Output, EventEmitter } from '@angular/core';\nimport { MatSelect } from '@angular/material/select';\n\nconst POINT_WHEN_EMMIT = 100;\n\n@Directive({\n selector: '[appInfinityScroll]',\n})\nexport class InfinityScrollDirective implements OnInit {\n @Output() topScrollPoint = new EventEmitter();\n\n constructor(private renderer: Renderer2, @Host() private el: MatSelect) {}\n\n ngOnInit(): void {\n if ('openedChange' in this.el) this.el.openedChange.subscribe((open: boolean) => this.registerPanel(open));\n else this.renderer.listen(this.el, 'scroll', this.onScrollPanel.bind(this));\n }\n\n registerPanel(open: boolean) {\n if (open) {\n const panel = (this.el as MatSelect).panel.nativeElement;\n this.renderer.listen(panel, 'scroll', this.onScrollPanel.bind(this));\n }\n }\n\n onScrollPanel(event: any) {\n const target = event.target;\n\n const height = Array.from(target.children).reduce((p, c) => p + c.clientHeight, 0) - target.clientHeight;\n if (target.scrollTop > height - POINT_WHEN_EMMIT) this.topScrollPoint.emit();\n }\n}\n", - "selector": "[appInfinityScroll]", - "providers": [], - "inputsClass": [], - "outputsClass": [ - { - "name": "topScrollPoint", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 21, - "type": "EventEmitter" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onScrollPanel", - "args": [ - { - "name": "event", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 37, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "registerPanel", - "args": [ - { - "name": "open", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "open", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "implements": [ - "OnInit" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "el", - "type": "MatSelect", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 21, - "jsdoctags": [ - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "el", - "type": "MatSelect", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "ListDirective", - "id": "directive-ListDirective-b2732117053d4e2c44a2067ed2b98ce7", - "file": "src/app/abstract-directives/list.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';\nimport { filter } from 'rxjs/operators';\nimport { Store } from '@ngrx/store';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { MatPaginator, PageEvent } from '@angular/material/paginator';\nimport { MatSort, Sort } from '@angular/material/sort';\nimport { MatTableDataSource } from '@angular/material/table';\nimport { MatDialog } from '@angular/material/dialog';\nimport { BaseDirective, EventHelper } from '@adwp-ui/widgets';\n\nimport { EmmitRow, TypeName } from '@app/core/types';\nimport { BaseListDirective } from '@app/shared/components/list/base-list.directive';\nimport { SocketState } from '@app/core/store';\nimport { ListService } from '@app/shared/components/list/list.service';\nimport { DialogComponent } from '@app/shared/components';\nimport { StatusData } from '@app/components/columns/status-column/status-column.component';\nimport { ICluster } from '@app/models/cluster';\nimport { LIST_SERVICE_PROVIDER } from '@app/shared/components/list/list-service-token';\n\nenum Direction {\n '' = '',\n 'asc' = '',\n 'desc' = '-',\n}\n\n@Directive({\n selector: '[appAbstractList]',\n})\nexport abstract class ListDirective extends BaseDirective implements OnInit, OnDestroy {\n\n @Input() type: TypeName;\n\n baseListDirective: BaseListDirective;\n\n current: any = {};\n\n @Input()\n columns: Array;\n\n @Output()\n listItemEvt = new EventEmitter();\n\n paginator: MatPaginator;\n\n sort: MatSort;\n\n data: MatTableDataSource = new MatTableDataSource([]);\n\n @Output() pageEvent = new EventEmitter();\n\n addToSorting = false;\n\n @Input()\n set dataSource(data: { results: any; count: number }) {\n if (data) {\n const list = data.results;\n this.data = new MatTableDataSource(list);\n this.changeCount(data.count);\n this.listItemEvt.emit({ cmd: 'onLoad', row: list[0] });\n }\n }\n\n sortParam = '';\n\n constructor(\n @Inject(LIST_SERVICE_PROVIDER) protected service: ListService,\n protected store: Store,\n public route: ActivatedRoute,\n public router: Router,\n public dialog: MatDialog,\n ) {\n super();\n }\n\n changeCount(count: number): void {\n this.paginator.length = count;\n }\n\n clickCell($e: MouseEvent, cmd?: string, row?: any, item?: any): void {\n EventHelper.stopPropagation($e);\n this.current = row;\n this.listItemEvt.emit({ cmd, row, item });\n }\n\n ngOnInit(): void {\n this.baseListDirective = new BaseListDirective(this, this.service, this.store);\n this.baseListDirective.typeName = this.type;\n this.baseListDirective.init();\n }\n\n ngOnDestroy(): void {\n this.baseListDirective.destroy();\n super.ngOnDestroy();\n }\n\n delete($event: MouseEvent, row: any): void {\n EventHelper.stopPropagation($event);\n this.dialog\n .open(DialogComponent, {\n data: {\n title: `Deleting \"${row.name || row.fqdn}\"`,\n text: 'Are you sure?',\n controls: ['Yes', 'No'],\n },\n })\n .beforeClosed()\n .pipe(filter((yes) => yes))\n .subscribe(() => this.listItemEvt.emit({ cmd: 'delete', row }));\n }\n\n getPageIndex(): number {\n return this.paginator.pageIndex;\n }\n\n getPageSize(): number {\n return this.paginator.pageSize;\n }\n\n changeSorting(sort: Sort): void {\n const _filter = this.route.snapshot.paramMap.get('filter') || '';\n const pageIndex = this.getPageIndex();\n const pageSize = this.getPageSize();\n const ordering = this.getSortParam(sort);\n\n this.router.navigate(\n [\n './',\n {\n page: pageIndex,\n limit: pageSize,\n filter: _filter,\n ordering,\n },\n ],\n { relativeTo: this.route }\n );\n\n this.sortParam = ordering;\n }\n\n getSortParam(a: Sort): string {\n const params: { [key: string]: string[] } = {\n prototype_version: ['prototype_display_name', 'prototype_version'],\n };\n\n if (a) {\n const dumb = params[a.active] ? params[a.active] : [a.active],\n active = dumb.map((b: string) => `${Direction[a.direction]}${b}`).join(',');\n\n const current = this.sortParam;\n if (current && this.addToSorting) {\n const result = current\n .split(',')\n .filter((b) => dumb.every((d) => d !== b.replace('-', '')))\n .join(',');\n return [result, a.direction ? active : ''].filter((e) => e).join(',');\n }\n\n return a.direction ? active : '';\n } else {\n return '';\n }\n }\n\n getSort(): Sort {\n return this.sort;\n }\n\n pageHandler(pageEvent: PageEvent): void {\n this.pageEvent.emit(pageEvent);\n localStorage.setItem('limit', String(pageEvent.pageSize));\n const f = this.route.snapshot.paramMap.get('filter') || '';\n const ordering = this.getSortParam(this.getSort());\n this.router.navigate(['./', { page: pageEvent.pageIndex, limit: pageEvent.pageSize, filter: f, ordering }], {\n relativeTo: this.route,\n });\n }\n\n gotoStatus(data: StatusData): void {\n this.clickCell(data.event, data.action, data.row);\n }\n\n}\n", - "selector": "[appAbstractList]", - "providers": [], - "inputsClass": [ - { - "name": "columns", - "deprecated": false, - "deprecationMessage": "", - "line": 38, - "type": "Array" - }, - { - "name": "dataSource", - "deprecated": false, - "deprecationMessage": "", - "line": 54, - "type": "literal type" - }, - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "line": 31, - "type": "TypeName" - } - ], - "outputsClass": [ - { - "name": "listItemEvt", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 41, - "type": "EventEmitter" - }, - { - "name": "pageEvent", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 49, - "type": "EventEmitter" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "addToSorting", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 51 - }, - { - "name": "baseListDirective", - "deprecated": false, - "deprecationMessage": "", - "type": "BaseListDirective", - "optional": false, - "description": "", - "line": 33 - }, - { - "name": "current", - "defaultValue": "{}", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "data", - "defaultValue": "new MatTableDataSource([])", - "deprecated": false, - "deprecationMessage": "", - "type": "MatTableDataSource", - "optional": false, - "description": "", - "line": 47 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 70, - "modifierKind": [ - 122 - ] - }, - { - "name": "paginator", - "deprecated": false, - "deprecationMessage": "", - "type": "MatPaginator", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "route", - "deprecated": false, - "deprecationMessage": "", - "type": "ActivatedRoute", - "optional": false, - "description": "", - "line": 68, - "modifierKind": [ - 122 - ] - }, - { - "name": "router", - "deprecated": false, - "deprecationMessage": "", - "type": "Router", - "optional": false, - "description": "", - "line": 69, - "modifierKind": [ - 122 - ] - }, - { - "name": "sort", - "deprecated": false, - "deprecationMessage": "", - "type": "MatSort", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "sortParam", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 63 - } - ], - "methodsClass": [ - { - "name": "changeCount", - "args": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 75, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "changeSorting", - "args": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 119, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clickCell", - "args": [ - { - "name": "$e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cmd", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true - }, - { - "name": "row", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "optional": true - }, - { - "name": "item", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 79, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "$e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cmd", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - }, - { - "name": "row", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - }, - { - "name": "item", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "delete", - "args": [ - { - "name": "$event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "row", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 96, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "$event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "row", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getPageIndex", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 111, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getPageSize", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 115, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getSort", - "args": [], - "optional": false, - "returnType": "Sort", - "typeParameters": [], - "line": 165, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getSortParam", - "args": [ - { - "name": "a", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 141, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "a", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "gotoStatus", - "args": [ - { - "name": "data", - "type": "StatusData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 179, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "StatusData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 91, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 85, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "pageHandler", - "args": [ - { - "name": "pageEvent", - "type": "PageEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 169, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "pageEvent", - "type": "PageEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "implements": [ - "OnInit", - "OnDestroy" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 63, - "jsdoctags": [ - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "dataSource": { - "name": "dataSource", - "setSignature": { - "name": "dataSource", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 54, - "jsdoctags": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "MenuItemAbstractDirective", - "id": "directive-MenuItemAbstractDirective-a01f00b70a77d7759db2385b1debcabb", - "file": "src/app/abstract-directives/menu-item.abstract.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Input } from '@angular/core';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { AdcmEntity } from '../models/entity';\n\n@Directive({\n selector: '[appMenuItemAbstract]',\n})\nexport abstract class MenuItemAbstractDirective extends BaseDirective {\n\n protected _entity: EntityType;\n\n @Input() label: string;\n @Input() link: string;\n @Input() get entity(): EntityType {\n return this._entity;\n }\n set entity(value: EntityType) {\n this._entity = value;\n }\n @Input() data: any;\n\n}\n", - "selector": "[appMenuItemAbstract]", - "providers": [], - "inputsClass": [ - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "line": 21, - "type": "any" - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "line": 15, - "type": "EntityType" - }, - { - "name": "label", - "deprecated": false, - "deprecationMessage": "", - "line": 13, - "type": "string" - }, - { - "name": "link", - "deprecated": false, - "deprecationMessage": "", - "line": 14, - "type": "string" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "_entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 11, - "modifierKind": [ - 121 - ] - } - ], - "methodsClass": [], - "accessors": { - "entity": { - "name": "entity", - "setSignature": { - "name": "entity", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "value", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 18, - "jsdoctags": [ - { - "name": "value", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "entity", - "type": "", - "returnType": "EntityType", - "line": 15 - } - } - } - }, - { - "name": "MTextareaDirective", - "id": "directive-MTextareaDirective-be20a57ee4266c26b8475a8d6b07cdca", - "file": "src/app/shared/directives/m-textarea.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit } from '@angular/core';\nimport { getProfile, ProfileService, ProfileState, setTextareaHeight } from '@app/core/store';\nimport { Store } from '@ngrx/store';\n\nimport { BaseDirective } from './base.directive';\n\n// textarea Material\nconst PADDING_TOP_BOTTOM = 16;\n\n@Directive({\n selector: '[appMTextarea]',\n providers: [ProfileService],\n})\nexport class MTextareaDirective extends BaseDirective implements OnInit, OnDestroy {\n flag = false;\n @Input('appMTextarea')\n key: string;\n\n constructor(private el: ElementRef, private profile: Store) {\n super();\n }\n\n @HostListener('mousedown')\n mouseDown() {\n this.flag = true;\n }\n\n ngOnInit(): void {\n window.addEventListener('mouseup', () => {\n this.profile\n .select(getProfile)\n .pipe(this.takeUntil())\n .subscribe(p => {\n const data = p.textarea;\n const old = data[this.key];\n const value = +this.el.nativeElement.offsetHeight - PADDING_TOP_BOTTOM;\n if (this.flag && old !== value) this.profile.dispatch(setTextareaHeight({ key: this.key, value }));\n this.flag = false;\n });\n });\n\n this.profile\n .select(getProfile)\n .pipe(this.takeUntil())\n .subscribe(p => {\n const k = Object.keys(p.textarea).find(key => key === this.key);\n if (k) (this.el.nativeElement as HTMLTextAreaElement).style.height = p.textarea[k] + 'px';\n });\n }\n}\n", - "selector": "[appMTextarea]", - "providers": [ - { - "name": "ProfileService" - } - ], - "inputsClass": [ - { - "name": "appMTextarea", - "deprecated": false, - "deprecationMessage": "", - "line": 28, - "type": "string" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "mousedown", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 35 - } - ], - "propertiesClass": [ - { - "name": "flag", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 26 - } - ], - "methodsClass": [ - { - "name": "mouseDown", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mousedown'" - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "OnInit", - "OnDestroy" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "profile", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 28, - "jsdoctags": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "profile", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "MultiSortDirective", - "id": "directive-MultiSortDirective-c283848e261b136d5b4037a8f5f58071", - "file": "src/app/shared/components/list/multi-sort.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, ElementRef, EventEmitter, HostListener, Input, Output, Renderer2 } from '@angular/core';\n\n@Directive({\n selector: '[appMultiSort]',\n})\nexport class MultiSortDirective {\n shiftKey = false;\n private params: string[] = [];\n\n @Input('appMultiSort') set sortParam(param: string) {\n const el = this.el.nativeElement;\n this.params = param.split(',');\n this.hideAllArrows(el);\n setTimeout(() => this.params.map((p) => this.preCell(p, el)), 0);\n }\n\n @Output() mousedownevent = new EventEmitter();\n\n @HostListener('mousedown', ['$event']) onmousedown(e: MouseEvent) {\n this.shiftKey = e.shiftKey;\n this.mousedownevent.emit(e.shiftKey);\n }\n\n @HostListener('mouseover', ['$event.target']) onmouseover(h: HTMLElement) {\n const el = this.el.nativeElement;\n this.params.map((p) => this.preCell(p, el));\n }\n\n @HostListener('mouseout', ['$event.target']) mouseleave(row: HTMLElement) {\n const el = this.el.nativeElement;\n setTimeout(() => this.params.map((p) => this.preCell(p, el)), 300);\n }\n\n constructor(private el: ElementRef, private renderer: Renderer2) {}\n\n hideAllArrows(el: any) {\n Array.from(el.getElementsByTagName('mat-header-cell')).forEach((e) => {\n const a = e.querySelector('div.mat-sort-header-container>div.mat-sort-header-arrow');\n if (a) this.renderer.setStyle(a, 'opacity', 0);\n });\n }\n\n preCell(p: string, el: HTMLElement) {\n const direction = p[0] === '-' ? 'descending' : 'ascending',\n active = p[0] === '-' ? p.substr(1) : p;\n\n const column = el.querySelector(`mat-header-cell.mat-column-${active}`) || el.querySelector(`mat-header-cell[mat-sort-header=\"${active}\"]`);\n if (p && column) {\n this.renderer.setAttribute(column, 'aria-sort', direction);\n\n const container = column.querySelector('div.mat-sort-header-container');\n this.renderer.addClass(container, 'mat-sort-header-sorted');\n\n const arrow = container.querySelector('div.mat-sort-header-arrow');\n if (arrow) {\n this.renderer.setStyle(arrow, 'opacity', 1);\n this.renderer.setStyle(arrow, 'transform', 'translateY(0px)');\n\n const indicator = arrow.querySelector('div.mat-sort-header-indicator');\n this.renderer.setStyle(indicator, 'transform', direction === 'descending' ? 'translateY(10px)' : 'translateY(0px)');\n\n if (direction === 'descending') {\n const left = indicator.querySelector('.mat-sort-header-pointer-left');\n this.renderer.setStyle(left, 'transform', 'rotate(45deg)');\n\n const right = indicator.querySelector('.mat-sort-header-pointer-right');\n this.renderer.setStyle(right, 'transform', 'rotate(-45deg)');\n }\n }\n }\n }\n}\n", - "selector": "[appMultiSort]", - "providers": [], - "inputsClass": [ - { - "name": "appMultiSort", - "deprecated": false, - "deprecationMessage": "", - "line": 21, - "type": "string" - } - ], - "outputsClass": [ - { - "name": "mousedownevent", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 28, - "type": "EventEmitter" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "mousedown", - "args": [ - { - "name": "e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "argsDecorator": [ - "$event" - ], - "deprecated": false, - "deprecationMessage": "", - "line": 30 - }, - { - "name": "mouseout", - "args": [ - { - "name": "row", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "" - } - ], - "argsDecorator": [ - "$event.target" - ], - "deprecated": false, - "deprecationMessage": "", - "line": 40 - }, - { - "name": "mouseover", - "args": [ - { - "name": "h", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "" - } - ], - "argsDecorator": [ - "$event.target" - ], - "deprecated": false, - "deprecationMessage": "", - "line": 35 - } - ], - "propertiesClass": [ - { - "name": "params", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "optional": false, - "description": "", - "line": 19, - "modifierKind": [ - 120 - ] - }, - { - "name": "shiftKey", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 18 - } - ], - "methodsClass": [ - { - "name": "hideAllArrows", - "args": [ - { - "name": "el", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 47, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "el", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "mouseleave", - "args": [ - { - "name": "row", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 40, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseout', ['$event.target']" - } - ], - "jsdoctags": [ - { - "name": "row", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "onmousedown", - "args": [ - { - "name": "e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mousedown', ['$event']" - } - ], - "jsdoctags": [ - { - "name": "e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "onmouseover", - "args": [ - { - "name": "h", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseover', ['$event.target']" - } - ], - "jsdoctags": [ - { - "name": "h", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "preCell", - "args": [ - { - "name": "p", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "el", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 54, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "p", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "el", - "type": "HTMLElement", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 43, - "jsdoctags": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "sortParam": { - "name": "sortParam", - "setSignature": { - "name": "sortParam", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "param", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 21, - "jsdoctags": [ - { - "name": "param", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "PopoverContentDirective", - "id": "directive-PopoverContentDirective-0880cc0a0ba2915551e48a7dba5f219f", - "file": "src/app/abstract-directives/popover-content.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive } from '@angular/core';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { PopoverInput } from '../directives/popover.directive';\n\nexport type PopoverEventFunc = (event: any) => void;\n\n@Directive({\n selector: '[appAbstractPopoverContent]',\n})\nexport abstract class PopoverContentDirective extends BaseDirective {\n\n abstract data: PopoverInput;\n\n event?: PopoverEventFunc;\n\n}\n", - "selector": "[appAbstractPopoverContent]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "type": "PopoverInput", - "optional": false, - "description": "", - "line": 13, - "modifierKind": [ - 125 - ] - }, - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "type": "PopoverEventFunc", - "optional": true, - "description": "", - "line": 15 - } - ], - "methodsClass": [] - }, - { - "name": "PopoverDirective", - "id": "directive-PopoverDirective-828cf763235e75cd27e094ca706187a9", - "file": "src/app/directives/popover.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { ComponentFactory, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Renderer2, Type, ViewContainerRef, } from '@angular/core';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { PopoverComponent } from '@app/components/popover/popover.component';\nimport { PopoverContentDirective, PopoverEventFunc } from '@app/abstract-directives/popover-content.directive';\n\nexport interface PopoverInput { [inputKey: string]: any; }\n\n@Directive({\n selector: '[appPopover]'\n})\nexport class PopoverDirective extends BaseDirective implements OnInit, OnDestroy {\n\n containerRef: ComponentRef;\n factory: ComponentFactory;\n leaveListener: () => void;\n\n shown = false;\n timeoutId: any;\n\n @Input() component: Type;\n @Input() data: PopoverInput = {};\n @Input() event: PopoverEventFunc;\n @Input() hideTimeout = 0;\n\n constructor(\n private elementRef: ElementRef,\n public viewContainer: ViewContainerRef,\n public componentFactoryResolver: ComponentFactoryResolver,\n public renderer: Renderer2,\n ) {\n super();\n }\n\n ngOnInit() {\n this.factory = this.componentFactoryResolver.resolveComponentFactory(PopoverComponent);\n }\n\n hideComponent() {\n if (!this.timeoutId) {\n this.timeoutId = setTimeout(() => {\n this.clear();\n this.shown = false;\n this.timeoutId = undefined;\n }, this.hideTimeout);\n }\n }\n\n checkReEnter() {\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n this.timeoutId = undefined;\n }\n }\n\n @HostListener('mouseenter') mouseEnter() {\n this.checkReEnter();\n if (this.component && !this.shown) {\n this.containerRef = this.viewContainer.createComponent(this.factory);\n this.containerRef.instance.component = this.component;\n this.containerRef.instance.data = this.data;\n this.containerRef.instance.event = this.event;\n\n this.leaveListener = this.renderer.listen(\n this.elementRef.nativeElement.parentElement,\n 'mouseleave',\n () => this.hideComponent(),\n );\n\n this.renderer.listen(\n this.containerRef.location.nativeElement,\n 'mouseenter',\n () => this.checkReEnter(),\n );\n\n this.shown = true;\n }\n }\n\n clear() {\n if (this.containerRef) {\n this.containerRef.destroy();\n }\n\n this.viewContainer.clear();\n\n if (this.leaveListener) {\n this.elementRef.nativeElement.parentElement.removeEventListener('mouseleave', this.leaveListener);\n }\n }\n\n ngOnDestroy() {\n super.ngOnDestroy();\n this.clear();\n }\n\n}\n", - "selector": "[appPopover]", - "providers": [], - "inputsClass": [ - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "line": 21, - "type": "Type" - }, - { - "name": "data", - "defaultValue": "{}", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "PopoverInput" - }, - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "PopoverEventFunc" - }, - { - "name": "hideTimeout", - "defaultValue": "0", - "deprecated": false, - "deprecationMessage": "", - "line": 24, - "type": "number" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "mouseenter", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 56 - } - ], - "propertiesClass": [ - { - "name": "componentFactoryResolver", - "deprecated": false, - "deprecationMessage": "", - "type": "ComponentFactoryResolver", - "optional": false, - "description": "", - "line": 29, - "modifierKind": [ - 122 - ] - }, - { - "name": "containerRef", - "deprecated": false, - "deprecationMessage": "", - "type": "ComponentRef", - "optional": false, - "description": "", - "line": 14 - }, - { - "name": "factory", - "deprecated": false, - "deprecationMessage": "", - "type": "ComponentFactory", - "optional": false, - "description": "", - "line": 15 - }, - { - "name": "leaveListener", - "deprecated": false, - "deprecationMessage": "", - "type": "function", - "optional": false, - "description": "", - "line": 16 - }, - { - "name": "renderer", - "deprecated": false, - "deprecationMessage": "", - "type": "Renderer2", - "optional": false, - "description": "", - "line": 30, - "modifierKind": [ - 122 - ] - }, - { - "name": "shown", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 18 - }, - { - "name": "timeoutId", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "viewContainer", - "deprecated": false, - "deprecationMessage": "", - "type": "ViewContainerRef", - "optional": false, - "description": "", - "line": 28, - "modifierKind": [ - 122 - ] - } - ], - "methodsClass": [ - { - "name": "checkReEnter", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "clear", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 80, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hideComponent", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "mouseEnter", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 56, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseenter'" - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 92, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "OnInit", - "OnDestroy" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "elementRef", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "viewContainer", - "type": "ViewContainerRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 24, - "jsdoctags": [ - { - "name": "elementRef", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "viewContainer", - "type": "ViewContainerRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "ScrollDirective", - "id": "directive-ScrollDirective-e2a0df59940a2b7306c7c01804345ad1", - "file": "src/app/shared/directives/scroll.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Output, HostListener, EventEmitter } from '@angular/core';\n\n@Directive({\n selector: '[appScroll]',\n})\nexport class ScrollDirective {\n private scrollTop = 0;\n\n @Output() read = new EventEmitter<{ direct: -1 | 1 | 0; scrollTop: number }>();\n\n @HostListener('scroll', ['$event.target']) onscroll(e: Element) {\n\n const { scrollHeight, scrollTop, clientHeight } = e;\n\n if (scrollTop < this.scrollTop) this.read.emit({ direct: -1, scrollTop });\n else this.read.emit( { direct: 1, scrollTop }); \n \n if (scrollHeight <= scrollTop + clientHeight) this.read.emit({ direct: 0, scrollTop });\n\n this.scrollTop = scrollTop;\n\n }\n}\n", - "selector": "[appScroll]", - "providers": [], - "inputsClass": [], - "outputsClass": [ - { - "name": "read", - "defaultValue": "new EventEmitter<{ direct: -1 | 1 | 0; scrollTop: number }>()", - "deprecated": false, - "deprecationMessage": "", - "line": 20, - "type": "EventEmitter" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "scroll", - "args": [ - { - "name": "e", - "type": "Element", - "deprecated": false, - "deprecationMessage": "" - } - ], - "argsDecorator": [ - "$event.target" - ], - "deprecated": false, - "deprecationMessage": "", - "line": 22 - } - ], - "propertiesClass": [ - { - "name": "scrollTop", - "defaultValue": "0", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 18, - "modifierKind": [ - 120 - ] - } - ], - "methodsClass": [ - { - "name": "onscroll", - "args": [ - { - "name": "e", - "type": "Element", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 22, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'scroll', ['$event.target']" - } - ], - "jsdoctags": [ - { - "name": "e", - "type": "Element", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ] - }, - { - "name": "SocketListenerDirective", - "id": "directive-SocketListenerDirective-fa0c54661488f8a796fa76d8835736e4", - "file": "src/app/shared/directives/socketListener.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, Injectable, OnDestroy } from '@angular/core';\nimport { select, Store } from '@ngrx/store';\nimport { filter, tap } from 'rxjs/operators';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { EventMessage, getMessage, SocketState, clearMessages } from '@app/core/store';\n\n@Directive({\n selector: '[appBase]',\n})\n@Injectable()\nexport class SocketListenerDirective extends BaseDirective implements OnDestroy {\n socket$ = this.socket.pipe(this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object));\n\n constructor(private socket: Store) {\n super();\n }\n\n ngOnDestroy() {\n super.ngOnDestroy();\n this.socket.dispatch(clearMessages());\n }\n\n startListenSocket(): void {\n this.socket$.pipe(\n tap(m => this.socketListener(m))\n ).subscribe();\n }\n\n socketListener(m: EventMessage) {\n console.warn('No implemented socketListener method', m);\n }\n}\n", - "selector": "[appBase]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "socket$", - "defaultValue": "this.socket.pipe(this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object))", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 24 - } - ], - "methodsClass": [ - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "socketListener", - "args": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "startListenSocket", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "" - } - ], - "implements": [ - "OnDestroy" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 24, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "StatusAbstractDirective", - "id": "directive-StatusAbstractDirective-9e65b4957844903d90f9c54452cc2f0f", - "file": "src/app/abstract-directives/status.abstract.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, OnInit, ViewChild } from '@angular/core';\nimport { BaseDirective } from '@adwp-ui/widgets';\nimport { BehaviorSubject } from 'rxjs';\nimport { Store } from '@ngrx/store';\nimport { ActivatedRoute, Params } from '@angular/router';\nimport { filter, switchMap, tap } from 'rxjs/operators';\n\nimport { StatusTreeSubject } from '../models/status-tree';\nimport { Folding } from '../components/status-tree/status-tree.component';\nimport { EventMessage, selectMessage, SocketState } from '../core/store';\nimport { HavingStatusTreeAbstractService } from '../abstract/having-status-tree.abstract.service';\nimport { AdcmEntity } from '@app/models/entity';\n\n@Directive({\n selector: '[appStatusAbstract]',\n})\nexport abstract class StatusAbstractDirective extends BaseDirective implements OnInit {\n\n @ViewChild('tree', { static: false }) tree: any;\n\n loading = false;\n\n entity: EntityType;\n entityId: number;\n statusTree = new BehaviorSubject(null);\n\n folding: Folding;\n\n abstract getEntityIdFromParams(params: Params): number;\n\n constructor(\n protected route: ActivatedRoute,\n protected store: Store,\n public entityService: HavingStatusTreeAbstractService,\n ) {\n super();\n }\n\n eventReceived(event: EventMessage): void {}\n\n prepareListeners() {\n return this.store.pipe(\n selectMessage,\n this.takeUntil(),\n filter(event => event.event === 'change_status'),\n ).subscribe((event: EventMessage) => this.eventReceived(event));\n }\n\n prepareStatusTree(input: StatusTreeType): StatusTreeType {\n return input;\n }\n\n pipeData(): any {}\n\n ngOnInit(): void {\n this.route.params.pipe(\n this.takeUntil(),\n tap(() => this.loading = true),\n tap(() => this.folding = Folding.Expanded),\n tap((params) => this.entityId = this.getEntityIdFromParams(params)),\n switchMap(() => this.entityService.get(this.entityId)),\n tap(entity => this.entity = entity),\n switchMap(() => this.entityService.getStatusTree(this.entityId)),\n ).subscribe((resp) => {\n this.loading = false;\n this.statusTree.next(this.prepareStatusTree(resp));\n this.prepareListeners();\n });\n }\n\n expandCollapseAll() {\n if (this.tree.hasCollapsed()) {\n this.tree.expandAll();\n } else {\n this.tree.collapseAll();\n }\n }\n\n}\n", - "selector": "[appStatusAbstract]", - "providers": [], - "inputsClass": [], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "propertiesClass": [ - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 23 - }, - { - "name": "entityId", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 24 - }, - { - "name": "entityService", - "deprecated": false, - "deprecationMessage": "", - "type": "HavingStatusTreeAbstractService", - "optional": false, - "description": "", - "line": 34, - "modifierKind": [ - 122 - ] - }, - { - "name": "folding", - "deprecated": false, - "deprecationMessage": "", - "type": "Folding", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "loading", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21 - }, - { - "name": "statusTree", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 25 - }, - { - "name": "tree", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 19, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'tree', {static: false}" - } - ] - } - ], - "methodsClass": [ - { - "name": "eventReceived", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "expandCollapseAll", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getEntityIdFromParams", - "args": [ - { - "name": "params", - "type": "Params", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 125 - ], - "jsdoctags": [ - { - "name": "params", - "type": "Params", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 55, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "pipeData", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 53, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "prepareListeners", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "prepareStatusTree", - "args": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "StatusTreeType", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "implements": [ - "OnInit" - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "entityService", - "type": "HavingStatusTreeAbstractService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 29, - "jsdoctags": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "entityService", - "type": "HavingStatusTreeAbstractService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "TooltipDirective", - "id": "directive-TooltipDirective-d74b801f6035df70b2158fb08675c0c8", - "file": "src/app/shared/components/tooltip/tooltip.directive.ts", - "type": "directive", - "description": "", - "rawdescription": "\n", - "sourceCode": "import { Directive, ElementRef, HostListener, Input } from '@angular/core';\nimport { EventHelper } from '@adwp-ui/widgets';\n\nimport { BaseEntity } from '@app/core/types/api';\nimport { ComponentName, PositionType, TooltipService } from '../tooltip/tooltip.service';\n\n@Directive({\n selector: '[appTooltip]',\n})\nexport class TooltipDirective {\n @Input() appTooltip: string | BaseEntity;\n @Input() appTooltipPosition: PositionType = 'bottom';\n @Input() appTooltipComponent: ComponentName;\n\n /**\n * TODO: To show tooltip by condition [04.12.2019]\n * ConditionType - under construction,\n * Now - one the condition this is width and scroll of source\n * tooltip.component.ts line: 118 checkBuild()\n */\n @Input() appTooltipShowByCondition: boolean;\n\n constructor(private el: ElementRef, private tooltip: TooltipService) {}\n\n @HostListener('mouseenter', ['$event']) menter(e: MouseEvent): void {\n EventHelper.stopPropagation(e);\n const options = {\n content: this.appTooltip,\n componentName: this.appTooltipComponent,\n position: this.appTooltipPosition,\n condition: this.appTooltipShowByCondition,\n };\n if (this.appTooltip) this.tooltip.show(e, this.el.nativeElement, options);\n }\n\n @HostListener('mouseleave') mleave(): void {\n this.tooltip.hide();\n }\n\n @HostListener('click') mclick(): void {\n this.tooltip.hide(true);\n }\n}\n", - "selector": "[appTooltip]", - "providers": [], - "inputsClass": [ - { - "name": "appTooltip", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "string | BaseEntity" - }, - { - "name": "appTooltipComponent", - "deprecated": false, - "deprecationMessage": "", - "line": 24, - "type": "ComponentName" - }, - { - "name": "appTooltipPosition", - "defaultValue": "'bottom'", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "PositionType" - }, - { - "name": "appTooltipShowByCondition", - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "TODO: To show tooltip by condition [04.12.2019]\nConditionType - under construction,\nNow - one the condition this is width and scroll of source\ntooltip.component.ts line: 118 checkBuild()", - "description": "

TODO: To show tooltip by condition [04.12.2019]\nConditionType - under construction,\nNow - one the condition this is width and scroll of source\ntooltip.component.ts line: 118 checkBuild()

\n", - "line": 32, - "type": "boolean" - } - ], - "outputsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "click", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 51 - }, - { - "name": "mouseenter", - "args": [ - { - "name": "e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "argsDecorator": [ - "$event" - ], - "deprecated": false, - "deprecationMessage": "", - "line": 36 - }, - { - "name": "mouseleave", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 47 - } - ], - "propertiesClass": [], - "methodsClass": [ - { - "name": "mclick", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 51, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'click'" - } - ] - }, - { - "name": "menter", - "args": [ - { - "name": "e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 36, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseenter', ['$event']" - } - ], - "jsdoctags": [ - { - "name": "e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "mleave", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 47, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseleave'" - } - ] - } - ], - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "tooltip", - "type": "TooltipService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 32, - "jsdoctags": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "tooltip", - "type": "TooltipService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - ], - "components": [ - { - "name": "ActionListComponent", - "id": "component-ActionListComponent-b73a6cb5f4edff543cabc7c54faff0b1", - "file": "src/app/shared/components/actions/action-list/action-list.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-action-list", - "styleUrls": [], - "styles": [], - "template": "\n play_circle_outline\n\n\n \n Run action\n  \n autorenew\n play_circle_outline\n \n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "actionLink", - "deprecated": false, - "deprecationMessage": "", - "line": 53, - "type": "string" - }, - { - "name": "actions", - "defaultValue": "[]", - "deprecated": true, - "deprecationMessage": "in the fight against caching", - "jsdoctags": [ - { - "pos": 1857, - "end": 1901, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 321, - "tagName": { - "pos": 1858, - "end": 1868, - "flags": 4227072, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "deprecated" - }, - "comment": "

in the fight against caching

\n" - } - ], - "line": 59, - "type": "{}" - }, - { - "name": "asButton", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 52, - "type": "boolean" - }, - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "line": 50, - "type": "literal type" - }, - { - "name": "disabled", - "deprecated": false, - "deprecationMessage": "", - "line": 51, - "type": "boolean" - }, - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "line": 54, - "type": "string" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "actions$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 61 - } - ], - "methodsClass": [ - { - "name": "getData", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 65, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { IAction } from '@app/core/types';\nimport { Observable } from 'rxjs';\n\nimport { ActionsService } from '../actions.service';\n\n@Component({\n selector: 'app-action-list',\n template: `\n \n play_circle_outline\n \n \n \n Run action\n  \n autorenew\n play_circle_outline\n \n \n \n `,\n})\nexport class ActionListComponent {\n @Input() cluster: { id: number; hostcomponent: string };\n @Input() disabled: boolean;\n @Input() asButton = false;\n @Input() actionLink: string;\n @Input() state: string;\n\n /**\n * @deprecated in the fight against caching\n */\n @Input() actions = [];\n\n actions$: Observable;\n\n constructor(private service: ActionsService) {}\n\n getData(): void {\n // if (!this.actions.length) ADCM-1505 it's possible cache after finished job\n this.actions$ = this.service.getActions(this.actionLink); //.subscribe((a) => (this.actions = a));\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ActionsService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 61, - "jsdoctags": [ - { - "name": "service", - "type": "ActionsService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - { - "name": "ActionMasterComponent", - "id": "component-ActionMasterComponent-68dbd4ca65382ae9a71958c5b56e1f40", - "file": "src/app/shared/components/actions/master/master.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "MasterService" - } - ], - "selector": "app-master", - "styleUrls": [], - "styles": [ - "\n .action-button {\n background: none !important;\n margin: 6px 0;\n\n &:hover {\n background: rgba(255, 255, 255, 0.04) !important;\n }\n }\n\n .controls-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n " - ], - "templateUrl": [ - "./master.component.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction", - "optional": false, - "description": "", - "line": 47 - }, - { - "name": "event", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "type": "EventEmitter", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "model", - "deprecated": false, - "deprecationMessage": "", - "type": "ActionParameters", - "optional": false, - "description": "", - "line": 46 - }, - { - "name": "runBtn", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 52, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'runBtn', {read: ElementRef}" - } - ] - }, - { - "name": "show", - "deprecated": false, - "deprecationMessage": "", - "type": "whatShow", - "optional": false, - "description": "", - "line": 48 - }, - { - "name": "verbose", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 50 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "cancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 86, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "choose", - "args": [ - { - "name": "action", - "type": "IAction", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 62, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "action", - "type": "IAction", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "isDisabled", - "args": [ - { - "name": "value", - "type": "IValue", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 67, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "IValue", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 58, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onEnterKey", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 82, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "run", - "args": [ - { - "name": "value", - "type": "IValue", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "IValue", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "{}", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ElementRef, EventEmitter, OnInit, ViewChild } from '@angular/core';\nimport { IAction } from '@app/core/types';\nimport { DynamicComponent, DynamicEvent } from '@app/shared/directives/dynamic.directive';\n\nimport { BaseDirective } from '../../../directives/base.directive';\nimport { ActionParameters } from '../actions.directive';\n\nimport { IMasterData, IValue, MasterService, whatShow } from './master.service';\n\n@Component({\n selector: 'app-master',\n templateUrl: './master.component.html',\n styles: [\n `\n .action-button {\n background: none !important;\n margin: 6px 0;\n\n &:hover {\n background: rgba(255, 255, 255, 0.04) !important;\n }\n }\n\n .controls-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n `,\n ],\n providers: [MasterService],\n})\nexport class ActionMasterComponent extends BaseDirective implements DynamicComponent, OnInit {\n event: EventEmitter = new EventEmitter();\n model: ActionParameters;\n action: IAction;\n show: whatShow;\n\n verbose = false;\n\n @ViewChild('runBtn', { read: ElementRef }) runBtn: ElementRef;\n\n constructor(private service: MasterService) {\n super();\n }\n\n ngOnInit(): void {\n if (this.model.actions.length === 1) this.choose(this.model.actions[0]);\n }\n\n choose(action: IAction) {\n this.action = action;\n this.show = this.service.spotShow(action);\n }\n\n isDisabled(value: IValue) {\n return value && ((value.hostmap && value.hostmap.noValid) || (value.config && !value.config.form?.valid));\n }\n\n run(value: IValue = {}) {\n const data: IMasterData = this.service.parseData(value);\n if (data) {\n data.verbose = this.verbose;\n }\n this.service\n .send(this.action.run, data)\n .pipe(this.takeUntil())\n .subscribe(() => this.cancel());\n }\n\n onEnterKey() {\n this.runBtn.nativeElement.click();\n }\n\n cancel() {\n this.event.emit({ name: 'cancel' });\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n .action-button {\n background: none !important;\n margin: 6px 0;\n\n &:hover {\n background: rgba(255, 255, 255, 0.04) !important;\n }\n }\n\n .controls-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n \n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "MasterService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 52, - "jsdoctags": [ - { - "name": "service", - "type": "MasterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "DynamicComponent", - "OnInit" - ], - "templateData": "\n

No data for the action!

\n
\n\n\n Let's choose first\n \n \n \n

\n
\n\n\n
\n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n \n \n Configuration\n \n
\n \n \n
\n
\n \n Host Components\n \n \n \n \n \n
\n\n
\n\n\n
\n\n Verbose\n\n
\n 1\">\n \n \n \n\n \n \n
\n\n
\n
\n" - }, - { - "name": "ActionMasterConfigComponent", - "id": "component-ActionMasterConfigComponent-01ad5f1230b2cda12feb3512193d26b9", - "file": "src/app/shared/components/actions/master/action-master-config.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-action-master-config", - "styleUrls": [], - "styles": [], - "template": "
\n Advanced\n
\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "line": 27, - "type": "IAction" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "fields", - "defaultValue": "{} as ConfigFieldsComponent", - "deprecated": false, - "deprecationMessage": "", - "type": "ConfigFieldsComponent", - "optional": false, - "description": "", - "line": 29, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'fields'" - } - ] - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, ViewChild } from '@angular/core';\nimport { IAction } from '@app/core/types';\nimport { FieldService } from '@app/shared/configuration/services/field.service';\nimport { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component';\n\n@Component({\n selector: 'app-action-master-config',\n template: `\n
\n Advanced\n
\n \n `,\n})\nexport class ActionMasterConfigComponent {\n @Input() action: IAction;\n\n @ViewChild('fields') fields: ConfigFieldsComponent = {} as ConfigFieldsComponent;\n\n set advanced(value: boolean) {\n this.config.filterApply(this.fields.dataOptions, { advanced: value, search: '' });\n }\n\n constructor(private config: FieldService) {}\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "config", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 33, - "jsdoctags": [ - { - "name": "config", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "advanced": { - "name": "advanced", - "setSignature": { - "name": "advanced", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "value", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 31, - "jsdoctags": [ - { - "name": "value", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "ActionsButtonComponent", - "id": "component-ActionsButtonComponent-20d379ab2d05757a48d0fabebf3eecca", - "file": "src/app/components/actions-button/actions-button.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-actions-button", - "styleUrls": [ - "./actions-button.component.scss" - ], - "styles": [], - "templateUrl": [ - "./actions-button.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "line": 15, - "type": "T" - } - ], - "outputsClass": [ - { - "name": "onMouseenter", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 17, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "EventHelper", - "defaultValue": "EventHelper", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 13 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "getClusterData", - "args": [ - { - "name": "row", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "{ id: any; hostcomponent: any; action: any; }", - "typeParameters": [], - "line": 19, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { BaseDirective, EventHelper } from '@adwp-ui/widgets';\n\nimport { BaseEntity } from '@app/core/types';\n\n@Component({\n selector: 'app-actions-button',\n templateUrl: './actions-button.component.html',\n styleUrls: ['./actions-button.component.scss']\n})\nexport class ActionsButtonComponent extends BaseDirective {\n\n EventHelper = EventHelper;\n\n @Input() row: T;\n\n @Output() onMouseenter = new EventEmitter();\n\n getClusterData(row: any) {\n const { id, hostcomponent } = row.cluster || row;\n const { action } = row;\n return { id, hostcomponent, action };\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "", - "styleUrl": "./actions-button.component.scss" - } - ], - "stylesData": "", - "extends": "BaseDirective", - "templateData": "\n\n\n \n\n" - }, - { - "name": "ActionsComponent", - "id": "component-ActionsComponent-be4b635a5be5a21612ac922757aba43d", - "file": "src/app/shared/components/actions/actions.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-actions", - "styleUrls": [ - "./actions.component.scss" - ], - "styles": [], - "template": "
\n \n {{ action.display_name }}\n \n
\n\n\n \n {{ a.display_name }}\n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "line": 61, - "type": "literal type" - }, - { - "name": "isIssue", - "deprecated": false, - "deprecationMessage": "", - "line": 60, - "type": "boolean" - }, - { - "name": "source", - "deprecated": false, - "deprecationMessage": "", - "line": 62, - "type": "[]" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "actions", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction[]", - "optional": false, - "description": "", - "line": 58 - }, - { - "name": "buttons", - "deprecated": false, - "deprecationMessage": "", - "type": "QueryList", - "optional": false, - "description": "", - "line": 72, - "decorators": [ - { - "name": "ViewChildren", - "stringifiedArguments": "'button', {read: ElementRef}" - } - ] - }, - { - "name": "forMenu", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction[]", - "optional": false, - "description": "", - "line": 68 - }, - { - "name": "more", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 71, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'more', {read: ElementRef, static: true}" - } - ] - }, - { - "name": "stateButtons", - "defaultValue": "0", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 67 - }, - { - "name": "trigger", - "deprecated": false, - "deprecationMessage": "", - "type": "MatMenuTrigger", - "optional": false, - "description": "", - "line": 73, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "MatMenuTrigger, {static: true}" - } - ] - }, - { - "name": "wrap", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 70, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'wrap', {read: ElementRef, static: true}" - } - ] - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "calcWidth", - "args": [ - { - "name": "w", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "bw", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "", - "typeParameters": [], - "line": 106, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "w", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "bw", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngAfterViewChecked", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 89, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 79, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onresize", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 96, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { AfterViewChecked, Component, ElementRef, Input, OnInit, QueryList, Renderer2, ViewChild, ViewChildren } from '@angular/core';\nimport { MatMenuTrigger } from '@angular/material/menu';\nimport { IAction } from '@app/core/types';\nimport { fromEvent } from 'rxjs';\nimport { debounceTime, tap } from 'rxjs/operators';\n\nimport { BaseDirective } from '../../directives/base.directive';\n\n@Component({\n selector: 'app-actions',\n template: `\n
\n \n {{ action.display_name }}\n \n
\n \n \n \n {{ a.display_name }}\n \n \n `,\n styleUrls: ['./actions.component.scss'],\n})\nexport class ActionsComponent extends BaseDirective implements OnInit, AfterViewChecked {\n actions: IAction[] = [];\n\n @Input() isIssue: boolean;\n @Input() cluster: { id: number; hostcomponent: string };\n @Input() set source(actions: IAction[]) {\n this.actions = actions;\n if (!actions.length) this.render.setStyle(this.more.nativeElement, 'display', 'none');\n }\n\n stateButtons = 0;\n forMenu: IAction[] = [];\n\n @ViewChild('wrap', { read: ElementRef, static: true }) wrap: ElementRef;\n @ViewChild('more', { read: ElementRef, static: true }) more: ElementRef;\n @ViewChildren('button', { read: ElementRef }) buttons: QueryList;\n @ViewChild(MatMenuTrigger, { static: true }) trigger: MatMenuTrigger;\n\n constructor(private render: Renderer2, private el: ElementRef) {\n super();\n }\n\n ngOnInit() {\n fromEvent(window, 'resize')\n .pipe(\n this.takeUntil(),\n tap(() => this.trigger.closeMenu()),\n debounceTime(500)\n )\n .subscribe(() => this.onresize());\n }\n\n ngAfterViewChecked(): void {\n if (this.stateButtons !== this.buttons.length) {\n this.stateButtons = this.buttons.length;\n setTimeout(() => this.onresize(), 0);\n }\n }\n\n onresize() {\n const bw = this.buttons.map((b) => b.nativeElement.offsetWidth + 10);\n const elWidth = +this.el.nativeElement.clientWidth - 50;\n const dw = this.calcWidth(elWidth, bw);\n //\n this.forMenu = this.actions.slice(dw[0]);\n this.render.setStyle(this.wrap.nativeElement, 'width', `${dw[1]}px`);\n this.render.setStyle(this.more.nativeElement, 'display', dw[2] ? 'block' : 'none');\n }\n\n calcWidth(w: number, bw: number[]): [number, number, boolean] {\n return bw.reduce((p, c, i) => (p[2] || p[1] + c > w ? [p[0], p[1], true] : [i + 1, p[1] + c, false]), [0, 0, false]);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n display: flex;\n overflow: hidden;\n width: 100%;\n justify-content: flex-end;\n\n & > div {\n overflow: hidden;\n margin-top: 4px;\n }\n}\n\n.button-more {\n display: none;\n}\n\n.menu-more-action {\n display: block;\n margin: 4px;\n}\n\nbutton {\n margin-left: 10px;\n}\n", - "styleUrl": "./actions.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "render", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 73, - "jsdoctags": [ - { - "name": "render", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "OnInit", - "AfterViewChecked" - ], - "accessors": { - "source": { - "name": "source", - "setSignature": { - "name": "source", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "actions", - "type": "IAction[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 62, - "jsdoctags": [ - { - "name": "actions", - "type": "IAction[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "AddButtonComponent", - "id": "component-AddButtonComponent-93f92e3ae770a7c02b794002b8ed5639", - "file": "src/app/shared/add-component/add-button.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-add-button", - "styleUrls": [], - "styles": [ - "button {margin-right: 6px;}" - ], - "template": "\n \n\n\n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "asIcon", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 38, - "type": "boolean" - }, - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "line": 40, - "type": "Type" - }, - { - "name": "name", - "deprecated": false, - "deprecationMessage": "", - "line": 39, - "type": "string" - } - ], - "outputsClass": [ - { - "name": "added", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 41, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "showForm", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 48, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Inject, Input, OnDestroy, Output, Type } from '@angular/core';\nimport { MatDialog } from '@angular/material/dialog';\n\nimport { DialogComponent } from '@app/shared/components';\nimport { BaseDirective } from '@app/shared/directives';\nimport { AddFormComponent } from './add-form.component';\nimport { ADD_SERVICE_PROVIDER, IAddService } from '@app/shared/add-component/add-service-model';\nimport { BaseFormDirective } from '@app/shared/add-component/base-form.directive';\n\n@Component({\n selector: 'app-add-button',\n template: `\n \n \n \n \n \n \n `,\n styles: ['button {margin-right: 6px;}'],\n})\nexport class AddButtonComponent extends BaseDirective implements OnDestroy {\n @Input() asIcon = false;\n @Input() name: string;\n @Input() component: Type;\n @Output() added = new EventEmitter();\n\n constructor(@Inject(ADD_SERVICE_PROVIDER) private service: IAddService,\n private dialog: MatDialog) {\n super();\n }\n\n showForm(): void {\n const model = this.service.model(this.name);\n model.component = this.component;\n\n const name = model.title || model.name;\n const title = ['cluster', 'provider', 'host'];\n this.dialog.open(DialogComponent, {\n width: '75%',\n maxWidth: '1400px',\n data: {\n title: `${title.includes(name) ? 'Create' : 'Add'} ${name}`,\n component: AddFormComponent,\n model,\n },\n });\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "button {margin-right: 6px;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "IAddService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 41, - "jsdoctags": [ - { - "name": "service", - "type": "IAddService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "OnDestroy" - ] - }, - { - "name": "AddClusterComponent", - "id": "component-AddClusterComponent-1a72eb27d779e6e25f38cc71fd9adb31", - "file": "src/app/shared/add-component/add-cluster.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-add-cluster", - "styleUrls": [], - "styles": [], - "template": "\n \n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "prototype", - "deprecated": false, - "deprecationMessage": "", - "type": "StackBase", - "optional": false, - "description": "", - "line": 34, - "modifierKind": [ - 120 - ] - }, - { - "name": "sgn", - "deprecated": false, - "deprecationMessage": "", - "type": "Subscription", - "optional": false, - "description": "", - "line": 33 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 27, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "IAddService", - "optional": false, - "description": "", - "line": 26, - "decorators": [ - { - "name": "Inject", - "stringifiedArguments": "ADD_SERVICE_PROVIDER" - } - ], - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 36, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "prototypeChanged", - "args": [ - { - "name": "event", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 45, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "save", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "onCancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit, OnDestroy } from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { take } from 'rxjs/operators';\n\nimport { clearEmptyField, StackBase } from '@app/core/types';\nimport { BaseFormDirective } from './base-form.directive';\nimport { ICluster } from '@app/models/cluster';\n\n@Component({\n selector: 'app-add-cluster',\n template: `\n \n \n \n \n \n \n `,\n})\nexport class AddClusterComponent extends BaseFormDirective implements OnInit, OnDestroy {\n\n sgn: Subscription;\n private prototype: StackBase;\n\n ngOnInit() {\n this.form = this.service.model('cluster').form;\n this.sgn = this.service.genName(this.form);\n }\n\n ngOnDestroy() {\n this.sgn.unsubscribe();\n }\n\n prototypeChanged(event: StackBase) {\n this.prototype = event;\n }\n\n save() {\n const data = clearEmptyField(this.form.value);\n this.service\n .add(data, 'cluster', this.prototype)\n .pipe(take(1))\n .subscribe((_) => this.onCancel());\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": "BaseFormDirective", - "implements": [ - "OnInit", - "OnDestroy" - ] - }, - { - "name": "AddConfigGroupComponent", - "id": "component-AddConfigGroupComponent-78cf36b0bb911bad673967c298a8371f", - "file": "src/app/config-groups/components/config-group-add/config-group-add.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "{ provide: ADD_SERVICE_PROVIDER, useExisting: forwardRef(() => ConfigGroupAddService) }" - } - ], - "selector": "app-config-group-add", - "styleUrls": [], - "styles": [], - "template": "\n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 27, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "IAddService", - "optional": false, - "description": "", - "line": 26, - "decorators": [ - { - "name": "Inject", - "stringifiedArguments": "ADD_SERVICE_PROVIDER" - } - ], - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 36, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "save", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 40, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "onCancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, forwardRef, OnInit } from '@angular/core';\n\nimport { BaseFormDirective } from '../../../shared/add-component';\nimport { ADD_SERVICE_PROVIDER } from '../../../shared/add-component/add-service-model';\nimport { ConfigGroupAddService } from '../../service';\nimport { clearEmptyField } from '../../../core/types';\nimport { ConfigGroup } from '../../model';\nimport { take } from 'rxjs/operators';\n\n@Component({\n selector: 'app-config-group-add',\n template: `\n \n \n \n \n \n `,\n providers: [\n { provide: ADD_SERVICE_PROVIDER, useExisting: forwardRef(() => ConfigGroupAddService) }\n ],\n})\nexport class AddConfigGroupComponent extends BaseFormDirective implements OnInit {\n\n ngOnInit(): void {\n this.form = this.service.model().form;\n }\n\n save(): void {\n const data = clearEmptyField(this.form.value) as ConfigGroup;\n this.service\n .add(data)\n .pipe(take(1))\n .subscribe((_) => this.onCancel());\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": "BaseFormDirective", - "implements": [ - "OnInit" - ] - }, - { - "name": "AddFormComponent", - "id": "component-AddFormComponent-66af7d2a91a5e5797fecc9e7c6c43b96", - "file": "src/app/shared/add-component/add-form.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-add-form", - "styleUrls": [], - "styles": [], - "template": "
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "container", - "deprecated": false, - "deprecationMessage": "", - "type": "BaseFormDirective", - "optional": false, - "description": "", - "line": 53, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'cc'" - } - ] - }, - { - "name": "model", - "deprecated": false, - "deprecationMessage": "", - "type": "FormModel", - "optional": false, - "description": "", - "line": 49 - }, - { - "name": "viewContainer", - "deprecated": false, - "deprecationMessage": "", - "type": "ViewContainerRef", - "optional": false, - "description": "", - "line": 51, - "modifierKind": [ - 122 - ] - } - ], - "methodsClass": [ - { - "name": "message", - "args": [ - { - "name": "m", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 61, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "onEnterKey", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 55, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ViewChild, ViewContainerRef } from '@angular/core';\n\nimport { ChannelService, keyChannelStrim } from '@app/core/services';\nimport { DynamicComponent } from '@app/shared/directives';\nimport { BaseFormDirective } from './base-form.directive';\nimport { FormModel } from '@app/shared/add-component/add-service-model';\n\n@Component({\n selector: 'app-add-form',\n template: `\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n `,\n})\nexport class AddFormComponent implements DynamicComponent {\n model: FormModel;\n\n constructor(private channel: ChannelService, public viewContainer: ViewContainerRef) {}\n\n @ViewChild('cc') container: BaseFormDirective;\n\n onEnterKey(): void {\n if (this.container) {\n if (this.container.form.valid) this.container.save();\n }\n }\n\n message(m: string): void {\n this.channel.next(keyChannelStrim.notifying, m);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "viewContainer", - "type": "ViewContainerRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 49, - "jsdoctags": [ - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "viewContainer", - "type": "ViewContainerRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "DynamicComponent" - ] - }, - { - "name": "AddHostToConfigGroupComponent", - "id": "component-AddHostToConfigGroupComponent-9354f627d58343ff3f0c88558d3cb8d2", - "file": "src/app/config-groups/components/config-group-host-add/config-group-host-add.component.ts", - "changeDetection": "ChangeDetectionStrategy.OnPush", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-config-group-host-add", - "styleUrls": [], - "styles": [], - "template": "\n \n All\n \n {{ host.fqdn }}\n \n \n \n \n\n\n

\n \n There are no new hosts. You config group already has all of them.\n \n

\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "list", - "deprecated": false, - "deprecationMessage": "", - "type": "MatSelectionList", - "optional": false, - "description": "", - "line": 63, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'selectionList'" - } - ], - "modifierKind": [ - 120 - ] - }, - { - "name": "list$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable>", - "optional": false, - "description": "", - "line": 61 - }, - { - "name": "pageIndex", - "defaultValue": "0", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 58 - }, - { - "name": "pageSize", - "defaultValue": "10", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 59 - }, - { - "name": "selected", - "defaultValue": "{}", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 52 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 27, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "IAddService", - "optional": false, - "description": "", - "line": 26, - "decorators": [ - { - "name": "Inject", - "stringifiedArguments": "ADD_SERVICE_PROVIDER" - } - ], - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "methodsClass": [ - { - "name": "getAvailableHosts", - "args": [ - { - "name": "pageIndex", - "type": "", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "pageSize", - "type": "", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 113, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "pageIndex", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "pageSize", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "pageHandler", - "args": [ - { - "name": "pageEvent", - "type": "PageEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 118, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "pageEvent", - "type": "PageEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "save", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 100, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "selectAll", - "args": [ - { - "name": "e", - "type": "MatSelectionListChange", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 73, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "e", - "type": "MatSelectionListChange", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "onCancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { ChangeDetectionStrategy, Component, OnInit, ViewChild } from '@angular/core';\nimport { MatSelectionList, MatSelectionListChange } from '@angular/material/list';\nimport { Host } from '@app/core/types';\nimport { Observable } from 'rxjs';\n\nimport { BaseFormDirective } from '@app/shared/add-component';\nimport { MatDialog } from '@angular/material/dialog';\nimport { ConfigGroupHostAddService } from '../../service';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ListResult } from '@app/models/list-result';\nimport { PageEvent } from '@angular/material/paginator';\n\n@Component({\n selector: 'app-config-group-host-add',\n template: `\n \n \n All\n \n {{ host.fqdn }}\n \n \n \n \n \n \n

\n \n There are no new hosts. You config group already has all of them.\n \n

\n
\n `,\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AddHostToConfigGroupComponent extends BaseFormDirective implements OnInit {\n\n selected: { [key: number]: boolean } = {};\n\n get disabled() {\n return !Object.keys(this.selected).length;\n }\n\n pageIndex = 0;\n pageSize = 10;\n\n list$: Observable>;\n @ViewChild('selectionList')\n private list: MatSelectionList;\n\n constructor(service: ConfigGroupHostAddService, dialog: MatDialog, private cluster: ClusterService) {\n super(service, dialog);\n }\n\n ngOnInit(): void {\n this.getAvailableHosts(this.pageIndex, this.pageSize);\n }\n\n selectAll(e: MatSelectionListChange): void {\n const value = e.option.value;\n if (!value) {\n if (e.option.selected) {\n this.list.selectAll();\n this.list.options.filter((o) => !!o.value).forEach((o) => {\n this.selected[o.value.id] = true;\n });\n\n } else {\n this.list.deselectAll();\n\n this.list.options.filter((o) => !!o.value).forEach((o) => {\n if (this.selected[o.value.id]) {\n delete this.selected[o.value.id];\n }\n });\n }\n } else {\n if (this.selected[value.id]) {\n delete this.selected[value.id];\n } else {\n this.selected[value.id] = true;\n }\n }\n }\n\n save(): void {\n const groupId = this.service.Current.id;\n const result = Object.entries(this.selected).map(([id]) => ({\n host: +id,\n group: groupId\n }));\n\n this.service\n .add(result)\n .pipe(this.takeUntil())\n .subscribe(() => this.dialog.closeAll());\n }\n\n getAvailableHosts(pageIndex, pageSize): void {\n const { typeName } = this.cluster.Current;\n this.list$ = this.service.getListResults(typeName, { limit: pageSize, page: pageIndex });\n }\n\n pageHandler(pageEvent: PageEvent): void {\n this.pageIndex = pageEvent.pageIndex;\n this.pageSize = pageEvent.pageSize;\n this.getAvailableHosts(this.pageIndex, this.pageSize);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ConfigGroupHostAddService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 63, - "jsdoctags": [ - { - "name": "service", - "type": "ConfigGroupHostAddService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cluster", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseFormDirective", - "implements": [ - "OnInit" - ], - "accessors": { - "disabled": { - "name": "disabled", - "getSignature": { - "name": "disabled", - "type": "", - "returnType": "", - "line": 54 - } - } - } - }, - { - "name": "AppComponent", - "id": "component-AppComponent-82c57e0b89a57234642fbe430f4f146b", - "file": "src/app/app.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "AppService" - } - ], - "selector": "app-root", - "styleUrls": [], - "styles": [], - "template": "\n
\n \n \n
\n\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "currentYear", - "defaultValue": "new Date().getFullYear()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 50 - }, - { - "name": "versionData", - "defaultValue": "{ version: '', commit_id: '' }", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "optional": false, - "description": "", - "line": 51 - } - ], - "methodsClass": [ - { - "name": "console", - "args": [ - { - "name": "text", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "css", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 88, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nTODO: move this to component and append through DomService (as TooltipComponent - line: 61)\nimportant - to approve with QA!\n", - "description": "

TODO: move this to component and append through DomService (as TooltipComponent - line: 61)\nimportant - to approve with QA!

\n", - "jsdoctags": [ - { - "name": "text", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "css", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ElementRef, OnInit } from '@angular/core';\nimport { AppService, ChannelService, DomService, keyChannelStrim } from '@app/core/services';\nimport { filter } from 'rxjs/operators';\n\nimport { TooltipComponent } from '@app/shared/components/tooltip';\n\n/** Magic strings for marking loading stages and other, for ci tests */\nconst enum flagForConsole {\n 'profile' = 'profile',\n 'socket' = 'socket',\n 'load_complete' = 'load_complete',\n}\n\n@Component({\n selector: 'app-root',\n template: `\n \n
\n \n \n
\n
\n
\n `,\n providers: [AppService],\n})\nexport class AppComponent implements OnInit {\n currentYear = new Date().getFullYear();\n versionData = { version: '', commit_id: '' };\n\n constructor(\n private elRef: ElementRef,\n private service: AppService,\n private radio: ChannelService,\n private dom: DomService\n ) {}\n\n ngOnInit() {\n this.dom.appendComponentToBody(TooltipComponent);\n\n this.service.getRootAndCheckAuth().subscribe((c) => {\n if (!c) this.elRef.nativeElement.innerHTML = '';\n else this.versionData = { ...c };\n });\n\n this.service.initListeners();\n\n this.service\n .checkWSconnectStatus()\n .pipe(filter((a) => a === 'open'))\n .subscribe((_) => this.console('Socket status :: open', flagForConsole.socket));\n\n this.service.checkUserProfile().subscribe((_) => this.console('User profile :: saved', flagForConsole.profile));\n\n this.versionData = this.service.getVersion(this.versionData);\n\n this.radio\n .on(keyChannelStrim.load_complete)\n .subscribe((a) => this.console(a, flagForConsole.load_complete));\n }\n\n /**\n * TODO: move this to component and append through DomService (as TooltipComponent - line: 61)\n * important - to approve with QA!\n */\n console(text: string, css?: string) {\n const console = this.elRef.nativeElement.querySelector('div.console');\n if (!text) console.innerHTML = '';\n else {\n const create = () => document.createElement('p');\n const isExist = () => console.querySelector(`.${css}`);\n const inner = (p: HTMLElement) => (p.innerText = text);\n const addClass = (p: HTMLElement) => p.classList.add(css);\n const append = (p: HTMLElement) => console.appendChild(p);\n const a = create();\n inner(a);\n if (css && !isExist()) {\n addClass(a);\n append(a);\n }\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "elRef", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "AppService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "radio", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dom", - "type": "DomService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 51, - "jsdoctags": [ - { - "name": "elRef", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "AppService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "radio", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dom", - "type": "DomService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "BellComponent", - "id": "component-BellComponent-391bc2abd632d574b4523b00c2426438", - "file": "src/app/components/bell/bell.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-bell", - "styleUrls": [ - "./bell.component.scss" - ], - "styles": [], - "template": "\n \n
\n
\n notifications\n
\n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "animationElem", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 59 - }, - { - "name": "animationRef", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 50, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'animation', {static: false}" - } - ] - }, - { - "name": "bellGradient", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 56 - }, - { - "name": "bindedPopoverEvent", - "defaultValue": "this.popoverEvent.bind(this)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 64, - "modifierKind": [ - 142 - ] - }, - { - "name": "counts", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 61 - }, - { - "name": "failedCount", - "defaultValue": "new BehaviorSubject(0)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 54 - }, - { - "name": "isAnimationRunning", - "defaultValue": "new BehaviorSubject(false)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 58 - }, - { - "name": "NotificationsComponent", - "defaultValue": "NotificationsComponent", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 48 - }, - { - "name": "runningCount", - "defaultValue": "new BehaviorSubject(0)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 52 - }, - { - "name": "successCount", - "defaultValue": "new BehaviorSubject(0)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 53 - }, - { - "name": "tasks", - "defaultValue": "new BehaviorSubject([])", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 62 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "afterCountChanged", - "args": [ - { - "name": "animationNeeds", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "true" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 111, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "animationNeeds", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "true", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "decRunningCount", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 134, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "endAnimation", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 104, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getChangeTaskObservable", - "args": [], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 130, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getCurrentCounts", - "args": [], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 186, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getLastTasks", - "args": [], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 193, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "listenToJobs", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 147, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngAfterViewInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 215, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onAnimationEnd", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 93, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onAnimationStart", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 89, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "popoverEvent", - "args": [ - { - "name": "event", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 75, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "startAnimation", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 97, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "updateTask", - "args": [ - { - "name": "updatedTaskId", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "task", - "type": "TaskRaw", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "status", - "type": "JobStatus", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 139, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "updatedTaskId", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "task", - "type": "TaskRaw", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "status", - "type": "JobStatus", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { AfterViewInit, Component, ElementRef, Renderer2, ViewChild } from '@angular/core';\nimport { BaseDirective } from '@adwp-ui/widgets';\nimport { BehaviorSubject, combineLatest, interval, Observable, zip } from 'rxjs';\nimport { filter, map, mergeMap, take, takeWhile } from 'rxjs/operators';\n\nimport { TaskService } from '@app/services/task.service';\nimport { ACKNOWLEDGE_EVENT, NotificationsComponent } from '@app/components/notifications/notifications.component';\nimport { JobStatus, Task, TaskRaw } from '@app/core/types';\nimport { EventMessage, ProfileService } from '@app/core/store';\nimport { Stats, StatsService } from '@app/services/stats.service';\n\nconst RUNNING_COLOR = '#FFEA00';\nconst SUCCESS_COLOR = '#1EE564';\nconst FAILED_COLOR = '#FF8A80';\n\nexport interface NotificationsData {\n runningCount: number;\n successCount: number;\n failedCount: number;\n}\n\n@Component({\n selector: 'app-bell',\n template: `\n \n \n
\n
\n notifications\n
\n \n \n `,\n styleUrls: ['./bell.component.scss']\n})\nexport class BellComponent extends BaseDirective implements AfterViewInit {\n\n NotificationsComponent = NotificationsComponent;\n\n @ViewChild('animation', { static: false }) animationRef: ElementRef;\n\n runningCount = new BehaviorSubject(0);\n successCount = new BehaviorSubject(0);\n failedCount = new BehaviorSubject(0);\n\n bellGradient = '';\n\n isAnimationRunning = new BehaviorSubject(false);\n animationElem = new BehaviorSubject(null);\n\n counts = new BehaviorSubject(null);\n tasks = new BehaviorSubject([]);\n\n readonly bindedPopoverEvent = this.popoverEvent.bind(this);\n\n constructor(\n private taskService: TaskService,\n private renderer: Renderer2,\n private profileService: ProfileService,\n private statsService: StatsService,\n ) {\n super();\n }\n\n popoverEvent(event: any) {\n if (event === ACKNOWLEDGE_EVENT) {\n const lastTaskId = this.tasks.value[0]?.id;\n if (lastTaskId) {\n this.profileService.setLastViewedTask(lastTaskId).subscribe();\n }\n this.tasks.next([]);\n this.successCount.next(0);\n this.runningCount.next(0);\n this.failedCount.next(0);\n this.afterCountChanged(false);\n }\n }\n\n onAnimationStart() {\n this.isAnimationRunning.next(true);\n }\n\n onAnimationEnd() {\n this.isAnimationRunning.next(false);\n }\n\n startAnimation() {\n if (this.animationElem.value && !this.isAnimationRunning.value) {\n this.renderer.removeClass(this.animationElem.value, 'hide');\n this.renderer.addClass(this.animationElem.value, 'animated');\n }\n }\n\n endAnimation() {\n if (this.animationElem.value) {\n this.renderer.addClass(this.animationElem.value, 'hide');\n this.renderer.removeClass(this.animationElem.value, 'animated');\n }\n }\n\n afterCountChanged(animationNeeds = true) {\n const total = this.runningCount.value + this.successCount.value + this.failedCount.value;\n if (total > 0) {\n const degOne = 360 / total;\n const degRunning = this.runningCount.value * degOne;\n const degSuccess = this.successCount.value * degOne;\n this.bellGradient =\n `conic-gradient(`\n + `${RUNNING_COLOR} 0deg ${degRunning}deg,`\n + `${SUCCESS_COLOR} ${degRunning}deg ${degRunning + degSuccess}deg,`\n + `${FAILED_COLOR} ${degRunning + degSuccess}deg 360deg)`;\n } else {\n this.bellGradient = 'transparent';\n }\n if (animationNeeds) {\n this.startAnimation();\n }\n }\n\n getChangeTaskObservable(): Observable {\n return this.taskService.events({ events: ['change_job_status'] }).pipe(this.takeUntil());\n }\n\n decRunningCount() {\n const runningCount = this.runningCount.value - 1;\n this.runningCount.next(runningCount < 0 ? 0 : runningCount);\n }\n\n updateTask(updatedTaskId: number, task: TaskRaw, status: JobStatus) {\n const tasks: TaskRaw[] = this.tasks.value.slice();\n const index = tasks.findIndex(item => item.id === updatedTaskId);\n task.status = status;\n tasks.splice(index, 1, task);\n this.tasks.next(tasks);\n }\n\n listenToJobs() {\n this.getChangeTaskObservable().subscribe((event) => {\n const status = event.object.details.value;\n if (status === 'running') {\n this.runningCount.next(this.runningCount.value + 1);\n this.afterCountChanged();\n } else if (status === 'success') {\n this.successCount.next(this.successCount.value + 1);\n this.decRunningCount();\n this.afterCountChanged();\n } else if (status === 'failed') {\n this.failedCount.next(this.failedCount.value + 1);\n this.decRunningCount();\n this.afterCountChanged();\n }\n });\n\n this.getChangeTaskObservable().pipe(\n filter(event => event.object.details.type === 'status'),\n filter(event => event.object.details.value !== 'created'),\n ).subscribe((event) => {\n const tasks: TaskRaw[] = this.tasks.value.slice();\n const updatedTaskId = event.object.id;\n const index = tasks.findIndex(item => item.id === updatedTaskId);\n if (index >= 0) {\n const task: TaskRaw = Object.assign({}, tasks[index]);\n this.taskService.get(updatedTaskId).subscribe((updatedTask) => this.updateTask(updatedTaskId, updatedTask, event.object.details.value));\n tasks.splice(index, 1, task);\n this.tasks.next(tasks);\n } else {\n this.taskService.get(event.object.id).subscribe((task) => {\n task.status = event.object.details.value;\n tasks.unshift(task);\n this.tasks.next(tasks.slice(0, 5));\n });\n }\n });\n }\n\n getCurrentCounts(): Observable {\n return this.profileService.getProfile().pipe(\n take(1),\n mergeMap((user) => this.statsService.tasks(user.profile?.lastViewedTask?.id)),\n );\n }\n\n getLastTasks(): Observable {\n return zip(\n this.taskService.list({ ordering: '-finish_date', status: 'failed', limit: '5' }),\n this.taskService.list({ ordering: '-finish_date', status: 'success', limit: '5' }),\n this.taskService.list({ ordering: '-start_date', status: 'running', limit: '5' }),\n this.profileService.getProfile(),\n ).pipe(map(([failed, succeed, running, user]) => {\n let tasks = [...failed.results, ...succeed.results, ...running.results].sort((a, b) => {\n const getDateField = (task: Task) => task.status === 'failed' || task.status === 'success' ? task.finish_date : task.start_date;\n const aDate = new Date(getDateField(a));\n const bDate = new Date(getDateField(b));\n return aDate.getDate() - bDate.getDate();\n }).slice(0, 5);\n\n if (user.profile?.lastViewedTask?.id) {\n tasks = tasks.filter(task => task.id > user.profile.lastViewedTask.id);\n }\n\n return tasks;\n }));\n }\n\n ngAfterViewInit(): void {\n interval(200).pipe(\n this.takeUntil(),\n takeWhile(() => !this.animationElem.value),\n ).subscribe(() => {\n this.animationElem.next(this.animationRef ? this.animationRef.nativeElement : null);\n });\n\n this.animationElem.pipe(\n this.takeUntil(),\n filter((elem) => !!elem),\n take(1),\n ).subscribe(() => {\n zip(this.getCurrentCounts(), this.getLastTasks())\n .subscribe(([stats, tasks]) => {\n this.runningCount.next(stats.running);\n this.successCount.next(stats.success);\n this.failedCount.next(stats.failed);\n this.afterCountChanged(!!(stats.running || stats.success || stats.failed));\n this.tasks.next(tasks);\n this.listenToJobs();\n });\n });\n\n this.isAnimationRunning.pipe(\n this.takeUntil(),\n filter(isRunning => !isRunning),\n ).subscribe(() => this.endAnimation());\n\n combineLatest(this.runningCount, this.successCount, this.failedCount)\n .pipe(this.takeUntil())\n .subscribe(\n ([runningCount, successCount, failedCount]) => this.counts.next({\n runningCount,\n successCount,\n failedCount,\n })\n );\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".bell-wrapper {\n width: 50px;\n height: 50px;\n background: none;\n}\n\n.circle {\n width: 50px;\n height: 50px;\n border-radius: 50%;\n background-repeat: no-repeat;\n\n cursor: pointer;\n position: relative;\n}\n\n@keyframes spinner {\n 0% {\n transform: rotate(0deg);\n opacity: 1;\n }\n 50% {\n transform: rotate(180deg);\n opacity: 0.8;\n }\n 75% {\n transform: rotate(270deg);\n opacity: 0.6;\n }\n 100% {\n transform: rotate(360deg);\n opacity: 0;\n }\n}\n\n.animation {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n background-repeat: no-repeat;\n background-image: conic-gradient(#fff, #262d37);\n animation-duration: 0.7s;\n animation-timing-function: linear;\n}\n\n.animated {\n animation-name: spinner;\n}\n\n.hide {\n opacity: 0;\n}\n\n.insider {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: #262d37;\n top: 7px;\n left: 7px;\n position: absolute;\n\n display: flex;\n align-items: center;\n justify-content: center;\n}\n", - "styleUrl": "./bell.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "taskService", - "type": "TaskService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "profileService", - "type": "ProfileService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "statsService", - "type": "StatsService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 64, - "jsdoctags": [ - { - "name": "taskService", - "type": "TaskService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "profileService", - "type": "ProfileService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "statsService", - "type": "StatsService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "AfterViewInit" - ] - }, - { - "name": "BooleanComponent", - "id": "component-BooleanComponent-608a307417228c9438a976eea023f0a4", - "file": "src/app/shared/form-elements/boolean.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "{ provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: options }" - } - ], - "selector": "app-fields-boolean", - "styleUrls": [], - "styles": [ - ":host {height: 58px;} mat-error { font-size: 0.75em; margin-left: 14px; }" - ], - "template": "\n \n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "cbChange", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 34, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox';\n\nimport { FieldDirective } from './field.directive';\n\nconst options = { clickAction: 'noop', color: 'accent' };\n\n@Component({\n selector: 'app-fields-boolean',\n template: `\n \n \n \n \n \n \n `,\n styles: [':host {height: 58px;} mat-error { font-size: 0.75em; margin-left: 14px; }'],\n providers: [{ provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: options }]\n})\nexport class BooleanComponent extends FieldDirective {\n cbChange() {\n if (this.field.read_only || this.control.disabled) return;\n const tape = this.field.validator.required ? [true, false] : [null, true, false];\n this.field.value = tape[(tape.indexOf(this.field.value as boolean) + 1) % tape.length];\n this.control.markAsDirty({\n onlySelf: true\n });\n this.control.setValue(this.field.value);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {height: 58px;} mat-error { font-size: 0.75em; margin-left: 14px; }\n", - "extends": "FieldDirective" - }, - { - "name": "BundleDetailsComponent", - "id": "component-BundleDetailsComponent-c28a79ec9adbf1f7c16d7037e33e9edf", - "file": "src/app/components/bundle/bundle-details/bundle-details.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-bundle-details", - "styleUrls": [ - "../../../styles/details.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/details.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityParam", - "defaultValue": "'bundle'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 20, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "leftMenu", - "defaultValue": "[\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.labelMenuItem('License', 'license'),\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 22, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 14, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "subjectService", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityService", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 121, - 125 - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "entityReceived", - "args": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Injector } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\n\nimport { DetailsFactory } from '@app/factories/details.factory';\nimport { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive';\nimport { Bundle } from '@app/core/types';\nimport { SocketState } from '@app/core/store';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ChannelService } from '@app/core/services';\nimport { BundleService } from '@app/services/bundle.service';\n\n@Component({\n selector: 'app-bundle-details',\n templateUrl: '../../../templates/details.html',\n styleUrls: ['../../../styles/details.scss']\n})\nexport class BundleDetailsComponent extends DetailAbstractDirective {\n\n entityParam = 'bundle';\n\n leftMenu = [\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.labelMenuItem('License', 'license'),\n ];\n\n constructor(\n socket: Store,\n protected route: ActivatedRoute,\n protected service: ClusterService,\n protected channel: ChannelService,\n protected store: Store,\n injector: Injector,\n protected subjectService: BundleService,\n ) {\n super(socket, route, service, channel, store, injector);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"node_modules/@angular/material/theming\";\n\n:host {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\nmat-drawer {\n min-width: 240px;\n background-color: transparent;\n padding-left: 10px;\n}\n\n.mat-card {\n flex: 1;\n padding: 10px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n & .mat-card-header {\n min-height: 40px;\n padding: 6px 10px 0;\n\n & .mat-card-title {\n font-size: 26px;\n }\n }\n\n .mat-card-content {\n display: flex;\n flex: 1;\n overflow: auto;\n }\n}\n\n.mat-toolbar {\n height: auto;\n min-height: 50px;\n}\n\n.issue-warning {\n width: 40px;\n height: 40px;\n position: relative;\n cursor: pointer;\n\n .mat-icon {\n margin: 8px 0 0 8px;\n }\n\n div {\n width: 40px;\n height: 40px;\n position: absolute;\n background: mat-color($mat-orange, 500);\n border-radius: 20px;\n top: 0;\n opacity: 0;\n animation: ripple 2s infinite ease-in-out;\n }\n}\n\n\n@keyframes ripple {\n 0% {\n opacity: .5;\n }\n\n 100% {\n opacity: 0;\n }\n}\n", - "styleUrl": "../../../styles/details.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "subjectService", - "type": "BundleService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 25, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "subjectService", - "type": "BundleService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "DetailAbstractDirective", - "templateData": "\n\n \n\n\n\n\n \n \n \n \n \n \n \n {{ currentName }}\n \n \n \n \n \n \n \n \n \n \n\n" - }, - { - "name": "BundleListComponent", - "id": "component-BundleListComponent-24b4f3c3c6725b2d90f3cdeb18df9a90", - "file": "src/app/entry/bundle/bundle-list.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-bundle-list", - "styleUrls": [], - "styles": [ - ":host { flex: 1; }" - ], - "template": "\n \n \n\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 84, - "modifierKind": [ - 122 - ] - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.nameColumn(),\n {\n label: 'Version',\n sort: 'version',\n value: row => row.version,\n },\n {\n label: 'Edition',\n type: 'component',\n component: EditionColumnComponent,\n instanceTaken: (componentRef: ComponentRef) => {\n componentRef.instance.onClick = this.license.bind(this);\n }\n },\n ListFactory.descriptionColumn(),\n ListFactory.deleteColumn(this),\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 57, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "route", - "deprecated": false, - "deprecationMessage": "", - "type": "ActivatedRoute", - "optional": false, - "description": "", - "line": 82, - "modifierKind": [ - 122 - ] - }, - { - "name": "router", - "deprecated": false, - "deprecationMessage": "", - "type": "Router", - "optional": false, - "description": "", - "line": 83, - "modifierKind": [ - 122 - ] - }, - { - "name": "type", - "defaultValue": "'bundle'", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 55 - }, - { - "name": "uploadBtn", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 76, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'uploadBtn', {static: true}" - } - ] - }, - { - "name": "data$", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject>", - "optional": false, - "description": "", - "line": 18, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "defaultSort", - "defaultValue": "{ active: 'id', direction: 'desc' }", - "deprecated": false, - "deprecationMessage": "", - "type": "Sort", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "paging", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 20, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "sorting", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "AdwpListDirective" - } - } - ], - "methodsClass": [ - { - "name": "license", - "args": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 93, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "upload", - "args": [ - { - "name": "data", - "type": "FormData[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 89, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "FormData[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "auxclickRow", - "args": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "changeCount", - "args": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "clickRow", - "args": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 42, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "findRow", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "BaseEntity", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "getPageIndex", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 52, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "getPageSize", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 56, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "getSort", - "args": [], - "optional": false, - "returnType": "Sort", - "typeParameters": [], - "line": 76, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "initBaseListDirective", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 38, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "onChangePaging", - "args": [ - { - "name": "paging", - "type": "Paging", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "paging", - "type": "Paging", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "onChangeSort", - "args": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "reload", - "args": [ - { - "name": "data", - "type": "IListResult", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "IListResult", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "rewriteRow", - "args": [ - { - "name": "row", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 80, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ComponentRef, OnInit, ViewChild } from '@angular/core';\nimport { Store } from '@ngrx/store';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { MatDialog } from '@angular/material/dialog';\nimport { IColumns } from '@adwp-ui/widgets';\nimport { Observable } from 'rxjs';\n\nimport { StackService } from '../../core/services';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { AdwpListDirective } from '@app/abstract-directives/adwp-list.directive';\nimport { ListService } from '@app/shared/components/list/list.service';\nimport { SocketState } from '@app/core/store';\nimport { TypeName } from '@app/core/types';\nimport { IBundle } from '@app/models/bundle';\nimport { ListFactory } from '../../factories/list.factory';\nimport { EditionColumnComponent } from '@app/components/columns/edition-column/edition-column.component';\n\n@Component({\n selector: 'app-bundle-list',\n template: `\n \n \n \n \n\n \n `,\n styles: [':host { flex: 1; }'],\n})\nexport class BundleListComponent extends AdwpListDirective {\n\n type: TypeName = 'bundle';\n\n listColumns = [\n ListFactory.nameColumn(),\n {\n label: 'Version',\n sort: 'version',\n value: row => row.version,\n },\n {\n label: 'Edition',\n type: 'component',\n component: EditionColumnComponent,\n instanceTaken: (componentRef: ComponentRef) => {\n componentRef.instance.onClick = this.license.bind(this);\n }\n },\n ListFactory.descriptionColumn(),\n ListFactory.deleteColumn(this),\n ] as IColumns;\n\n @ViewChild('uploadBtn', { static: true }) uploadBtn: any;\n\n constructor(\n private stack: StackService,\n protected service: ListService,\n protected store: Store,\n public route: ActivatedRoute,\n public router: Router,\n public dialog: MatDialog,\n ) {\n super(service, store, route, router, dialog);\n }\n\n upload(data: FormData[]) {\n this.stack.upload(data).subscribe();\n }\n\n license(data: { event: MouseEvent, action: string, row: any }) {\n this.clickCell(data.event, data.action, data.row);\n }\n\n}\n\n@Component({\n selector: 'app-main',\n template: `\n \n `,\n styles: [':host {width: 100%; max-width: 960px}']\n})\nexport class MainComponent implements OnInit {\n model: any;\n\n keys = ['display_name', 'version', 'license', 'license_path'];\n\n listColumns = [\n ListFactory.keyColumn(),\n ListFactory.valueColumn(),\n ] as IColumns;\n\n constructor(private service: ClusterService) {}\n\n ngOnInit() {\n this.model = this.service.Current;\n }\n\n}\n\n@Component({\n selector: 'app-license',\n template: `\n
{{ text | async }}
\n `,\n styles: [`:host {\n width: 100%;\n max-width: 960px\n }\n\n pre {\n white-space: pre-wrap;\n }`]\n})\nexport class LicenseComponent implements OnInit {\n text: Observable;\n\n constructor(private service: ClusterService) {}\n\n ngOnInit(): void {\n this.text = this.service.getBundleLicenseText();\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host { flex: 1; }\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "stack", - "type": "StackService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 76, - "jsdoctags": [ - { - "name": "stack", - "type": "StackService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "AdwpListDirective" - }, - { - "name": "BundlesComponent", - "id": "component-BundlesComponent-8f0bbd656f97c2f80899eb84ec337a96", - "file": "src/app/shared/form-elements/bundles.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-bundles", - "styleUrls": [], - "styles": [ - ".row { align-items: center;display:flex; }", - "mat-form-field {flex: 1}" - ], - "template": "
\n \n \n ...\n {{ bundle.display_name }} \n \n \n   \n \n \n {{ bundle.version }} {{ bundle.bundle_edition }} \n \n \n\n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "typeName", - "deprecated": false, - "deprecationMessage": "", - "line": 56, - "type": "\"cluster\" | \"provider\"" - }, - { - "name": "controlName", - "deprecated": false, - "deprecationMessage": "", - "line": 35, - "type": "string", - "inheritance": { - "file": "InputComponent" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 34, - "type": "FormGroup", - "inheritance": { - "file": "InputComponent" - } - }, - { - "name": "isRequired", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 37, - "type": "boolean", - "inheritance": { - "file": "InputComponent" - } - }, - { - "name": "label", - "deprecated": false, - "deprecationMessage": "", - "line": 36, - "type": "string", - "inheritance": { - "file": "InputComponent" - } - } - ], - "outputsClass": [ - { - "name": "prototypeChanged", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 65, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "bundles", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "StackBase[]", - "optional": false, - "description": "", - "line": 59 - }, - { - "name": "disabledVersion", - "defaultValue": "true", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 63 - }, - { - "name": "EventHelper", - "defaultValue": "EventHelper", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 54 - }, - { - "name": "limit", - "defaultValue": "50", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 62 - }, - { - "name": "loadedBundle", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 58 - }, - { - "name": "page", - "defaultValue": "1", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 61 - }, - { - "name": "uploadBtn", - "deprecated": false, - "deprecationMessage": "", - "type": "ButtonUploaderComponent", - "optional": false, - "description": "", - "line": 57, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'uploadBtn', {static: true}" - } - ] - }, - { - "name": "versions", - "deprecated": false, - "deprecationMessage": "", - "type": "StackBase[]", - "optional": false, - "description": "", - "line": 60 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "getBundles", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 112, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getNextPage", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 104, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "selectOne", - "args": [ - { - "name": "a", - "type": "Partial[]", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "[]" - }, - { - "name": "formName", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 121, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "a", - "type": "Partial[]", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "[]", - "tagName": { - "text": "param" - } - }, - { - "name": "formName", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "upload", - "args": [ - { - "name": "data", - "type": "FormData[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 127, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "FormData[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "error", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 44, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "error", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "InputComponent" - } - }, - { - "name": "isError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "InputComponent" - } - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';\nimport { FormControl } from '@angular/forms';\nimport { Prototype, StackBase } from '@app/core/types';\nimport { of } from 'rxjs';\nimport { filter, map, switchMap } from 'rxjs/operators';\nimport { EventHelper } from '@adwp-ui/widgets';\n\nimport { AddService } from '../add-component/add.service';\nimport { ButtonUploaderComponent } from './button-uploader.component';\nimport { InputComponent } from './input.component';\n\n@Component({\n selector: 'app-bundles',\n template: `\n
\n \n \n ...\n {{ bundle.display_name }} \n \n \n   \n \n \n {{ bundle.version }} {{ bundle.bundle_edition }} \n \n \n\n \n
\n `,\n styles: ['.row { align-items: center;display:flex; }', 'mat-form-field {flex: 1}'],\n})\nexport class BundlesComponent extends InputComponent implements OnInit {\n EventHelper = EventHelper;\n\n @Input() typeName: 'cluster' | 'provider';\n @ViewChild('uploadBtn', { static: true }) uploadBtn: ButtonUploaderComponent;\n loadedBundle: { bundle_id: number; display_name: string };\n bundles: StackBase[] = [];\n versions: StackBase[];\n page = 1;\n limit = 50;\n disabledVersion = true;\n\n @Output() prototypeChanged = new EventEmitter();\n\n constructor(private service: AddService) {\n super();\n }\n\n ngOnInit(): void {\n this.form.addControl('display_name', new FormControl());\n this.form.addControl('bundle_id', new FormControl());\n\n this.getBundles();\n\n this.form\n .get('display_name')\n .valueChanges.pipe(\n this.takeUntil(),\n switchMap((value) => (value ? this.service.getPrototype(this.typeName, { page: 0, limit: 500, ordering: '-version', display_name: value }) : of([])))\n )\n .subscribe((a) => {\n this.versions = a;\n this.selectOne(a, 'bundle_id');\n this.loadedBundle = null;\n });\n\n // for check license agreement\n this.form\n .get('bundle_id')\n .valueChanges.pipe(\n this.takeUntil(),\n filter((a) => a)\n )\n .subscribe((a) => {\n const prototype = this.versions.find((b) => b.bundle_id === +a);\n this.service.currentPrototype = prototype;\n this.prototypeChanged.emit(prototype);\n this.form.get('prototype_id').setValue(this.service.currentPrototype.id);\n });\n }\n\n getNextPage() {\n const count = this.bundles.length;\n if (count === this.page * this.limit) {\n this.page++;\n this.getBundles();\n }\n }\n\n getBundles() {\n const offset = (this.page - 1) * this.limit;\n const params = { fields: 'display_name', distinct: 1, ordering: 'display_name', limit: this.limit, offset };\n this.service.getPrototype(this.typeName, params).subscribe((a) => {\n this.bundles = [...this.bundles, ...a];\n this.selectOne(a, 'display_name');\n });\n }\n\n selectOne(a: Partial[] = [], formName: string) {\n const el = this.loadedBundle ? a.find((e) => e[formName] === this.loadedBundle[formName]) : null;\n const id = el ? el[formName] : a.length ? (formName === 'bundle_id' || a.length === 1 ? a[0][formName] : '') : '';\n this.form.get(formName).setValue(id);\n }\n\n upload(data: FormData[]) {\n this.service\n .upload(data)\n .pipe(map((a) => a.map((e) => ({ bundle_id: e.id, display_name: e.display_name, version: e.version }))))\n .subscribe((a) => {\n this.loadedBundle = a[0];\n this.uploadBtn.fileUploadInput.nativeElement.value = '';\n this.page = 0;\n this.bundles = [];\n this.getBundles();\n });\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ".row { align-items: center;display:flex; }\nmat-form-field {flex: 1}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "AddService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 65, - "jsdoctags": [ - { - "name": "service", - "type": "AddService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "InputComponent", - "implements": [ - "OnInit" - ] - }, - { - "name": "ButtonSpinnerComponent", - "id": "component-ButtonSpinnerComponent-098b94dee8377e441820102751f3dd12", - "file": "src/app/shared/components/button-spinner.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-spinner", - "styleUrls": [], - "styles": [ - ".spinner {position: relative; bottom: 5px; display: inline; }" - ], - "template": "", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "color", - "deprecated": false, - "deprecationMessage": "", - "line": 29, - "type": "ThemePalette" - }, - { - "name": "disabled", - "deprecated": false, - "deprecationMessage": "", - "line": 30, - "type": "boolean" - }, - { - "name": "spinner", - "deprecated": false, - "deprecationMessage": "", - "line": 32, - "type": "any" - }, - { - "name": "title", - "deprecated": false, - "deprecationMessage": "", - "line": 28, - "type": "string" - } - ], - "outputsClass": [ - { - "name": "clickHandler", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 35, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "_showSpinner", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 37 - }, - { - "name": "_timer", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 38, - "modifierKind": [ - 120 - ] - } - ], - "methodsClass": [ - { - "name": "hideSpinner", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 122 - ] - }, - { - "name": "send", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 40, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "showSpinner", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 52, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 122 - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, EventEmitter, Output } from '@angular/core';\nimport { ThemePalette } from '@angular/material/core';\n\n@Component({\n selector: 'app-button-spinner',\n template: ``,\n styles: ['.spinner {position: relative; bottom: 5px; display: inline; }'],\n})\nexport class ButtonSpinnerComponent {\n @Input() title: string;\n @Input() color: ThemePalette;\n @Input() disabled: boolean;\n @Input()\n set spinner(flag) {\n this._showSpinner = flag;\n }\n @Output() clickHandler = new EventEmitter();\n\n _showSpinner = false;\n private _timer: any;\n\n send() {\n this.showSpinner();\n this.clickHandler.emit(this); \n this._timer = setTimeout(() => this.hideSpinner(), 5000);\n }\n\n public hideSpinner() {\n this.disabled = false;\n this._showSpinner = false;\n clearTimeout(this._timer);\n }\n\n public showSpinner() {\n this.disabled = true;\n this._showSpinner = true;\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ".spinner {position: relative; bottom: 5px; display: inline; }\n", - "accessors": { - "spinner": { - "name": "spinner", - "setSignature": { - "name": "spinner", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "flag", - "type": "", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 32, - "jsdoctags": [ - { - "name": "flag", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "ButtonUploaderComponent", - "id": "component-ButtonUploaderComponent-78e540d70b5ac60b9fe3ca89aa266e21", - "file": "src/app/shared/form-elements/button-uploader.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-uploader", - "styleUrls": [], - "styles": [], - "template": "\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "asIcon", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 34, - "type": "boolean" - }, - { - "name": "color", - "deprecated": false, - "deprecationMessage": "", - "line": 32, - "type": "CanColor" - }, - { - "name": "label", - "deprecated": false, - "deprecationMessage": "", - "line": 33, - "type": "string" - } - ], - "outputsClass": [ - { - "name": "output", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 38, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "fileUploadInput", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 36, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'fileUploadInput', {static: true}" - } - ] - } - ], - "methodsClass": [ - { - "name": "fileUploadHandler", - "args": [ - { - "name": "fu", - "type": "HTMLInputElement", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 44, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "fu", - "type": "HTMLInputElement", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "show", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 40, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';\nimport { CanColor } from '@angular/material/core';\n\n@Component({\n selector: 'app-button-uploader',\n template: `\n \n \n \n `\n})\nexport class ButtonUploaderComponent {\n @Input() color: CanColor;\n @Input() label: string;\n @Input() asIcon = false;\n\n @ViewChild('fileUploadInput', { static: true }) fileUploadInput: ElementRef;\n\n @Output() output = new EventEmitter();\n\n show() {\n this.fileUploadInput.nativeElement.click();\n }\n\n fileUploadHandler(fu: HTMLInputElement) {\n let output: FormData[] = [];\n for (let i = 0; i < fu.files.length; i++) {\n const file = fu.files.item(i);\n const form = new FormData();\n form.append('file', file, file.name);\n output.push(form);\n }\n this.output.emit(output);\n this.fileUploadInput.nativeElement.value = '';\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "" - }, - { - "name": "CheckComponent", - "id": "component-CheckComponent-c426f21f229f87413fe9405fae8180a3", - "file": "src/app/entry/job/log/check.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-log-check", - "styleUrls": [], - "styles": [ - "\n .status {\n white-space: nowrap;\n }\n\n .item-info {\n align-items: center;\n justify-content: flex-end;\n }\n\n textarea {\n background-color: #424242;\n border: 0;\n color: #fff;\n height: 300px;\n width: 100%;\n }\n " - ], - "template": "\n \n list {{ item.title }} \n \n [ {{ item.result ? 'Success' : 'Fails' }} ]\n \n \n \n

{{ item.message }}

\n \n \n \n
\n \n \n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "content", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "line": 58, - "type": "CheckLog[]" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "CheckLog", - "optional": false, - "description": "", - "line": 59 - } - ], - "methodsClass": [ - { - "name": "trackBy", - "args": [ - { - "name": "index", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "index", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { CheckLog, LogFile } from '@app/core/types/task-job';\n\n@Component({\n selector: 'app-log-check',\n template: `\n \n \n list {{ item.title }} \n \n [ {{ item.result ? 'Success' : 'Fails' }} ]\n \n \n \n

{{ item.message }}

\n \n \n \n
\n \n \n \n
\n `,\n styles: [\n `\n .status {\n white-space: nowrap;\n }\n\n .item-info {\n align-items: center;\n justify-content: flex-end;\n }\n\n textarea {\n background-color: #424242;\n border: 0;\n color: #fff;\n height: 300px;\n width: 100%;\n }\n `,\n ],\n})\nexport class CheckComponent {\n @Input() content: CheckLog[] = [];\n current: CheckLog;\n trackBy(index: number) {\n return index;\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n .status {\n white-space: nowrap;\n }\n\n .item-info {\n align-items: center;\n justify-content: flex-end;\n }\n\n textarea {\n background-color: #424242;\n border: 0;\n color: #fff;\n height: 300px;\n width: 100%;\n }\n \n" - }, - { - "name": "ClusterColumnComponent", - "id": "component-ClusterColumnComponent-b821baa6ddbe88af207bd4338cb664ea", - "file": "src/app/components/columns/cluster-column/cluster-column.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-cluster-column", - "styleUrls": [], - "styles": [ - "\n :host {\n width: 100%;\n }\n " - ], - "template": "\n \n\n \n \n ...\n \n {{ item.title }}\n \n \n \n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "line": 44, - "type": "IHost" - } - ], - "outputsClass": [ - { - "name": "onAddCluster", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 48, - "type": "EventEmitter" - }, - { - "name": "onGetClusters", - "defaultValue": "new EventEmitter>()", - "deprecated": false, - "deprecationMessage": "", - "line": 47, - "type": "EventEmitter" - }, - { - "name": "onGetNextPageCluster", - "defaultValue": "new EventEmitter>()", - "deprecated": false, - "deprecationMessage": "", - "line": 46, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "EventHelper", - "defaultValue": "EventHelper", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "linkColumn", - "defaultValue": "{\n label: '',\n type: 'link',\n value: (row) => row.cluster_name,\n url: (row) => `/cluster/${row.cluster_id}`,\n }", - "deprecated": false, - "deprecationMessage": "", - "type": "ILinkColumn", - "optional": false, - "description": "", - "line": 50 - } - ], - "methodsClass": [ - { - "name": "addCluster", - "args": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cluster", - "type": "ICluster", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 65, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cluster", - "type": "ICluster", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getClusters", - "args": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 61, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getNextPageCluster", - "args": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 57, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, Output, EventEmitter } from '@angular/core';\nimport { AdwpCellComponent, ILinkColumn, EventHelper } from '@adwp-ui/widgets';\n\nimport { IHost } from '@app/models/host';\nimport { UniversalAdcmEventData } from '@app/models/universal-adcm-event-data';\nimport { ICluster } from '@app/models/cluster';\n\nexport interface AddClusterEventData extends UniversalAdcmEventData {\n cluster: ICluster;\n}\n\n@Component({\n selector: 'app-cluster-column',\n template: `\n \n \n\n \n \n ...\n \n {{ item.title }}\n \n \n \n\n \n `,\n styles: [`\n :host {\n width: 100%;\n }\n `],\n})\nexport class ClusterColumnComponent implements AdwpCellComponent {\n\n EventHelper = EventHelper;\n\n @Input() row: IHost;\n\n @Output() onGetNextPageCluster = new EventEmitter>();\n @Output() onGetClusters = new EventEmitter>();\n @Output() onAddCluster = new EventEmitter();\n\n linkColumn: ILinkColumn = {\n label: '',\n type: 'link',\n value: (row) => row.cluster_name,\n url: (row) => `/cluster/${row.cluster_id}`,\n };\n\n getNextPageCluster(event: MouseEvent) {\n this.onGetNextPageCluster.emit({ event, action: 'getNextPageCluster', row: this.row });\n }\n\n getClusters(event: MouseEvent) {\n this.onGetClusters.emit({ event, action: 'getClusters', row: this.row });\n }\n\n addCluster(event: MouseEvent, cluster: ICluster) {\n this.onAddCluster.emit({ event, action: 'addCluster', row: this.row, cluster });\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n :host {\n width: 100%;\n }\n \n", - "implements": [ - "AdwpCellComponent" - ] - }, - { - "name": "ClusterDetailsComponent", - "id": "component-ClusterDetailsComponent-9faa5836784ffcd9e79743d17ef017c6", - "file": "src/app/components/cluster/cluster-details/cluster-details.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-cluster-details", - "styleUrls": [ - "../../../styles/details.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/details.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityParam", - "defaultValue": "'cluster'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "leftMenu", - "defaultValue": "[\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.labelMenuItem('Services', 'service'),\n DetailsFactory.labelMenuItem('Hosts', 'host'),\n DetailsFactory.concernMenuItem('Hosts - Components', 'host_component', 'host-component', ConcernEventType.Cluster, 'cluster'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.Cluster, 'cluster'),\n DetailsFactory.labelMenuItem('Configuration groups', 'group_config'),\n DetailsFactory.statusMenuItem('Status', 'status', 'cluster'),\n DetailsFactory.concernMenuItem('Import', 'import', 'import', ConcernEventType.Cluster, 'cluster'),\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 14, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "subjectService", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityService", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 121, - 125 - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "entityReceived", - "args": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Injector } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\n\nimport { DetailsFactory } from '@app/factories/details.factory';\nimport { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive';\nimport { ICluster } from '@app/models/cluster';\nimport { SocketState } from '@app/core/store';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ChannelService } from '@app/core/services';\nimport { ClusterEntityService } from '@app/services/cluster-entity.service';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n@Component({\n selector: 'app-cluster-details',\n templateUrl: '../../../templates/details.html',\n styleUrls: ['../../../styles/details.scss']\n})\nexport class ClusterDetailsComponent extends DetailAbstractDirective {\n\n entityParam = 'cluster';\n\n leftMenu = [\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.labelMenuItem('Services', 'service'),\n DetailsFactory.labelMenuItem('Hosts', 'host'),\n DetailsFactory.concernMenuItem('Hosts - Components', 'host_component', 'host-component', ConcernEventType.Cluster, 'cluster'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.Cluster, 'cluster'),\n DetailsFactory.labelMenuItem('Configuration groups', 'group_config'),\n DetailsFactory.statusMenuItem('Status', 'status', 'cluster'),\n DetailsFactory.concernMenuItem('Import', 'import', 'import', ConcernEventType.Cluster, 'cluster'),\n ];\n\n constructor(\n socket: Store,\n protected route: ActivatedRoute,\n protected service: ClusterService,\n protected channel: ChannelService,\n protected store: Store,\n injector: Injector,\n protected subjectService: ClusterEntityService,\n ) {\n super(socket, route, service, channel, store, injector);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"node_modules/@angular/material/theming\";\n\n:host {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\nmat-drawer {\n min-width: 240px;\n background-color: transparent;\n padding-left: 10px;\n}\n\n.mat-card {\n flex: 1;\n padding: 10px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n & .mat-card-header {\n min-height: 40px;\n padding: 6px 10px 0;\n\n & .mat-card-title {\n font-size: 26px;\n }\n }\n\n .mat-card-content {\n display: flex;\n flex: 1;\n overflow: auto;\n }\n}\n\n.mat-toolbar {\n height: auto;\n min-height: 50px;\n}\n\n.issue-warning {\n width: 40px;\n height: 40px;\n position: relative;\n cursor: pointer;\n\n .mat-icon {\n margin: 8px 0 0 8px;\n }\n\n div {\n width: 40px;\n height: 40px;\n position: absolute;\n background: mat-color($mat-orange, 500);\n border-radius: 20px;\n top: 0;\n opacity: 0;\n animation: ripple 2s infinite ease-in-out;\n }\n}\n\n\n@keyframes ripple {\n 0% {\n opacity: .5;\n }\n\n 100% {\n opacity: 0;\n }\n}\n", - "styleUrl": "../../../styles/details.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "subjectService", - "type": "ClusterEntityService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 32, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "subjectService", - "type": "ClusterEntityService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "DetailAbstractDirective", - "templateData": "\n\n \n\n\n\n\n \n \n \n \n \n \n \n {{ currentName }}\n \n \n \n \n \n \n \n \n \n \n\n" - }, - { - "name": "ClusterHostComponent", - "id": "component-ClusterHostComponent-452fcebebe77d8351088c0cb349316e1", - "file": "src/app/components/cluster/host/cluster-host.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-cluster-host", - "styleUrls": [], - "styles": [ - ":host { flex: 1; }", - ".add-button {position:fixed; right: 20px;top:120px;}" - ], - "template": "Add hosts\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "eventTypes", - "defaultValue": "[ConcernEventType.Host]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 33, - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.fqdnColumn(),\n ListFactory.providerColumn(),\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.configColumn(this),\n {\n type: 'buttons',\n className: 'list-control',\n headerClassName: 'list-control',\n buttons: [{\n icon: 'link_off',\n tooltip: 'Remove from cluster',\n callback: (row, event) => this.delete(event, row),\n }],\n }\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "type", - "defaultValue": "'host2cluster'", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 24, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "route", - "deprecated": false, - "deprecationMessage": "", - "type": "ActivatedRoute", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "router", - "deprecated": false, - "deprecationMessage": "", - "type": "Router", - "optional": false, - "description": "", - "line": 23, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { IColumns } from '@adwp-ui/widgets';\n\nimport { TypeName } from '@app/core/types';\nimport { IHost } from '@app/models/host';\nimport { ListFactory } from '../../../factories/list.factory';\nimport { ConcernListDirective } from '@app/abstract-directives/concern-list.directive';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n@Component({\n selector: 'app-cluster-host',\n template: `\n Add hosts\n\n \n `,\n styles: [':host { flex: 1; }', '.add-button {position:fixed; right: 20px;top:120px;}'],\n})\nexport class ClusterHostComponent extends ConcernListDirective {\n\n type: TypeName = 'host2cluster';\n eventTypes = [ConcernEventType.Host];\n\n listColumns = [\n ListFactory.fqdnColumn(),\n ListFactory.providerColumn(),\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.configColumn(this),\n {\n type: 'buttons',\n className: 'list-control',\n headerClassName: 'list-control',\n buttons: [{\n icon: 'link_off',\n tooltip: 'Remove from cluster',\n callback: (row, event) => this.delete(event, row),\n }],\n }\n ] as IColumns;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host { flex: 1; }\n.add-button {position:fixed; right: 20px;top:120px;}\n", - "extends": "ConcernListDirective" - }, - { - "name": "ClusterListComponent", - "id": "component-ClusterListComponent-e3c481ed7e40d3ba12e45f040eb5081b", - "file": "src/app/entry/cluster/cluster.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "styleUrls": [], - "styles": [ - "\n :host {\n flex: 1;\n max-width: 100%;\n }\n " - ], - "template": "\n \n Create {{ type }}\n\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "eventTypes", - "defaultValue": "[ConcernEventType.Cluster]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 52, - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.nameColumn(),\n ListFactory.bundleColumn(),\n ListFactory.descriptionColumn(),\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.importColumn(this),\n ListFactory.updateColumn(),\n ListFactory.configColumn(this),\n ListFactory.deleteColumn(this),\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 54 - }, - { - "name": "type", - "defaultValue": "'cluster'", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 51 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 24, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "route", - "deprecated": false, - "deprecationMessage": "", - "type": "ActivatedRoute", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "router", - "deprecated": false, - "deprecationMessage": "", - "type": "Router", - "optional": false, - "description": "", - "line": 23, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { IColumns } from '@adwp-ui/widgets';\n\nimport { ICluster } from '@app/models/cluster';\nimport { TypeName } from '@app/core/types';\nimport { ListFactory } from '../../factories/list.factory';\nimport { ConcernListDirective } from '../../abstract-directives/concern-list.directive';\nimport { ConcernEventType } from '../../models/concern/concern-reason';\n\n@Component({\n template: `\n \n \n Create {{ type }}\n \n\n \n `,\n styles: [`\n :host {\n flex: 1;\n max-width: 100%;\n }\n `],\n})\nexport class ClusterListComponent extends ConcernListDirective {\n\n type: TypeName = 'cluster';\n eventTypes = [ConcernEventType.Cluster];\n\n listColumns = [\n ListFactory.nameColumn(),\n ListFactory.bundleColumn(),\n ListFactory.descriptionColumn(),\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.importColumn(this),\n ListFactory.updateColumn(),\n ListFactory.configColumn(this),\n ListFactory.deleteColumn(this),\n ] as IColumns;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n :host {\n flex: 1;\n max-width: 100%;\n }\n \n", - "extends": "ConcernListDirective" - }, - { - "name": "ClusterStatusComponent", - "id": "component-ClusterStatusComponent-4ac5bff5bfa07f87ad6ac90979041c72", - "file": "src/app/components/cluster/cluster-status/cluster-status.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-cluster-status", - "styleUrls": [ - "../../../styles/status-tree.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/status-tree.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityService", - "deprecated": false, - "deprecationMessage": "", - "type": "ClusterEntityService", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "entityId", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 24, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "folding", - "deprecated": false, - "deprecationMessage": "", - "type": "Folding", - "optional": false, - "description": "", - "line": 27, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "loading", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "statusTree", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 25, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "tree", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 19, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'tree', {static: false}" - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "eventReceived", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "getEntityIdFromParams", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 87, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "prepareStatusTree", - "args": [ - { - "name": "input", - "type": "ClusterStatusTree", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "ClusterStatusTree", - "typeParameters": [], - "line": 91, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "input", - "type": "ClusterStatusTree", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "expandCollapseAll", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 55, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "pipeData", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 53, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "prepareListeners", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { fromJS, updateIn } from 'immutable';\n\nimport { ClusterEntityService } from '@app/services/cluster-entity.service';\nimport { ClusterStatusTree } from '@app/models/status-tree';\nimport { EventMessage, SocketState } from '@app/core/store';\nimport { StatusAbstractDirective } from '@app/abstract-directives/status.abstract.directive';\nimport { ICluster } from '../../../models/cluster';\n\n@Component({\n selector: 'app-cluster-status',\n templateUrl: '../../../templates/status-tree.html',\n styleUrls: ['../../../styles/status-tree.scss']\n})\nexport class ClusterStatusComponent extends StatusAbstractDirective {\n\n constructor(\n protected route: ActivatedRoute,\n protected store: Store,\n public entityService: ClusterEntityService,\n ) {\n super(route, store, entityService);\n }\n\n eventReceived(event: EventMessage) {\n let output;\n switch (event.object.type) {\n case 'hostcomponent':\n output = updateIn(fromJS(this.statusTree.value), ['chilren', 'services'], (services: any[]) =>\n services.map(service => updateIn(service, ['hc'], (components: any) =>\n components.map( (component: any) => updateIn(component, ['hosts'], (hosts: any) =>\n hosts.map((host: any) => {\n if (host.get('id') === event.object.id && component.get('id') === +event.object.details.id) {\n return host.set('status', +event.object.details.value);\n }\n return host;\n })\n ))\n ))\n );\n this.statusTree.next(output.toJS() as any as ClusterStatusTree);\n break;\n case 'component':\n output = updateIn(fromJS(this.statusTree.value), ['chilren', 'services'], (services: any[]) => (\n services.map(service => updateIn(service, ['hc'], (components: any) => components.map( (component: any) => {\n if (component.get('id') === event.object.id) {\n return component.set('status', +event.object.details.value);\n }\n return component;\n })))\n ));\n this.statusTree.next(output.toJS() as any as ClusterStatusTree);\n break;\n case 'service':\n output = updateIn(fromJS(this.statusTree.value), ['chilren', 'services'], (services: any[]) => (\n services.map(service => {\n if (service.get('id') === event.object.id) {\n return service.set('status', +event.object.details.value);\n }\n return service;\n })));\n this.statusTree.next(output.toJS() as any as ClusterStatusTree);\n break;\n case 'host':\n output = updateIn(fromJS(this.statusTree.value), ['chilren', 'hosts'], (hosts: any[]) => (\n hosts.map(host => {\n if (host.get('id') === event.object.id) {\n return host.set('status', +event.object.details.value);\n }\n return host;\n })\n ));\n this.statusTree.next(output.toJS() as any as ClusterStatusTree);\n break;\n case 'cluster':\n output = fromJS(this.statusTree.value);\n if (output.get('id') === event.object.id) {\n output = output.set('status', +event.object.details.value);\n }\n this.statusTree.next(output.toJS() as any as ClusterStatusTree);\n break;\n }\n }\n\n getEntityIdFromParams(): number {\n return +this.route.parent.snapshot.params.cluster;\n }\n\n prepareStatusTree(input: ClusterStatusTree): ClusterStatusTree {\n input.id = this.entityId;\n return input;\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n flex: 1;\n}\n\n.controls {\n position: fixed;\n top: 130px;\n right: 10px;\n\n .notify {\n opacity: 0;\n\n &>span {\n line-height: 24px;\n vertical-align: text-bottom;\n }\n }\n}\n", - "styleUrl": "../../../styles/status-tree.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "entityService", - "type": "ClusterEntityService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 17, - "jsdoctags": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "entityService", - "type": "ClusterEntityService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "StatusAbstractDirective", - "templateData": "\n

Loading...

\n
\n\n\n\n
\n \n
\n\n \n\n
\n" - }, - { - "name": "ConcernComponent", - "id": "component-ConcernComponent-69e43a1e2e7751781e4b7f1696f91b5e", - "file": "src/app/components/concern/concern.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-concern", - "styleUrls": [ - "./concern.component.scss" - ], - "styles": [], - "templateUrl": [ - "./concern.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "concern", - "deprecated": false, - "deprecationMessage": "", - "line": 14, - "type": "" - }, - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "line": 24, - "type": "literal type" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "ownConcern", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern", - "optional": false, - "description": "", - "line": 13, - "modifierKind": [ - 120 - ] - }, - { - "name": "preparedMessage", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "optional": false, - "description": "", - "line": 31 - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\n\nimport { ConcernService } from '@app/services/concern.service';\nimport { Concern } from '@app/models/concern/concern';\n\n@Component({\n selector: 'app-concern',\n templateUrl: './concern.component.html',\n styleUrls: ['./concern.component.scss']\n})\nexport class ConcernComponent {\n\n private ownConcern: Concern;\n @Input() set concern(concern: Concern) {\n this.ownConcern = concern;\n if (this.concern) {\n this.preparedMessage = this.concernService.parse(this.concern.reason.message);\n }\n }\n get concern(): Concern {\n return this.ownConcern;\n }\n\n @Input() set data(data: { concern: Concern }) {\n if (data?.concern) {\n this.ownConcern = data.concern;\n this.preparedMessage = this.concernService.parse(this.concern.reason.message);\n }\n }\n\n preparedMessage: string[];\n\n constructor(\n private concernService: ConcernService,\n ) { }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "", - "styleUrl": "./concern.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "concernService", - "type": "ConcernService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 31, - "jsdoctags": [ - { - "name": "concernService", - "type": "ConcernService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "concern": { - "name": "concern", - "setSignature": { - "name": "concern", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "concern", - "type": "Concern", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 14, - "jsdoctags": [ - { - "name": "concern", - "type": "Concern", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "concern", - "type": "", - "returnType": "Concern", - "line": 20 - } - }, - "data": { - "name": "data", - "setSignature": { - "name": "data", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 24, - "jsdoctags": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - }, - "templateData": "\n \n {{item}}\n\n" - }, - { - "name": "ConcernItemComponent", - "id": "component-ConcernItemComponent-89417e0225e70de039599d1329820c93", - "file": "src/app/components/concern/concern-item/concern-item.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-concern-item", - "styleUrls": [ - "./concern-item.component.scss" - ], - "styles": [], - "templateUrl": [ - "./concern-item.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "item", - "deprecated": false, - "deprecationMessage": "", - "line": 14, - "type": "string" - }, - { - "name": "placeholder", - "deprecated": false, - "deprecationMessage": "", - "line": 15, - "type": "IMPlaceholderItem" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "IMPlaceholderItemType", - "defaultValue": "IMPlaceholderItemType", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 12 - } - ], - "methodsClass": [ - { - "name": "runAction", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 17, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\n\nimport { IMPlaceholderItem, IMPlaceholderItemType } from '@app/models/concern/concern-reason';\n\n@Component({\n selector: 'app-concern-item',\n templateUrl: './concern-item.component.html',\n styleUrls: ['./concern-item.component.scss']\n})\nexport class ConcernItemComponent {\n\n IMPlaceholderItemType = IMPlaceholderItemType;\n\n @Input() item: string;\n @Input() placeholder: IMPlaceholderItem;\n\n runAction() {}\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"~@angular/material/_theming\";\n\n.action-link {\n color: #1ee564;\n cursor: pointer;\n}\n\n.action-button {\n padding: 0;\n min-width: auto;\n line-height: normal;\n}\n\na {\n cursor: pointer;\n color: mat-color($mat-blue, 200) !important;\n\n &:hover {\n text-decoration: underline;\n }\n\n .red {\n color: #f00;\n }\n}\n", - "styleUrl": "./concern-item.component.scss" - } - ], - "stylesData": "", - "templateData": "\n \n \n play_circle_outline {{placeholder.name}}\n \n \n {{placeholder.name}}
\n {{placeholder.name}}\n {{placeholder.name}}\n {{placeholder.name}} \n {{placeholder.name}}\n {{placeholder.name}}\n {{placeholder.name}}\n\n" - }, - { - "name": "ConcernListComponent", - "id": "component-ConcernListComponent-8643d33470159a9f00c2b6732660a775", - "file": "src/app/components/concern/concern-list/concern-list.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-concern-list", - "styleUrls": [ - "./concern-list.component.scss" - ], - "styles": [], - "template": "
    \n
  • \n \n
  • \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "concerns", - "deprecated": false, - "deprecationMessage": "", - "line": 19, - "type": "[]" - }, - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "line": 26, - "type": "literal type" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "ownConcerns", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern[]", - "optional": false, - "description": "", - "line": 18, - "modifierKind": [ - 120 - ] - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\n\nimport { Concern } from '@app/models/concern/concern';\n\n@Component({\n selector: 'app-concern-list',\n template: `\n
    \n
  • \n \n
  • \n
\n `,\n styleUrls: ['./concern-list.component.scss']\n})\nexport class ConcernListComponent {\n\n private ownConcerns: Concern[] = [];\n @Input() set concerns(concerns: Concern[]) {\n this.ownConcerns = concerns;\n }\n get concerns(): Concern[] {\n return this.ownConcerns;\n }\n\n @Input() set data(data: { concerns: Concern[] }) {\n if (data?.concerns) {\n this.ownConcerns = data.concerns;\n }\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "ul {\n padding-inline-start: 0px;\n padding-left: 15px;\n margin-block-start: 0px;\n margin-block-end: 0px;\n}\n", - "styleUrl": "./concern-list.component.scss" - } - ], - "stylesData": "", - "accessors": { - "concerns": { - "name": "concerns", - "setSignature": { - "name": "concerns", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "concerns", - "type": "Concern[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 19, - "jsdoctags": [ - { - "name": "concerns", - "type": "Concern[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "concerns", - "type": "[]", - "returnType": "Concern[]", - "line": 22 - } - }, - "data": { - "name": "data", - "setSignature": { - "name": "data", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 26, - "jsdoctags": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "ConcernListRefComponent", - "id": "component-ConcernListRefComponent-905aa9a4bab05cc6e832af97f9e6a89d", - "file": "src/app/components/concern/concern-list-ref/concern-list-ref.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-concern-list-ref", - "styleUrls": [ - "./concern-list-ref.component.scss" - ], - "styles": [], - "template": "\n priority_hight\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "concerns", - "deprecated": false, - "deprecationMessage": "", - "line": 27, - "type": "[]" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "ConcernListComponent", - "defaultValue": "ConcernListComponent", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 24 - }, - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 33 - }, - { - "name": "ownConcerns", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern[]", - "optional": false, - "description": "", - "line": 26, - "modifierKind": [ - 120 - ] - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\n\nimport { ConcernListComponent } from '@app/components/concern/concern-list/concern-list.component';\nimport { Concern } from '@app/models/concern/concern';\n\n@Component({\n selector: 'app-concern-list-ref',\n template: `\n \n priority_hight\n \n `,\n styleUrls: ['./concern-list-ref.component.scss']\n})\nexport class ConcernListRefComponent {\n\n ConcernListComponent = ConcernListComponent;\n\n private ownConcerns: Concern[];\n @Input() set concerns(concerns: Concern[]) {\n this.ownConcerns = concerns;\n this.data = {\n concerns,\n };\n }\n data: { concerns: Concern[] };\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "", - "styleUrl": "./concern-list-ref.component.scss" - } - ], - "stylesData": "", - "accessors": { - "concerns": { - "name": "concerns", - "setSignature": { - "name": "concerns", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "concerns", - "type": "Concern[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 27, - "jsdoctags": [ - { - "name": "concerns", - "type": "Concern[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "ConcernMenuItemComponent", - "id": "component-ConcernMenuItemComponent-d7d923215ebc81229ec89255c926120e", - "file": "src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-concern-menu-item", - "styleUrls": [], - "styles": [ - "a span { white-space: nowrap; }" - ], - "template": "\n {{ label }} \n \n \n priority_hight\n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "line": 30, - "type": "", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "line": 21, - "type": "any", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "label", - "deprecated": false, - "deprecationMessage": "", - "line": 13, - "type": "string", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "link", - "deprecated": false, - "deprecationMessage": "", - "line": 14, - "type": "string", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "concernsPresent", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 28 - }, - { - "name": "_entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 11, - "modifierKind": [ - 121 - ], - "inheritance": { - "file": "MenuItemAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "getConcernStatus", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 51, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, OnInit } from '@angular/core';\nimport { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive';\nimport { BaseEntity } from '@app/core/types';\nimport { ApiService } from '@app/core/api';\nimport { ConcernService } from '@app/services/concern.service';\nimport { environment } from '@env/environment';\n\n@Component({\n selector: 'app-concern-menu-item',\n template: `\n \n {{ label }} \n \n \n priority_hight\n \n \n \n `,\n styles: ['a span { white-space: nowrap; }'],\n})\nexport class ConcernMenuItemComponent extends MenuItemAbstractDirective implements OnInit {\n\n concernsPresent = false;\n\n @Input() set entity(entity: BaseEntity) {\n this._entity = entity;\n this.getConcernStatus();\n }\n\n get entity(): BaseEntity {\n return this._entity;\n }\n\n constructor(\n private api: ApiService,\n private concernService: ConcernService\n ) {\n super();\n }\n\n ngOnInit(): void {\n this.concernService.events({ types: [this.data.type] })\n .subscribe(_ => this.getConcernStatus());\n }\n\n private getConcernStatus(): void {\n const params = {\n owner_type: this.data.owner_type,\n owner_id: this.entity.id + '',\n cause: this.data.cause\n };\n\n this.api.get(`${environment.apiRoot}/concern`, params)\n .subscribe((concerns: any[]) => this.concernsPresent = !!concerns?.length);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "a span { white-space: nowrap; }\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "concernService", - "type": "ConcernService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 37, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "concernService", - "type": "ConcernService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "MenuItemAbstractDirective", - "implements": [ - "OnInit" - ], - "accessors": { - "entity": { - "name": "entity", - "setSignature": { - "name": "entity", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "entity", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 30, - "jsdoctags": [ - { - "name": "entity", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "entity", - "type": "", - "returnType": "BaseEntity", - "line": 35 - } - } - } - }, - { - "name": "ConfigComponent", - "id": "component-ConfigComponent-74a39b6e09f4a82c95ec0e6c533143c7", - "file": "src/app/shared/configuration/main/config.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "MainService" - } - ], - "selector": "app-config-form", - "styleUrls": [ - "./config.component.scss" - ], - "styles": [], - "templateUrl": [ - "./config.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "configUrl", - "deprecated": false, - "deprecationMessage": "", - "line": 62, - "type": "string" - }, - { - "name": "isGroupConfig", - "deprecated": false, - "deprecationMessage": "", - "line": 65, - "type": "boolean" - } - ], - "outputsClass": [ - { - "name": "event", - "defaultValue": "new EventEmitter<{ name: string; data?: any }>()", - "deprecated": false, - "deprecationMessage": "", - "line": 68, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "_workerSubscription", - "defaultValue": "Subscription.EMPTY", - "deprecated": false, - "deprecationMessage": "", - "type": "Subscription", - "optional": false, - "description": "", - "line": 69, - "modifierKind": [ - 120 - ] - }, - { - "name": "cd", - "deprecated": false, - "deprecationMessage": "", - "type": "ChangeDetectorRef", - "optional": false, - "description": "", - "line": 74, - "modifierKind": [ - 122 - ] - }, - { - "name": "fields", - "deprecated": false, - "deprecationMessage": "", - "type": "ConfigFieldsComponent", - "optional": false, - "description": "", - "line": 57, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'fls'" - } - ] - }, - { - "name": "historyComponent", - "deprecated": false, - "deprecationMessage": "", - "type": "HistoryComponent", - "optional": false, - "description": "", - "line": 58, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'history'" - } - ] - }, - { - "name": "historyShow", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 51 - }, - { - "name": "isLoading", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 53 - }, - { - "name": "isLock", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 52 - }, - { - "name": "loadingStatus", - "defaultValue": "'Loading...'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 48 - }, - { - "name": "rawConfig", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 49 - }, - { - "name": "saveFlag", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 50 - }, - { - "name": "tools", - "deprecated": false, - "deprecationMessage": "", - "type": "ToolsComponent", - "optional": false, - "description": "", - "line": 59, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'tools'" - } - ] - }, - { - "name": "worker$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 55 - }, - { - "name": "socket$", - "defaultValue": "this.socket.pipe(this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object))", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 24, - "inheritance": { - "file": "SocketListenerDirective" - } - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "_getConfig", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 203, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ], - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "changeVersion", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 179, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "compareVersion", - "args": [ - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 192, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "ids", - "type": "number[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "filter", - "args": [ - { - "name": "c", - "type": "ISearchParam", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 121, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "c", - "type": "ISearchParam", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getConfigUrlFromWorker", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 139, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngAfterViewInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 83, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnChanges", - "args": [ - { - "name": "changes", - "type": "SimpleChanges", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 87, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "changes", - "type": "SimpleChanges", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 100, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 93, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onReady", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 105, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "reset", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 196, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "save", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 145, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "socketListener", - "args": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 126, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "SocketListenerDirective" - } - }, - { - "name": "startListenSocket", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "SocketListenerDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import {\n AfterViewInit,\n ChangeDetectorRef,\n Component,\n EventEmitter,\n Input,\n OnChanges,\n OnInit,\n Output,\n SimpleChanges,\n ViewChild\n} from '@angular/core';\nimport { EventMessage, SocketState } from '@app/core/store';\nimport { SocketListenerDirective } from '@app/shared/directives';\nimport { Store } from '@ngrx/store';\nimport { BehaviorSubject, Observable, of, Subscription } from 'rxjs';\nimport { catchError, finalize, tap } from 'rxjs/operators';\n\nimport { ConfigFieldsComponent } from '../fields/fields.component';\nimport { HistoryComponent } from '../tools/history.component';\nimport { ToolsComponent } from '../tools/tools.component';\nimport { IConfig } from '../types';\nimport { historyAnime, ISearchParam, MainService } from './main.service';\nimport { WorkerInstance } from '@app/core/services/cluster.service';\nimport { ActivatedRoute } from '@angular/router';\nimport { AttributeService } from '@app/shared/configuration/attributes/attribute.service';\nimport * as deepmerge from 'deepmerge';\n\n@Component({\n selector: 'app-config-form',\n templateUrl: './config.component.html',\n styleUrls: ['./config.component.scss'],\n animations: historyAnime,\n providers: [MainService]\n})\nexport class ConfigComponent extends SocketListenerDirective implements OnChanges, OnInit, AfterViewInit {\n loadingStatus = 'Loading...';\n rawConfig = new BehaviorSubject(null);\n saveFlag = false;\n historyShow = false;\n isLock = false;\n isLoading = false;\n\n worker$: Observable;\n\n @ViewChild('fls') fields: ConfigFieldsComponent;\n @ViewChild('history') historyComponent: HistoryComponent;\n @ViewChild('tools') tools: ToolsComponent;\n\n @Input()\n configUrl: string;\n\n @Input()\n isGroupConfig: boolean;\n\n @Output()\n event = new EventEmitter<{ name: string; data?: any }>();\n private _workerSubscription: Subscription = Subscription.EMPTY;\n\n constructor(\n private service: MainService,\n private attributesSrv: AttributeService,\n public cd: ChangeDetectorRef,\n socket: Store,\n route: ActivatedRoute,\n ) {\n super(socket);\n this.isGroupConfig = route.snapshot.data['isGroupConfig'];\n this.worker$ = service.worker$.pipe(this.takeUntil());\n }\n\n ngAfterViewInit(): void {\n\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n const url = changes['configUrl'];\n const firstChange = url?.firstChange;\n if (!firstChange || !url) this.getConfigUrlFromWorker();\n }\n\n ngOnInit(): void {\n if (!this.configUrl) this.getConfigUrlFromWorker();\n this._getConfig(this.configUrl).subscribe();\n\n super.startListenSocket();\n }\n\n ngOnDestroy() {\n super.ngOnDestroy();\n this._workerSubscription.unsubscribe();\n }\n\n onReady(): void {\n this.tools.isAdvanced = this.fields.isAdvanced;\n this.tools.description.setValue(this.rawConfig.value.description);\n this.filter(this.tools.filterParams);\n this.cd.detectChanges();\n\n if (!this.isGroupConfig) {\n this.service.getHistoryList(this.configUrl, this.rawConfig.value.id).subscribe((h) => {\n this.historyComponent.compareConfig = h;\n this.tools.disabledHistory = !h.length;\n this.cd.detectChanges();\n });\n }\n\n };\n\n filter(c: ISearchParam): void {\n this.service.filterApply(this.fields.dataOptions, c);\n this.cd.detectChanges();\n }\n\n socketListener(m: EventMessage): void {\n if (\n m.object.type === this.service.Current?.typeName &&\n m.object.id === this.service.Current.id &&\n !this.saveFlag &&\n (m.event === 'change_config' || m.event === 'change_state')\n ) {\n this.isLock = m.object.details.value === 'locked';\n this.reset();\n this._getConfig(this.configUrl).subscribe();\n }\n }\n\n getConfigUrlFromWorker(): void {\n this._workerSubscription.unsubscribe();\n this._workerSubscription = this.worker$\n .subscribe(_ => this.configUrl = this.service.Current?.config);\n }\n\n save(url: string): void {\n const form = this.fields.form;\n\n if (form.valid) {\n this.saveFlag = true;\n this.historyComponent.reset();\n const config = this.service.parseValue(this.fields.form.getRawValue(), this.rawConfig.value.config);\n const send = {\n config,\n attr: deepmerge(deepmerge(this.rawConfig.getValue().attr, this.fields.attr), this.attributesSrv.rawAttributes()),\n description: this.tools.description.value,\n obj_ref: this.rawConfig.value.obj_ref\n };\n\n if (this.tools.description.value === this.rawConfig.value.description) {\n delete send.description;\n }\n\n this.isLoading = true;\n\n this.service.send(url, send).pipe(\n tap((c) => {\n this.saveFlag = false;\n this.rawConfig.next(c);\n this.cd.detectChanges();\n this.event.emit({ name: 'send', data: this.fields });\n }),\n finalize(() => this.isLoading = false),\n ).subscribe();\n } else {\n Object.keys(form.controls).forEach((controlName) => form.controls[controlName].markAsTouched());\n }\n }\n\n changeVersion(url: string, id: number): void {\n this.isLoading = true;\n this.reset();\n this.service.changeVersion(url, id).pipe(\n tap((c) => this.rawConfig.next(c)),\n finalize(() => this.isLoading = false),\n catchError(() => {\n this.loadingStatus = 'There is no config for this object.';\n return of(null);\n })\n ).subscribe();\n }\n\n compareVersion(ids: number[]): void {\n if (ids) this.service.compareConfig(ids, this.fields.dataOptions, this.historyComponent.compareConfig);\n }\n\n reset(): void {\n this.fields.form.reset();\n this.fields.dataOptions = [];\n this.historyComponent.reset();\n }\n\n\n private _getConfig(url: string): Observable {\n this.isLoading = true;\n return this.service.getConfig(url).pipe(\n tap((c) => {\n this.attributesSrv.init(c.attr);\n }),\n tap((c) => this.rawConfig.next(c)),\n finalize(() => this.isLoading = false),\n catchError(() => {\n this.loadingStatus = 'There is no config for this object.';\n return of(null);\n })\n );\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n flex: 1;\n position: relative;\n\n ::ng-deep {\n .mat-form-field-infix {\n display: flex;\n }\n }\n}\n\n.na-hu {\n position: absolute;\n top: -80000px;\n}\n\n.fields {\n position: absolute;\n top: 70px;\n bottom: 0;\n left: 0;\n right: 0;\n overflow: auto;\n z-index: 2;\n padding: 0 10px;\n}\n\n.pre-load {\n position: absolute;\n top: 60px;\n width: 100%;\n text-align: center;\n}\n", - "styleUrl": "./config.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "MainService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "attributesSrv", - "type": "AttributeService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cd", - "type": "ChangeDetectorRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 69, - "jsdoctags": [ - { - "name": "service", - "type": "MainService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "attributesSrv", - "type": "AttributeService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cd", - "type": "ChangeDetectorRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "SocketListenerDirective", - "implements": [ - "OnChanges", - "OnInit", - "AfterViewInit" - ], - "templateData": "\n\n\n\n
\n \n
\n\n
\n {{ loadingStatus }}\n
\n\n
\n \n
\n\n" - }, - { - "name": "ConfigFieldAttributeProviderComponent", - "id": "component-ConfigFieldAttributeProviderComponent-e261db5c02c260b0522b272fa9521958", - "file": "src/app/shared/configuration/attributes/attribute-provider.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-config-field-attribute-provider", - "styleUrls": [], - "styles": [ - ":host {display: flex; width: 100%; margin-bottom: 20px}", - ":host:last-child {margin-bottom: 0}", - ":host:nth-child(odd) {\n background-color: #4e4e4e;\n }" - ], - "template": "\n \n\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 46, - "type": "FormGroup" - }, - { - "name": "options", - "deprecated": false, - "deprecationMessage": "", - "line": 49, - "type": "IFieldOptions" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "attributesSrv", - "deprecated": false, - "deprecationMessage": "", - "type": "AttributeService", - "optional": false, - "description": "", - "line": 61, - "modifierKind": [ - 122 - ] - }, - { - "name": "container", - "deprecated": false, - "deprecationMessage": "", - "type": "ViewContainerRef", - "optional": false, - "description": "", - "line": 52, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'container', {read: ViewContainerRef}" - } - ] - }, - { - "name": "containerRef", - "deprecated": false, - "deprecationMessage": "", - "type": "ComponentRef", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "type": "ConfigFieldMarker", - "optional": false, - "description": "", - "line": 55, - "decorators": [ - { - "name": "ContentChild", - "stringifiedArguments": "ConfigFieldMarker" - } - ] - }, - { - "name": "fieldComponent", - "deprecated": false, - "deprecationMessage": "", - "type": "QueryList", - "optional": false, - "description": "", - "line": 58, - "decorators": [ - { - "name": "ContentChildren", - "stringifiedArguments": "CONFIG_FIELD, {descendants: true}" - } - ] - }, - { - "name": "template", - "deprecated": false, - "deprecationMessage": "", - "type": "TemplateRef", - "optional": false, - "description": "", - "line": 41 - } - ], - "methodsClass": [ - { - "name": "ngAfterViewInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 64, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import {\n AfterViewInit,\n ChangeDetectorRef,\n Component,\n ComponentFactory,\n ComponentFactoryResolver,\n ComponentRef,\n ContentChild,\n ContentChildren,\n Input,\n QueryList,\n TemplateRef,\n ViewChild,\n ViewContainerRef\n} from '@angular/core';\nimport { ConfigFieldMarker } from '@app/shared/configuration/attributes/config-field.directive';\nimport { AttributeService, AttributeWrapper } from '@app/shared/configuration/attributes/attribute.service';\nimport { FormGroup } from '@angular/forms';\nimport { IFieldOptions } from '@app/shared/configuration/types';\nimport { CONFIG_FIELD, FieldComponent } from '@app/shared/configuration/field/field.component';\n\n@Component({\n selector: 'app-config-field-attribute-provider',\n template: `\n \n \n \n\n \n `,\n styles: [\n ':host {display: flex; width: 100%; margin-bottom: 20px}',\n ':host:last-child {margin-bottom: 0}',\n `:host:nth-child(odd) {\n background-color: #4e4e4e;\n }`\n ],\n})\nexport class ConfigFieldAttributeProviderComponent implements AfterViewInit {\n\n template: TemplateRef;\n\n containerRef: ComponentRef;\n\n @Input('form')\n parametersForm: FormGroup;\n\n @Input()\n options: IFieldOptions;\n\n @ViewChild('container', { read: ViewContainerRef })\n container: ViewContainerRef;\n\n @ContentChild(ConfigFieldMarker)\n field: ConfigFieldMarker;\n\n @ContentChildren(CONFIG_FIELD, { descendants: true })\n fieldComponent: QueryList;\n\n constructor(private componentFactoryResolver: ComponentFactoryResolver,\n public attributesSrv: AttributeService,\n private _cdr: ChangeDetectorRef) {}\n\n ngAfterViewInit(): void {\n this.container.clear();\n if (this.attributesSrv.attributes) {\n this.attributesSrv.attributes.forEach((attribute) => {\n if (attribute.wrapper) {\n const factory: ComponentFactory = this.componentFactoryResolver.resolveComponentFactory(attribute.wrapper);\n this.containerRef = this.container.createComponent(factory);\n this.containerRef.instance.fieldTemplate = this.field.template;\n this.containerRef.instance.wrapperOptions = attribute.options;\n this.containerRef.instance.fieldOptions = this.options;\n this.containerRef.instance.attributeForm = attribute.form;\n this.containerRef.instance.parametersForm = this.parametersForm;\n Promise.resolve().then(() => this.containerRef.instance.field = this.fieldComponent.first);\n }\n });\n } else {\n this.template = this.field.template;\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {display: flex; width: 100%; margin-bottom: 20px}\n:host:last-child {margin-bottom: 0}\n:host:nth-child(odd) {\n background-color: #4e4e4e;\n }\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "attributesSrv", - "type": "AttributeService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "_cdr", - "type": "ChangeDetectorRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 58, - "jsdoctags": [ - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "attributesSrv", - "type": "AttributeService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "_cdr", - "type": "ChangeDetectorRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "AfterViewInit" - ] - }, - { - "name": "ConfigFieldsComponent", - "id": "component-ConfigFieldsComponent-ce16c0bfc18c5a7c34ead3187556d46c", - "file": "src/app/shared/configuration/fields/fields.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-config-fields", - "styleUrls": [], - "styles": [], - "template": "\n \n \n \n \n \n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "dataOptions", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "line": 38, - "type": "TFormOptions[]" - }, - { - "name": "form", - "defaultValue": "this.service.toFormGroup()", - "deprecated": false, - "deprecationMessage": "", - "line": 39, - "type": "any" - }, - { - "name": "model", - "deprecated": false, - "deprecationMessage": "", - "line": 50, - "type": "" - } - ], - "outputsClass": [ - { - "name": "event", - "defaultValue": "new EventEmitter<{ name: string; data?: any }>()", - "deprecated": false, - "deprecationMessage": "", - "line": 41, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "fields", - "deprecated": false, - "deprecationMessage": "", - "type": "QueryList", - "optional": false, - "description": "", - "line": 62, - "decorators": [ - { - "name": "ViewChildren", - "stringifiedArguments": "FieldComponent" - } - ] - }, - { - "name": "groups", - "deprecated": false, - "deprecationMessage": "", - "type": "QueryList", - "optional": false, - "description": "", - "line": 65, - "decorators": [ - { - "name": "ViewChildren", - "stringifiedArguments": "GroupFieldsComponent" - } - ] - }, - { - "name": "isAdvanced", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 46 - }, - { - "name": "rawConfig", - "deprecated": false, - "deprecationMessage": "", - "type": "IConfig", - "optional": false, - "description": "", - "line": 44 - }, - { - "name": "shapshot", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "isPanel", - "args": [ - { - "name": "item", - "type": "TFormOptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 78, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "TFormOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "stableView", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 92, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nThis method detects the moment rendering final of all fields and groups (with internal fields) on the page\nit's need for test\n\n", - "description": "

This method detects the moment rendering final of all fields and groups (with internal fields) on the page\nit's need for test

\n", - "jsdoctags": [] - }, - { - "name": "trackBy", - "args": [ - { - "name": "index", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "item", - "type": "IPanelOptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 82, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "index", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "item", - "type": "IPanelOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, Output, QueryList, ViewChildren } from '@angular/core';\n\nimport { ChannelService, FullyRenderedService, keyChannelStrim } from '@app/core/services';\nimport { FieldService, TFormOptions } from '../services/field.service';\nimport { FieldComponent } from '../field/field.component';\nimport { GroupFieldsComponent } from '../group-fields/group-fields.component';\nimport { IConfig, IPanelOptions } from '../types';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\n@Component({\n selector: 'app-config-fields',\n template: `\n \n \n \n \n \n \n \n \n \n \n `\n})\nexport class ConfigFieldsComponent extends BaseDirective {\n\n @Input() dataOptions: TFormOptions[] = [];\n @Input() form = this.service.toFormGroup();\n @Output()\n event = new EventEmitter<{ name: string; data?: any }>();\n\n\n rawConfig: IConfig;\n shapshot: any;\n isAdvanced = false;\n\n\n @Input()\n set model(data: IConfig) {\n if (!data) return;\n this.rawConfig = data;\n this.dataOptions = this.service.getPanels(data);\n this.form = this.service.toFormGroup(this.dataOptions);\n this.isAdvanced = data.config.some((a) => a.ui_options && a.ui_options.advanced);\n this.shapshot = { ...this.form.value };\n this.event.emit({ name: 'load', data: { form: this.form } });\n this.stableView();\n }\n\n @ViewChildren(FieldComponent)\n fields: QueryList;\n\n @ViewChildren(GroupFieldsComponent)\n groups: QueryList;\n\n constructor(private service: FieldService,\n private fr: FullyRenderedService,\n private radio: ChannelService) {super();}\n\n get attr() {\n return this.dataOptions.filter((a) => a.type === 'group' && (a as IPanelOptions).activatable).reduce((p, c: IPanelOptions) => ({\n ...p,\n [c.name]: { active: c.active }\n }), {});\n }\n\n isPanel(item: TFormOptions) {\n return 'options' in item && !item.hidden;\n }\n\n trackBy(index: number, item: IPanelOptions): string {\n return item.name;\n }\n\n /**\n * This method detects the moment rendering final of all fields and groups (with internal fields) on the page\n * it's need for test\n *\n * @member ConfigFieldsComponent\n */\n stableView() {\n this.fr.stableView(() => this.radio.next(keyChannelStrim.load_complete, 'Config has been loaded'));\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "fr", - "type": "FullyRenderedService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "radio", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 65, - "jsdoctags": [ - { - "name": "service", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "fr", - "type": "FullyRenderedService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "radio", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "accessors": { - "model": { - "name": "model", - "setSignature": { - "name": "model", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "data", - "type": "IConfig", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 50, - "jsdoctags": [ - { - "name": "data", - "type": "IConfig", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - }, - "attr": { - "name": "attr", - "getSignature": { - "name": "attr", - "type": "", - "returnType": "", - "line": 71 - } - } - } - }, - { - "name": "ConfigGroupHostListComponent", - "id": "component-ConfigGroupHostListComponent-c550208ac1aa36e286951778bbee01de", - "file": "src/app/config-groups/pages/host-list/host-list.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "{ provide: LIST_SERVICE_PROVIDER, useClass: ConfigGroupHostListService }" - }, - { - "name": "{ provide: ADD_SERVICE_PROVIDER, useClass: ConfigGroupHostAddService }" - } - ], - "selector": "app-config-group-host-list", - "styleUrls": [], - "styles": [ - ":host { flex: 1; }", - ".add-button {position:fixed; right: 20px;top:120px;}" - ], - "template": "Add hosts\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "addComponent", - "defaultValue": "AddHostToConfigGroupComponent", - "deprecated": false, - "deprecationMessage": "", - "type": "Type", - "optional": false, - "description": "", - "line": 39 - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.fqdnColumn(),\n ListFactory.deleteColumn(this),\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 41, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "type", - "defaultValue": "'group_config_hosts'", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 38 - }, - { - "name": "data$", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject>", - "optional": false, - "description": "", - "line": 18, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "defaultSort", - "defaultValue": "{ active: 'id', direction: 'desc' }", - "deprecated": false, - "deprecationMessage": "", - "type": "Sort", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "paging", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 20, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "sorting", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "AdwpListDirective" - } - } - ], - "methodsClass": [ - { - "name": "clickRow", - "args": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "auxclickRow", - "args": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "changeCount", - "args": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "findRow", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "BaseEntity", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "getPageIndex", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 52, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "getPageSize", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 56, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "getSort", - "args": [], - "optional": false, - "returnType": "Sort", - "typeParameters": [], - "line": 76, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "initBaseListDirective", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 38, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "onChangePaging", - "args": [ - { - "name": "paging", - "type": "Paging", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "paging", - "type": "Paging", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "onChangeSort", - "args": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "reload", - "args": [ - { - "name": "data", - "type": "IListResult", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "IListResult", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "rewriteRow", - "args": [ - { - "name": "row", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 80, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Type } from '@angular/core';\nimport { IColumns, RowEventData } from '@adwp-ui/widgets';\nimport { AdwpListDirective } from '@app/abstract-directives/adwp-list.directive';\nimport { TypeName } from '@app/core/types';\nimport { ListFactory } from '@app/factories/list.factory';\nimport { IHost } from '@app/models/host';\nimport { LIST_SERVICE_PROVIDER } from '@app/shared/components/list/list-service-token';\nimport { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model';\nimport { ConfigGroupHostAddService, ConfigGroupHostListService } from '../../service';\nimport { BaseFormDirective } from '@app/shared/add-component';\nimport { AddHostToConfigGroupComponent } from '../../components';\n\n\n@Component({\n selector: 'app-config-group-host-list',\n template: `\n Add hosts\n\n \n `,\n styles: [':host { flex: 1; }', '.add-button {position:fixed; right: 20px;top:120px;}'],\n providers: [\n { provide: LIST_SERVICE_PROVIDER, useClass: ConfigGroupHostListService },\n { provide: ADD_SERVICE_PROVIDER, useClass: ConfigGroupHostAddService }\n ],\n})\nexport class ConfigGroupHostListComponent extends AdwpListDirective {\n type: TypeName = 'group_config_hosts';\n addComponent: Type = AddHostToConfigGroupComponent;\n\n listColumns = [\n ListFactory.fqdnColumn(),\n ListFactory.deleteColumn(this),\n ] as IColumns;\n\n clickRow(data: RowEventData): void {\n data.event.preventDefault();\n data.event.stopPropagation();\n return;\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host { flex: 1; }\n.add-button {position:fixed; right: 20px;top:120px;}\n", - "extends": "AdwpListDirective" - }, - { - "name": "ConfigGroupListComponent", - "id": "component-ConfigGroupListComponent-56b162fcf979ff9b53b31932cba6a4d2", - "file": "src/app/config-groups/pages/group-list/group-list.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "{ provide: LIST_SERVICE_PROVIDER, useClass: ConfigGroupListService }" - }, - { - "name": "{ provide: ADD_SERVICE_PROVIDER, useClass: ConfigGroupAddService }" - } - ], - "selector": "app-config-group-list", - "styleUrls": [], - "styles": [ - ":host { flex: 1; }", - ".add-button {position:fixed; right: 20px;top:120px;}" - ], - "template": "Add config group\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "addComponent", - "defaultValue": "AddConfigGroupComponent", - "deprecated": false, - "deprecationMessage": "", - "type": "Type", - "optional": false, - "description": "", - "line": 38 - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.nameColumn(),\n ListFactory.descriptionColumn(),\n ListFactory.deleteColumn(this),\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "IColumns", - "optional": false, - "description": "", - "line": 40, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "type", - "defaultValue": "'group_config'", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 37 - }, - { - "name": "data$", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject>", - "optional": false, - "description": "", - "line": 18, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "defaultSort", - "defaultValue": "{ active: 'id', direction: 'desc' }", - "deprecated": false, - "deprecationMessage": "", - "type": "Sort", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "paging", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 20, - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "sorting", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "AdwpListDirective" - } - } - ], - "methodsClass": [ - { - "name": "auxclickRow", - "args": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "changeCount", - "args": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "count", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "clickRow", - "args": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 42, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "RowEventData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "findRow", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "BaseEntity", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "getPageIndex", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 52, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "getPageSize", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 56, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "getSort", - "args": [], - "optional": false, - "returnType": "Sort", - "typeParameters": [], - "line": 76, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "initBaseListDirective", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 29, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 38, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "onChangePaging", - "args": [ - { - "name": "paging", - "type": "Paging", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "paging", - "type": "Paging", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "onChangeSort", - "args": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "sort", - "type": "Sort", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "reload", - "args": [ - { - "name": "data", - "type": "IListResult", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "IListResult", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - }, - { - "name": "rewriteRow", - "args": [ - { - "name": "row", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 80, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "row", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "AdwpListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit, Type } from '@angular/core';\nimport { TypeName } from '@app/core/types';\nimport { AdwpListDirective } from '@app/abstract-directives/adwp-list.directive';\nimport { IColumns } from '@adwp-ui/widgets';\nimport { ListFactory } from '@app/factories/list.factory';\nimport { ConfigGroupAddService, ConfigGroupListService } from '../../service';\nimport { LIST_SERVICE_PROVIDER } from '@app/shared/components/list/list-service-token';\nimport { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model';\nimport { BaseFormDirective } from '@app/shared/add-component';\nimport { AddConfigGroupComponent } from '../../components';\n\n@Component({\n selector: 'app-config-group-list',\n template: `\n Add config group\n\n \n `,\n styles: [':host { flex: 1; }', '.add-button {position:fixed; right: 20px;top:120px;}'],\n providers: [\n { provide: LIST_SERVICE_PROVIDER, useClass: ConfigGroupListService },\n { provide: ADD_SERVICE_PROVIDER, useClass: ConfigGroupAddService }\n ],\n})\nexport class ConfigGroupListComponent extends AdwpListDirective implements OnInit {\n type: TypeName = 'group_config';\n addComponent: Type = AddConfigGroupComponent;\n\n listColumns: IColumns = [\n ListFactory.nameColumn(),\n ListFactory.descriptionColumn(),\n ListFactory.deleteColumn(this),\n ];\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host { flex: 1; }\n.add-button {position:fixed; right: 20px;top:120px;}\n", - "extends": "AdwpListDirective", - "implements": [ - "OnInit" - ] - }, - { - "name": "ControlsComponent", - "id": "component-ControlsComponent-e14c098c46506c5f57764632946d91ce", - "file": "src/app/shared/add-component/controls.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-add-controls", - "styleUrls": [], - "styles": [], - "template": "

\n \n \n \n

\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "disabled", - "deprecated": false, - "deprecationMessage": "", - "line": 26, - "type": "boolean" - }, - { - "name": "title", - "defaultValue": "'Create'", - "deprecated": false, - "deprecationMessage": "", - "line": 25, - "type": "string" - } - ], - "outputsClass": [ - { - "name": "cancel", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 27, - "type": "EventEmitter" - }, - { - "name": "save", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 28, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "saveBtn", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 30, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'btn', {static: true, read: ElementRef}" - } - ] - } - ], - "methodsClass": [ - { - "name": "oncancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onsave", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 36, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, Output, ViewChild, ElementRef } from '@angular/core';\n\n@Component({\n selector: 'app-add-controls',\n template: `\n

\n \n \n \n

\n `,\n})\nexport class ControlsComponent {\n @Input() title = 'Create';\n @Input() disabled: boolean;\n @Output() cancel = new EventEmitter();\n @Output() save = new EventEmitter();\n\n @ViewChild('btn', { static: true, read: ElementRef }) saveBtn: ElementRef;\n\n oncancel() {\n this.cancel.emit();\n }\n\n onsave() {\n this.save.emit();\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "" - }, - { - "name": "CrumbsComponent", - "id": "component-CrumbsComponent-112035fcb4509db0c663d484c8407647", - "file": "src/app/shared/components/crumbs.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-crumbs", - "styleUrls": [], - "styles": [ - "\n :host {\n font-size: 0.8em;\n margin-left: 8px;\n }\n mat-nav-list {\n display: flex;\n align-items: center;\n }\n a {\n line-height: normal;\n }\n mat-icon {\n margin-bottom: 5px;\n }\n " - ], - "template": "\n apps\n  / \n \n {{ item.title | uppercase }}\n priority_hight\n  / \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "navigation", - "deprecated": false, - "deprecationMessage": "", - "line": 46, - "type": "INavItem[]" - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "trackBy", - "args": [ - { - "name": "index", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "item", - "type": "INavItem", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 47, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "index", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "item", - "type": "INavItem", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { INavItem } from '@app/models/details';\n\n@Component({\n selector: 'app-crumbs',\n template: `\n \n apps\n  / \n \n {{ item.title | uppercase }}\n priority_hight\n  / \n \n \n `,\n styles: [\n `\n :host {\n font-size: 0.8em;\n margin-left: 8px;\n }\n mat-nav-list {\n display: flex;\n align-items: center;\n }\n a {\n line-height: normal;\n }\n mat-icon {\n margin-bottom: 5px;\n }\n `,\n ],\n})\nexport class CrumbsComponent {\n @Input() navigation: INavItem[];\n trackBy(index: number, item: INavItem) {\n return item.url;\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n :host {\n font-size: 0.8em;\n margin-left: 8px;\n }\n mat-nav-list {\n display: flex;\n align-items: center;\n }\n a {\n line-height: normal;\n }\n mat-icon {\n margin-bottom: 5px;\n }\n \n" - }, - { - "name": "DependenciesComponent", - "id": "component-DependenciesComponent-812bc7f9516b28c1233cd10cb61aab84", - "file": "src/app/shared/host-components-map/dependencies.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-dependencies", - "styleUrls": [], - "styles": [ - "li {padding: 6px 0;}" - ], - "template": "
    \n
  • \n {{ item.display_name }}\n \n
  • \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "components", - "deprecated": false, - "deprecationMessage": "", - "line": 30, - "type": "IRequires[]" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "items", - "deprecated": false, - "deprecationMessage": "", - "type": "IRequires[]", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "model", - "deprecated": false, - "deprecationMessage": "", - "type": "IRequires[]", - "optional": false, - "description": "", - "line": 29 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, OnInit } from '@angular/core';\nimport { IRequires } from '@app/core/types';\n\n@Component({\n selector: 'app-dependencies',\n template: `\n
    \n
  • \n {{ item.display_name }}\n \n
  • \n
\n `,\n styles: ['li {padding: 6px 0;}'],\n})\nexport class DependenciesComponent implements OnInit {\n // by dialog window\n model: IRequires[];\n @Input() components: IRequires[];\n items: IRequires[];\n ngOnInit(): void {\n this.items = this.model || this.components;\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "li {padding: 6px 0;}\n", - "implements": [ - "OnInit" - ] - }, - { - "name": "DialogComponent", - "id": "component-DialogComponent-068900a1cc4916fa3b799a2be53b23f7", - "file": "src/app/shared/components/dialog.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-dialog", - "styleUrls": [], - "styles": [ - "pre {white-space: pre-wrap;}" - ], - "template": "

{{ data.title || 'Notification' }}

\n\n
{{ data.text }}
\n \n
\n\n \n \n \n\n\n \n \n\n\n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "controls", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "optional": false, - "description": "", - "line": 57 - }, - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "type": "DialogData", - "optional": false, - "description": "", - "line": 74, - "decorators": [ - { - "name": "Inject", - "stringifiedArguments": "MAT_DIALOG_DATA" - } - ], - "modifierKind": [ - 122 - ] - }, - { - "name": "dialogRef", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialogRef", - "optional": false, - "description": "", - "line": 73, - "modifierKind": [ - 122 - ] - }, - { - "name": "dynamic", - "deprecated": false, - "deprecationMessage": "", - "type": "DynamicDirective", - "optional": false, - "description": "", - "line": 62, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "DynamicDirective, {static: true}" - } - ] - }, - { - "name": "instance", - "deprecated": false, - "deprecationMessage": "", - "type": "DynamicComponent", - "optional": false, - "description": "", - "line": 60 - }, - { - "name": "noClose", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean | undefined", - "optional": false, - "description": "", - "line": 58 - } - ], - "methodsClass": [ - { - "name": "_noClick", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 103, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "controlsIsArray", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 79, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "handleKeyDown", - "args": [ - { - "name": "event", - "type": "KeyboardEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 65, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'window:keydown', ['$event']" - } - ], - "jsdoctags": [ - { - "name": "event", - "type": "KeyboardEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 83, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "scroll", - "args": [ - { - "name": "stop", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 99, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "stop", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "window:keydown", - "args": [ - { - "name": "event", - "type": "KeyboardEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "argsDecorator": [ - "$event" - ], - "deprecated": false, - "deprecationMessage": "", - "line": 65 - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ComponentFactoryResolver, EventEmitter, Inject, OnInit, Type, ViewChild, HostListener } from '@angular/core';\nimport { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';\n\nimport { DynamicComponent, DynamicDirective, DynamicEvent } from '../directives/dynamic.directive';\nimport { ChannelService } from '@app/core/services';\nimport { keyChannelStrim } from '@app/core/services';\nimport { ActionParameters } from '@app/shared/components/actions/actions.directive';\n\nexport interface DialogData {\n title: string;\n component: Type;\n model?: ActionParameters | any;\n event?: EventEmitter;\n text?: string;\n controls?: any[] | any;\n disabled?: boolean;\n}\n\n@Component({\n selector: 'app-dialog',\n template: `\n

{{ data.title || 'Notification' }}

\n \n
{{ data.text }}
\n \n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n `,\n styles: ['pre {white-space: pre-wrap;}'],\n})\nexport class DialogComponent implements OnInit {\n controls: string[];\n noClose: boolean | undefined;\n\n instance: DynamicComponent;\n\n @ViewChild(DynamicDirective, { static: true }) dynamic: DynamicDirective;\n\n @HostListener('window:keydown', ['$event'])\n handleKeyDown(event: KeyboardEvent) {\n if (event.key === 'Enter') {\n const c = this.instance;\n if (c?.onEnterKey) c.onEnterKey();\n }\n }\n\n constructor(\n public dialogRef: MatDialogRef,\n @Inject(MAT_DIALOG_DATA) public data: DialogData,\n private componentFactoryResolever: ComponentFactoryResolver,\n private channel: ChannelService\n ) {}\n\n controlsIsArray() {\n return Array.isArray(this.data.controls);\n }\n\n ngOnInit(): void {\n if (this.data.component) {\n const componentFactory = this.componentFactoryResolever.resolveComponentFactory(this.data.component);\n const viewContainerRef = this.dynamic.viewContainerRef;\n viewContainerRef.clear();\n\n const componentRef = viewContainerRef.createComponent(componentFactory);\n this.instance = componentRef.instance;\n this.instance.model = this.data.model;\n // event define in the component\n if (this.instance.event) this.instance.event.subscribe((e: DynamicEvent) => this.dialogRef.close(e));\n\n if (this.data.event) this.instance.event = this.data.event;\n }\n }\n\n scroll(stop: { direct: -1 | 1 | 0; screenTop: number }) {\n this.channel.next(keyChannelStrim.scroll, stop);\n }\n\n _noClick(): void {\n this.dialogRef.close();\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "pre {white-space: pre-wrap;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "dialogRef", - "type": "MatDialogRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "data", - "type": "DialogData", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "componentFactoryResolever", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 70, - "jsdoctags": [ - { - "name": "dialogRef", - "type": "MatDialogRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "data", - "type": "DialogData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "componentFactoryResolever", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "DropdownComponent", - "id": "component-DropdownComponent-5b001ba7e016f51f026a3c77d372403c", - "file": "src/app/shared/form-elements/dropdown.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-fields-dropdown", - "styleUrls": [], - "styles": [], - "template": "\n \n \n \n \n \n \n {{ option.name }}\n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "options$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 35 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 37, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "FieldDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\nimport { Observable, of } from 'rxjs';\n\nimport { FieldDirective } from './field.directive';\n\n@Component({\n selector: 'app-fields-dropdown',\n template: `\n \n \n \n \n \n \n \n {{ option.name }}\n \n \n \n \n `,\n})\nexport class DropdownComponent extends FieldDirective implements OnInit {\n options$: Observable<{ id: number | string; name: string }[]>;\n\n ngOnInit() {\n super.ngOnInit();\n if (this.field.limits) {\n const o = Object.entries(this.field.limits.option).map((e) => ({\n id: String(e[1]),\n name: e[0],\n }));\n this.options$ = of(o);\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": "FieldDirective", - "implements": [ - "OnInit" - ] - }, - { - "name": "EditionColumnComponent", - "id": "component-EditionColumnComponent-d0e03475d97e78b2f45b0f600a3b4004", - "file": "src/app/components/columns/edition-column/edition-column.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-edition-column", - "styleUrls": [], - "styles": [], - "template": "{{ row.edition }}\n\n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "line": 20, - "type": "IBundle" - } - ], - "outputsClass": [ - { - "name": "onClick", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "function" - } - ], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, Output } from '@angular/core';\nimport { AdwpCellComponent } from '@adwp-ui/widgets';\n\nimport { IBundle } from '@app/models/bundle';\n\n@Component({\n selector: 'app-edition-column',\n template: `\n {{ row.edition }}\n \n \n \n `,\n})\nexport class EditionColumnComponent implements AdwpCellComponent {\n\n @Input() row: IBundle;\n\n @Output() onClick: (data: { event: MouseEvent, action: string, row: any }) => void;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "implements": [ - "AdwpCellComponent" - ] - }, - { - "name": "ErrorInfoComponent", - "id": "component-ErrorInfoComponent-32056f9d7f14842eed4d1cebb5c9064d", - "file": "src/app/shared/form-elements/error-info.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-error-info", - "styleUrls": [], - "styles": [], - "template": "Field [{{ field.display_name }}] is required!\nField [{{ field.display_name }}] is invalid!\nField [{{ field.display_name }}] value cannot be less than {{ field.validator.min }}!\nField [{{ field.display_name }}] value cannot be greater than {{ field.validator.max }}!\nJson parsing error!\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "control", - "deprecated": false, - "deprecationMessage": "", - "line": 28, - "type": "FormControl" - }, - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 29, - "type": "IFieldOptions" - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { FormControl } from '@angular/forms';\n\nimport { IFieldOptions } from '../configuration/types';\n\n@Component({\n selector: 'app-error-info',\n template: `\n Field [{{ field.display_name }}] is required!\n Field [{{ field.display_name }}] is invalid!\n Field [{{ field.display_name }}] value cannot be less than {{ field.validator.min }}!\n Field [{{ field.display_name }}] value cannot be greater than {{ field.validator.max }}!\n Json parsing error!\n `\n})\nexport class ErrorInfoComponent {\n @Input() control: FormControl;\n @Input() field: IFieldOptions;\n\n hasError(name: string) {\n return this.control.hasError(name);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "" - }, - { - "name": "ExportComponent", - "id": "component-ExportComponent-3c17dd4f9160f4d8db43f357e0ec37f1", - "file": "src/app/shared/components/import/import.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-exports", - "styleUrls": [], - "styles": [ - ".component {padding: 6px 8px; margin-bottom: 18px; font-size: 18px;}", - ".component div {font-size: 12px;margin-left: 24px; margin-top: 4px;}" - ], - "template": "\n \n
\n {{ item.obj_name }}\n
{{ item.bundle_name }} {{ item.bundle_version }}
\n
\n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 47, - "type": "FormGroup" - }, - { - "name": "import", - "deprecated": false, - "deprecationMessage": "", - "line": 48, - "type": "IImport" - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "change", - "args": [ - { - "name": "e", - "type": "MatCheckboxChange", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "item", - "type": "IExport", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 54, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "e", - "type": "MatCheckboxChange", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "item", - "type": "IExport", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getKey", - "args": [ - { - "name": "id", - "type": "IComposite", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "IComposite", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, OnInit } from '@angular/core';\nimport { AbstractControl, FormControl, FormGroup, ValidatorFn } from '@angular/forms';\nimport { MatCheckboxChange } from '@angular/material/checkbox';\nimport { Observable } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\nimport { ChannelService } from '@app/core/services';\nimport { keyChannelStrim } from '@app/core/services';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { IExport, IImport } from '@app/core/types';\n\ninterface IComposite {\n [key: string]: number;\n}\n\nconst trueOnly = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (control.value ? null : { trueOnly: !control.value });\n\nconst requiredObject = (): ValidatorFn => (control: AbstractControl): { [key: string]: boolean } | null =>\n Object.keys(control.value).some((key) => control.value[key]) ? null : { requiered: true };\n\n@Component({\n selector: 'app-exports',\n template: `\n \n \n
\n {{ item.obj_name }}\n
{{ item.bundle_name }} {{ item.bundle_version }}
\n
\n
\n
\n `,\n styles: ['.component {padding: 6px 8px; margin-bottom: 18px; font-size: 18px;}', '.component div {font-size: 12px;margin-left: 24px; margin-top: 4px;}'],\n})\nexport class ExportComponent {\n @Input() form: FormGroup;\n @Input() import: IImport;\n\n getKey(id: IComposite) {\n return JSON.stringify(id);\n }\n\n change(e: MatCheckboxChange, item: IExport) {\n if (!this.import.multibind) {\n const group = this.form.controls[this.getKey({ import_id: this.import.id })] as FormGroup;\n\n if (e.checked)\n Object.keys(group.controls)\n .map((key) => {\n group.controls[key].clearValidators();\n return key;\n })\n .filter((key) => key !== this.getKey(item.id))\n .map((key) => group.controls[key].setValue(false));\n else if (this.import.required) {\n Object.keys(group.controls).map((key) => {\n const c = group.controls[key];\n c.setValidators(trueOnly());\n c.updateValueAndValidity();\n });\n }\n }\n }\n}\n\n@Component({\n selector: 'app-import',\n template: `\n

\n \n

\n
\n
\n

\n {{ item.name }}\n This import is required!\n

\n \n
\n
\n `,\n styleUrls: ['./import.component.scss'],\n})\nexport class ImportComponent implements OnInit {\n form = new FormGroup({});\n data$: Observable;\n asIs = false;\n\n constructor(private current: ClusterService, private channel: ChannelService) {}\n\n getKey(id: IComposite) {\n return JSON.stringify(id);\n }\n\n hasError(id: number) {\n return this.form.get(this.getKey({ import_id: id })).invalid;\n }\n\n ngOnInit() {\n this.data$ = this.current.getImportData().pipe(\n tap((a) => (this.asIs = !!a.length)),\n tap((a) =>\n a.map((i: IImport) => {\n const validFlag = i.required && !i.multibind && i.exports.every((e) => !e.binded);\n const exportGroup = i.exports.reduce((p, c) => {\n const fc = {};\n fc[`${this.getKey(c.id)}`] = new FormControl(c.binded, validFlag ? trueOnly() : null);\n return { ...p, ...fc };\n }, {});\n const import_id = this.getKey({ import_id: i.id });\n this.form.addControl(import_id, new FormGroup(exportGroup, i.required ? requiredObject() : null));\n })\n )\n );\n }\n\n go() {\n if (!this.form.invalid) {\n let bind = [];\n Object.keys(this.form.controls)\n .filter((a) => Object.keys(this.form.controls[a].value).length)\n .map((key) => {\n const obj = JSON.parse(key);\n const value = this.form.controls[key].value;\n const items = Object.keys(value)\n .filter((a) => value[a] === true)\n .map((a) => ({ ...obj, export_id: JSON.parse(a) }));\n bind = [...bind, ...items];\n });\n this.current.bindImport({ bind }).subscribe((_) => this.channel.next(keyChannelStrim.notifying, 'Successfully saved'));\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ".component {padding: 6px 8px; margin-bottom: 18px; font-size: 18px;}\n.component div {font-size: 12px;margin-left: 24px; margin-top: 4px;}\n" - }, - { - "name": "FatalErrorComponent", - "id": "component-FatalErrorComponent-ab7f01615421ad17b1b760b49a67020e", - "file": "src/app/main/server-status.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "styleUrls": [], - "styles": [ - "styleCSS" - ], - "template": "
Critical error on the server.

Contact to support.

", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\n\nconst styleCSS = 'div { font-weight:bold; margin: 40px auto; width: 400px;}';\n\n// http 500\n@Component({\n styles: [styleCSS],\n template: '
Critical error on the server.

Contact to support.

',\n})\nexport class FatalErrorComponent {}\n\n// http 504\n@Component({\n styles: [styleCSS],\n template: '
Gateway Timeout.
',\n})\nexport class GatewayTimeoutComponent {}\n\n// http 404\n@Component({\n styles: [styleCSS],\n template: '
Page not found.
',\n})\nexport class PageNotFoundComponent {}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "styleCSS\n" - }, - { - "name": "FieldComponent", - "id": "component-FieldComponent-5957c1540e05cecae03146353c436802", - "file": "src/app/shared/configuration/field/field.component.ts", - "encapsulation": [], - "entryComponents": [], - "host": {}, - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "{ provide: CONFIG_FIELD, useExisting: FieldComponent }", - "type": "component" - } - ], - "selector": "app-field", - "styleUrls": [ - "./field.component.scss" - ], - "styles": [], - "templateUrl": [ - "./field.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 39, - "type": "FormGroup" - }, - { - "name": "options", - "deprecated": false, - "deprecationMessage": "", - "line": 37, - "type": "IFieldOptions" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "currentFormGroup", - "deprecated": false, - "deprecationMessage": "", - "type": "FormGroup", - "optional": false, - "description": "", - "line": 40 - }, - { - "name": "disabled", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "inputControl", - "deprecated": false, - "deprecationMessage": "", - "type": "FieldDirective", - "optional": false, - "description": "", - "line": 44, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'cc'" - } - ] - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "getTestName", - "args": [], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 59, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "initCurrentGroup", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 54, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "isAdvanced", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnChanges", - "args": [ - { - "name": "changes", - "type": "SimpleChanges", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "changes", - "type": "SimpleChanges", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "outputValue", - "args": [ - { - "name": "v", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "isPart", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "false" - } - ], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 63, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "v", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "isPart", - "type": "", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "false", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "restore", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 77, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nTODO: should be own restore() for each fieldComponent *\n", - "description": "

TODO: should be own restore() for each fieldComponent *

\n", - "jsdoctags": [] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, InjectionToken, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { FieldDirective } from '@app/shared/form-elements/field.directive';\nimport { BaseMapListDirective } from '@app/shared/form-elements/map.component';\n\nimport { SchemeComponent } from '../scheme/scheme.component';\nimport { IFieldOptions } from '../types';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nexport const CONFIG_FIELD = new InjectionToken('Config field');\n\n@Component({\n selector: 'app-field',\n templateUrl: './field.component.html',\n styleUrls: ['./field.component.scss'],\n host: {\n class: 'field-row w100 d-flex ',\n '[class.read-only]': 'options.read_only'\n },\n providers: [\n { provide: CONFIG_FIELD, useExisting: FieldComponent }\n ]\n})\nexport class FieldComponent extends BaseDirective implements OnInit, OnChanges {\n @Input()\n options: IFieldOptions;\n @Input()\n form: FormGroup;\n currentFormGroup: FormGroup;\n\n disabled: boolean = false;\n\n @ViewChild('cc') inputControl: FieldDirective;\n\n ngOnInit() {\n this.initCurrentGroup();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (!changes.form.firstChange) this.initCurrentGroup();\n }\n\n initCurrentGroup() {\n const [_, name] = this.options.key.split('/');\n this.currentFormGroup = name ? (this.form.controls[name] as FormGroup) : this.form;\n }\n\n getTestName() {\n return `${this.options.name}${this.options.subname ? '/' + this.options.subname : ''}`;\n }\n\n outputValue(v: string, isPart = false) {\n if (this.options.type === 'password') v = v.replace(/\\w/gi, '*');\n if (this.options.type === 'secrettext') v = '****';\n return v.length > 80 ? (isPart ? v : `${v.substr(0, 80)}...`) : v;\n }\n\n isAdvanced() {\n return this.options.ui_options && this.options.ui_options.advanced;\n }\n\n /**\n * TODO: should be own restore() for each fieldComponent *\n * @member FieldComponent\n */\n restore() {\n if (this.disabled) return;\n\n const field = this.currentFormGroup.controls[this.options.name];\n const defaultValue = this.options.default;\n const type = this.options.type;\n if (field) {\n if (type === 'json') {\n field.setValue(defaultValue === null ? '' : JSON.stringify(defaultValue, undefined, 4));\n } else if (type === 'boolean') {\n const allow = String(defaultValue) === 'true' || String(defaultValue) === 'false' || String(defaultValue) === 'null';\n field.setValue(allow ? defaultValue : null);\n } else if (type === 'password') {\n field.setValue(defaultValue);\n field.updateValueAndValidity();\n\n const confirm = this.currentFormGroup.controls[`confirm_${this.options.name}`];\n if (confirm) {\n confirm.setValue(defaultValue);\n confirm.updateValueAndValidity();\n }\n } else if (type === 'map' || type === 'list') {\n this.options.value = defaultValue;\n (this.inputControl as BaseMapListDirective).reload();\n } else if (type === 'structure') {\n this.options.value = defaultValue;\n (this.inputControl as SchemeComponent).reload();\n } else field.setValue(defaultValue);\n\n this.options.value = field.value;\n this.form.updateValueAndValidity();\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n flex-wrap: wrap;\n\n .field {\n display: flex;\n align-items: center;\n padding: 0 20px;\n\n &.advanced {\n label {\n border-bottom: dotted 1px #00e676 !important;\n }\n }\n\n & label {\n font-size: 16px;\n flex-basis: 25%;\n border-bottom: dotted 1px #606060;\n margin-right: 10px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n & label + * {\n width: 100%;\n display: flex;\n align-items: center;\n }\n }\n\n & > .read-only {\n background-color: #484848;\n font-style: italic;\n color: #a7a7a7;\n }\n\n .compare-list-container {\n .compare-list {\n .label {\n margin: 0 10px;\n }\n }\n }\n\n .info {\n margin-left: 10px;\n display: flex;\n align-items: center;\n\n & > mat-icon {\n margin-top: 3px;\n }\n\n .icon-info {\n vertical-align: middle;\n }\n }\n}\n\n.break {\n flex-basis: 100%;\n height: 0;\n}\n", - "styleUrl": "./field.component.scss" - } - ], - "stylesData": "", - "extends": "BaseDirective", - "implements": [ - "OnInit", - "OnChanges" - ], - "templateData": "
\n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n info_outline\n \n \n \n
\n\n \n more_vert\n \n {{ item.date | date: 'short' }}\n  ----  {{ outputValue(item.value, true) }}\n \n\n" - }, - { - "name": "FieldListComponent", - "id": "component-FieldListComponent-c4849ca5fb4d9a382681ce222fff0dff", - "file": "src/app/shared/form-elements/map.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-fields-list", - "styleUrls": [ - "./map.component.scss" - ], - "styles": [], - "templateUrl": [ - "./map-list.template.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "asList", - "defaultValue": "true", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 90, - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "items", - "defaultValue": "new FormArray([])", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 22, - "inheritance": { - "file": "BaseMapListDirective" - } - } - ], - "methodsClass": [ - { - "name": "add", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "check", - "args": [ - { - "name": "item", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 75, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "clear", - "args": [ - { - "name": "i", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 79, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "i", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "prepare", - "args": [ - { - "name": "a", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "a", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "reload", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 59, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseMapListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Directive, OnInit } from '@angular/core';\nimport { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';\n\nimport { FieldDirective } from './field.directive';\n\n@Directive({\n selector: '[appBaseMapList]'\n})\nexport class BaseMapListDirective extends FieldDirective implements OnInit {\n asList: boolean;\n items = new FormArray([]);\n\n constructor(private fb: FormBuilder) {\n super();\n }\n\n ngOnInit() {\n if (!Object.keys(this.field.value || {}).length) this.control.setValue('');\n this.reload();\n this.items.valueChanges.pipe(\n this.takeUntil()\n ).subscribe((a: { key: string; value: string }[]) => this.prepare(a));\n\n this.control.statusChanges.pipe(\n this.takeUntil()\n ).subscribe((state) => {\n if (state === 'DISABLED') {\n this.items.controls.forEach((control) => {\n control.disable({ emitEvent: false });\n });\n } else {\n this.items.controls.forEach((control) => {\n control.enable({ emitEvent: false });\n });\n }\n });\n }\n\n prepare(a: { key: string; value: string }[]) {\n let value = this.asList ? a.map(b => b.value).filter(c => c) : a.length ? a.reduce((p, c) => ({\n ...p,\n [c.key]: c.value\n }), {}) : null;\n if (value && this.asList) value = (value as Array).length ? value : null;\n this.control.setValue(value);\n }\n\n reload() {\n this.items.reset([]);\n this.items.controls = [];\n const fieldValue = this.field.value ? { ...(this.field.value as Object) } : {};\n Object.keys(fieldValue).forEach(a => this.items.push(this.fb.group({\n key: [{ value: a, disabled: this.control.disabled }, Validators.required],\n value: [{ value: fieldValue[a], disabled: this.control.disabled }],\n })));\n }\n\n add() {\n const group = this.fb.group({ key: ['', Validators.required], value: '' });\n this.items.push(group);\n group.controls['key'].markAsTouched();\n }\n\n check(item: FormGroup) {\n return item.controls['key'].hasError('required');\n }\n\n clear(i: number) {\n this.items.removeAt(i);\n }\n}\n\n@Component({\n selector: 'app-fields-list',\n templateUrl: './map-list.template.html',\n styleUrls: ['./map.component.scss']\n})\nexport class FieldListComponent extends BaseMapListDirective {\n asList = true;\n}\n\n@Component({\n selector: 'app-fields-map',\n templateUrl: './map-list.template.html',\n styleUrls: ['./map.component.scss']\n})\nexport class FieldMapComponent extends BaseMapListDirective {\n asList = false;\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n margin-bottom: 10px;\n flex-direction: column;\n\n .tools {\n align-self: flex-end;\n }\n\n & div.item {\n width: 100%;\n display: flex;\n align-items: baseline;\n\n & .key-field {\n flex: 0 1 50%;\n margin-right: 10px;\n }\n\n & .value-field {\n flex: 1 0 50%;\n }\n }\n\n .error {\n font-size: 75%;\n }\n}\n", - "styleUrl": "./map.component.scss" - } - ], - "stylesData": "", - "extends": "BaseMapListDirective", - "templateData": "
\n \n
\n\n
\n \n :\n \n Map property name is required!\n \n \n \n \n \n
\nField [{{ field.display_name }}] is required!\n" - }, - { - "name": "FieldMapComponent", - "id": "component-FieldMapComponent-c4849ca5fb4d9a382681ce222fff0dff", - "file": "src/app/shared/form-elements/map.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-fields-map", - "styleUrls": [ - "./map.component.scss" - ], - "styles": [], - "templateUrl": [ - "./map-list.template.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "asList", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 99, - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "items", - "defaultValue": "new FormArray([])", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 22, - "inheritance": { - "file": "BaseMapListDirective" - } - } - ], - "methodsClass": [ - { - "name": "add", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "check", - "args": [ - { - "name": "item", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 75, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "clear", - "args": [ - { - "name": "i", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 79, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "i", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "prepare", - "args": [ - { - "name": "a", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "a", - "type": "literal type[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "BaseMapListDirective" - } - }, - { - "name": "reload", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 59, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseMapListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Directive, OnInit } from '@angular/core';\nimport { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';\n\nimport { FieldDirective } from './field.directive';\n\n@Directive({\n selector: '[appBaseMapList]'\n})\nexport class BaseMapListDirective extends FieldDirective implements OnInit {\n asList: boolean;\n items = new FormArray([]);\n\n constructor(private fb: FormBuilder) {\n super();\n }\n\n ngOnInit() {\n if (!Object.keys(this.field.value || {}).length) this.control.setValue('');\n this.reload();\n this.items.valueChanges.pipe(\n this.takeUntil()\n ).subscribe((a: { key: string; value: string }[]) => this.prepare(a));\n\n this.control.statusChanges.pipe(\n this.takeUntil()\n ).subscribe((state) => {\n if (state === 'DISABLED') {\n this.items.controls.forEach((control) => {\n control.disable({ emitEvent: false });\n });\n } else {\n this.items.controls.forEach((control) => {\n control.enable({ emitEvent: false });\n });\n }\n });\n }\n\n prepare(a: { key: string; value: string }[]) {\n let value = this.asList ? a.map(b => b.value).filter(c => c) : a.length ? a.reduce((p, c) => ({\n ...p,\n [c.key]: c.value\n }), {}) : null;\n if (value && this.asList) value = (value as Array).length ? value : null;\n this.control.setValue(value);\n }\n\n reload() {\n this.items.reset([]);\n this.items.controls = [];\n const fieldValue = this.field.value ? { ...(this.field.value as Object) } : {};\n Object.keys(fieldValue).forEach(a => this.items.push(this.fb.group({\n key: [{ value: a, disabled: this.control.disabled }, Validators.required],\n value: [{ value: fieldValue[a], disabled: this.control.disabled }],\n })));\n }\n\n add() {\n const group = this.fb.group({ key: ['', Validators.required], value: '' });\n this.items.push(group);\n group.controls['key'].markAsTouched();\n }\n\n check(item: FormGroup) {\n return item.controls['key'].hasError('required');\n }\n\n clear(i: number) {\n this.items.removeAt(i);\n }\n}\n\n@Component({\n selector: 'app-fields-list',\n templateUrl: './map-list.template.html',\n styleUrls: ['./map.component.scss']\n})\nexport class FieldListComponent extends BaseMapListDirective {\n asList = true;\n}\n\n@Component({\n selector: 'app-fields-map',\n templateUrl: './map-list.template.html',\n styleUrls: ['./map.component.scss']\n})\nexport class FieldMapComponent extends BaseMapListDirective {\n asList = false;\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n margin-bottom: 10px;\n flex-direction: column;\n\n .tools {\n align-self: flex-end;\n }\n\n & div.item {\n width: 100%;\n display: flex;\n align-items: baseline;\n\n & .key-field {\n flex: 0 1 50%;\n margin-right: 10px;\n }\n\n & .value-field {\n flex: 1 0 50%;\n }\n }\n\n .error {\n font-size: 75%;\n }\n}\n", - "styleUrl": "./map.component.scss" - } - ], - "stylesData": "", - "extends": "BaseMapListDirective", - "templateData": "
\n \n
\n\n
\n \n :\n \n Map property name is required!\n \n \n \n \n \n
\nField [{{ field.display_name }}] is required!\n" - }, - { - "name": "GatewayTimeoutComponent", - "id": "component-GatewayTimeoutComponent-ab7f01615421ad17b1b760b49a67020e", - "file": "src/app/main/server-status.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "styleUrls": [], - "styles": [ - "styleCSS" - ], - "template": "
Gateway Timeout.
", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\n\nconst styleCSS = 'div { font-weight:bold; margin: 40px auto; width: 400px;}';\n\n// http 500\n@Component({\n styles: [styleCSS],\n template: '
Critical error on the server.

Contact to support.

',\n})\nexport class FatalErrorComponent {}\n\n// http 504\n@Component({\n styles: [styleCSS],\n template: '
Gateway Timeout.
',\n})\nexport class GatewayTimeoutComponent {}\n\n// http 404\n@Component({\n styles: [styleCSS],\n template: '
Page not found.
',\n})\nexport class PageNotFoundComponent {}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "styleCSS\n" - }, - { - "name": "GroupConfigDetailsComponent", - "id": "component-GroupConfigDetailsComponent-5f1177f1278239f0fc9d4c4137b5099a", - "file": "src/app/components/hostprovider/group-config-details/group-config-details.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-group-config-provider-details", - "styleUrls": [ - "../../../styles/details.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/details.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityParam", - "defaultValue": "'group_config'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 20, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "leftMenu", - "defaultValue": "[\n DetailsFactory.labelMenuItem('Hosts', 'host'),\n DetailsFactory.labelMenuItem('Configuration', 'config'),\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 22, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 14, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "subjectService", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityService", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 121, - 125 - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "initContext", - "args": [ - { - "name": "param", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "param", - "type": "ParamMap", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "entityReceived", - "args": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Injector } from '@angular/core';\nimport { ActivatedRoute, ParamMap } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { Observable } from 'rxjs';\n\nimport { DetailsFactory } from '@app/factories/details.factory';\nimport { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive';\nimport { SocketState } from '@app/core/store';\nimport { ClusterService, WorkerInstance } from '@app/core/services/cluster.service';\nimport { ChannelService } from '@app/core/services';\nimport { ConfigGroup, ConfigGroupListService } from '@app/config-groups';\n\n@Component({\n selector: 'app-group-config-provider-details',\n templateUrl: '../../../templates/details.html',\n styleUrls: ['../../../styles/details.scss']\n})\nexport class GroupConfigDetailsComponent extends DetailAbstractDirective {\n\n entityParam = 'group_config';\n\n leftMenu = [\n DetailsFactory.labelMenuItem('Hosts', 'host'),\n DetailsFactory.labelMenuItem('Configuration', 'config'),\n ];\n\n constructor(\n socket: Store,\n protected route: ActivatedRoute,\n protected service: ClusterService,\n protected channel: ChannelService,\n protected store: Store,\n injector: Injector,\n protected subjectService: ConfigGroupListService,\n ) {\n super(socket, route, service, channel, store, injector);\n }\n\n initContext(param: ParamMap): Observable {\n return this.service.getContext(param, this.subjectService);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"node_modules/@angular/material/theming\";\n\n:host {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\nmat-drawer {\n min-width: 240px;\n background-color: transparent;\n padding-left: 10px;\n}\n\n.mat-card {\n flex: 1;\n padding: 10px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n & .mat-card-header {\n min-height: 40px;\n padding: 6px 10px 0;\n\n & .mat-card-title {\n font-size: 26px;\n }\n }\n\n .mat-card-content {\n display: flex;\n flex: 1;\n overflow: auto;\n }\n}\n\n.mat-toolbar {\n height: auto;\n min-height: 50px;\n}\n\n.issue-warning {\n width: 40px;\n height: 40px;\n position: relative;\n cursor: pointer;\n\n .mat-icon {\n margin: 8px 0 0 8px;\n }\n\n div {\n width: 40px;\n height: 40px;\n position: absolute;\n background: mat-color($mat-orange, 500);\n border-radius: 20px;\n top: 0;\n opacity: 0;\n animation: ripple 2s infinite ease-in-out;\n }\n}\n\n\n@keyframes ripple {\n 0% {\n opacity: .5;\n }\n\n 100% {\n opacity: 0;\n }\n}\n", - "styleUrl": "../../../styles/details.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "subjectService", - "type": "ConfigGroupListService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 25, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "subjectService", - "type": "ConfigGroupListService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "DetailAbstractDirective", - "templateData": "\n\n \n\n\n\n\n \n \n \n \n \n \n \n {{ currentName }}\n \n \n \n \n \n \n \n \n \n \n\n" - }, - { - "name": "GroupFieldsComponent", - "id": "component-GroupFieldsComponent-4737181957c0c2d80f3d2f044b2a2c70", - "file": "src/app/shared/configuration/group-fields/group-fields.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-group-fields", - "styleUrls": [], - "styles": [ - ".title {font-size: 22px;}", - ".title > mat-slide-toggle {margin-left: 20px;}", - ".advanced {border: dotted 1px #00e676;}", - "mat-panel-description {justify-content: flex-end;}" - ], - "templateUrl": [ - "./group-fields.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 33, - "type": "FormGroup" - }, - { - "name": "panel", - "deprecated": false, - "deprecationMessage": "", - "line": 32, - "type": "IPanelOptions" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "active", - "defaultValue": "true", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "expanel", - "deprecated": false, - "deprecationMessage": "", - "type": "MatExpansionPanel", - "optional": false, - "description": "", - "line": 34, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'ep'" - } - ] - } - ], - "methodsClass": [ - { - "name": "activatable", - "args": [ - { - "name": "flag", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 51, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "flag", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "activeToggle", - "args": [ - { - "name": "e", - "type": "MatSlideToggleChange", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "e", - "type": "MatSlideToggleChange", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "checkFields", - "args": [ - { - "name": "flag", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 56, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "flag", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 38, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "updateValidator", - "args": [ - { - "name": "formControl", - "type": "AbstractControl", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "flag", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "a", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "currentFormControl", - "type": "AbstractControl", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "formControl", - "type": "AbstractControl", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "flag", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "a", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "currentFormControl", - "type": "AbstractControl", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, OnInit, ViewChild } from '@angular/core';\nimport { AbstractControl, FormGroup } from '@angular/forms';\nimport { MatExpansionPanel } from '@angular/material/expansion';\nimport { MatSlideToggleChange } from '@angular/material/slide-toggle';\nimport { FieldService } from '@app/shared/configuration/services/field.service';\n\nimport { IFieldOptions, IPanelOptions } from '../types';\n\n@Component({\n selector: 'app-group-fields',\n templateUrl: './group-fields.component.html',\n styles: [\n '.title {font-size: 22px;}',\n '.title > mat-slide-toggle {margin-left: 20px;}',\n '.advanced {border: dotted 1px #00e676;}',\n 'mat-panel-description {justify-content: flex-end;}',\n ],\n})\nexport class GroupFieldsComponent implements OnInit {\n active = true;\n @Input() panel: IPanelOptions;\n @Input() form: FormGroup;\n @ViewChild('ep') expanel: MatExpansionPanel;\n\n constructor(private service: FieldService) {}\n\n ngOnInit(): void {\n if (this.panel.activatable) this.activatable(this.panel.active);\n }\n\n get isAdvanced() {\n return this.panel.ui_options && this.panel.ui_options.advanced;\n }\n\n activeToggle(e: MatSlideToggleChange) {\n this.panel.active = e.checked;\n this.activatable(e.checked);\n }\n\n activatable(flag: boolean) {\n this.active = flag;\n this.checkFields(this.active);\n }\n\n checkFields(flag: boolean) {\n this.panel.options\n .filter((a) => !('options' in a))\n .forEach((a: IFieldOptions) => {\n const split = a.key.split('/');\n const [name, ...other] = split;\n const currentFormGroup = (other.reverse().reduce((p, c) => p.get(c), this.form)) as FormGroup;\n const formControl = currentFormGroup.controls[name];\n this.updateValidator(formControl, flag, a);\n if (a.type === 'password') this.updateValidator(currentFormGroup.controls['confirm_' + name], flag, a, formControl);\n });\n }\n\n updateValidator(formControl: AbstractControl, flag: boolean, a: IFieldOptions, currentFormControl?: AbstractControl) {\n if (formControl) {\n if (!flag) formControl.clearValidators();\n else formControl.setValidators(this.service.setValidator(a, currentFormControl));\n formControl.updateValueAndValidity();\n formControl.markAsTouched();\n this.form.updateValueAndValidity();\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ".title {font-size: 22px;}\n.title > mat-slide-toggle {margin-left: 20px;}\n.advanced {border: dotted 1px #00e676;}\nmat-panel-description {justify-content: flex-end;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 34, - "jsdoctags": [ - { - "name": "service", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ], - "accessors": { - "isAdvanced": { - "name": "isAdvanced", - "getSignature": { - "name": "isAdvanced", - "type": "", - "returnType": "", - "line": 42 - } - } - }, - "templateData": "\n \n \n {{ panel.display_name }}\n \n \n \n \n \n info_outline\n \n \n \n \n\n" - }, - { - "name": "GroupKeysWrapperComponent", - "id": "component-GroupKeysWrapperComponent-db8e3b5399a5b2a3676b927e32077285", - "file": "src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-group-keys-wrapper", - "styleUrls": [ - "group-keys-wrapper.component.scss" - ], - "styles": [], - "template": "
\n
\n \n
\n
\n \n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "attributeForm", - "deprecated": false, - "deprecationMessage": "", - "line": 40, - "type": "FormGroup" - }, - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 46, - "type": "FieldComponent" - }, - { - "name": "fieldOptions", - "deprecated": false, - "deprecationMessage": "", - "line": 44, - "type": "IFieldOptions" - }, - { - "name": "fieldTemplate", - "deprecated": false, - "deprecationMessage": "", - "line": 36, - "type": "TemplateRef" - }, - { - "name": "parametersForm", - "deprecated": false, - "deprecationMessage": "", - "line": 42, - "type": "FormGroup" - }, - { - "name": "wrapperOptions", - "deprecated": false, - "deprecationMessage": "", - "line": 38, - "type": "ConfigAttributeOptions" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "_disabled", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 48, - "modifierKind": [ - 120 - ] - }, - { - "name": "groupControl", - "deprecated": false, - "deprecationMessage": "", - "type": "FormControl", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "parameterControl", - "deprecated": false, - "deprecationMessage": "", - "type": "FormControl", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "tooltipText", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "_resolveAndSetupControls", - "args": [ - { - "name": "attributeForm", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "parametersForm", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "fieldOptions", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 59, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ], - "jsdoctags": [ - { - "name": "attributeForm", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "parametersForm", - "type": "FormGroup", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "fieldOptions", - "type": "IFieldOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "_restoreStatus", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 102, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 54, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onChange", - "args": [ - { - "name": "e", - "type": "MatCheckboxChange", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 92, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "e", - "type": "MatCheckboxChange", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, OnInit, TemplateRef } from '@angular/core';\nimport {\n AttributeService,\n AttributeWrapper,\n ConfigAttributeNames,\n ConfigAttributeOptions\n} from '@app/shared/configuration/attributes/attribute.service';\nimport { FormControl, FormGroup } from '@angular/forms';\nimport { IFieldOptions } from '@app/shared/configuration/types';\nimport { BaseDirective } from '@adwp-ui/widgets';\nimport { MatCheckboxChange } from '@angular/material/checkbox';\nimport { FieldComponent } from '@app/shared/configuration/field/field.component';\n\n@Component({\n selector: 'app-group-keys-wrapper',\n template: `\n
\n
\n \n
\n
\n \n
\n
\n `,\n styleUrls: ['group-keys-wrapper.component.scss'],\n})\nexport class GroupKeysWrapperComponent extends BaseDirective implements AttributeWrapper, OnInit {\n tooltipText: string = '';\n\n groupControl: FormControl;\n\n parameterControl: FormControl;\n\n @Input() fieldTemplate: TemplateRef;\n\n @Input() wrapperOptions: ConfigAttributeOptions;\n\n @Input() attributeForm: FormGroup;\n\n @Input() parametersForm: FormGroup;\n\n @Input() fieldOptions: IFieldOptions;\n\n @Input() field: FieldComponent;\n\n private _disabled: boolean;\n\n constructor(private _attributeSrv: AttributeService) {\n super();\n }\n\n ngOnInit(): void {\n this._resolveAndSetupControls(this.attributeForm, this.parametersForm, this.fieldOptions);\n Promise.resolve().then(() => this._restoreStatus());\n }\n\n private _resolveAndSetupControls(attributeForm: FormGroup, parametersForm: FormGroup, fieldOptions: IFieldOptions): void {\n let attributeControl: FormGroup = attributeForm;\n let parameterControl: FormGroup = parametersForm;\n let disabled = this._attributeSrv.attributes.get(ConfigAttributeNames.CUSTOM_GROUP_KEYS).value;\n let text = this._attributeSrv.attributes.get(ConfigAttributeNames.CUSTOM_GROUP_KEYS).options.tooltipText;\n\n const path = fieldOptions.key?.split('/').reverse();\n\n this.groupControl = attributeControl.get(path) as FormControl;\n this.parameterControl = parameterControl.get(path) as FormControl;\n\n path.forEach((part) => {\n disabled = disabled[part];\n });\n\n if (!disabled) {\n attributeControl.disable();\n parameterControl.disable();\n\n this.tooltipText = text;\n } else {\n attributeControl.enable();\n if (attributeControl.value) {\n parameterControl.enable();\n } else {\n parameterControl.disable();\n }\n\n this.tooltipText = this.wrapperOptions.tooltipText;\n this._disabled = !attributeControl.value;\n }\n }\n\n onChange(e: MatCheckboxChange) {\n if (e.checked) {\n this.parameterControl.enable();\n this.field.disabled = false;\n } else {\n this.parameterControl.disable();\n this.field.disabled = true;\n }\n }\n\n private _restoreStatus() {\n if (this.field?.disabled) {\n this.field.disabled = this._disabled;\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host, .group-field, .group-keys-wrapper {\n display: flex;\n width: 100%;\n}\n\n.group-checkbox {\n display: flex;\n align-items: center;\n padding: 0 0 0 20px;\n}\n\n", - "styleUrl": "group-keys-wrapper.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "_attributeSrv", - "type": "AttributeService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 48, - "jsdoctags": [ - { - "name": "_attributeSrv", - "type": "AttributeService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "AttributeWrapper", - "OnInit" - ] - }, - { - "name": "HcmapComponent", - "id": "component-HcmapComponent-1d3c2c22411dcc542141553536261e73", - "file": "src/app/components/cluster/hcmap/hcmap.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "styleUrls": [], - "styles": [ - ":host { flex: 1; }" - ], - "template": "", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 10 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 13, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\n\nimport { ClusterService } from '@app/core/services/cluster.service';\n\n@Component({\n template: ` `,\n styles: [':host { flex: 1; }'],\n})\nexport class HcmapComponent implements OnInit {\n cluster: { id: number; hostcomponent: string };\n constructor(private service: ClusterService) {}\n\n ngOnInit() {\n const { id, hostcomponent } = { ...this.service.Cluster };\n this.cluster = { id, hostcomponent };\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host { flex: 1; }\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 10, - "jsdoctags": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "HistoryComponent", - "id": "component-HistoryComponent-c0a407cd2b8bcc454f41d1ea0f2b1338", - "file": "src/app/shared/configuration/tools/history.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-history", - "styleUrls": [], - "styles": [ - ":host {height: 64px;}", - "mat-form-field {flex: auto; margin: 0 10px; font-size: 14px; }" - ], - "template": "\n \n \n [#{{ item.id }}] - {{ item.date | date: 'short' }} {{ item.description }} \n \n \n   \n \n \n \n [#{{ item.id }}] - {{ item.date | date: 'short' }} {{ item.description }}\n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "compareConfig", - "deprecated": false, - "deprecationMessage": "", - "line": 40, - "type": "CompareConfig[]" - } - ], - "outputsClass": [ - { - "name": "compare", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 42, - "type": "EventEmitter" - }, - { - "name": "version", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 41, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "comparator", - "defaultValue": "new FormControl()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 44 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "changeVersion", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "reset", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 58, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "trackById", - "args": [ - { - "name": "item", - "type": "CompareConfig", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 54, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "CompareConfig", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';\nimport { FormControl } from '@angular/forms';\nimport { BaseDirective } from '@app/shared/directives/base.directive';\n\nimport { CompareConfig } from '../types';\n\n@Component({\n selector: 'app-history',\n template: `\n \n \n \n [#{{ item.id }}] - {{ item.date | date: 'short' }} {{ item.description }} \n \n \n   \n \n \n \n [#{{ item.id }}] - {{ item.date | date: 'short' }} {{ item.description }}\n \n \n \n \n `,\n styles: [':host {height: 64px;}', 'mat-form-field {flex: auto; margin: 0 10px; font-size: 14px; }'],\n})\nexport class HistoryComponent extends BaseDirective implements OnInit {\n @Input() compareConfig: CompareConfig[];\n @Output() version = new EventEmitter();\n @Output() compare = new EventEmitter();\n\n comparator = new FormControl();\n\n ngOnInit() {\n this.comparator.valueChanges.pipe(this.takeUntil()).subscribe((ids: number[]) => this.compare.emit(ids));\n }\n\n changeVersion(id: number) {\n this.version.emit(id);\n }\n\n trackById(item: CompareConfig): number {\n return item.id;\n }\n\n reset() {\n this.compareConfig = [];\n this.comparator.reset();\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {height: 64px;}\nmat-form-field {flex: auto; margin: 0 10px; font-size: 14px; }\n", - "extends": "BaseDirective", - "implements": [ - "OnInit" - ] - }, - { - "name": "Host2clusterComponent", - "id": "component-Host2clusterComponent-cf60d76a56676355996251c55d8b5bd4", - "file": "src/app/shared/add-component/host2cluster.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-add-host2cluster", - "styleUrls": [ - "host2cluster.component.scss" - ], - "styles": [], - "template": "
\n \n \n
\n\n
\n
\n
All
\n
\n \n {{ showForm ? 'clear' : 'add' }}\n \n  \n \n
\n
\n \n \n {{ host.fqdn }}\n \n \n \n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [ - { - "name": "event", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 70, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "allCbx", - "deprecated": false, - "deprecationMessage": "", - "type": "MatCheckbox", - "optional": false, - "description": "", - "line": 73, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'cb'" - } - ] - }, - { - "name": "Count", - "defaultValue": "0", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 68 - }, - { - "name": "displayMode", - "defaultValue": "DisplayMode.default", - "deprecated": false, - "deprecationMessage": "", - "type": "DisplayMode", - "optional": false, - "description": "", - "line": 69 - }, - { - "name": "hostForm", - "deprecated": false, - "deprecationMessage": "", - "type": "HostComponent", - "optional": false, - "description": "", - "line": 71, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'form'" - } - ] - }, - { - "name": "list", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "Host[]", - "optional": false, - "description": "", - "line": 66 - }, - { - "name": "listHosts", - "deprecated": false, - "deprecationMessage": "", - "type": "MatSelectionList", - "optional": false, - "description": "", - "line": 72, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'listHosts'" - } - ] - }, - { - "name": "paginator", - "deprecated": false, - "deprecationMessage": "", - "type": "MatPaginator", - "optional": false, - "description": "", - "line": 74, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "MatPaginator" - } - ] - }, - { - "name": "selected", - "defaultValue": "{}", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 76 - }, - { - "name": "showForm", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 67 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 27, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "IAddService", - "optional": false, - "description": "", - "line": 26, - "decorators": [ - { - "name": "Inject", - "stringifiedArguments": "ADD_SERVICE_PROVIDER" - } - ], - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "methodsClass": [ - { - "name": "addHost2Cluster", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 129, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getAvailableHosts", - "args": [ - { - "name": "pageIndex", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "0" - }, - { - "name": "pageSize", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "10" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 86, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "pageIndex", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "0", - "tagName": { - "text": "param" - } - }, - { - "name": "pageSize", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "10", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 82, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "pageHandler", - "args": [ - { - "name": "pageEvent", - "type": "PageEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 141, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "pageEvent", - "type": "PageEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "save", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 115, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "selectAllHost", - "args": [ - { - "name": "flag", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 99, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "flag", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "selectionChange", - "args": [ - { - "name": "e", - "type": "MatSelectionListChange", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 145, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "e", - "type": "MatSelectionListChange", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "onCancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';\nimport { MatCheckbox } from '@angular/material/checkbox';\nimport { MatSelectionList, MatSelectionListChange } from '@angular/material/list';\nimport { MatPaginator, PageEvent } from '@angular/material/paginator';\nimport { openClose } from '@app/core/animations';\nimport { Host } from '@app/core/types';\n\nimport { BaseFormDirective } from './base-form.directive';\nimport { HostComponent } from './host.component';\nimport { DisplayMode } from './provider.component';\n\n@Component({\n selector: 'app-add-host2cluster',\n template: `\n
\n \n \n
\n\n
\n
\n
All
\n
\n \n {{ showForm ? 'clear' : 'add' }}\n \n  \n \n
\n
\n \n \n {{ host.fqdn }}\n \n \n \n \n
\n `,\n styleUrls: ['host2cluster.component.scss'],\n animations: [openClose],\n})\nexport class Host2clusterComponent extends BaseFormDirective implements OnInit, OnDestroy {\n list: Host[] = [];\n showForm = false;\n Count = 0;\n displayMode: DisplayMode = DisplayMode.default;\n @Output() event = new EventEmitter();\n @ViewChild('form') hostForm: HostComponent;\n @ViewChild('listHosts') listHosts: MatSelectionList;\n @ViewChild('cb') allCbx: MatCheckbox;\n @ViewChild(MatPaginator) paginator: MatPaginator;\n\n selected: { [key: number]: boolean } = {};\n\n get disabled() {\n return !Object.keys(this.selected).length;\n }\n\n ngOnInit() {\n this.getAvailableHosts();\n }\n\n getAvailableHosts(pageIndex = 0, pageSize = 10) {\n this.service\n .getListResults('host', { limit: pageSize, page: pageIndex, cluster_is_null: 'true' })\n .pipe(this.takeUntil())\n .subscribe((r) => {\n this.Count = r.count;\n this.showForm = !r.count;\n this.displayMode = r.count > 0 ? 2 : 1;\n this.list = r.results;\n if (this.listHosts?.options.length) this.allCbx.checked = false;\n });\n }\n\n selectAllHost(flag: boolean) {\n if (!flag) {\n this.listHosts.selectAll();\n this.listHosts.options.forEach((o) => {\n this.selected[o.value] = true;\n });\n } else {\n this.listHosts.deselectAll();\n this.listHosts.options.forEach((o) => {\n if (this.selected[o.value]) {\n delete this.selected[o.value];\n }\n });\n }\n }\n\n save() {\n if (this.hostForm.form.valid) {\n const host = this.hostForm.form.value;\n host.cluster_id = this.service.Cluster.id;\n this.service\n .addHost(host)\n .pipe(this.takeUntil())\n .subscribe((a) => {\n this.hostForm.form.controls['fqdn'].setValue('');\n this.event.emit(`Host [ ${a.fqdn} ] has been added successfully.`);\n });\n }\n }\n\n addHost2Cluster() {\n const value = Object.keys(this.selected);\n\n this.service\n .addHostInCluster(value.map((a) => +a))\n .pipe(this.takeUntil())\n .subscribe(() => {\n this.paginator.firstPage();\n this.getAvailableHosts();\n });\n }\n\n pageHandler(pageEvent: PageEvent) {\n this.getAvailableHosts(pageEvent.pageIndex, pageEvent.pageSize);\n }\n\n selectionChange(e: MatSelectionListChange): void {\n const value = e.option.value;\n if (this.selected[value]) {\n delete this.selected[value];\n } else {\n this.selected[value] = true;\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".add-host2cluster {\n flex: 1;\n}\n\n.tools {\n display: flex;\n width: 100%;\n align-items: center;\n flex: 0 0 45px;\n padding: 0 16px;\n box-sizing: border-box;\n\n > .text {\n display: flex;\n width: 100%;\n }\n\n > .actions {\n display: flex;\n align-items: center;\n }\n}\n", - "styleUrl": "host2cluster.component.scss" - } - ], - "stylesData": "", - "extends": "BaseFormDirective", - "implements": [ - "OnInit", - "OnDestroy" - ], - "accessors": { - "disabled": { - "name": "disabled", - "getSignature": { - "name": "disabled", - "type": "", - "returnType": "", - "line": 78 - } - } - } - }, - { - "name": "HostComponent", - "id": "component-HostComponent-5fb809d459784eddea51d4829bc7e828", - "file": "src/app/shared/add-component/host.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "ActionsDirective", - "type": "directive" - } - ], - "selector": "app-add-host", - "styleUrls": [], - "styles": [ - ":host {display: block; margin-top: 10px;}", - ".inner {overflow: hidden; margin: 0 -6px;}", - ".inner app-add-provider {padding: 10px 24px; background-color: #4e4e4e;display:block;}", - ".row {display: flex;}" - ], - "template": "\n
\n \n \n ...\n {{ p.name }}\n \n \n {{ expanded ? 'clear' : 'add' }}\n \n \n Hostprovider is required. If no hostprovider is available, add it here.\n \n \n
\n\n
\n \n
\n\n \n\n
\n \n \n \n Fully qualified domain name is required \n \n
\n\n \n
\n \n \n ...\n {{ c.name }}\n \n \n
\n \n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "displayMode", - "defaultValue": "DisplayMode.default", - "deprecated": false, - "deprecationMessage": "", - "line": 91, - "type": "DisplayMode" - } - ], - "outputsClass": [ - { - "name": "event", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 92, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "clusters$", - "defaultValue": "new BehaviorSubject[]>([])", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 95 - }, - { - "name": "createdProviderId", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 97 - }, - { - "name": "expanded", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 96 - }, - { - "name": "limit", - "defaultValue": "10", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 101 - }, - { - "name": "pageCluster", - "defaultValue": "1", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 99 - }, - { - "name": "pageProvider", - "defaultValue": "1", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 100 - }, - { - "name": "providers$", - "defaultValue": "new BehaviorSubject>([])", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 94 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 27, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "IAddService", - "optional": false, - "description": "", - "line": 26, - "decorators": [ - { - "name": "Inject", - "stringifiedArguments": "ADD_SERVICE_PROVIDER" - } - ], - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "methodsClass": [ - { - "name": "checkAction", - "args": [ - { - "name": "provider_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 131, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "provider_id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "createdProvider", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 157, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getClusters", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 189, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getNextPageClusters", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 165, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getNextPageProvider", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 173, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getProviders", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 181, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "isError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 120, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 107, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "save", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 145, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "showHostproviderForm", - "args": [ - { - "name": "e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 125, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "e", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "onCancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';\nimport { MatDialog } from '@angular/material/dialog';\nimport { BehaviorSubject } from 'rxjs';\nimport { filter, tap } from 'rxjs/operators';\nimport { EventHelper } from '@adwp-ui/widgets';\n\nimport { openClose } from '@app/core/animations';\nimport { clearEmptyField, Host, Provider } from '@app/core/types';\nimport { ActionsDirective } from '../components/actions/actions.directive';\nimport { AddService } from './add.service';\nimport { BaseFormDirective } from './base-form.directive';\nimport { DisplayMode } from './provider.component';\nimport { ICluster } from '@app/models/cluster';\n\n@Component({\n selector: 'app-add-host',\n template: `\n \n
\n \n \n ...\n {{ p.name }}\n \n \n {{ expanded ? 'clear' : 'add' }}\n \n \n Hostprovider is required. If no hostprovider is available, add it here.\n \n \n
\n\n
\n \n
\n\n \n\n
\n \n \n \n Fully qualified domain name is required \n \n
\n\n \n
\n \n \n ...\n {{ c.name }}\n \n \n
\n \n
\n
\n `,\n styles: [\n ':host {display: block; margin-top: 10px;}',\n '.inner {overflow: hidden; margin: 0 -6px;}',\n '.inner app-add-provider {padding: 10px 24px; background-color: #4e4e4e;display:block;}',\n '.row {display: flex;}',\n ],\n providers: [ActionsDirective],\n animations: [openClose],\n})\nexport class HostComponent extends BaseFormDirective implements OnInit {\n @Input() displayMode: DisplayMode = DisplayMode.default;\n @Output() event = new EventEmitter();\n\n providers$ = new BehaviorSubject>([]);\n clusters$ = new BehaviorSubject[]>([]);\n expanded = false;\n createdProviderId: number;\n\n pageCluster = 1;\n pageProvider = 1;\n limit = 10;\n\n constructor(private action: ActionsDirective, service: AddService, dialog: MatDialog) {\n super(service, dialog);\n }\n\n ngOnInit() {\n this.form = this.service.model('host').form;\n this.getProviders();\n this.getClusters();\n this.form\n .get('provider_id')\n .valueChanges.pipe(\n this.takeUntil(),\n filter((a) => a)\n )\n .subscribe((value) => this.checkAction(+value));\n }\n\n isError(name: string) {\n const fi = this.form.get(name);\n return fi.invalid && (fi.dirty || fi.touched);\n }\n\n showHostproviderForm(e: MouseEvent) {\n EventHelper.stopPropagation(e);\n this.expanded = !this.expanded;\n this.form.get('provider_id').setValue('');\n }\n\n checkAction(provider_id: number) {\n const ACTION_NAME = 'create_host';\n const provider = this.providers$.getValue().find((a) => a.id === provider_id);\n\n if (provider && provider.actions) {\n const actions = provider.actions.filter((a) => a.button === ACTION_NAME);\n if (actions && actions.length) {\n this.action.inputData = { actions };\n this.onCancel();\n this.action.onClick();\n }\n }\n }\n\n save() {\n const data = clearEmptyField(this.form.value) as Host;\n if (this.displayMode !== 0) data.cluster_id = this.service.Cluster.id;\n this.service\n .addHost(data)\n .pipe(\n this.takeUntil(),\n tap(() => this.form.controls['fqdn'].setValue(''))\n )\n .subscribe((a) => this.event.emit(`Host [ ${a.fqdn} ] has been added successfully.`));\n }\n\n createdProvider(id: number) {\n this.expanded = false;\n this.service\n .getList('provider', { limit: this.limit, page: this.pageProvider - 1 })\n .pipe(tap((_) => this.form.get('provider_id').setValue(id)))\n .subscribe((list) => this.providers$.next(list));\n }\n\n getNextPageClusters() {\n const count = this.clusters$.getValue().length;\n if (count === this.pageCluster * this.limit) {\n this.pageCluster++;\n this.getClusters();\n }\n }\n\n getNextPageProvider() {\n const count = this.providers$.getValue().length;\n if (count === this.pageProvider * this.limit) {\n this.pageProvider++;\n this.getProviders();\n }\n }\n\n getProviders() {\n this.service\n .getList('provider', { limit: this.limit, page: this.pageProvider - 1 })\n .pipe(tap((list) => this.form.get('provider_id').setValue(list.length === 1 ? list[0].id : '')))\n .subscribe((list) => this.providers$.next([...this.providers$.getValue(), ...list]));\n if (this.form.get('provider_id').value) this.expanded = false;\n }\n\n getClusters() {\n this.service\n .getList('cluster', { limit: this.limit, page: this.pageCluster - 1 })\n .subscribe((list) => this.clusters$.next([...this.clusters$.getValue(), ...list]));\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {display: block; margin-top: 10px;}\n.inner {overflow: hidden; margin: 0 -6px;}\n.inner app-add-provider {padding: 10px 24px; background-color: #4e4e4e;display:block;}\n.row {display: flex;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "action", - "type": "ActionsDirective", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "AddService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 101, - "jsdoctags": [ - { - "name": "action", - "type": "ActionsDirective", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "AddService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseFormDirective", - "implements": [ - "OnInit" - ] - }, - { - "name": "HostDetailsComponent", - "id": "component-HostDetailsComponent-59358932429f53da381ee3a5bf9c3078", - "file": "src/app/components/host/host-details/host-details.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-host-details", - "styleUrls": [ - "../../../styles/details.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/details.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityParam", - "defaultValue": "'host'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "leftMenu", - "defaultValue": "[\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.Host, 'host'),\n DetailsFactory.statusMenuItem('Status', 'status', 'host'),\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 14, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "subjectService", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityService", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 121, - 125 - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "entityReceived", - "args": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Injector } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\n\nimport { DetailsFactory } from '@app/factories/details.factory';\nimport { IHost } from '@app/models/host';\nimport { SocketState } from '@app/core/store';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ChannelService } from '@app/core/services';\nimport { HostService } from '@app/services/host.service';\nimport { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n@Component({\n selector: 'app-host-details',\n templateUrl: '../../../templates/details.html',\n styleUrls: ['../../../styles/details.scss']\n})\nexport class HostDetailsComponent extends DetailAbstractDirective {\n\n entityParam = 'host';\n\n leftMenu = [\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.Host, 'host'),\n DetailsFactory.statusMenuItem('Status', 'status', 'host'),\n ];\n\n constructor(\n socket: Store,\n protected route: ActivatedRoute,\n protected service: ClusterService,\n protected channel: ChannelService,\n protected store: Store,\n injector: Injector,\n protected subjectService: HostService,\n ) {\n super(socket, route, service, channel, store, injector);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"node_modules/@angular/material/theming\";\n\n:host {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\nmat-drawer {\n min-width: 240px;\n background-color: transparent;\n padding-left: 10px;\n}\n\n.mat-card {\n flex: 1;\n padding: 10px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n & .mat-card-header {\n min-height: 40px;\n padding: 6px 10px 0;\n\n & .mat-card-title {\n font-size: 26px;\n }\n }\n\n .mat-card-content {\n display: flex;\n flex: 1;\n overflow: auto;\n }\n}\n\n.mat-toolbar {\n height: auto;\n min-height: 50px;\n}\n\n.issue-warning {\n width: 40px;\n height: 40px;\n position: relative;\n cursor: pointer;\n\n .mat-icon {\n margin: 8px 0 0 8px;\n }\n\n div {\n width: 40px;\n height: 40px;\n position: absolute;\n background: mat-color($mat-orange, 500);\n border-radius: 20px;\n top: 0;\n opacity: 0;\n animation: ripple 2s infinite ease-in-out;\n }\n}\n\n\n@keyframes ripple {\n 0% {\n opacity: .5;\n }\n\n 100% {\n opacity: 0;\n }\n}\n", - "styleUrl": "../../../styles/details.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "subjectService", - "type": "HostService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 27, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "subjectService", - "type": "HostService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "DetailAbstractDirective", - "templateData": "\n\n \n\n\n\n\n \n \n \n \n \n \n \n {{ currentName }}\n \n \n \n \n \n \n \n \n \n \n\n" - }, - { - "name": "HostListComponent", - "id": "component-HostListComponent-583245bda4e49e35339a286a3913235b", - "file": "src/app/components/host/host-list/host-list.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-host-list", - "styleUrls": [], - "styles": [ - ":host { flex: 1; }" - ], - "template": "\n \n Create {{ type }}\n\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 109, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "eventTypes", - "defaultValue": "[ConcernEventType.Host]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 47, - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.fqdnColumn(),\n ListFactory.providerColumn(),\n {\n type: 'component',\n label: 'Cluster',\n sort: 'cluster_name',\n component: ClusterColumnComponent,\n instanceTaken: (componentRef: ComponentRef) => {\n componentRef.instance\n .onGetNextPageCluster\n .pipe(this.takeUntil())\n .subscribe((data: UniversalAdcmEventData) => {\n this.clickCell(data.event, data.action, data.row);\n });\n\n componentRef.instance\n .onGetClusters\n .pipe(this.takeUntil())\n .subscribe((data: UniversalAdcmEventData) => {\n this.clickCell(data.event, data.action, data.row);\n });\n\n componentRef.instance\n .onAddCluster\n .pipe(this.takeUntil())\n .subscribe((data: AddClusterEventData) => {\n if (data?.cluster) {\n this.hostService.addToCluster(data.row.id, data.cluster as any as number)\n .subscribe((host) => {\n if (this.data$?.value?.results) {\n this.api.getOne('cluster', host.cluster_id).subscribe((cluster: ICluster) => {\n const tableData = Object.assign({}, this.data$.value);\n const index = tableData.results.findIndex(item => item.id === host.id);\n const row = Object.assign({}, tableData.results[index]);\n\n row.cluster_id = cluster.id;\n row.cluster_name = cluster.name;\n\n tableData.results.splice(index, 1, row);\n this.reload(tableData as IListResult);\n });\n }\n });\n }\n });\n }\n },\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.configColumn(this),\n ListFactory.deleteColumn(this),\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 49 - }, - { - "name": "route", - "deprecated": false, - "deprecationMessage": "", - "type": "ActivatedRoute", - "optional": false, - "description": "", - "line": 107, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "router", - "deprecated": false, - "deprecationMessage": "", - "type": "Router", - "optional": false, - "description": "", - "line": 108, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "type", - "defaultValue": "'host'", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 46 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ComponentRef } from '@angular/core';\nimport { IColumns, IListResult } from '@adwp-ui/widgets';\nimport { Store } from '@ngrx/store';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { MatDialog } from '@angular/material/dialog';\n\nimport { TypeName } from '@app/core/types';\nimport { IHost } from '@app/models/host';\nimport { ListFactory } from '@app/factories/list.factory';\nimport { AddClusterEventData, ClusterColumnComponent } from '@app/components/columns/cluster-column/cluster-column.component';\nimport { UniversalAdcmEventData } from '@app/models/universal-adcm-event-data';\nimport { ConcernListDirective } from '@app/abstract-directives/concern-list.directive';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\nimport { ICluster } from '@app/models/cluster';\nimport { ListService } from '@app/shared/components/list/list.service';\nimport { SocketState } from '@app/core/store';\nimport { ConcernService } from '@app/services/concern.service';\nimport { HostService } from '@app/services/host.service';\nimport { ApiService } from '@app/core/api';\n\n@Component({\n selector: 'app-host-list',\n template: `\n \n \n Create {{ type }}\n \n\n \n `,\n styles: [':host { flex: 1; }'],\n})\nexport class HostListComponent extends ConcernListDirective {\n\n type: TypeName = 'host';\n eventTypes = [ConcernEventType.Host];\n\n listColumns = [\n ListFactory.fqdnColumn(),\n ListFactory.providerColumn(),\n {\n type: 'component',\n label: 'Cluster',\n sort: 'cluster_name',\n component: ClusterColumnComponent,\n instanceTaken: (componentRef: ComponentRef) => {\n componentRef.instance\n .onGetNextPageCluster\n .pipe(this.takeUntil())\n .subscribe((data: UniversalAdcmEventData) => {\n this.clickCell(data.event, data.action, data.row);\n });\n\n componentRef.instance\n .onGetClusters\n .pipe(this.takeUntil())\n .subscribe((data: UniversalAdcmEventData) => {\n this.clickCell(data.event, data.action, data.row);\n });\n\n componentRef.instance\n .onAddCluster\n .pipe(this.takeUntil())\n .subscribe((data: AddClusterEventData) => {\n if (data?.cluster) {\n this.hostService.addToCluster(data.row.id, data.cluster as any as number)\n .subscribe((host) => {\n if (this.data$?.value?.results) {\n this.api.getOne('cluster', host.cluster_id).subscribe((cluster: ICluster) => {\n const tableData = Object.assign({}, this.data$.value);\n const index = tableData.results.findIndex(item => item.id === host.id);\n const row = Object.assign({}, tableData.results[index]);\n\n row.cluster_id = cluster.id;\n row.cluster_name = cluster.name;\n\n tableData.results.splice(index, 1, row);\n this.reload(tableData as IListResult);\n });\n }\n });\n }\n });\n }\n },\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.configColumn(this),\n ListFactory.deleteColumn(this),\n ] as IColumns;\n\n constructor(\n protected service: ListService,\n protected store: Store,\n public route: ActivatedRoute,\n public router: Router,\n public dialog: MatDialog,\n protected concernService: ConcernService,\n protected hostService: HostService,\n protected api: ApiService,\n ) {\n super(service, store, route, router, dialog, concernService);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host { flex: 1; }\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "concernService", - "type": "ConcernService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hostService", - "type": "HostService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 102, - "jsdoctags": [ - { - "name": "service", - "type": "ListService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "concernService", - "type": "ConcernService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "hostService", - "type": "HostService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "ConcernListDirective" - }, - { - "name": "HostproviderComponent", - "id": "component-HostproviderComponent-ab38e837e7006e8006c8d79fc1bdc8f7", - "file": "src/app/components/hostprovider/hostprovider.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-hostprovider", - "styleUrls": [], - "styles": [ - ":host { flex: 1; }" - ], - "template": "\n \n Create {{ type }}\n\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "eventTypes", - "defaultValue": "[ConcernEventType.HostProvider]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 46, - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.nameColumn(),\n ListFactory.bundleColumn(),\n ListFactory.stateColumn(),\n ListFactory.actionsButton(this),\n ListFactory.updateColumn(),\n ListFactory.configColumn(this),\n ListFactory.deleteColumn(this),\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 48 - }, - { - "name": "type", - "defaultValue": "'provider'", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 24, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "route", - "deprecated": false, - "deprecationMessage": "", - "type": "ActivatedRoute", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "router", - "deprecated": false, - "deprecationMessage": "", - "type": "Router", - "optional": false, - "description": "", - "line": 23, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { IColumns } from '@adwp-ui/widgets';\n\nimport { TypeName } from '@app/core/types';\nimport { ListFactory } from '@app/factories/list.factory';\nimport { ConcernListDirective } from '@app/abstract-directives/concern-list.directive';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n@Component({\n selector: 'app-hostprovider',\n template: `\n \n \n Create {{ type }}\n \n\n \n `,\n styles: [':host { flex: 1; }'],\n})\nexport class HostproviderComponent extends ConcernListDirective {\n\n type: TypeName = 'provider';\n eventTypes = [ConcernEventType.HostProvider];\n\n listColumns = [\n ListFactory.nameColumn(),\n ListFactory.bundleColumn(),\n ListFactory.stateColumn(),\n ListFactory.actionsButton(this),\n ListFactory.updateColumn(),\n ListFactory.configColumn(this),\n ListFactory.deleteColumn(this),\n ] as IColumns;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host { flex: 1; }\n", - "extends": "ConcernListDirective" - }, - { - "name": "HostStatusComponent", - "id": "component-HostStatusComponent-bbffdb4f4192d1068186cb343654107c", - "file": "src/app/components/host/host-status/host-status.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-host-status", - "styleUrls": [ - "../../../styles/status-tree.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/status-tree.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityService", - "deprecated": false, - "deprecationMessage": "", - "type": "HostService", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "entityId", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 24, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "folding", - "deprecated": false, - "deprecationMessage": "", - "type": "Folding", - "optional": false, - "description": "", - "line": 27, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "loading", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "statusTree", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 25, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "tree", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 19, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'tree', {static: false}" - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "eventReceived", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "getEntityIdFromParams", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 51, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "expandCollapseAll", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 55, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "pipeData", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 53, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "prepareListeners", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "prepareStatusTree", - "args": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "StatusTreeType", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { fromJS, updateIn } from 'immutable';\n\nimport { EventMessage, SocketState } from '@app/core/store';\nimport { HostStatusTree } from '@app/models/status-tree';\nimport { HostService } from '@app/services/host.service';\nimport { StatusAbstractDirective } from '@app/abstract-directives/status.abstract.directive';\nimport { IHost } from '@app/models/host';\n\n@Component({\n selector: 'app-host-status',\n templateUrl: '../../../templates/status-tree.html',\n styleUrls: ['../../../styles/status-tree.scss']\n})\nexport class HostStatusComponent extends StatusAbstractDirective {\n\n constructor(\n protected route: ActivatedRoute,\n protected store: Store,\n public entityService: HostService,\n ) {\n super(route, store, entityService);\n }\n\n eventReceived(event: EventMessage) {\n let output;\n switch (event.object.type) {\n case 'host':\n output = fromJS(this.statusTree.value);\n if (output.get('id') === event.object.id) {\n output = output.set('status', +event.object.details.value);\n }\n this.statusTree.next(output.toJS() as any as HostStatusTree);\n break;\n case 'hostcomponent':\n output = fromJS(this.statusTree.value);\n const hostId = output.get('id');\n output = updateIn(output, ['hc'], (components: any[]) => components.map((component: any) => {\n if (component.get('id') === +event.object.details.id && hostId === event.object.id) {\n return component.set('status', +event.object.details.value);\n }\n return component;\n }));\n this.statusTree.next(output.toJS() as any as HostStatusTree);\n break;\n }\n }\n\n getEntityIdFromParams(): number {\n return +this.route.parent.snapshot.params.host;\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n flex: 1;\n}\n\n.controls {\n position: fixed;\n top: 130px;\n right: 10px;\n\n .notify {\n opacity: 0;\n\n &>span {\n line-height: 24px;\n vertical-align: text-bottom;\n }\n }\n}\n", - "styleUrl": "../../../styles/status-tree.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "entityService", - "type": "HostService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 17, - "jsdoctags": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "entityService", - "type": "HostService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "StatusAbstractDirective", - "templateData": "\n

Loading...

\n
\n\n\n\n
\n \n
\n\n \n\n
\n" - }, - { - "name": "ImportComponent", - "id": "component-ImportComponent-3c17dd4f9160f4d8db43f357e0ec37f1", - "file": "src/app/shared/components/import/import.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-import", - "styleUrls": [ - "./import.component.scss" - ], - "styles": [], - "template": "

\n \n

\n
\n
\n

\n {{ item.name }}\n This import is required!\n

\n \n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "asIs", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 98 - }, - { - "name": "data$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 97 - }, - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 96 - } - ], - "methodsClass": [ - { - "name": "getKey", - "args": [ - { - "name": "id", - "type": "IComposite", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 102, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "IComposite", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "go", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 128, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hasError", - "args": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 106, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "id", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 110, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, OnInit } from '@angular/core';\nimport { AbstractControl, FormControl, FormGroup, ValidatorFn } from '@angular/forms';\nimport { MatCheckboxChange } from '@angular/material/checkbox';\nimport { Observable } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\nimport { ChannelService } from '@app/core/services';\nimport { keyChannelStrim } from '@app/core/services';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { IExport, IImport } from '@app/core/types';\n\ninterface IComposite {\n [key: string]: number;\n}\n\nconst trueOnly = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (control.value ? null : { trueOnly: !control.value });\n\nconst requiredObject = (): ValidatorFn => (control: AbstractControl): { [key: string]: boolean } | null =>\n Object.keys(control.value).some((key) => control.value[key]) ? null : { requiered: true };\n\n@Component({\n selector: 'app-exports',\n template: `\n \n \n
\n {{ item.obj_name }}\n
{{ item.bundle_name }} {{ item.bundle_version }}
\n
\n
\n
\n `,\n styles: ['.component {padding: 6px 8px; margin-bottom: 18px; font-size: 18px;}', '.component div {font-size: 12px;margin-left: 24px; margin-top: 4px;}'],\n})\nexport class ExportComponent {\n @Input() form: FormGroup;\n @Input() import: IImport;\n\n getKey(id: IComposite) {\n return JSON.stringify(id);\n }\n\n change(e: MatCheckboxChange, item: IExport) {\n if (!this.import.multibind) {\n const group = this.form.controls[this.getKey({ import_id: this.import.id })] as FormGroup;\n\n if (e.checked)\n Object.keys(group.controls)\n .map((key) => {\n group.controls[key].clearValidators();\n return key;\n })\n .filter((key) => key !== this.getKey(item.id))\n .map((key) => group.controls[key].setValue(false));\n else if (this.import.required) {\n Object.keys(group.controls).map((key) => {\n const c = group.controls[key];\n c.setValidators(trueOnly());\n c.updateValueAndValidity();\n });\n }\n }\n }\n}\n\n@Component({\n selector: 'app-import',\n template: `\n

\n \n

\n
\n
\n

\n {{ item.name }}\n This import is required!\n

\n \n
\n
\n `,\n styleUrls: ['./import.component.scss'],\n})\nexport class ImportComponent implements OnInit {\n form = new FormGroup({});\n data$: Observable;\n asIs = false;\n\n constructor(private current: ClusterService, private channel: ChannelService) {}\n\n getKey(id: IComposite) {\n return JSON.stringify(id);\n }\n\n hasError(id: number) {\n return this.form.get(this.getKey({ import_id: id })).invalid;\n }\n\n ngOnInit() {\n this.data$ = this.current.getImportData().pipe(\n tap((a) => (this.asIs = !!a.length)),\n tap((a) =>\n a.map((i: IImport) => {\n const validFlag = i.required && !i.multibind && i.exports.every((e) => !e.binded);\n const exportGroup = i.exports.reduce((p, c) => {\n const fc = {};\n fc[`${this.getKey(c.id)}`] = new FormControl(c.binded, validFlag ? trueOnly() : null);\n return { ...p, ...fc };\n }, {});\n const import_id = this.getKey({ import_id: i.id });\n this.form.addControl(import_id, new FormGroup(exportGroup, i.required ? requiredObject() : null));\n })\n )\n );\n }\n\n go() {\n if (!this.form.invalid) {\n let bind = [];\n Object.keys(this.form.controls)\n .filter((a) => Object.keys(this.form.controls[a].value).length)\n .map((key) => {\n const obj = JSON.parse(key);\n const value = this.form.controls[key].value;\n const items = Object.keys(value)\n .filter((a) => value[a] === true)\n .map((a) => ({ ...obj, export_id: JSON.parse(a) }));\n bind = [...bind, ...items];\n });\n this.current.bindImport({ bind }).subscribe((_) => this.channel.next(keyChannelStrim.notifying, 'Successfully saved'));\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n padding: 0 20px;\n}\n\n.controls {\n position: fixed;\n top: 110px;\n right: 80px;\n}\n\n.group {\n margin: 0.2em;\n}\n\n.items {\n display: flex;\n flex-wrap: wrap;\n}\n\nmat-error {\n display: block;\n margin-top: 6px;\n font-weight: normal;\n}", - "styleUrl": "./import.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "current", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 98, - "jsdoctags": [ - { - "name": "current", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "InputComponent", - "id": "component-InputComponent-b0b190ca214ce77eb027e42677f4fa72", - "file": "src/app/shared/form-elements/input.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-input", - "styleUrls": [], - "styles": [ - ".row {display:flex;}" - ], - "template": "
\n \n \n \n Ensure this field has no more than 30 characters.\n \n {{ label }} is required.\n {{ label }} is not correct.\n \n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "controlName", - "deprecated": false, - "deprecationMessage": "", - "line": 35, - "type": "string" - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 34, - "type": "FormGroup" - }, - { - "name": "isRequired", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 37, - "type": "boolean" - }, - { - "name": "label", - "deprecated": false, - "deprecationMessage": "", - "line": 36, - "type": "string" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "error", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 44, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "error", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "isError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { BaseDirective } from '../directives';\n\n@Component({\n selector: 'app-input',\n template: `\n
\n \n \n \n Ensure this field has no more than 30 characters.\n \n {{ label }} is required.\n {{ label }} is not correct.\n \n \n
\n `,\n styles: ['.row {display:flex;}'],\n})\nexport class InputComponent extends BaseDirective {\n @Input() form: FormGroup;\n @Input() controlName: string;\n @Input() label: string;\n @Input() isRequired = false;\n\n isError(name: string) {\n const f = this.form.get(name);\n return f.invalid && (f.dirty || f.touched);\n }\n\n hasError(name: string, error: string) {\n return this.form.controls[name].hasError(error);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ".row {display:flex;}\n", - "extends": "BaseDirective" - }, - { - "name": "IntroComponent", - "id": "component-IntroComponent-dc9aca833ab95acdc626bee47e770186", - "file": "src/app/admin/intro.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-intro", - "styleUrls": [], - "styles": [ - ":host {padding: 0 10px;}", - ".admin-warn {border:solid 1px #ff9800;margin-right: 20px;}", - ".admin-warn ul li {padding: 8px 0;}" - ], - "template": "

\n This is Arenadata Cluster Manager (ADCM) - the home of all your data. It connects together different data applications, providing a fast, reliable and enterprise-ready way to\n manage your data landscape. Please read this short notice to start use ADCM in its most efficient way.\n

\n
\n
    \n
  • \n We have to know ADCM's Url [ {{ adcm_url }} ] to send information from host. We try to gues that information from url you enter in\n browser.
    But if your network has more complicated structure and we gues wrong, please fix that here.
    \n
  • \n
\n
\n

Bundle

\n

\n Bundle is a set of functionality that you can add to your ADCM. Every data application (Database, Hadoop cluster, etc.) is created using a bundle. For example, to start a\n Hadoop cluster version 3.0.0, you will need a Hadoop 3.0.0 bundle. Other bundles may contain virtual machine access method (Amazon, Google, etc.), widgets, etc. Think of it\n like a plugin, or a mobile phone application.\n

\n

Cluster

\n

\n This is the main functionality. Cluster is a set of hosts, running one distributed application. Cluster is deployed from bundle. Of course, you can have multiple clusters set\n up from the same bundle.\n

\n

Service

\n

\n Service is a part of a cluster. It contain part of the cluster functionality. Service can run across all hosts in the cluster, or only across some of them.\n

\n

Component

\n

\n Component is a part of a service that is running on one host.\n

\n

Hostprovider

\n

\n Hostprovider is a set of access credentials for ADCM to create new hosts or access existing, For example, when you want to create a VM in a public cloud, you will need to add\n username, access key and other access credentials to ADCM. Do it by creating a new Hostprovider and editing its config.\n

\n

Host

\n

\n This is a machine that your data app is running on. A host may be a virtual machine, a physical server, or something else.
\n A host can be added to only one cluster - you cannot share a host between multiple clusters.\n

\n

 

\nShortly:\n
    \n
  • Bundle is a packet with functionality (ex. Hadoop)
  • \n
  • Cluster is a logical set of functionality. Cluster is created from bundle (ex Hadoop cluster)
  • \n
  • Service is a logical part of cluster (ex. HDFS)
  • \n
  • Component is a part of service, that is located on some host (ex. DataNode)
  • \n
\nIf you need a more deep dive into ADCM's functionality,\nstart from docs.\n
\nNow you are ready to start exploring ADCM by yourself - enjoy it!\n

 

\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "adcm_url", - "defaultValue": "`${location.protocol}//${location.host}`", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 77 - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\n\n@Component({\n selector: 'app-intro',\n template: `\n

\n This is Arenadata Cluster Manager (ADCM) - the home of all your data. It connects together different data applications, providing a fast, reliable and enterprise-ready way to\n manage your data landscape. Please read this short notice to start use ADCM in its most efficient way.\n

\n
\n
    \n
  • \n We have to know ADCM's Url [ {{ adcm_url }} ] to send information from host. We try to gues that information from url you enter in\n browser.
    But if your network has more complicated structure and we gues wrong, please fix that here.
    \n
  • \n
\n
\n

Bundle

\n

\n Bundle is a set of functionality that you can add to your ADCM. Every data application (Database, Hadoop cluster, etc.) is created using a bundle. For example, to start a\n Hadoop cluster version 3.0.0, you will need a Hadoop 3.0.0 bundle. Other bundles may contain virtual machine access method (Amazon, Google, etc.), widgets, etc. Think of it\n like a plugin, or a mobile phone application.\n

\n

Cluster

\n

\n This is the main functionality. Cluster is a set of hosts, running one distributed application. Cluster is deployed from bundle. Of course, you can have multiple clusters set\n up from the same bundle.\n

\n

Service

\n

\n Service is a part of a cluster. It contain part of the cluster functionality. Service can run across all hosts in the cluster, or only across some of them.\n

\n

Component

\n

\n Component is a part of a service that is running on one host.\n

\n

Hostprovider

\n

\n Hostprovider is a set of access credentials for ADCM to create new hosts or access existing, For example, when you want to create a VM in a public cloud, you will need to add\n username, access key and other access credentials to ADCM. Do it by creating a new Hostprovider and editing its config.\n

\n

Host

\n

\n This is a machine that your data app is running on. A host may be a virtual machine, a physical server, or something else.
\n A host can be added to only one cluster - you cannot share a host between multiple clusters.\n

\n

 

\n Shortly:\n
    \n
  • Bundle is a packet with functionality (ex. Hadoop)
  • \n
  • Cluster is a logical set of functionality. Cluster is created from bundle (ex Hadoop cluster)
  • \n
  • Service is a logical part of cluster (ex. HDFS)
  • \n
  • Component is a part of service, that is located on some host (ex. DataNode)
  • \n
\n If you need a more deep dive into ADCM's functionality,\n start from docs.\n
\n Now you are ready to start exploring ADCM by yourself - enjoy it!\n

 

\n `,\n styles: [':host {padding: 0 10px;}', '.admin-warn {border:solid 1px #ff9800;margin-right: 20px;}', '.admin-warn ul li {padding: 8px 0;}'],\n})\nexport class IntroComponent {\n adcm_url = `${location.protocol}//${location.host}`;\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {padding: 0 10px;}\n.admin-warn {border:solid 1px #ff9800;margin-right: 20px;}\n.admin-warn ul li {padding: 8px 0;}\n" - }, - { - "name": "IssueInfoComponent", - "id": "component-IssueInfoComponent-aa24c13e7e5ce20ee9dbfb0bcd56e06c", - "file": "src/app/shared/components/issue-info.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-issue-info", - "styleUrls": [], - "styles": [ - "a, .item-step { display: block; margin: 6px 0 8px 12px; white-space: nowrap;}" - ], - "template": "
{{ intro }}
\n
\n \n
\n {{ name }}:\n \n {{ o.name }} \n \n
\n
\n \n {{ IssueNames[name] || name }}\n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "line": 49, - "type": "IIssueInfo" - }, - { - "name": "intro", - "defaultValue": "'Issues in:'", - "deprecated": false, - "deprecationMessage": "", - "line": 47, - "type": "string" - }, - { - "name": "parent", - "deprecated": false, - "deprecationMessage": "", - "line": 50, - "type": "IIssueInfo" - }, - { - "name": "path", - "deprecated": false, - "deprecationMessage": "", - "line": 48, - "type": "string" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "IssueNames", - "defaultValue": "{\n config: 'Configuration',\n host_component: 'Host - Components',\n required_service: 'Required a service',\n required_import: 'Required a import',\n }", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "optional": false, - "description": "", - "line": 57 - }, - { - "name": "IssuePatch", - "defaultValue": "{\n required_service: 'service',\n required_import: 'import',\n }", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "optional": false, - "description": "", - "line": 52 - } - ], - "methodsClass": [ - { - "name": "isArray", - "args": [ - { - "name": "issue", - "type": " | ", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 77, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "issue", - "type": " | ", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 66, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, OnInit } from '@angular/core';\n\nimport { ComponentData } from './tooltip/tooltip.service';\nimport { IIssues } from '@app/models/issue';\n\nexport interface IIssueInfo {\n id: number;\n issue: IIssues;\n cluster_id?: number;\n name?: string;\n path?: string;\n}\n\n@Component({\n selector: 'app-issue-info',\n template: `\n
{{ intro }}
\n
\n \n
\n {{ name }}:\n \n {{ o.name }} \n \n
\n
\n \n {{ IssueNames[name] || name }}\n \n
\n `,\n styles: ['a, .item-step { display: block; margin: 6px 0 8px 12px; white-space: nowrap;}'],\n})\nexport class IssueInfoComponent implements OnInit {\n\n @Input() intro = 'Issues in:';\n @Input() path: string;\n @Input() current: IIssueInfo;\n @Input() parent: IIssueInfo;\n\n IssuePatch = {\n required_service: 'service',\n required_import: 'import',\n };\n\n IssueNames = {\n config: 'Configuration',\n host_component: 'Host - Components',\n required_service: 'Required a service',\n required_import: 'Required a import',\n };\n\n constructor(private componentData: ComponentData) {}\n\n ngOnInit(): void {\n this.current = this.current || this.componentData.current;\n this.path = this.path || this.componentData.path;\n this.current.path = this.path;\n this.componentData.emitter.emit('Done');\n }\n\n get Path() {\n return this.parent && this.parent.cluster_id !== this.current.id ? `${this.parent.path}/${this.parent.id}/${this.path}` : this.path;\n }\n\n isArray(issue: [] | false): boolean {\n return Array.isArray(issue);\n }\n\n get namesIssue() {\n return Object.keys(this.current.issue || {});\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "a, .item-step { display: block; margin: 6px 0 8px 12px; white-space: nowrap;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "componentData", - "type": "ComponentData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 62, - "jsdoctags": [ - { - "name": "componentData", - "type": "ComponentData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ], - "accessors": { - "Path": { - "name": "Path", - "getSignature": { - "name": "Path", - "type": "", - "returnType": "", - "line": 73 - } - }, - "namesIssue": { - "name": "namesIssue", - "getSignature": { - "name": "namesIssue", - "type": "", - "returnType": "", - "line": 81 - } - } - } - }, - { - "name": "ItemComponent", - "id": "component-ItemComponent-4aa42cebbb69487312b969b0c701f830", - "file": "src/app/shared/configuration/scheme/item.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-item-scheme", - "styleUrls": [], - "styles": [ - ":host {flex: 1}", - "mat-form-field {margin: 6px 0 0; width: 100%}", - ".chbox-field {margin:6px 0;}" - ], - "template": "\n \n \n \n \n \n \n\n \n
\n {{ item.name }}\n \n Field [{{ item.name }}] is required!\n \n
\n \n {{ item.name }}\n \n \n Field [{{ item.name }}] is required!\n Field [{{ item.name }}] is invalid!\n Field [{{ item.name }}] value cannot be less than {{ validator.min }}!\n Field [{{ item.name }}] value cannot be greater than {{ validator.max }}!\n \n \n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "index", - "deprecated": false, - "deprecationMessage": "", - "line": 56, - "type": "number" - }, - { - "name": "isReadOnly", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 57, - "type": "boolean" - }, - { - "name": "item", - "deprecated": false, - "deprecationMessage": "", - "line": 55, - "type": "IControl" - } - ], - "outputsClass": [ - { - "name": "remove", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 58, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "controlType", - "deprecated": false, - "deprecationMessage": "", - "type": "controlType", - "optional": false, - "description": "", - "line": 60 - }, - { - "name": "validator", - "deprecated": false, - "deprecationMessage": "", - "type": "IValidator", - "optional": false, - "description": "", - "line": 61 - } - ], - "methodsClass": [ - { - "name": "emmit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hasError", - "args": [ - { - "name": "title", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "title", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 63, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';\nimport { AbstractControl } from '@angular/forms';\n\nimport { controlType, IValidator } from '../types';\nimport { IYField } from '../yspec/yspec.service';\nimport { IControl } from './scheme.service';\n\n@Component({\n selector: 'app-item-scheme',\n template: `\n \n \n \n \n \n \n \n\n \n
\n {{ item.name }}\n \n Field [{{ item.name }}] is required!\n \n
\n \n {{ item.name }}\n \n \n Field [{{ item.name }}] is required!\n Field [{{ item.name }}] is invalid!\n Field [{{ item.name }}] value cannot be less than {{ validator.min }}!\n Field [{{ item.name }}] value cannot be greater than {{ validator.max }}!\n \n \n
\n
\n `,\n styles: [':host {flex: 1}', 'mat-form-field {margin: 6px 0 0; width: 100%}', '.chbox-field {margin:6px 0;}'],\n})\nexport class ItemComponent implements OnInit {\n @Input() item: IControl;\n @Input() index: number;\n @Input() isReadOnly = false;\n @Output() remove = new EventEmitter();\n\n controlType: controlType;\n validator: IValidator;\n\n ngOnInit() {\n const rules = this.item.rules as IYField;\n this.controlType = rules.controlType;\n this.validator = rules.validator;\n if (this.controlType === 'boolean' && this.isReadOnly) this.control.disable();\n this.item.form.markAllAsTouched();\n }\n\n emmit() {\n this.remove.emit(this.item.name);\n }\n\n get control() {\n return this.item.form.controls[this.item.name] as AbstractControl;\n }\n\n get isValid() {\n const f = this.control;\n return f.valid && (f.dirty || f.touched);\n }\n\n hasError(title: string) {\n return this.control.hasError(title);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {flex: 1}\nmat-form-field {margin: 6px 0 0; width: 100%}\n.chbox-field {margin:6px 0;}\n", - "implements": [ - "OnInit" - ], - "accessors": { - "control": { - "name": "control", - "getSignature": { - "name": "control", - "type": "", - "returnType": "", - "line": 75 - } - }, - "isValid": { - "name": "isValid", - "getSignature": { - "name": "isValid", - "type": "", - "returnType": "", - "line": 79 - } - } - } - }, - { - "name": "JobDetailsComponent", - "id": "component-JobDetailsComponent-f3b3c247e5cd485ba33a816a9f562855", - "file": "src/app/components/job/job-details/job-details.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-job-details", - "styleUrls": [ - "../../../styles/details.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/details.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityParam", - "defaultValue": "'job'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 22, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "jobEvents$", - "deprecated": false, - "deprecationMessage": "", - "type": "Subscription", - "optional": false, - "description": "", - "line": 26 - }, - { - "name": "leftMenu", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 24, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 14, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "subjectService", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityService", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 121, - 125 - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "entityReceived", - "args": [ - { - "name": "entity", - "type": "Job", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 51, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "Job", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "prepareMenuItems", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 40, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Injector } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { filter, switchMap } from 'rxjs/operators';\nimport { Subscription } from 'rxjs';\n\nimport { Job } from '@app/core/types';\nimport { DetailsFactory } from '@app/factories/details.factory';\nimport { SocketState } from '@app/core/store';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ChannelService } from '@app/core/services';\nimport { JobService } from '@app/services/job.service';\nimport { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive';\n\n@Component({\n selector: 'app-job-details',\n templateUrl: '../../../templates/details.html',\n styleUrls: ['../../../styles/details.scss']\n})\nexport class JobDetailsComponent extends DetailAbstractDirective {\n\n entityParam = 'job';\n\n leftMenu = [];\n\n jobEvents$: Subscription;\n\n constructor(\n socket: Store,\n protected route: ActivatedRoute,\n protected service: ClusterService,\n protected channel: ChannelService,\n protected store: Store,\n injector: Injector,\n protected subjectService: JobService,\n ) {\n super(socket, route, service, channel, store, injector);\n }\n\n prepareMenuItems() {\n const itemsOfFiles = this.entity.log_files.map(\n (file) => DetailsFactory.logMenuItem(`${file.name} [ ${file.type} ]`, file.id.toString(), file.id)\n );\n\n this.leftMenu = [\n DetailsFactory.labelMenuItem('Main', 'main'),\n ...itemsOfFiles,\n ];\n }\n\n entityReceived(entity: Job) {\n super.entityReceived(entity);\n\n this.prepareMenuItems();\n\n if (this.jobEvents$) {\n this.jobEvents$.unsubscribe();\n }\n\n this.jobEvents$ = this.subjectService.events({\n events: ['change_job_status', 'add_job_log'],\n }).pipe(\n this.takeUntil(),\n filter(event => event?.object?.id === this.entity.id),\n switchMap(() => this.subjectService.get(this.entity.id)),\n ).subscribe((resp) => {\n this.entity = resp;\n this.prepareMenuItems();\n });\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"node_modules/@angular/material/theming\";\n\n:host {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\nmat-drawer {\n min-width: 240px;\n background-color: transparent;\n padding-left: 10px;\n}\n\n.mat-card {\n flex: 1;\n padding: 10px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n & .mat-card-header {\n min-height: 40px;\n padding: 6px 10px 0;\n\n & .mat-card-title {\n font-size: 26px;\n }\n }\n\n .mat-card-content {\n display: flex;\n flex: 1;\n overflow: auto;\n }\n}\n\n.mat-toolbar {\n height: auto;\n min-height: 50px;\n}\n\n.issue-warning {\n width: 40px;\n height: 40px;\n position: relative;\n cursor: pointer;\n\n .mat-icon {\n margin: 8px 0 0 8px;\n }\n\n div {\n width: 40px;\n height: 40px;\n position: absolute;\n background: mat-color($mat-orange, 500);\n border-radius: 20px;\n top: 0;\n opacity: 0;\n animation: ripple 2s infinite ease-in-out;\n }\n}\n\n\n@keyframes ripple {\n 0% {\n opacity: .5;\n }\n\n 100% {\n opacity: 0;\n }\n}\n", - "styleUrl": "../../../styles/details.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "subjectService", - "type": "JobService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 26, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "subjectService", - "type": "JobService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "DetailAbstractDirective", - "templateData": "\n\n \n\n\n\n\n \n \n \n \n \n \n \n {{ currentName }}\n \n \n \n \n \n \n \n \n \n \n\n" - }, - { - "name": "JobInfoComponent", - "id": "component-JobInfoComponent-89339c16573c5363a5f735f94b56e019", - "file": "src/app/entry/job/job-info.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-job-info", - "styleUrls": [], - "styles": [ - "\n :host {\n position: fixed;\n right: 40px;\n top: 120px;\n }\n .time-info,\n .time-info div {\n display: flex;\n align-items: center;\n }\n .time-info div mat-icon {\n margin-right: 6px;\n }\n .time-info div span {\n margin-right: 30px;\n }\n .start_flag {\n transform: rotate(30deg);\n font-size: 20px;\n margin-top: 8px;\n }\n .finish_flag {\n transform: rotate(150deg);\n font-size: 20px;\n }\n " - ], - "template": "
\n
\n outlined_flag\n {{ timeInfo?.start }}\n
\n
\n autorenew\n {{ Icon(status) }}\n {{ timeInfo?.time }}\n
\n
\n outlined_flag\n {{ timeInfo?.end }}\n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "line": 67, - "type": "JobStatus" - }, - { - "name": "timeInfo", - "deprecated": false, - "deprecationMessage": "", - "line": 66, - "type": "ITimeInfo" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "Icon", - "defaultValue": "() => {...}", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 68 - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { JobStatus } from '@app/core/types';\n\nimport { ITimeInfo } from './log/log.component';\n\n@Component({\n selector: 'app-job-info',\n styles: [\n `\n :host {\n position: fixed;\n right: 40px;\n top: 120px;\n }\n .time-info,\n .time-info div {\n display: flex;\n align-items: center;\n }\n .time-info div mat-icon {\n margin-right: 6px;\n }\n .time-info div span {\n margin-right: 30px;\n }\n .start_flag {\n transform: rotate(30deg);\n font-size: 20px;\n margin-top: 8px;\n }\n .finish_flag {\n transform: rotate(150deg);\n font-size: 20px;\n }\n `,\n ],\n template: `\n
\n
\n outlined_flag\n {{ timeInfo?.start }}\n
\n
\n autorenew\n {{ Icon(status) }}\n {{ timeInfo?.time }}\n
\n
\n outlined_flag\n {{ timeInfo?.end }}\n
\n
\n `,\n})\nexport class JobInfoComponent {\n @Input() timeInfo: ITimeInfo;\n @Input() status: JobStatus;\n Icon = (status: string): string => (status === 'aborted' ? 'block' : 'done_all');\n get isRun(): boolean {\n return this.status === 'running';\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n :host {\n position: fixed;\n right: 40px;\n top: 120px;\n }\n .time-info,\n .time-info div {\n display: flex;\n align-items: center;\n }\n .time-info div mat-icon {\n margin-right: 6px;\n }\n .time-info div span {\n margin-right: 30px;\n }\n .start_flag {\n transform: rotate(30deg);\n font-size: 20px;\n margin-top: 8px;\n }\n .finish_flag {\n transform: rotate(150deg);\n font-size: 20px;\n }\n \n", - "accessors": { - "isRun": { - "name": "isRun", - "getSignature": { - "name": "isRun", - "type": "boolean", - "returnType": "boolean", - "line": 69 - } - } - } - }, - { - "name": "JobNameComponent", - "id": "component-JobNameComponent-4808605e6edc228fc92b2e59ecc57bf0", - "file": "src/app/components/columns/job-name/job-name.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-job-name", - "styleUrls": [ - "./job-name.component.scss" - ], - "styles": [], - "template": "
\n \n {{ row.display_name || row.id }}\n \n \n \n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "linkColumn", - "defaultValue": "{\n label: '',\n type: 'link',\n value: (row) => row.display_name || row.id,\n url: (row) => `/job/${row.id}`,\n }", - "deprecated": false, - "deprecationMessage": "", - "type": "ILinkColumn", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "type": "Job", - "optional": false, - "description": "", - "line": 25 - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { AdwpCellComponent, ILinkColumn } from '@adwp-ui/widgets';\n\nimport { Job } from '@app/core/types';\n\n@Component({\n selector: 'app-job-name',\n template: `\n
\n \n {{ row.display_name || row.id }}\n \n \n \n \n
\n `,\n styleUrls: ['./job-name.component.scss']\n})\nexport class JobNameComponent implements AdwpCellComponent {\n\n row: Job;\n\n linkColumn: ILinkColumn = {\n label: '',\n type: 'link',\n value: (row) => row.display_name || row.id,\n url: (row) => `/job/${row.id}`,\n };\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".job-name-container {\n padding-left: 30px;\n}\n\n.regular-name {\n padding-left: 4px;\n}\n", - "styleUrl": "./job-name.component.scss" - } - ], - "stylesData": "", - "implements": [ - "AdwpCellComponent" - ] - }, - { - "name": "JobsComponent", - "id": "component-JobsComponent-54149aff5c98cbf92116758df42f27bf", - "file": "src/app/components/job/jobs/jobs.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-jobs", - "styleUrls": [ - "./jobs.component.scss" - ], - "styles": [], - "template": "
\n 1\"\n [columns]=\"columns\"\n [dataSource]=\"data\"\n headerRowClassName=\"hidden\"\n >\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "expandedTask", - "deprecated": false, - "deprecationMessage": "", - "line": 77, - "type": "BehaviorSubject" - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "line": 69, - "type": "" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "columns", - "defaultValue": "[\n {\n type: 'component',\n label: '',\n component: JobNameComponent,\n },\n {\n label: '',\n value: (row) => {\n return row.status !== 'created' ? DateHelper.short(row.start_date) : '';\n },\n className: 'action_date',\n headerClassName: 'action_date',\n },\n {\n label: '',\n value: (row) => row.status === 'success' || row.status === 'failed' ? DateHelper.short(row.finish_date) : '',\n className: 'action_date',\n headerClassName: 'action_date',\n },\n {\n label: '',\n type: 'component',\n component: JobStatusColumnComponent,\n className: 'table-end center status',\n headerClassName: 'table-end center status',\n }\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "IColumns", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "ownData", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 63, - "modifierKind": [ - 120 - ] - }, - { - "name": "ownRow", - "deprecated": false, - "deprecationMessage": "", - "type": "Task", - "optional": false, - "description": "", - "line": 68, - "modifierKind": [ - 120 - ] - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { animate, state, style, transition, trigger } from '@angular/animations';\nimport { IColumns, AdwpComponentHolder } from '@adwp-ui/widgets';\nimport { BehaviorSubject } from 'rxjs';\n\nimport { Job, Task } from '@app/core/types';\nimport { DateHelper } from '@app/helpers/date-helper';\nimport { JobStatusColumnComponent } from '@app/components/columns/job-status-column/job-status-column.component';\nimport { JobNameComponent } from '@app/components/columns/job-name/job-name.component';\n\n@Component({\n selector: 'app-jobs',\n animations: [\n trigger('jobsExpand', [\n state('collapsed', style({ height: '0px', minHeight: '0' })),\n state('expanded', style({ height: '*' })),\n transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),\n ]),\n ],\n template: `\n
\n 1\"\n [columns]=\"columns\"\n [dataSource]=\"data\"\n headerRowClassName=\"hidden\"\n >\n
\n `,\n styleUrls: ['./jobs.component.scss'],\n})\nexport class JobsComponent implements AdwpComponentHolder {\n\n columns: IColumns = [\n {\n type: 'component',\n label: '',\n component: JobNameComponent,\n },\n {\n label: '',\n value: (row) => {\n return row.status !== 'created' ? DateHelper.short(row.start_date) : '';\n },\n className: 'action_date',\n headerClassName: 'action_date',\n },\n {\n label: '',\n value: (row) => row.status === 'success' || row.status === 'failed' ? DateHelper.short(row.finish_date) : '',\n className: 'action_date',\n headerClassName: 'action_date',\n },\n {\n label: '',\n type: 'component',\n component: JobStatusColumnComponent,\n className: 'table-end center status',\n headerClassName: 'table-end center status',\n }\n ];\n\n private ownData: { results: Job[], count: number };\n get data(): { results: Job[], count: number } {\n return this.ownData;\n }\n\n private ownRow: Task;\n @Input() set row(row: Task) {\n this.ownRow = row;\n this.ownData = { results: this.ownRow?.jobs, count: 0 };\n }\n get row(): Task {\n return this.ownRow;\n }\n\n @Input() expandedTask: BehaviorSubject;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n width: 100%;\n}\n\nadwp-table {\n width: 100%;\n}\n\n:host adwp-table ::ng-deep mat-table {\n width: 100%;\n}\n\n:host ::ng-deep .action_date {\n width: 200px;\n flex-basis: 200px;\n flex-grow: 0;\n}\n\n:host ::ng-deep .padding20 {\n padding-right: 20px;\n}\n\n:host ::ng-deep .table-end {\n width: 50px;\n flex-basis: 50px;\n flex-grow: 0;\n}\n\n:host ::ng-deep .center {\n text-align: center;\n}\n\n:host ::ng-deep .status {\n display: flex;\n justify-content: center;\n}\n", - "styleUrl": "./jobs.component.scss" - } - ], - "stylesData": "", - "implements": [ - "AdwpComponentHolder" - ], - "accessors": { - "data": { - "name": "data", - "getSignature": { - "name": "data", - "type": "literal type", - "returnType": "literal type", - "line": 64 - } - }, - "row": { - "name": "row", - "setSignature": { - "name": "row", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "row", - "type": "Task", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 69, - "jsdoctags": [ - { - "name": "row", - "type": "Task", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "row", - "type": "", - "returnType": "Task", - "line": 73 - } - } - } - }, - { - "name": "JobStatusColumnComponent", - "id": "component-JobStatusColumnComponent-fddfe743cb540f24a306be8ab34d5601", - "file": "src/app/components/columns/job-status-column/job-status-column.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-job-status-column", - "styleUrls": [ - "./job-status-column.component.scss" - ], - "styles": [], - "template": "\n {{ iconDisplay[row.status] }}\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "iconDisplay", - "defaultValue": "{\n created: 'watch_later',\n running: 'autorenew',\n success: 'done',\n failed: 'error',\n aborted: 'block'\n }", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "optional": false, - "description": "", - "line": 19 - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "type": "Job", - "optional": false, - "description": "", - "line": 17 - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { AdwpCellComponent } from '@adwp-ui/widgets';\n\nimport { Job } from '@app/core/types';\n\n@Component({\n selector: 'app-job-status-column',\n template: `\n \n {{ iconDisplay[row.status] }}\n \n `,\n styleUrls: ['./job-status-column.component.scss']\n})\nexport class JobStatusColumnComponent implements AdwpCellComponent {\n\n row: Job;\n\n iconDisplay = {\n created: 'watch_later',\n running: 'autorenew',\n success: 'done',\n failed: 'error',\n aborted: 'block'\n };\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".mat-icon {\n vertical-align: middle;\n font-size: 1.2em;\n width: auto;\n height: auto;\n}\n", - "styleUrl": "./job-status-column.component.scss" - } - ], - "stylesData": "", - "implements": [ - "AdwpCellComponent" - ] - }, - { - "name": "JsonComponent", - "id": "component-JsonComponent-74191a63eceff3d8757e84bfd7f1b645", - "file": "src/app/shared/form-elements/json.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-fields-json", - "styleUrls": [], - "styles": [], - "template": "\n \n \n \n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "FieldDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\n\nimport { FieldDirective } from './field.directive';\nimport { debounceTime } from 'rxjs/operators';\n\n@Component({\n selector: 'app-fields-json',\n template: `\n \n \n \n \n \n \n \n \n `,\n})\nexport class JsonComponent extends FieldDirective implements OnInit {\n ngOnInit() {\n super.ngOnInit();\n const control = this.form.controls[this.field.name];\n control.valueChanges.pipe(debounceTime(500)).subscribe((value) => {\n try {\n const v = JSON.parse(value);\n control.setValue(JSON.stringify(v, undefined, 4), { emitEvent: false });\n } catch (e) {\n }\n });\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": "FieldDirective", - "implements": [ - "OnInit" - ] - }, - { - "name": "LabelMenuItemComponent", - "id": "component-LabelMenuItemComponent-db32f0a380a3d26e8ff233e8a85f76d9", - "file": "src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-label-menu-item", - "styleUrls": [], - "styles": [ - "a span { white-space: nowrap; }" - ], - "template": "\n {{ label }}\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "line": 21, - "type": "any", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "line": 15, - "type": "EntityType", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "label", - "deprecated": false, - "deprecationMessage": "", - "line": 13, - "type": "string", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "link", - "deprecated": false, - "deprecationMessage": "", - "line": 14, - "type": "string", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "_entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 11, - "modifierKind": [ - 121 - ], - "inheritance": { - "file": "MenuItemAbstractDirective" - } - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\n\nimport { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive';\n\n@Component({\n selector: 'app-label-menu-item',\n template: `\n \n {{ label }}\n \n `,\n styles: ['a span { white-space: nowrap; }'],\n})\nexport class LabelMenuItemComponent extends MenuItemAbstractDirective {}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "a span { white-space: nowrap; }\n", - "extends": "MenuItemAbstractDirective" - }, - { - "name": "LeftMenuComponent", - "id": "component-LeftMenuComponent-3efccba74ac1719d45f4a3d82ada60e7", - "file": "src/app/shared/details/left-menu/left-menu.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-left-menu", - "styleUrls": [ - "./left-menu.component.scss" - ], - "styles": [], - "template": "\n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "line": 35, - "type": "" - }, - { - "name": "leftMenu", - "deprecated": false, - "deprecationMessage": "", - "line": 27, - "type": "[]" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "_entity", - "deprecated": false, - "deprecationMessage": "", - "type": "AdcmEntity", - "optional": false, - "description": "", - "line": 44, - "modifierKind": [ - 120 - ] - }, - { - "name": "_leftMenu", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "LeftMenuItem[]", - "optional": false, - "description": "", - "line": 26, - "modifierKind": [ - 120 - ] - }, - { - "name": "componentsRef", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "Array>", - "optional": false, - "description": "", - "line": 43, - "modifierKind": [ - 120 - ] - }, - { - "name": "menuRef", - "deprecated": false, - "deprecationMessage": "", - "type": "ViewContainerRef", - "optional": false, - "description": "", - "line": 24, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'menu', {read: ViewContainerRef}" - } - ] - } - ], - "methodsClass": [ - { - "name": "rebuildComponents", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ComponentFactoryResolver, ComponentRef, Input, Type, ViewChild, ViewContainerRef } from '@angular/core';\n\nimport { AdcmEntity } from '@app/models/entity';\nimport { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive';\n\nexport interface LeftMenuItem {\n link: string;\n label: string;\n data?: any;\n component: Type;\n}\n\n@Component({\n selector: 'app-left-menu',\n template: `\n \n \n \n `,\n styleUrls: ['./left-menu.component.scss']\n})\nexport class LeftMenuComponent {\n\n @ViewChild('menu', { read: ViewContainerRef }) menuRef: ViewContainerRef;\n\n private _leftMenu: LeftMenuItem[] = [];\n @Input() set leftMenu(leftMenu: LeftMenuItem[]) {\n this._leftMenu = leftMenu;\n this.rebuildComponents();\n }\n get leftMenu(): LeftMenuItem[] {\n return this._leftMenu;\n }\n\n @Input() set entity(entity: AdcmEntity) {\n this._entity = entity;\n this.componentsRef.forEach((componentRef) => componentRef.instance.entity = entity);\n }\n get entity(): AdcmEntity {\n return this._entity;\n }\n\n private componentsRef: Array> = [];\n private _entity: AdcmEntity;\n\n constructor(\n protected componentFactoryResolver: ComponentFactoryResolver,\n ) {}\n\n rebuildComponents() {\n setTimeout(() => {\n this.componentsRef = [];\n this.menuRef.clear();\n this.leftMenu.forEach((item) => {\n const componentFactory =\n this.componentFactoryResolver.resolveComponentFactory(item.component);\n const componentRef = this.menuRef.createComponent(componentFactory);\n componentRef.instance.label = item.label;\n componentRef.instance.link = item.link;\n if (item.data) {\n componentRef.instance.data = item.data;\n }\n if (this.entity !== undefined) {\n componentRef.instance.entity = this.entity;\n }\n this.componentsRef.push(componentRef);\n });\n });\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "mat-nav-list {\n padding-top: 20px;\n}\n", - "styleUrl": "./left-menu.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 44, - "jsdoctags": [ - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "accessors": { - "leftMenu": { - "name": "leftMenu", - "setSignature": { - "name": "leftMenu", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "leftMenu", - "type": "LeftMenuItem[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 27, - "jsdoctags": [ - { - "name": "leftMenu", - "type": "LeftMenuItem[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "leftMenu", - "type": "[]", - "returnType": "LeftMenuItem[]", - "line": 31 - } - }, - "entity": { - "name": "entity", - "setSignature": { - "name": "entity", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "entity", - "type": "AdcmEntity", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 35, - "jsdoctags": [ - { - "name": "entity", - "type": "AdcmEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "entity", - "type": "", - "returnType": "AdcmEntity", - "line": 39 - } - } - } - }, - { - "name": "LicenseComponent", - "id": "component-LicenseComponent-24b4f3c3c6725b2d90f3cdeb18df9a90", - "file": "src/app/entry/bundle/bundle-list.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-license", - "styleUrls": [], - "styles": [ - ":host {\n width: 100%;\n max-width: 960px\n }\n\n pre {\n white-space: pre-wrap;\n }" - ], - "template": "
{{ text | async }}
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "text", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 142 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 146, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ComponentRef, OnInit, ViewChild } from '@angular/core';\nimport { Store } from '@ngrx/store';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { MatDialog } from '@angular/material/dialog';\nimport { IColumns } from '@adwp-ui/widgets';\nimport { Observable } from 'rxjs';\n\nimport { StackService } from '../../core/services';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { AdwpListDirective } from '@app/abstract-directives/adwp-list.directive';\nimport { ListService } from '@app/shared/components/list/list.service';\nimport { SocketState } from '@app/core/store';\nimport { TypeName } from '@app/core/types';\nimport { IBundle } from '@app/models/bundle';\nimport { ListFactory } from '../../factories/list.factory';\nimport { EditionColumnComponent } from '@app/components/columns/edition-column/edition-column.component';\n\n@Component({\n selector: 'app-bundle-list',\n template: `\n \n \n \n \n\n \n `,\n styles: [':host { flex: 1; }'],\n})\nexport class BundleListComponent extends AdwpListDirective {\n\n type: TypeName = 'bundle';\n\n listColumns = [\n ListFactory.nameColumn(),\n {\n label: 'Version',\n sort: 'version',\n value: row => row.version,\n },\n {\n label: 'Edition',\n type: 'component',\n component: EditionColumnComponent,\n instanceTaken: (componentRef: ComponentRef) => {\n componentRef.instance.onClick = this.license.bind(this);\n }\n },\n ListFactory.descriptionColumn(),\n ListFactory.deleteColumn(this),\n ] as IColumns;\n\n @ViewChild('uploadBtn', { static: true }) uploadBtn: any;\n\n constructor(\n private stack: StackService,\n protected service: ListService,\n protected store: Store,\n public route: ActivatedRoute,\n public router: Router,\n public dialog: MatDialog,\n ) {\n super(service, store, route, router, dialog);\n }\n\n upload(data: FormData[]) {\n this.stack.upload(data).subscribe();\n }\n\n license(data: { event: MouseEvent, action: string, row: any }) {\n this.clickCell(data.event, data.action, data.row);\n }\n\n}\n\n@Component({\n selector: 'app-main',\n template: `\n \n `,\n styles: [':host {width: 100%; max-width: 960px}']\n})\nexport class MainComponent implements OnInit {\n model: any;\n\n keys = ['display_name', 'version', 'license', 'license_path'];\n\n listColumns = [\n ListFactory.keyColumn(),\n ListFactory.valueColumn(),\n ] as IColumns;\n\n constructor(private service: ClusterService) {}\n\n ngOnInit() {\n this.model = this.service.Current;\n }\n\n}\n\n@Component({\n selector: 'app-license',\n template: `\n
{{ text | async }}
\n `,\n styles: [`:host {\n width: 100%;\n max-width: 960px\n }\n\n pre {\n white-space: pre-wrap;\n }`]\n})\nexport class LicenseComponent implements OnInit {\n text: Observable;\n\n constructor(private service: ClusterService) {}\n\n ngOnInit(): void {\n this.text = this.service.getBundleLicenseText();\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {\n width: 100%;\n max-width: 960px\n }\n\n pre {\n white-space: pre-wrap;\n }\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 142, - "jsdoctags": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "LogComponent", - "id": "component-LogComponent-59263ce90a12572430d765b098f37e68", - "file": "src/app/ws-logs/log.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-log", - "styleUrls": [ - "./log.component.scss" - ], - "styles": [], - "templateUrl": [ - "./log.component.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 27 - }, - { - "name": "eventName", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "events", - "defaultValue": "[\n 'all',\n 'change_state',\n 'add',\n 'create',\n 'delete',\n 'remove',\n 'change_config',\n 'change_status',\n 'change_job_status',\n 'change_hostcomponentmap',\n 'upgrade',\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 40 - }, - { - "name": "form", - "defaultValue": "new FormGroup({\n typesName: new FormControl('cluster'),\n eventsName: new FormControl('change_state'),\n timeOut: new FormControl(false),\n })", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "logs$", - "defaultValue": "new BehaviorSubject<{ event: EventMessage; response: any }[]>([])", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 38 - }, - { - "name": "slider", - "deprecated": false, - "deprecationMessage": "", - "type": "MatSlider", - "optional": false, - "description": "", - "line": 56, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'slider'" - } - ] - }, - { - "name": "typeName", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 29 - }, - { - "name": "types", - "defaultValue": "['all', 'job', 'task', 'cluster', 'host', 'service']", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 54 - } - ], - "methodsClass": [ - { - "name": "list", - "args": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 86, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 62, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "reflect", - "args": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 72, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "refresh", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 98, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit, ViewChild } from '@angular/core';\nimport { FormControl, FormGroup } from '@angular/forms';\nimport { MatSlider } from '@angular/material/slider';\nimport { ApiService } from '@app/core/api';\nimport { EventMessage, getMessage, State } from '@app/core/store';\nimport { select, Store } from '@ngrx/store';\nimport { BehaviorSubject, Subject } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\n\n@Component({\n selector: 'app-log',\n templateUrl: './log.component.html',\n styleUrls: ['./log.component.scss'],\n})\nexport class LogComponent implements OnInit {\n destroy$ = new Subject();\n\n typeName: string;\n eventName: string;\n\n form = new FormGroup({\n typesName: new FormControl('cluster'),\n eventsName: new FormControl('change_state'),\n timeOut: new FormControl(false),\n });\n\n logs$ = new BehaviorSubject<{ event: EventMessage; response: any }[]>([]);\n\n events = [\n 'all',\n 'change_state',\n 'add',\n 'create',\n 'delete',\n 'remove',\n 'change_config',\n 'change_status',\n 'change_job_status',\n 'change_hostcomponentmap',\n 'upgrade',\n ];\n\n types = ['all', 'job', 'task', 'cluster', 'host', 'service'];\n\n @ViewChild('slider') slider: MatSlider;\n\n constructor(private store: Store, private api: ApiService) {\n // this.store.dispatch(socketInit());\n }\n\n ngOnInit() {\n this.store\n .pipe(\n select(getMessage),\n filter((m: EventMessage) => !!m && !!m.event),\n takeUntil(this.destroy$)\n )\n .subscribe(m => this.reflect(m));\n }\n\n reflect(m: EventMessage) {\n const typeName = this.form.get('typesName').value,\n eventName = this.form.get('eventsName').value;\n if ((m.object.type === typeName || typeName === 'all') && (m.event === eventName || eventName === 'all')) {\n if (this.form.get('timeOut').value)\n setTimeout(\n () => this.api.getOne(m.object.type, m.object.id).subscribe(value => this.list(m, value)),\n this.slider.value\n );\n else this.api.getOne(m.object.type, m.object.id).subscribe(value => this.list(m, value));\n }\n // else this.list(m, `Not request for ${eventName} event.`);\n }\n\n list(m: EventMessage, value: any) {\n const { type, id } = m.object;\n const list = [\n ...this.logs$.getValue(),\n {\n event: m,\n response: { title: `Request for [ /api/v1/${type}/${id}/ ]`, value },\n },\n ];\n this.logs$.next(list.reverse());\n }\n\n refresh() {\n this.logs$.next([]);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".tools, .logs {\n display: flex;\n margin: 10px 0;\n}\n\n.tools {\n justify-content: space-evenly;\n}\n\n.logs div:last-child {\n margin-left: 40px;\n}\n\nmat-select {\n width: 250px;\n}\n\npre { font-size: 12px;}\n\nlabel {font-size: 12px;}\nmat-select {margin-left: 20px; border: solid 1px #ccc; padding: 4px 8px;}\n", - "styleUrl": "./log.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 56, - "jsdoctags": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ], - "templateData": "
\n
\n
\n \n \n \n {{ item }}\n \n \n
\n
\n \n \n \n {{ item }}\n \n \n
\n Timeout\n \n \n \n \n
\n\n
\n
\n
{{ log.event | json }}
\n
\n
\n

{{ log.response.title }}

\n
{{ log.response.value | json }}
\n
\n
\n
\n" - }, - { - "name": "LogComponent", - "id": "component-LogComponent-a4ca3857c8a3fa9637042e138d2d1c95-1", - "file": "src/app/entry/job/log/log.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-job-log", - "styleUrls": [], - "styles": [ - "\n :host {\n display: flex;\n flex: 1;\n padding: 10px 20px;\n }\n\n div.wrap {\n display: flex;\n flex: 1;\n }\n\n .accordion {\n flex: 1;\n display: flex;\n flex-direction: column;\n }\n " - ], - "template": "\n \n
\n \n \n \n \n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "currentLog$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 65 - }, - { - "name": "job", - "deprecated": false, - "deprecationMessage": "", - "type": "Job", - "optional": false, - "description": "", - "line": 69 - }, - { - "name": "logUrl", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 67 - }, - { - "name": "textComp", - "deprecated": false, - "deprecationMessage": "", - "type": "TextComponent", - "optional": false, - "description": "", - "line": 71, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "TextComponent, {static: true}" - } - ] - }, - { - "name": "timeInfo", - "deprecated": false, - "deprecationMessage": "", - "type": "ITimeInfo", - "optional": false, - "description": "", - "line": 66 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 98, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "refresh", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 111, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "socketListener", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 81, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "startListenSocket", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 91, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit, ViewChild } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Subject } from 'rxjs';\nimport { filter, switchMap } from 'rxjs/operators';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { Job, JobStatus, LogFile } from '@app/core/types';\nimport { TextComponent } from './text.component';\nimport { JobService } from '@app/services/job.service';\nimport { EventMessage } from '@app/core/store';\n\nexport interface ITimeInfo {\n start: string;\n end: string;\n time: string;\n}\n\n@Component({\n selector: 'app-job-log',\n styles: [\n `\n :host {\n display: flex;\n flex: 1;\n padding: 10px 20px;\n }\n\n div.wrap {\n display: flex;\n flex: 1;\n }\n\n .accordion {\n flex: 1;\n display: flex;\n flex-direction: column;\n }\n `,\n ],\n template: `\n \n \n
\n \n \n \n \n
\n
\n `,\n})\nexport class LogComponent extends BaseDirective implements OnInit {\n currentLog$ = new Subject();\n timeInfo: ITimeInfo;\n logUrl: string;\n\n job: Job;\n\n @ViewChild(TextComponent, { static: true }) textComp: TextComponent;\n\n constructor(\n private service: ClusterService,\n private route: ActivatedRoute,\n private jobService: JobService,\n ) {\n super();\n }\n\n socketListener(event: EventMessage) {\n if (event.event === 'change_job_status') {\n this.job.status = event.object.details.value as JobStatus;\n this.job.finish_date = new Date().toISOString();\n this.timeInfo = this.service.getOperationTimeData(this.job);\n if (this.textComp) this.textComp.update(this.job.status);\n }\n this.refresh();\n }\n\n startListenSocket() {\n this.jobService.events().pipe(\n this.takeUntil(),\n filter(event => event?.object?.id === this.job.id),\n ).subscribe((event) => this.socketListener(event));\n }\n\n ngOnInit() {\n this.route.paramMap.pipe(\n this.takeUntil(),\n switchMap(() => this.jobService.get(+this.route.parent.snapshot.paramMap.get('job'))),\n ).subscribe((job) => {\n this.job = job;\n this.timeInfo = this.service.getOperationTimeData(this.job);\n this.logUrl = this.job.log_files.find((a) => a.id === +this.route.snapshot.paramMap.get('log')).url;\n this.refresh();\n });\n this.startListenSocket();\n }\n\n refresh() {\n if (!this.logUrl) return;\n this.service.getLog(this.logUrl).subscribe((a) => this.currentLog$.next(a));\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n :host {\n display: flex;\n flex: 1;\n padding: 10px 20px;\n }\n\n div.wrap {\n display: flex;\n flex: 1;\n }\n\n .accordion {\n flex: 1;\n display: flex;\n flex-direction: column;\n }\n \n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "jobService", - "type": "JobService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 71, - "jsdoctags": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "jobService", - "type": "JobService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "OnInit" - ], - "isDuplicate": true, - "duplicateId": 1, - "duplicateName": "LogComponent-1" - }, - { - "name": "LoginComponent", - "id": "component-LoginComponent-494e72c068c27513ced813277dd53172", - "file": "src/app/main/login/login.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-login", - "styleUrls": [ - "./login.component.scss" - ], - "styles": [], - "templateUrl": [ - "./login.component.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "authForm", - "defaultValue": "new FormGroup({ login: new FormControl('', Validators.required), password: new FormControl('', Validators.required) })", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "checkGL$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "message", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "google", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 72, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "login", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 64, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 38, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnDestroy, OnInit } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { Observable } from 'rxjs';\nimport { filter } from 'rxjs/operators';\nimport { FormGroup, FormControl, Validators } from '@angular/forms';\n\nimport { AuthService } from '@app/core/auth/auth.service';\nimport { authLogin, authLogout, AuthState, getAuthState } from '@app/core/auth/auth.store';\nimport { clearProfile } from '@app/core/store';\nimport { BaseDirective } from '@app/shared/directives';\n\n@Component({\n selector: 'app-login',\n templateUrl: './login.component.html',\n styleUrls: ['./login.component.scss'],\n})\nexport class LoginComponent extends BaseDirective implements OnInit, OnDestroy {\n authForm = new FormGroup({ login: new FormControl('', Validators.required), password: new FormControl('', Validators.required) });\n message: string;\n checkGL$: Observable;\n\n constructor(private auth: AuthService, private router: Router, private store: Store, private route: ActivatedRoute) {\n super();\n }\n\n ngOnInit() {\n this.checkGL$ = this.auth.checkGoogle();\n this.store.dispatch(authLogout());\n\n const a$ = this.store\n .select(getAuthState)\n .pipe(this.takeUntil())\n .subscribe(state => {\n if (state.isValid) {\n a$.unsubscribe();\n const redirectUrl = this.auth.redirectUrl;\n this.router.navigateByUrl(redirectUrl && redirectUrl !== 'login' && redirectUrl !== '/504' ? redirectUrl : '/admin');\n } else {\n this.store.dispatch(clearProfile());\n this.message = state.message;\n }\n });\n\n this.route.queryParams\n .pipe(\n filter(p => p['error_code'] === 'AUTH_ERROR'),\n this.takeUntil()\n )\n .subscribe(p => (this.message = p['error_msg']));\n }\n\n login() {\n this.message = '';\n if (this.authForm.valid) {\n const { login, password } = this.authForm.value;\n this.store.dispatch(authLogin({ login, password }));\n }\n }\n\n google() {\n window.location.href = '/social/login/google-oauth2/';\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n flex: 1;\n}\n\n.container {\n max-width: 900px;\n background: #424242;\n box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12);\n border-radius: 4px;\n padding-top: 32px;\n}\n\n.double-auth {\n display: flex;\n justify-content: center;\n align-items: center;\n\n & div {\n flex-basis: 50%;\n text-align: center;\n }\n\n & .or {\n flex: 0;\n border: solid 1px #666;\n border-radius: 42px;\n padding: 8px;\n line-height: 24px;\n }\n}\n\n.google-auth {\n line-height: 46px;\n padding: 0;\n\n & svg {\n width: 46px;\n height: 46px;\n }\n\n & span {\n padding: 0 16px;\n }\n}\n\n.form-auth {\n width: 300px;\n margin: 0 auto;\n\n & p {\n text-align: right;\n }\n\n & mat-form-field {\n width: 100%;\n }\n}\n\n.warn {\n width: 300px;\n margin: 0 auto;\n padding: 16px;\n}\n", - "styleUrl": "./login.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "auth", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 32, - "jsdoctags": [ - { - "name": "auth", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "OnInit", - "OnDestroy" - ], - "templateData": "
\n
\n
\n
\n \n
\n
OR
\n
\n \n
\n
\n \n
\n \n \n \n \n \n \n

\n \n

\n
\n
\n

{{ message }}

\n
\n" - }, - { - "name": "LogMenuItemComponent", - "id": "component-LogMenuItemComponent-a6a7589d917cd59335e29d8ea66561c1", - "file": "src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-log-menu-item", - "styleUrls": [], - "styles": [ - "a span { white-space: nowrap; }" - ], - "template": "\n {{ label }} \n\n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "line": 21, - "type": "any", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "line": 15, - "type": "EntityType", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "label", - "deprecated": false, - "deprecationMessage": "", - "line": 13, - "type": "string", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "link", - "deprecated": false, - "deprecationMessage": "", - "line": 14, - "type": "string", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "_entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 11, - "modifierKind": [ - 121 - ], - "inheritance": { - "file": "MenuItemAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "download", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 28, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\n\nimport { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive';\nimport { BaseEntity, Job } from '@app/core/types';\n\n@Component({\n selector: 'app-log-menu-item',\n template: `\n \n {{ label }} \n\n \n \n `,\n styles: ['a span { white-space: nowrap; }'],\n})\nexport class LogMenuItemComponent extends MenuItemAbstractDirective {\n\n download() {\n if (this.data?.logId) {\n const file = (this.entity as Job).log_files.find(job => job.id === this.data.logId);\n if (file) {\n location.href = file.download_url;\n } else {\n throw new Error('Log file not found!');\n }\n } else {\n throw new Error('Log id isn\\'t provided!');\n }\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "a span { white-space: nowrap; }\n", - "extends": "MenuItemAbstractDirective" - }, - { - "name": "MainComponent", - "id": "component-MainComponent-24b4f3c3c6725b2d90f3cdeb18df9a90", - "file": "src/app/entry/bundle/bundle-list.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-main", - "styleUrls": [], - "styles": [ - ":host {width: 100%; max-width: 960px}" - ], - "template": "\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "keys", - "defaultValue": "['display_name', 'version', 'license', 'license_path']", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 112 - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.keyColumn(),\n ListFactory.valueColumn(),\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 114 - }, - { - "name": "model", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 110 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 121, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ComponentRef, OnInit, ViewChild } from '@angular/core';\nimport { Store } from '@ngrx/store';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { MatDialog } from '@angular/material/dialog';\nimport { IColumns } from '@adwp-ui/widgets';\nimport { Observable } from 'rxjs';\n\nimport { StackService } from '../../core/services';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { AdwpListDirective } from '@app/abstract-directives/adwp-list.directive';\nimport { ListService } from '@app/shared/components/list/list.service';\nimport { SocketState } from '@app/core/store';\nimport { TypeName } from '@app/core/types';\nimport { IBundle } from '@app/models/bundle';\nimport { ListFactory } from '../../factories/list.factory';\nimport { EditionColumnComponent } from '@app/components/columns/edition-column/edition-column.component';\n\n@Component({\n selector: 'app-bundle-list',\n template: `\n \n \n \n \n\n \n `,\n styles: [':host { flex: 1; }'],\n})\nexport class BundleListComponent extends AdwpListDirective {\n\n type: TypeName = 'bundle';\n\n listColumns = [\n ListFactory.nameColumn(),\n {\n label: 'Version',\n sort: 'version',\n value: row => row.version,\n },\n {\n label: 'Edition',\n type: 'component',\n component: EditionColumnComponent,\n instanceTaken: (componentRef: ComponentRef) => {\n componentRef.instance.onClick = this.license.bind(this);\n }\n },\n ListFactory.descriptionColumn(),\n ListFactory.deleteColumn(this),\n ] as IColumns;\n\n @ViewChild('uploadBtn', { static: true }) uploadBtn: any;\n\n constructor(\n private stack: StackService,\n protected service: ListService,\n protected store: Store,\n public route: ActivatedRoute,\n public router: Router,\n public dialog: MatDialog,\n ) {\n super(service, store, route, router, dialog);\n }\n\n upload(data: FormData[]) {\n this.stack.upload(data).subscribe();\n }\n\n license(data: { event: MouseEvent, action: string, row: any }) {\n this.clickCell(data.event, data.action, data.row);\n }\n\n}\n\n@Component({\n selector: 'app-main',\n template: `\n \n `,\n styles: [':host {width: 100%; max-width: 960px}']\n})\nexport class MainComponent implements OnInit {\n model: any;\n\n keys = ['display_name', 'version', 'license', 'license_path'];\n\n listColumns = [\n ListFactory.keyColumn(),\n ListFactory.valueColumn(),\n ] as IColumns;\n\n constructor(private service: ClusterService) {}\n\n ngOnInit() {\n this.model = this.service.Current;\n }\n\n}\n\n@Component({\n selector: 'app-license',\n template: `\n
{{ text | async }}
\n `,\n styles: [`:host {\n width: 100%;\n max-width: 960px\n }\n\n pre {\n white-space: pre-wrap;\n }`]\n})\nexport class LicenseComponent implements OnInit {\n text: Observable;\n\n constructor(private service: ClusterService) {}\n\n ngOnInit(): void {\n this.text = this.service.getBundleLicenseText();\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {width: 100%; max-width: 960px}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 117, - "jsdoctags": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "MainComponent", - "id": "component-MainComponent-f78a5354d94de64edaa70ed6d18cfe3c-1", - "file": "src/app/entry/job/job.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-main", - "styleUrls": [], - "styles": [], - "template": "", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { ClusterService } from '@app/core/services/cluster.service';\n\n@Component({\n selector: 'app-main',\n template: '',\n})\nexport class MainComponent extends BaseDirective implements OnInit {\n\n constructor(\n private clusterService: ClusterService,\n private router: Router,\n private route: ActivatedRoute,\n ) {\n super();\n }\n\n ngOnInit() {\n this.route.parent.params.pipe(this.takeUntil()).subscribe(params => {\n this.clusterService.one_job(params?.job).subscribe(job => {\n const logs = job.log_files;\n const log = logs.find((a) => a.type === 'check') || logs[0];\n if (log) this.router.navigate([`../${log.id}`], { relativeTo: this.route, replaceUrl: true });\n });\n });\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "clusterService", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 22, - "jsdoctags": [ - { - "name": "clusterService", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "OnInit" - ], - "isDuplicate": true, - "duplicateId": 1, - "duplicateName": "MainComponent-1" - }, - { - "name": "MainInfoComponent", - "id": "component-MainInfoComponent-dd38044d2b486a9baec1c48f63ade898", - "file": "src/app/shared/components/main-info.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-main-info", - "styleUrls": [], - "styles": [ - ":host {padding: 0 20px;}" - ], - "template": "
", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "SafeHtml", - "optional": false, - "description": "", - "line": 23 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\n\nimport { ClusterService } from '@app/core/services/cluster.service';\n\n@Component({\n selector: 'app-main-info',\n template: '
',\n styles: [':host {padding: 0 20px;}'],\n})\nexport class MainInfoComponent implements OnInit {\n value: SafeHtml;\n constructor(private service: ClusterService, private sanitizer: DomSanitizer) {}\n ngOnInit() {\n this.service.getMainInfo().subscribe((value) => (this.value = this.sanitizer.bypassSecurityTrustHtml(value)));\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {padding: 0 20px;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "sanitizer", - "type": "DomSanitizer", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 23, - "jsdoctags": [ - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "sanitizer", - "type": "DomSanitizer", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "MenuItemComponent", - "id": "component-MenuItemComponent-00e39716c030f0770583e0412a34a272", - "file": "src/app/shared/components/actions/action-list/menu-item/menu-item.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-menu-item", - "styleUrls": [ - "./menu-item.component.scss" - ], - "styles": [], - "template": "
\n No actions\n
\n \n \n \n \n \n \n \n \n \n
", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "line": 40, - "type": "literal type" - }, - { - "name": "items", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "line": 39, - "type": "IAction[]" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "menu", - "deprecated": false, - "deprecationMessage": "", - "type": "MatMenu", - "optional": false, - "description": "", - "line": 41, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'menu', {static: true}" - } - ] - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, ViewChild } from '@angular/core';\nimport { IAction } from '@app/core/types/actions';\nimport { MatMenu } from '@angular/material/menu';\n\n@Component({\n selector: 'app-menu-item',\n styleUrls: ['./menu-item.component.scss'],\n template: ` \n
\n No actions\n
\n \n \n \n \n \n \n \n \n \n
`,\n})\nexport class MenuItemComponent {\n @Input() items: IAction[] = [];\n @Input() cluster: { id: number; hostcomponent: string };\n @ViewChild('menu', { static: true }) menu: MatMenu;\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".mat-menu-item-submenu-trigger::after {\n left: 6px;\n transform: rotate(180deg) translateY(50%);\n}\n", - "styleUrl": "./menu-item.component.scss" - } - ], - "stylesData": "" - }, - { - "name": "Much2ManyComponent", - "id": "component-Much2ManyComponent-34d2b009b3cc8b9cec80179b099bf8e7", - "file": "src/app/shared/host-components-map/much-2-many/much-2-many.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-much-2-many", - "styleUrls": [ - "./much-2-many.component.scss" - ], - "styles": [], - "templateUrl": [ - "./much-2-many.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 29, - "type": "FormGroup" - }, - { - "name": "model", - "deprecated": false, - "deprecationMessage": "", - "line": 28, - "type": "Tile" - } - ], - "outputsClass": [ - { - "name": "clearRelationEvt", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 27, - "type": "EventEmitter" - }, - { - "name": "clickToTitleEvt", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 26, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "isShow", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 24 - } - ], - "methodsClass": [ - { - "name": "clearDisabled", - "args": [ - { - "name": "rel", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "rel", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clearRelation", - "args": [ - { - "name": "relation", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 59, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "relation", - "type": "Tile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clickToTitle", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 51, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "isDisabled", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "isError", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 36, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "setNotify", - "args": [], - "optional": false, - "returnType": "string", - "typeParameters": [], - "line": 64, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "toggleRelations", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 55, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { isNumber } from '@app/core/types';\n\nimport { CompTile, Tile } from '../types';\n\n@Component({\n selector: 'app-much-2-many',\n templateUrl: './much-2-many.component.html',\n styleUrls: ['./much-2-many.component.scss'],\n})\nexport class Much2ManyComponent {\n isShow = false;\n\n @Output() clickToTitleEvt: EventEmitter = new EventEmitter();\n @Output() clearRelationEvt: EventEmitter<{ relation: Tile; model: Tile }> = new EventEmitter();\n @Input() model: Tile;\n @Input() form: FormGroup;\n\n isDisabled() {\n if (this.model.actions) return !this.model.actions.length;\n return this.model.disabled;\n }\n\n isError() {\n if ('service_id' in this.model && Object.keys(this.form.controls).length) {\n const sc = this.model as CompTile;\n const control = this.form.controls[`${sc.service_id}/${sc.id}`];\n if (!control) return false;\n sc.notification = control.errors?.error;\n return control.invalid;\n } else return false;\n }\n\n clearDisabled(rel: Tile) {\n if (this.model.actions) return this.model.actions.every((e) => e !== 'remove');\n return rel.disabled || this.model.disabled;\n }\n\n clickToTitle() {\n this.clickToTitleEvt.emit(this.model);\n }\n\n toggleRelations() {\n this.isShow = !this.isShow;\n }\n\n clearRelation(relation: Tile) {\n this.model.relations = this.model.relations.filter((a) => a !== relation);\n this.clearRelationEvt.emit({ relation, model: this.model });\n }\n\n setNotify() {\n const [a, b, c] = this.model.limit,\n lim = isNumber(b) ? b : a === 'odd' ? 1 : a === 'depend' ? 0 : a;\n return `${this.model.relations.length}${lim !== 0 ? ` / ${lim}` : ''}`;\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "div.m2m {\n border: solid 1px rgb(238, 236, 236);\n margin-bottom: 8px;\n padding: 8px;\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);\n\n &.selected {\n border-color: #76FF03;\n\n .title-container {\n .title {\n font-weight: bolder;\n color: #76FF03;\n }\n }\n }\n\n &.linked {\n border-color: #18FFFF;\n\n .title-container {\n .title {\n font-weight: bolder;\n color: #18FFFF;\n }\n }\n\n }\n\n & .title-container {\n display: flex;\n\n & .title {\n flex: 1;\n line-height: 40px;\n font-size: 18px;\n width: 1px;\n overflow: hidden;\n text-overflow: ellipsis;\n\n mat-icon {\n vertical-align: middle;\n line-height: .9\n }\n }\n\n & .relations-count {\n box-shadow: none;\n background-color: #e4f9ef;\n margin-left: 8px;\n }\n }\n\n & .relations-list {\n padding: 4px 40px;\n display: none;\n\n & div {\n display: flex;\n\n & span {\n font-size: 14px;\n font-weight: 500;\n flex: 1 0 auto;\n line-height: 40px;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 1px;\n }\n\n & button {\n flex: 0 1 auto;\n }\n }\n }\n\n & .notification {\n display: none;\n }\n\n & .show {\n display: block;\n }\n}\n\n\n\n.mat-mini-fab[disabled][disabled] {\n color: rgba(0, 0, 0, 0.4);\n}\n", - "styleUrl": "./much-2-many.component.scss" - } - ], - "stylesData": "", - "templateData": "
\n
\n \n \n
\n
\n
\n {{ rel.name }}\n \n
\n
\n
\n" - }, - { - "name": "NavigationComponent", - "id": "component-NavigationComponent-3d5ec0ae61bd032d6bf26061449bb56a", - "file": "src/app/components/navigation/navigation.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-navigation", - "styleUrls": [], - "styles": [ - "\n :host {\n font-size: 14px;\n margin-left: 8px;\n width: 100%;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n mat-nav-list {\n padding-top: 0;\n display: flex;\n align-items: center;\n max-width: 100%;\n overflow: hidden;\n flex-flow: row nowrap;\n justify-content: flex-start;\n }\n\n mat-nav-list > * {\n display: block;\n box-sizing: border-box;\n }\n\n mat-nav-list a {\n display: flex;\n align-items: center;\n line-height: normal;\n }\n\n .mat-nav-list .entity {\n border: 1px solid #54646E;\n border-radius: 5px;\n padding: 2px 8px;\n display: flex;\n align-items: center;\n justify-content: space-around;\n flex: 0 1 auto;\n overflow: hidden;\n\n }\n\n .mat-nav-list .entity.last {\n flex: 0 0 auto;\n }\n\n .mat-nav-list .entity * {\n flex: 0 0 auto;\n }\n\n .mat-nav-list .entity .link {\n flex: 0 1 auto;\n overflow: hidden;\n }\n\n .mat-nav-list .entity a {\n line-height: 40px;\n text-overflow: ellipsis;\n overflow: hidden;\n display: block;\n }\n\n .mat-nav-list app-upgrade {\n margin-left: -8px;\n }\n\n " - ], - "template": "\n apps\n  / \n \n \n \n \n \n \n  / \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "path", - "deprecated": false, - "deprecationMessage": "", - "line": 113, - "type": "" - } - ], - "outputsClass": [ - { - "name": "refresh", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 134, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "actionFlag", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 103 - }, - { - "name": "actionLink", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 104 - }, - { - "name": "actions", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "IAction[]", - "optional": false, - "description": "", - "line": 105 - }, - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 107 - }, - { - "name": "isIssue", - "defaultValue": "() => {...}", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 111 - }, - { - "name": "ownPath", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 109, - "modifierKind": [ - 120 - ] - }, - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 106 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { AdcmTypedEntity } from '@app/models/entity';\nimport { EmmitRow, IAction } from '@app/core/types';\nimport { IIssues } from '@app/models/issue';\n\n@Component({\n selector: 'app-navigation',\n template: `\n \n apps\n  / \n \n \n \n \n \n \n  / \n \n \n `,\n styles: [`\n :host {\n font-size: 14px;\n margin-left: 8px;\n width: 100%;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n mat-nav-list {\n padding-top: 0;\n display: flex;\n align-items: center;\n max-width: 100%;\n overflow: hidden;\n flex-flow: row nowrap;\n justify-content: flex-start;\n }\n\n mat-nav-list > * {\n display: block;\n box-sizing: border-box;\n }\n\n mat-nav-list a {\n display: flex;\n align-items: center;\n line-height: normal;\n }\n\n .mat-nav-list .entity {\n border: 1px solid #54646E;\n border-radius: 5px;\n padding: 2px 8px;\n display: flex;\n align-items: center;\n justify-content: space-around;\n flex: 0 1 auto;\n overflow: hidden;\n\n }\n\n .mat-nav-list .entity.last {\n flex: 0 0 auto;\n }\n\n .mat-nav-list .entity * {\n flex: 0 0 auto;\n }\n\n .mat-nav-list .entity .link {\n flex: 0 1 auto;\n overflow: hidden;\n }\n\n .mat-nav-list .entity a {\n line-height: 40px;\n text-overflow: ellipsis;\n overflow: hidden;\n display: block;\n }\n\n .mat-nav-list app-upgrade {\n margin-left: -8px;\n }\n\n `],\n})\nexport class NavigationComponent extends BaseDirective {\n\n actionFlag = false;\n actionLink: string;\n actions: IAction[] = [];\n state: string;\n cluster: { id: number; hostcomponent: string };\n\n private ownPath: Observable;\n\n isIssue = (issue: IIssues): boolean => !!(issue && Object.keys(issue).length);\n\n @Input() set path(path: Observable) {\n this.ownPath = path;\n this.ownPath.pipe(this.takeUntil()).subscribe((lPath) => {\n if (lPath && !!lPath.length) {\n const last = lPath[lPath.length - 1];\n const exclude = ['bundle', 'job'];\n this.actionFlag = !exclude.includes(last.typeName);\n this.actionLink = (last).action;\n this.actions = (last).actions;\n this.state = (last).state;\n const { id, hostcomponent } = lPath[0];\n this.cluster = { id, hostcomponent };\n }\n });\n }\n\n get path(): Observable {\n return this.ownPath;\n }\n\n @Output()\n refresh: EventEmitter = new EventEmitter();\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n :host {\n font-size: 14px;\n margin-left: 8px;\n width: 100%;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n mat-nav-list {\n padding-top: 0;\n display: flex;\n align-items: center;\n max-width: 100%;\n overflow: hidden;\n flex-flow: row nowrap;\n justify-content: flex-start;\n }\n\n mat-nav-list > * {\n display: block;\n box-sizing: border-box;\n }\n\n mat-nav-list a {\n display: flex;\n align-items: center;\n line-height: normal;\n }\n\n .mat-nav-list .entity {\n border: 1px solid #54646E;\n border-radius: 5px;\n padding: 2px 8px;\n display: flex;\n align-items: center;\n justify-content: space-around;\n flex: 0 1 auto;\n overflow: hidden;\n\n }\n\n .mat-nav-list .entity.last {\n flex: 0 0 auto;\n }\n\n .mat-nav-list .entity * {\n flex: 0 0 auto;\n }\n\n .mat-nav-list .entity .link {\n flex: 0 1 auto;\n overflow: hidden;\n }\n\n .mat-nav-list .entity a {\n line-height: 40px;\n text-overflow: ellipsis;\n overflow: hidden;\n display: block;\n }\n\n .mat-nav-list app-upgrade {\n margin-left: -8px;\n }\n\n \n", - "extends": "BaseDirective", - "accessors": { - "path": { - "name": "path", - "setSignature": { - "name": "path", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "path", - "type": "Observable", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 113, - "jsdoctags": [ - { - "name": "path", - "type": "Observable", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "path", - "type": "", - "returnType": "Observable", - "line": 129 - } - } - } - }, - { - "name": "NotificationsComponent", - "id": "component-NotificationsComponent-c3452fb90fd9c20c78b325f077ae33df", - "file": "src/app/components/notifications/notifications.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-notifications", - "styleUrls": [ - "./notifications.component.scss" - ], - "styles": [], - "template": "
\n
\n autorenew {{ (data?.counts | async)?.runningCount }}\n
\n
\n done_all {{ (data?.counts | async)?.successCount }}\n
\n
\n done_all {{ (data?.counts | async)?.failedCount }}\n
\n
\n\n\n
\n Last {{(data.tasks | async)?.length}} notifications:\n
\n\n
\n
\n \n autorenew\n block\n done_all\n \n {{ task.action.display_name }}\n
\n\n \n\n
\n
\n\n
\n Nothing to display\n
\n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "line": 64, - "type": "literal type" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "type": "PopoverEventFunc", - "optional": false, - "description": "", - "line": 66 - }, - { - "name": "minHeightNotifications", - "defaultValue": "200", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 60 - }, - { - "name": "notificationsRef", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 62, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'notifications', {static: false}" - } - ] - } - ], - "methodsClass": [ - { - "name": "acknowledge", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 72, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "setLabelHeightAfterAcknowledge", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 68, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, ElementRef, Input, ViewChild } from '@angular/core';\nimport { BehaviorSubject } from 'rxjs';\n\nimport { NotificationsData } from '@app/components/bell/bell.component';\nimport { TaskRaw } from '@app/core/types';\nimport { PopoverEventFunc } from '@app/abstract-directives/popover-content.directive';\n\nexport const ACKNOWLEDGE_EVENT = 'acknowledge';\n\n@Component({\n selector: 'app-notifications',\n template: `\n
\n
\n autorenew {{ (data?.counts | async)?.runningCount }}\n
\n
\n done_all {{ (data?.counts | async)?.successCount }}\n
\n
\n done_all {{ (data?.counts | async)?.failedCount }}\n
\n
\n\n \n
\n Last {{(data.tasks | async)?.length}} notifications:\n
\n\n
\n
\n \n autorenew\n block\n done_all\n \n {{ task.action.display_name }}\n
\n\n \n\n
\n
\n \n
\n Nothing to display\n
\n \n
\n `,\n styleUrls: ['./notifications.component.scss']\n})\nexport class NotificationsComponent {\n\n minHeightNotifications = 200;\n\n @ViewChild('notifications', { static: false }) notificationsRef: ElementRef;\n\n @Input() data: { counts: BehaviorSubject, tasks: BehaviorSubject };\n\n event: PopoverEventFunc;\n\n setLabelHeightAfterAcknowledge() {\n this.minHeightNotifications = this.notificationsRef.nativeElement.clientHeight;\n }\n\n acknowledge() {\n this.setLabelHeightAfterAcknowledge();\n this.event(ACKNOWLEDGE_EVENT);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".counters {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 300px;\n\n & .item {\n display: flex;\n align-items: center;\n cursor: pointer;\n }\n}\n\n.notifications {\n margin-top: 10px;\n padding-top: 10px;\n width: 100%;\n}\n\n.notification {\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.notification + .notification {\n border-top: solid 1px #455A64;\n margin-top: 5px;\n padding-top: 5px;\n}\n\n.footer, .header {\n margin-top: 20px;\n}\n\n.footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.acknowledge {\n cursor: pointer;\n display: flex;\n align-items: center;\n text-decoration: none;\n}\n\n.empty-label {\n margin: 20px 0;\n text-align: center;\n font-style: italic;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.empty-footer {\n margin-bottom: 10px;\n display: flex;\n justify-content: center;\n}\n\nmat-icon {\n margin-right: 3px;\n}\n", - "styleUrl": "./notifications.component.scss" - } - ], - "stylesData": "" - }, - { - "name": "PageNotFoundComponent", - "id": "component-PageNotFoundComponent-ab7f01615421ad17b1b760b49a67020e", - "file": "src/app/main/server-status.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "styleUrls": [], - "styles": [ - "styleCSS" - ], - "template": "
Page not found.
", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\n\nconst styleCSS = 'div { font-weight:bold; margin: 40px auto; width: 400px;}';\n\n// http 500\n@Component({\n styles: [styleCSS],\n template: '
Critical error on the server.

Contact to support.

',\n})\nexport class FatalErrorComponent {}\n\n// http 504\n@Component({\n styles: [styleCSS],\n template: '
Gateway Timeout.
',\n})\nexport class GatewayTimeoutComponent {}\n\n// http 404\n@Component({\n styles: [styleCSS],\n template: '
Page not found.
',\n})\nexport class PageNotFoundComponent {}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "styleCSS\n" - }, - { - "name": "PasswordComponent", - "id": "component-PasswordComponent-16478709b72d26532a38216f56a831fe", - "file": "src/app/shared/form-elements/password/password.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-fields-password", - "styleUrls": [ - "./password.component.scss" - ], - "styles": [], - "templateUrl": [ - "./password.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "conf", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 44, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'conf', {read: ElementRef}" - } - ] - }, - { - "name": "dummy", - "defaultValue": "'********'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "input", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 43, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'input', {read: ElementRef}" - } - ] - }, - { - "name": "isHideDummy", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 36 - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 37 - } - ], - "methodsClass": [ - { - "name": "change", - "args": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 174, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "confirmPasswordFieldUpdate", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 159, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getConfirmPasswordFieldErrors", - "args": [ - { - "name": "error", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 166, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "error", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "hasErrorConfirm", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 154, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "hideDummy", - "args": [ - { - "name": "isConfirmField", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 135, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "isConfirmField", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "initConfirm", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "isCleared", - "args": [], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 131, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "isValidField", - "args": [], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 127, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngAfterViewInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 88, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnChanges", - "args": [ - { - "name": "changes", - "type": "SimpleChanges", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 46, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "changes", - "type": "SimpleChanges", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 52, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "FieldDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import {\n AfterViewInit,\n ChangeDetectorRef,\n Component,\n ElementRef,\n OnChanges,\n OnInit,\n SimpleChanges,\n ViewChild,\n} from '@angular/core';\nimport { AbstractControl, FormControl } from '@angular/forms';\nimport { fromEvent, merge } from 'rxjs';\nimport { debounceTime, pluck, tap } from 'rxjs/operators';\n\nimport { FieldDirective } from '../field.directive';\nimport { FieldService } from '../../configuration/services/field.service';\n\n@Component({\n selector: 'app-fields-password',\n templateUrl: './password.component.html',\n styleUrls: ['./password.component.scss'],\n})\nexport class PasswordComponent extends FieldDirective implements OnInit, AfterViewInit, OnChanges {\n dummy = '********';\n isHideDummy = false;\n value: string;\n\n constructor(private service: FieldService, private cd: ChangeDetectorRef) {\n super();\n }\n\n @ViewChild('input', { read: ElementRef }) input: ElementRef;\n @ViewChild('conf', { read: ElementRef }) conf: ElementRef;\n\n ngOnChanges(changes: SimpleChanges) {\n if (!changes.field.firstChange) {\n this.initConfirm();\n }\n }\n\n ngOnInit() {\n this.initConfirm();\n super.ngOnInit();\n\n if (!this.control.value) this.dummy = '';\n this.value = this.control.value;\n }\n\n initConfirm(): void {\n if (!this.field.ui_options?.no_confirm) {\n this.form.addControl(\n `confirm_${this.field.name}`,\n new FormControl(\n { value: this.field.value, disabled: this.control.disabled },\n this.field.activatable ? [] : this.service.setValidator(this.field, this.control)\n )\n );\n\n this.control.statusChanges.pipe(\n this.takeUntil()\n ).subscribe((state) => {\n if (state === 'DISABLED') {\n this.form.controls[`confirm_${this.field.name}`].disable();\n } else {\n this.form.controls[`confirm_${this.field.name}`].enable();\n }\n });\n }\n\n if (this.field.required && !this.field.value) {\n this.hideDummy(false);\n }\n\n if (this.ConfirmPasswordField) this.ConfirmPasswordField.markAllAsTouched();\n }\n\n ngAfterViewInit(): void {\n if (this.ConfirmPasswordField) {\n const a = fromEvent(this.input.nativeElement, 'blur');\n const c = fromEvent(this.input.nativeElement, 'focus');\n const b = fromEvent(this.conf.nativeElement, 'blur');\n const d = fromEvent(this.conf.nativeElement, 'focus');\n\n merge(a, b, c, d)\n .pipe(\n debounceTime(100),\n pluck('type'),\n tap((res: 'focus' | 'blur') => {\n if (res === 'blur' && (this.isValidField() || this.isCleared())) {\n if ((this.isValidField() && this.isCleared()) || this.isCleared()) {\n this.control.setValue(this.value);\n this.ConfirmPasswordField.setValue(this.value);\n }\n this.isHideDummy = false;\n this.cd.detectChanges();\n }\n })\n )\n .subscribe();\n } else {\n fromEvent(this.input.nativeElement, 'blur')\n .pipe(\n tap(_ => {\n if (this.control.valid || this.value !== '' && this.control.value === '') {\n if ((this.control.valid && this.value !== '' && this.control.value === '') || this.value !== '' && this.control.value === '') {\n this.control.setValue(this.value);\n }\n this.isHideDummy = false;\n this.cd.detectChanges();\n }\n })\n ).subscribe();\n }\n }\n\n isValidField(): boolean {\n return this.control.valid && this.ConfirmPasswordField.valid;\n }\n\n isCleared(): boolean {\n return this.value !== '' && this.control.value === '' && this.ConfirmPasswordField.value === '';\n }\n\n hideDummy(isConfirmField: boolean): void {\n if (this.field.read_only) return null;\n this.isHideDummy = true;\n this.cd.detectChanges();\n\n if (isConfirmField) {\n this.conf.nativeElement.focus();\n } else {\n this.input.nativeElement.focus();\n }\n\n this.control.setValue('');\n if (this.ConfirmPasswordField) this.ConfirmPasswordField.setValue('');\n }\n\n get ConfirmPasswordField(): AbstractControl {\n return this.form.controls['confirm_' + this.field.name];\n }\n\n hasErrorConfirm(name: string) {\n const c = this.ConfirmPasswordField;\n return this.getConfirmPasswordFieldErrors(name) && (c.touched || c.dirty);\n }\n\n confirmPasswordFieldUpdate() {\n this.dummy = this.control.value;\n this.value = this.control.value;\n const confirm = this.ConfirmPasswordField;\n return confirm ? confirm.updateValueAndValidity() : '';\n }\n\n getConfirmPasswordFieldErrors(error: string) {\n const confirm = this.ConfirmPasswordField;\n if (confirm && confirm.errors) {\n return confirm.errors[error];\n }\n return null;\n }\n\n change(value: string) {\n if (value === null) {\n this.hideDummy(false);\n this.cd.detectChanges();\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "div {\n flex: 1;\n\n & mat-form-field {\n flex-basis: 50%;\n }\n\n & mat-form-field:first-child {\n margin-right: 10px;\n }\n}\n", - "styleUrl": "./password.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cd", - "type": "ChangeDetectorRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 37, - "jsdoctags": [ - { - "name": "service", - "type": "FieldService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cd", - "type": "ChangeDetectorRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "FieldDirective", - "implements": [ - "OnInit", - "AfterViewInit", - "OnChanges" - ], - "accessors": { - "ConfirmPasswordField": { - "name": "ConfirmPasswordField", - "getSignature": { - "name": "ConfirmPasswordField", - "type": "", - "returnType": "AbstractControl", - "line": 150 - } - } - }, - "templateData": "
\n \n \n \n \n \n \n
\n\n
\n \n \n Field [{{ field.display_name }}] is required! \n \n \n \n Confirm [{{ field.display_name }}] is required! \n \n Field [{{ field.display_name }}] and confirm [{{ field.display_name }}] does not match!\n \n \n
\n" - }, - { - "name": "PatternComponent", - "id": "component-PatternComponent-df6255474545fbce67d0c49e26727d6f", - "file": "src/app/admin/pattern.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-pattern", - "styleUrls": [ - "../styles/details.scss" - ], - "styles": [], - "template": "\n \n
\n
\n\n \n \n {{ item.title }} \n \n \n \n \n \n {{ title }}\n \n \n \n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "crumbs", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 50 - }, - { - "name": "data", - "defaultValue": "{\n '/admin': { title: 'Hi there!', crumbs: [{ path: '/admin/', name: 'intro' }] },\n '/admin/intro': { title: 'Hi there!', crumbs: [{ path: '/admin/', name: 'intro' }] },\n '/admin/settings': { title: 'Global configuration', crumbs: [{ path: '/admin/settings', name: 'settings' }] },\n '/admin/users': { title: 'User management', crumbs: [{ path: '/admin/users', name: 'users' }] },\n }", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "optional": false, - "description": "", - "line": 56 - }, - { - "name": "leftMenu", - "defaultValue": "[\n { url: 'intro', title: 'Intro' },\n { url: 'settings', title: 'Settings' },\n { url: 'users', title: 'Users' },\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 51 - }, - { - "name": "title", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 49 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "getContext", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 97, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 67, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnDestroy, OnInit } from '@angular/core';\nimport { NavigationEnd, Router } from '@angular/router';\nimport { ApiService } from '@app/core/api';\nimport { getProfileSelector, settingsSave, State } from '@app/core/store';\nimport { BaseDirective } from '@app/shared/directives';\nimport { IConfig } from '@app/shared/configuration/types';\nimport { select, Store } from '@ngrx/store';\nimport { exhaustMap, filter } from 'rxjs/operators';\n\n@Component({\n selector: 'app-pattern',\n template: `\n \n \n
\n
\n \n \n \n {{ item.title }} \n \n \n \n \n \n {{ title }}\n \n \n \n \n \n \n \n `,\n styleUrls: ['../styles/details.scss'],\n})\nexport class PatternComponent extends BaseDirective implements OnInit, OnDestroy {\n title = '';\n crumbs = [];\n leftMenu = [\n { url: 'intro', title: 'Intro' },\n { url: 'settings', title: 'Settings' },\n { url: 'users', title: 'Users' },\n ];\n data = {\n '/admin': { title: 'Hi there!', crumbs: [{ path: '/admin/', name: 'intro' }] },\n '/admin/intro': { title: 'Hi there!', crumbs: [{ path: '/admin/', name: 'intro' }] },\n '/admin/settings': { title: 'Global configuration', crumbs: [{ path: '/admin/settings', name: 'settings' }] },\n '/admin/users': { title: 'User management', crumbs: [{ path: '/admin/users', name: 'users' }] },\n };\n\n constructor(private store: Store, private api: ApiService, private router: Router) {\n super();\n }\n\n ngOnInit() {\n this.getContext(this.router.routerState.snapshot.url);\n\n this.router.events\n .pipe(\n filter((e) => e instanceof NavigationEnd),\n this.takeUntil()\n )\n .subscribe((e: NavigationEnd) => this.getContext(e.url));\n\n // auto-save and flag in to profile\n this.store\n .pipe(\n select(getProfileSelector),\n filter((p) => p.username === 'admin' && !p.profile.settingsSaved),\n exhaustMap(() =>\n this.api.get('/api/v1/adcm/1/config/current/?noview').pipe(\n exhaustMap((c) => {\n const config = c.config;\n const global = config['global'] || {};\n global.adcm_url = global.adcm_url || `${location.protocol}//${location.host}`;\n return this.api.post('/api/v1/adcm/1/config/history/', c);\n })\n )\n ),\n this.takeUntil()\n )\n .subscribe(() => this.store.dispatch(settingsSave({ isSet: true })));\n }\n\n getContext(url: string) {\n const a = this.data[url];\n this.title = a.title;\n this.crumbs = a.crumbs;\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"node_modules/@angular/material/theming\";\n\n:host {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\nmat-drawer {\n min-width: 240px;\n background-color: transparent;\n padding-left: 10px;\n}\n\n.mat-card {\n flex: 1;\n padding: 10px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n & .mat-card-header {\n min-height: 40px;\n padding: 6px 10px 0;\n\n & .mat-card-title {\n font-size: 26px;\n }\n }\n\n .mat-card-content {\n display: flex;\n flex: 1;\n overflow: auto;\n }\n}\n\n.mat-toolbar {\n height: auto;\n min-height: 50px;\n}\n\n.issue-warning {\n width: 40px;\n height: 40px;\n position: relative;\n cursor: pointer;\n\n .mat-icon {\n margin: 8px 0 0 8px;\n }\n\n div {\n width: 40px;\n height: 40px;\n position: absolute;\n background: mat-color($mat-orange, 500);\n border-radius: 20px;\n top: 0;\n opacity: 0;\n animation: ripple 2s infinite ease-in-out;\n }\n}\n\n\n@keyframes ripple {\n 0% {\n opacity: .5;\n }\n\n 100% {\n opacity: 0;\n }\n}\n", - "styleUrl": "../styles/details.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 61, - "jsdoctags": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "OnInit", - "OnDestroy" - ] - }, - { - "name": "PopoverComponent", - "id": "component-PopoverComponent-3ff4f7f4944c2f64226e4c300903ecf2", - "file": "src/app/components/popover/popover.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-popover", - "styleUrls": [ - "./popover.component.scss" - ], - "styles": [], - "template": "
\n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "component", - "deprecated": false, - "deprecationMessage": "", - "line": 32, - "type": "Type" - }, - { - "name": "data", - "defaultValue": "{}", - "deprecated": false, - "deprecationMessage": "", - "line": 33, - "type": "PopoverInput" - }, - { - "name": "event", - "deprecated": false, - "deprecationMessage": "", - "line": 34, - "type": "PopoverEventFunc" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "container", - "deprecated": false, - "deprecationMessage": "", - "type": "ViewContainerRef", - "optional": false, - "description": "", - "line": 29, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'container', {read: ViewContainerRef}" - } - ] - }, - { - "name": "containerRef", - "deprecated": false, - "deprecationMessage": "", - "type": "ComponentRef", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "right", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 40, - "decorators": [ - { - "name": "HostBinding", - "stringifiedArguments": "'style.right'" - } - ] - } - ], - "methodsClass": [ - { - "name": "click", - "args": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 36, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'click', ['$event']" - } - ], - "jsdoctags": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngAfterViewInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 47, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [ - { - "name": "style.right", - "deprecated": false, - "deprecationMessage": "", - "line": 40, - "type": "string" - } - ], - "hostListeners": [ - { - "name": "click", - "args": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "argsDecorator": [ - "$event" - ], - "deprecated": false, - "deprecationMessage": "", - "line": 36 - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import {\n Component,\n ViewChild,\n ViewContainerRef,\n ComponentRef,\n Input,\n ComponentFactory,\n ComponentFactoryResolver,\n AfterViewInit,\n Type,\n HostListener, ElementRef, HostBinding,\n} from '@angular/core';\nimport { EventHelper } from '@adwp-ui/widgets';\n\nimport { PopoverContentDirective, PopoverEventFunc } from '@app/abstract-directives/popover-content.directive';\nimport { PopoverInput } from '@app/directives/popover.directive';\n\n@Component({\n selector: 'app-popover',\n template: `\n
\n \n
\n `,\n styleUrls: ['./popover.component.scss']\n})\nexport class PopoverComponent implements AfterViewInit {\n\n @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;\n containerRef: ComponentRef;\n\n @Input() component: Type;\n @Input() data: PopoverInput = {};\n @Input() event: PopoverEventFunc;\n\n @HostListener('click', ['$event']) click(event: MouseEvent) {\n EventHelper.stopPropagation(event);\n }\n\n @HostBinding('style.right') right: string;\n\n constructor(\n private componentFactoryResolver: ComponentFactoryResolver,\n private elementRef: ElementRef,\n ) {}\n\n ngAfterViewInit() {\n setTimeout(() => {\n const factory: ComponentFactory = this.componentFactoryResolver.resolveComponentFactory(this.component);\n this.container.clear();\n this.containerRef = this.container.createComponent(factory);\n this.containerRef.instance.data = this.data;\n this.containerRef.instance.event = this.event;\n setTimeout(() => {\n const left = document.documentElement.clientWidth - (this.elementRef.nativeElement.offsetLeft + this.elementRef.nativeElement.offsetWidth);\n if (left < 0) {\n this.right = `0px`;\n }\n });\n });\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n line-height: normal;\n text-align: left;\n font-family: Roboto, \"Helvetica Neue\", sans-serif;\n color: #fff;\n font-size: 14px;\n position: absolute;\n display: block;\n border: solid 1px #455A64;\n padding: 0;\n background-color: #37474F;\n border-radius: 5px;\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),\n 0px 2px 2px 0px rgba(0, 0, 0, 0.14),\n 0px 1px 5px 0px rgba(0, 0, 0, 0.12);\n height: auto;\n z-index: 1100;\n overflow: auto;\n box-sizing: content-box;\n cursor: auto;\n}\n\n.container {\n margin: 8px 14px;\n box-sizing: content-box;\n width: auto !important;\n}\n", - "styleUrl": "./popover.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "elementRef", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 40, - "jsdoctags": [ - { - "name": "componentFactoryResolver", - "type": "ComponentFactoryResolver", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "elementRef", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "AfterViewInit" - ] - }, - { - "name": "ProfileComponent", - "id": "component-ProfileComponent-867ee8014831c2a9d971522f910b211b", - "file": "src/app/main/profile/profile.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-profile", - "styleUrls": [], - "styles": [ - ":host {flex: 1 }", - ".container { padding-top: 40px; }", - "hr { margin: 40px 0; border: 0; border-top: dashed 1px rgb(140, 140, 140); }", - "h3, h4, h5 { font-weight: normal; }" - ], - "template": "
\n
\n

\n You are authorized as [ {{ user.username }} ]\n

\n
\n
\n

Change Password

\n \n \n \n  \n \n \n \n  \n \n
\n
\n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "cpForm", - "defaultValue": "new FormGroup({\n password: new FormControl('', Validators.required),\n cpassword: new FormControl('', Validators.required),\n })", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 69 - }, - { - "name": "link", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 66 - }, - { - "name": "user$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 67 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "changePassword", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 84, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 78, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnDestroy, OnInit } from '@angular/core';\nimport { FormControl, FormGroup, Validators } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { Observable } from 'rxjs';\n\nimport { getProfileSelector, ProfileService, ProfileState } from '@app/core/store';\nimport { BaseDirective } from '@app/shared/directives';\n\n@Component({\n selector: 'app-profile',\n template: `\n
\n
\n

\n You are authorized as [ {{ user.username }} ]\n

\n
\n
\n

Change Password

\n \n \n \n  \n \n \n \n  \n \n
\n
\n
\n
\n `,\n styles: [\n ':host {flex: 1 }',\n '.container { padding-top: 40px; }',\n 'hr { margin: 40px 0; border: 0; border-top: dashed 1px rgb(140, 140, 140); }',\n 'h3, h4, h5 { font-weight: normal; }',\n ],\n})\nexport class ProfileComponent extends BaseDirective implements OnInit, OnDestroy {\n link: string;\n user$: Observable;\n\n cpForm = new FormGroup({\n password: new FormControl('', Validators.required),\n cpassword: new FormControl('', Validators.required),\n });\n\n constructor(private router: Router, private store: Store, private service: ProfileService) {\n super();\n }\n\n ngOnInit() {\n this.user$ = this.store.select(getProfileSelector).pipe(\n this.takeUntil()\n );\n }\n\n changePassword() {\n const password = this.cpForm.get('password').value;\n this.service.setPassword(password).subscribe(() => this.router.navigate(['/login']));\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {flex: 1 }\n.container { padding-top: 40px; }\nhr { margin: 40px 0; border: 0; border-top: dashed 1px rgb(140, 140, 140); }\nh3, h4, h5 { font-weight: normal; }\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ProfileService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 72, - "jsdoctags": [ - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ProfileService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "OnInit", - "OnDestroy" - ] - }, - { - "name": "ProgressComponent", - "id": "component-ProgressComponent-4e47a32ca945d3ebe7ed8cacb035c729", - "file": "src/app/main/progress.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-progress", - "styleUrls": [], - "styles": [ - ".progress-bar {position: absolute;width: 100%;height: 3px;z-index: 3;}" - ], - "template": "\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "show$", - "defaultValue": "of(false)", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 29 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\nimport { PreloaderService } from '@app/core/services';\nimport { Observable, of } from 'rxjs';\nimport { delay } from 'rxjs/operators';\n\n@Component({\n selector: 'app-progress',\n template: `\n \n `,\n styles: ['.progress-bar {position: absolute;width: 100%;height: 3px;z-index: 3;}'],\n})\nexport class ProgressComponent implements OnInit {\n show$: Observable = of(false);\n constructor(private preloader: PreloaderService) {}\n ngOnInit() {\n this.show$ = this.preloader.active$.pipe(delay(1));\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ".progress-bar {position: absolute;width: 100%;height: 3px;z-index: 3;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "preloader", - "type": "PreloaderService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 29, - "jsdoctags": [ - { - "name": "preloader", - "type": "PreloaderService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "ProviderComponent", - "id": "component-ProviderComponent-001d736e2901a12141c44680d731e893", - "file": "src/app/shared/add-component/provider.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-add-provider", - "styleUrls": [], - "styles": [ - ".row {display: flex;}" - ], - "template": "\n \n \n \n \n \n \n \n
\n \n \n \n Hostprovider name is required \n \n
\n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "displayMode", - "defaultValue": "DisplayMode.default", - "deprecated": false, - "deprecationMessage": "", - "line": 52, - "type": "DisplayMode" - } - ], - "outputsClass": [ - { - "name": "cancel", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 53, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "prototype", - "deprecated": false, - "deprecationMessage": "", - "type": "StackBase", - "optional": false, - "description": "", - "line": 51, - "modifierKind": [ - 120 - ] - }, - { - "name": "sgn", - "deprecated": false, - "deprecationMessage": "", - "type": "Subscription", - "optional": false, - "description": "", - "line": 50 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 27, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "IAddService", - "optional": false, - "description": "", - "line": 26, - "decorators": [ - { - "name": "Inject", - "stringifiedArguments": "ADD_SERVICE_PROVIDER" - } - ], - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 55, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "prototypeChanged", - "args": [ - { - "name": "event", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 64, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "StackBase", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "save", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 68, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "onCancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, OnInit, EventEmitter, Output, OnDestroy } from '@angular/core';\nimport { Subscription } from 'rxjs';\n\nimport { clearEmptyField, Provider, StackBase } from '@app/core/types';\nimport { BaseFormDirective } from './base-form.directive';\n\nexport enum DisplayMode {\n default,\n inHost,\n noCluster\n}\n\n@Component({\n selector: 'app-add-provider',\n template: `\n \n \n \n \n \n \n \n \n
\n \n \n \n Hostprovider name is required \n \n
\n
\n
\n `,\n styles: ['.row {display: flex;}'],\n})\nexport class ProviderComponent extends BaseFormDirective implements OnInit, OnDestroy {\n sgn: Subscription;\n private prototype: StackBase;\n @Input() displayMode: DisplayMode = DisplayMode.default;\n @Output() cancel = new EventEmitter();\n\n ngOnInit() {\n this.form = this.service.model('provider').form;\n this.sgn = this.service.genName(this.form);\n }\n\n ngOnDestroy() {\n this.sgn.unsubscribe();\n }\n\n prototypeChanged(event: StackBase) {\n this.prototype = event;\n }\n\n save() {\n const data = clearEmptyField(this.form.value);\n this.service\n .add(data, 'provider', this.prototype)\n .pipe(this.takeUntil())\n .subscribe((x) => {\n if (this.displayMode === 0) this.onCancel();\n else {\n this.form.reset();\n this.cancel.emit(x.id);\n }\n });\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ".row {display: flex;}\n", - "extends": "BaseFormDirective", - "implements": [ - "OnInit", - "OnDestroy" - ] - }, - { - "name": "ProviderDetailsComponent", - "id": "component-ProviderDetailsComponent-0e457d3bb311fc9c56259f818a6843e0", - "file": "src/app/components/hostprovider/provider-details/provider-details.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-provider-details", - "styleUrls": [ - "../../../styles/details.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/details.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityParam", - "defaultValue": "'provider'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "leftMenu", - "defaultValue": "[\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.HostProvider, 'provider'),\n DetailsFactory.labelMenuItem('Configuration groups', 'group_config'),\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 14, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "subjectService", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityService", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 121, - 125 - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "entityReceived", - "args": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Injector } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\n\nimport { DetailsFactory } from '@app/factories/details.factory';\nimport { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive';\nimport { Provider } from '@app/core/types';\nimport { SocketState } from '@app/core/store';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ChannelService } from '@app/core/services';\nimport { ProviderService } from '@app/services/provider.service';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n@Component({\n selector: 'app-provider-details',\n templateUrl: '../../../templates/details.html',\n styleUrls: ['../../../styles/details.scss']\n})\nexport class ProviderDetailsComponent extends DetailAbstractDirective {\n\n entityParam = 'provider';\n\n leftMenu = [\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.HostProvider, 'provider'),\n DetailsFactory.labelMenuItem('Configuration groups', 'group_config'),\n ];\n\n constructor(\n socket: Store,\n protected route: ActivatedRoute,\n protected service: ClusterService,\n protected channel: ChannelService,\n protected store: Store,\n injector: Injector,\n protected subjectService: ProviderService,\n ) {\n super(socket, route, service, channel, store, injector);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"node_modules/@angular/material/theming\";\n\n:host {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\nmat-drawer {\n min-width: 240px;\n background-color: transparent;\n padding-left: 10px;\n}\n\n.mat-card {\n flex: 1;\n padding: 10px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n & .mat-card-header {\n min-height: 40px;\n padding: 6px 10px 0;\n\n & .mat-card-title {\n font-size: 26px;\n }\n }\n\n .mat-card-content {\n display: flex;\n flex: 1;\n overflow: auto;\n }\n}\n\n.mat-toolbar {\n height: auto;\n min-height: 50px;\n}\n\n.issue-warning {\n width: 40px;\n height: 40px;\n position: relative;\n cursor: pointer;\n\n .mat-icon {\n margin: 8px 0 0 8px;\n }\n\n div {\n width: 40px;\n height: 40px;\n position: absolute;\n background: mat-color($mat-orange, 500);\n border-radius: 20px;\n top: 0;\n opacity: 0;\n animation: ripple 2s infinite ease-in-out;\n }\n}\n\n\n@keyframes ripple {\n 0% {\n opacity: .5;\n }\n\n 100% {\n opacity: 0;\n }\n}\n", - "styleUrl": "../../../styles/details.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "subjectService", - "type": "ProviderService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 27, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "subjectService", - "type": "ProviderService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "DetailAbstractDirective", - "templateData": "\n\n \n\n\n\n\n \n \n \n \n \n \n \n {{ currentName }}\n \n \n \n \n \n \n \n \n \n \n\n" - }, - { - "name": "RootComponent", - "id": "component-RootComponent-0d7d1367306549fa685c589a9cbaa72d", - "file": "src/app/shared/configuration/scheme/root.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-root-scheme", - "styleUrls": [ - "./root.component.scss" - ], - "styles": [], - "templateUrl": [ - "./root.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 25, - "type": "FormGroup | FormArray" - }, - { - "name": "isReadOnly", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 28, - "type": "boolean" - }, - { - "name": "options", - "deprecated": false, - "deprecationMessage": "", - "line": 26, - "type": "IYContainer | IYField" - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "line": 27, - "type": "TValue" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "controls", - "defaultValue": "[]", - "deprecated": false, - "deprecationMessage": "", - "type": "IControl[]", - "optional": false, - "description": "", - "line": 30 - } - ], - "methodsClass": [ - { - "name": "add", - "args": [ - { - "name": "v", - "type": "[string, ]", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "['', '']" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 56, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "v", - "type": "[string, ]", - "deprecated": false, - "deprecationMessage": "", - "defaultValue": "['', '']", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "init", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 34, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 43, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "reload", - "args": [ - { - "name": "value", - "type": "TValue", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 47, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "value", - "type": "TValue", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "remove", - "args": [ - { - "name": "name", - "type": "string | number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string | number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "showControls", - "args": [], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 65, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, OnInit } from '@angular/core';\nimport { FormArray, FormGroup } from '@angular/forms';\n\nimport { TNReq, TValue } from '../types';\nimport { IYContainer, IYField } from '../yspec/yspec.service';\nimport { IControl, IValue, SchemeService } from './scheme.service';\n\n@Component({\n selector: 'app-root-scheme',\n templateUrl: './root.component.html',\n styleUrls: ['./root.component.scss'],\n})\nexport class RootComponent implements OnInit {\n @Input() form: FormGroup | FormArray;\n @Input() options: IYContainer | IYField;\n @Input() value: TValue;\n @Input() isReadOnly = false;\n\n controls: IControl[] = [];\n\n constructor(private scheme: SchemeService) {}\n\n init() {\n if (this.value) {\n if (this.options.type === 'list' && Array.isArray(this.value)) (this.value as IValue[]).map((x, i) => this.add(['', x]));\n else if (typeof this.value === 'object') Object.keys(this.value).map((x) => this.add([x, this.value[x]]));\n } else if (this.options.type === 'dict' && Array.isArray(this.options.options)) {\n this.options.options.map((x) => this.add([x.name, '']));\n }\n }\n\n ngOnInit(): void {\n this.init();\n }\n\n reload(value: TValue) {\n this.value = value;\n this.controls = [];\n if (Array.isArray(this.form.controls)) {\n this.form.controls.forEach((v, i) => (this.form as FormArray).removeAt(i));\n }\n this.init();\n }\n\n add(v: [string, IValue | TValue] = ['', '']) {\n const [name, value] = v;\n const flag = (this.rules as IYContainer).type === 'dict';\n const item = flag\n ? this.scheme.addControlsDict(name, value, this.form as FormArray, this.itemRules as IYContainer[])\n : this.scheme.addControls(name, value, this.form, this.rules, this.options.type as TNReq);\n this.controls = [...this.controls, item];\n }\n\n showControls() {\n return !this.isReadOnly && (this.options.type === 'list' || this.options.type === 'dict');\n }\n\n remove(name: string | number) {\n if (Array.isArray(this.form.controls)) {\n (this.form as FormArray).removeAt(+name);\n this.controls = this.controls.filter((a, i) => (a.name ? a.name !== name : i !== +name));\n }\n }\n\n get rules(): IYField | IYContainer | (IYField | IYContainer)[] {\n if ('options' in this.options) return this.options.options;\n else return this.options;\n }\n\n get itemRules(): (IYField | IYContainer)[] {\n return (this.rules as IYContainer).options as (IYField | IYContainer)[];\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n display: block;\n width: 100%;\n margin-bottom: 20px;\n\n & div.label {\n display: flex;\n align-items: center;\n justify-content: space-between\n }\n\n & div.content {\n margin-left: 10px;\n\n & .item-iteration.dif:nth-child(even) {\n background-color: #545454;\n }\n\n & .item-iteration {\n display: flex;\n\n &>div {\n flex: 1;\n }\n }\n\n & .remote-btn {\n align-self: center;\n margin-left: 10px;\n }\n }\n}\n", - "styleUrl": "./root.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "scheme", - "type": "SchemeService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 30, - "jsdoctags": [ - { - "name": "scheme", - "type": "SchemeService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ], - "accessors": { - "rules": { - "name": "rules", - "getSignature": { - "name": "rules", - "type": "", - "returnType": "IYField | IYContainer | []", - "line": 76 - } - }, - "itemRules": { - "name": "itemRules", - "getSignature": { - "name": "itemRules", - "type": "[]", - "returnType": "[]", - "line": 81 - } - } - }, - "templateData": "
\n \n \n
\n
\n \n
\n\n \n \n\n \n \n \n \n\n \n
\n
\n
\n" - }, - { - "name": "SchemeComponent", - "id": "component-SchemeComponent-c78387c61af573a74288850d9226c9ed", - "file": "src/app/shared/configuration/scheme/scheme.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-scheme", - "styleUrls": [], - "styles": [ - "\n div.main {\n flex: 1;\n }\n .error {\n display: block;\n margin: -20px 0 6px 10px;\n }\n " - ], - "template": "
\n Field [{{ field.display_name }}] is required!\n
", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "AbstractControl", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "root", - "deprecated": false, - "deprecationMessage": "", - "type": "RootComponent", - "optional": false, - "description": "", - "line": 43, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'root'" - } - ] - }, - { - "name": "rules", - "deprecated": false, - "deprecationMessage": "", - "type": "IYField | IYContainer", - "optional": false, - "description": "", - "line": 40 - } - ], - "methodsClass": [ - { - "name": "ngOnChanges", - "args": [ - { - "name": "changes", - "type": "SimpleChanges", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 53, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\n\nafter saving, the link between the form and the current (form) is lost\nTODO: eliminate\n", - "description": "

after saving, the link between the form and the current (form) is lost\nTODO: eliminate

\n", - "jsdoctags": [ - { - "name": "changes", - "type": "SimpleChanges", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 60, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "reload", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 69, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\nthis is using for restore default value", - "description": "

this is using for restore default value

\n" - }, - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "FieldDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';\nimport { AbstractControl } from '@angular/forms';\nimport { FieldDirective } from '@app/shared/form-elements/field.directive';\n\nimport { TNReq } from '../types';\nimport { IYContainer, IYField, YspecService } from '../yspec/yspec.service';\nimport { RootComponent } from './root.component';\nimport { SchemeService } from './scheme.service';\n\n@Component({\n selector: 'app-scheme',\n styles: [\n `\n div.main {\n flex: 1;\n }\n .error {\n display: block;\n margin: -20px 0 6px 10px;\n }\n `,\n ],\n template: `
\n \n Field [{{ field.display_name }}] is required!\n
`,\n})\nexport class SchemeComponent extends FieldDirective implements OnInit, OnChanges {\n rules: IYField | IYContainer;\n current: AbstractControl;\n\n @ViewChild('root') root: RootComponent;\n\n constructor(private yspec: YspecService, private scheme: SchemeService) {\n super();\n }\n\n /**\n * after saving, the link between the form and the current (form) is lost\n * TODO: eliminate\n */\n ngOnChanges(changes: SimpleChanges): void {\n if (!changes.form.firstChange) {\n this.field.limits.rules = this.rules;\n this.form.setControl(this.field.name, this.current);\n }\n }\n\n ngOnInit() {\n this.yspec.Root = this.field.limits.yspec;\n this.rules = this.yspec.build();\n this.field.limits.rules = this.rules;\n this.rules.name = '';\n this.current = this.scheme.setCurrentForm(this.rules.type as TNReq, this.form, this.field);\n }\n\n /** this is using for restore default value */\n reload() {\n this.root.reload(this.field.default);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n div.main {\n flex: 1;\n }\n .error {\n display: block;\n margin: -20px 0 6px 10px;\n }\n \n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "yspec", - "type": "YspecService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "scheme", - "type": "SchemeService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 43, - "jsdoctags": [ - { - "name": "yspec", - "type": "YspecService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "scheme", - "type": "SchemeService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "FieldDirective", - "implements": [ - "OnInit", - "OnChanges" - ] - }, - { - "name": "SearchComponent", - "id": "component-SearchComponent-9090bcee97f1cf88ae7298306e1fff12", - "file": "src/app/shared/configuration/tools/search.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-search", - "styleUrls": [], - "styles": [ - "mat-form-field {flex: auto;margin: 0 10px;font-size: 14px;}" - ], - "template": "\n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [ - { - "name": "pattern", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 32, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "search", - "defaultValue": "new FormControl()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 38, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';\nimport { FormControl } from '@angular/forms';\nimport { BaseDirective } from '@app/shared/directives/base.directive';\nimport { debounceTime, distinctUntilChanged } from 'rxjs/operators';\n\n@Component({\n selector: 'app-search',\n template: `\n \n \n \n \n \n `,\n styles: ['mat-form-field {flex: auto;margin: 0 10px;font-size: 14px;}'],\n})\nexport class SearchComponent extends BaseDirective implements OnInit, OnDestroy {\n search = new FormControl();\n @Output() pattern = new EventEmitter();\n\n constructor() {\n super();\n }\n\n ngOnInit() {\n this.search.valueChanges.pipe(this.takeUntil(), debounceTime(300), distinctUntilChanged()).subscribe((value) => this.pattern.emit(value));\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "mat-form-field {flex: auto;margin: 0 10px;font-size: 14px;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [], - "line": 32 - }, - "extends": "BaseDirective", - "implements": [ - "OnInit", - "OnDestroy" - ] - }, - { - "name": "SecretTextComponent", - "id": "component-SecretTextComponent-b449e366b5f5d18ae217c89db186eb3f", - "file": "src/app/shared/form-elements/secret-text/secret-text.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-fields-secret-text", - "styleUrls": [], - "styles": [], - "templateUrl": [ - "./secret-text.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "dummy", - "defaultValue": "'********'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 22 - }, - { - "name": "dummyControl", - "deprecated": false, - "deprecationMessage": "", - "type": "FormControl", - "optional": false, - "description": "", - "line": 23 - }, - { - "name": "value", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 24 - } - ], - "methodsClass": [ - { - "name": "_initDummyControl", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 43, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 120 - ] - }, - { - "name": "ngOnChanges", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 26, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "onBlur", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 34, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onFocus", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "FieldDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnChanges, OnInit, } from '@angular/core';\n\nimport { FieldDirective } from '../field.directive';\nimport { FormControl, Validators } from '@angular/forms';\n\n@Component({\n selector: 'app-fields-secret-text',\n templateUrl: './secret-text.component.html',\n})\nexport class SecretTextComponent extends FieldDirective implements OnInit, OnChanges {\n dummy = '********';\n dummyControl: FormControl;\n value: string;\n\n ngOnChanges(): void {\n this.value = this.field.value as string;\n }\n\n ngOnInit(): void {\n this._initDummyControl();\n }\n\n onBlur(): void {\n this.control.setValue(this.dummyControl.value || this.value);\n this.dummyControl.setValue(this.dummyControl.value ? this.dummy : '');\n }\n\n onFocus(): void {\n this.dummyControl.setValue(null);\n }\n\n private _initDummyControl(): void {\n this.dummyControl = new FormControl(\n { value: this.control.value ? this.dummy : '', disabled: this.control.disabled },\n Validators.compose(this.field.required ? [Validators.required] : [])\n );\n this.dummyControl.markAllAsTouched();\n\n\n this.control.statusChanges.pipe(this.takeUntil()).subscribe((status) => {\n if (status === 'VALID') {\n this.dummyControl.enable();\n } else if (status === 'DISABLED') {\n this.dummyControl.disable();\n }\n });\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": "FieldDirective", - "implements": [ - "OnInit", - "OnChanges" - ], - "templateData": "\n \n \n \n \n\n" - }, - { - "name": "ServiceComponent", - "id": "component-ServiceComponent-eb48b86de9d2c7cd6a6d972d692aa5b3", - "file": "src/app/shared/add-component/service.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-add-service", - "styleUrls": [], - "styles": [], - "template": "\n \n All\n \n {{ proto.name }}\n \n \n \n\n\n

\n \n There are no new services. You cluster already has all of them.\n \n

\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "listServices", - "deprecated": false, - "deprecationMessage": "", - "type": "MatSelectionList", - "optional": false, - "description": "", - "line": 43, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'listServices'" - } - ], - "modifierKind": [ - 120 - ] - }, - { - "name": "options$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 27, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "IAddService", - "optional": false, - "description": "", - "line": 26, - "decorators": [ - { - "name": "Inject", - "stringifiedArguments": "ADD_SERVICE_PROVIDER" - } - ], - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 45, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "save", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 57, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - }, - { - "name": "selectAll", - "args": [ - { - "name": "e", - "type": "MatSelectionListChange", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 50, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "e", - "type": "MatSelectionListChange", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "onCancel", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseFormDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit, ViewChild } from '@angular/core';\nimport { MatSelectionList, MatSelectionListChange } from '@angular/material/list';\nimport { SelectOption } from '@app/core/types';\nimport { Observable } from 'rxjs';\n\nimport { BaseFormDirective } from './base-form.directive';\n\n@Component({\n selector: 'app-add-service',\n template: `\n \n \n All\n \n {{ proto.name }}\n \n \n \n \n \n

\n \n There are no new services. You cluster already has all of them.\n \n

\n
\n `\n})\nexport class ServiceComponent extends BaseFormDirective implements OnInit {\n options$: Observable;\n @ViewChild('listServices')\n private listServices: MatSelectionList;\n\n ngOnInit() {\n this.options$ = this.service.getProtoServiceForCurrentCluster();\n }\n\n\n selectAll(e: MatSelectionListChange) {\n if (!e.option.value) {\n if (e.option.selected) this.listServices.selectAll();\n else this.listServices.deselectAll();\n }\n }\n\n save() {\n const result = this.listServices.selectedOptions.selected.filter(a => a.value).map(a => ({ prototype_id: +a.value.id }));\n this.service\n .addService(result)\n .pipe(this.takeUntil())\n .subscribe(() => this.dialog.closeAll());\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": "BaseFormDirective", - "implements": [ - "OnInit" - ] - }, - { - "name": "ServiceComponentDetailsComponent", - "id": "component-ServiceComponentDetailsComponent-c7897d1dd368093f90b7f0253788dd97", - "file": "src/app/components/service-component/service-component-details/service-component-details.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-service-component-details", - "styleUrls": [ - "../../../styles/details.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/details.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityParam", - "defaultValue": "'servicecomponent'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "leftMenu", - "defaultValue": "[\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.ServiceComponent, 'component'),\n DetailsFactory.labelMenuItem('Configuration groups', 'group_config'),\n DetailsFactory.statusMenuItem('Status', 'status', 'component'),\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 14, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "subjectService", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityService", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 121, - 125 - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "entityReceived", - "args": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Injector } from '@angular/core';\nimport { Store } from '@ngrx/store';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive';\nimport { SocketState } from '@app/core/store';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ChannelService } from '@app/core/services';\nimport { ServiceComponentService } from '@app/services/service-component.service';\nimport { DetailsFactory } from '@app/factories/details.factory';\nimport { IServiceComponent } from '@app/models/service-component';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n@Component({\n selector: 'app-service-component-details',\n templateUrl: '../../../templates/details.html',\n styleUrls: ['../../../styles/details.scss']\n})\nexport class ServiceComponentDetailsComponent extends DetailAbstractDirective {\n\n entityParam = 'servicecomponent';\n\n leftMenu = [\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.ServiceComponent, 'component'),\n DetailsFactory.labelMenuItem('Configuration groups', 'group_config'),\n DetailsFactory.statusMenuItem('Status', 'status', 'component'),\n ];\n\n constructor(\n socket: Store,\n protected route: ActivatedRoute,\n protected service: ClusterService,\n protected channel: ChannelService,\n protected store: Store,\n injector: Injector,\n protected subjectService: ServiceComponentService,\n ) {\n super(socket, route, service, channel, store, injector);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"node_modules/@angular/material/theming\";\n\n:host {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\nmat-drawer {\n min-width: 240px;\n background-color: transparent;\n padding-left: 10px;\n}\n\n.mat-card {\n flex: 1;\n padding: 10px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n & .mat-card-header {\n min-height: 40px;\n padding: 6px 10px 0;\n\n & .mat-card-title {\n font-size: 26px;\n }\n }\n\n .mat-card-content {\n display: flex;\n flex: 1;\n overflow: auto;\n }\n}\n\n.mat-toolbar {\n height: auto;\n min-height: 50px;\n}\n\n.issue-warning {\n width: 40px;\n height: 40px;\n position: relative;\n cursor: pointer;\n\n .mat-icon {\n margin: 8px 0 0 8px;\n }\n\n div {\n width: 40px;\n height: 40px;\n position: absolute;\n background: mat-color($mat-orange, 500);\n border-radius: 20px;\n top: 0;\n opacity: 0;\n animation: ripple 2s infinite ease-in-out;\n }\n}\n\n\n@keyframes ripple {\n 0% {\n opacity: .5;\n }\n\n 100% {\n opacity: 0;\n }\n}\n", - "styleUrl": "../../../styles/details.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "subjectService", - "type": "ServiceComponentService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 28, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "subjectService", - "type": "ServiceComponentService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "DetailAbstractDirective", - "templateData": "\n\n \n\n\n\n\n \n \n \n \n \n \n \n {{ currentName }}\n \n \n \n \n \n \n \n \n \n \n\n" - }, - { - "name": "ServiceComponentsComponent", - "id": "component-ServiceComponentsComponent-44b8d9f4e68707a23a5df732d83c7c26", - "file": "src/app/components/service-component/service-components.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-service-components", - "styleUrls": [], - "styles": [ - "\n :host { flex: 1; }\n " - ], - "template": "\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "eventTypes", - "defaultValue": "[ConcernEventType.ServiceComponent]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 32, - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.nameColumn('display_name'),\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.configColumn(this),\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "type", - "defaultValue": "'servicecomponent'", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 24, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "route", - "deprecated": false, - "deprecationMessage": "", - "type": "ActivatedRoute", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "router", - "deprecated": false, - "deprecationMessage": "", - "type": "Router", - "optional": false, - "description": "", - "line": 23, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { IColumns } from '@adwp-ui/widgets';\nimport { Component } from '@angular/core';\n\nimport { TypeName } from '@app/core/types';\nimport { ListFactory } from '@app/factories/list.factory';\nimport { ConcernListDirective } from '@app/abstract-directives/concern-list.directive';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n@Component({\n selector: 'app-service-components',\n template: `\n \n `,\n styles: [`\n :host { flex: 1; }\n `],\n})\nexport class ServiceComponentsComponent extends ConcernListDirective {\n\n type: TypeName = 'servicecomponent';\n eventTypes = [ConcernEventType.ServiceComponent];\n\n listColumns = [\n ListFactory.nameColumn('display_name'),\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.configColumn(this),\n ] as IColumns;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n :host { flex: 1; }\n \n", - "extends": "ConcernListDirective" - }, - { - "name": "ServiceComponentStatusComponent", - "id": "component-ServiceComponentStatusComponent-c5083b2c8a72cc4f2994a4172e50993c", - "file": "src/app/components/service-component/service-component-status/service-component-status.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-service-component-status", - "styleUrls": [ - "../../../styles/status-tree.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/status-tree.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityService", - "deprecated": false, - "deprecationMessage": "", - "type": "ServiceComponentService", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "entityId", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 24, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "folding", - "deprecated": false, - "deprecationMessage": "", - "type": "Folding", - "optional": false, - "description": "", - "line": 27, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "loading", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "statusTree", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 25, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "tree", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 19, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'tree', {static: false}" - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "eventReceived", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "getEntityIdFromParams", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 56, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "pipeData", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "expandCollapseAll", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 55, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "prepareListeners", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "prepareStatusTree", - "args": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "StatusTreeType", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { fromJS, updateIn } from 'immutable';\n\nimport { StatusAbstractDirective } from '@app/abstract-directives/status.abstract.directive';\nimport { HostComponentStatusTree } from '@app/models/status-tree';\nimport { EventMessage, SocketState } from '@app/core/store';\nimport { ServiceComponentService } from '@app/services/service-component.service';\nimport { IServiceComponent } from '@app/models/service-component';\n\n@Component({\n selector: 'app-service-component-status',\n templateUrl: '../../../templates/status-tree.html',\n styleUrls: ['../../../styles/status-tree.scss']\n})\nexport class ServiceComponentStatusComponent extends StatusAbstractDirective {\n\n constructor(\n protected route: ActivatedRoute,\n protected store: Store,\n public entityService: ServiceComponentService,\n ) {\n super(route, store, entityService);\n }\n\n pipeData(): any {\n return this.entity.cluster_id;\n }\n\n eventReceived(event: EventMessage) {\n let output;\n switch (event.object.type) {\n case 'hostcomponent':\n const componentId = this.statusTree.value.id;\n output = updateIn(fromJS(this.statusTree.value), ['hosts'], (hosts: any[]) =>\n hosts.map(host => {\n if (host.get('id') === event.object.id && componentId === +event.object.details.id) {\n return host.set('status', +event.object.details.value);\n }\n return host;\n })\n );\n this.statusTree.next(output.toJS() as any as HostComponentStatusTree);\n break;\n case 'component':\n output = fromJS(this.statusTree.value);\n if (output.get('id') === event.object.id) {\n output = output.set('status', +event.object.details.value);\n }\n this.statusTree.next(output.toJS() as any as HostComponentStatusTree);\n break;\n }\n }\n\n getEntityIdFromParams(): number {\n return +this.route.parent.snapshot.params.servicecomponent;\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n flex: 1;\n}\n\n.controls {\n position: fixed;\n top: 130px;\n right: 10px;\n\n .notify {\n opacity: 0;\n\n &>span {\n line-height: 24px;\n vertical-align: text-bottom;\n }\n }\n}\n", - "styleUrl": "../../../styles/status-tree.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "entityService", - "type": "ServiceComponentService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 17, - "jsdoctags": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "entityService", - "type": "ServiceComponentService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "StatusAbstractDirective", - "templateData": "\n

Loading...

\n
\n\n\n\n
\n \n
\n\n \n\n
\n" - }, - { - "name": "ServiceDetailsComponent", - "id": "component-ServiceDetailsComponent-606faf1f579ac48a28130e600e925f72", - "file": "src/app/components/service/service-details/service-details.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-service-details", - "styleUrls": [ - "../../../styles/details.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/details.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityParam", - "defaultValue": "'service'", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "leftMenu", - "defaultValue": "[\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.concernMenuItem('Components', 'component', 'host-component', ConcernEventType.Service, 'service'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.Service, 'service'),\n DetailsFactory.labelMenuItem('Configuration groups', 'group_config'),\n DetailsFactory.statusMenuItem('Status', 'status', 'service'),\n DetailsFactory.concernMenuItem('Import', 'import', 'import', ConcernEventType.Service, 'service'),\n ]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 14, - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "subjectService", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityService", - "optional": false, - "description": "", - "line": 17, - "modifierKind": [ - 121, - 125 - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "entityReceived", - "args": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 20, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "entity", - "type": "EntityType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "DetailAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "DetailAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Injector } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\n\nimport { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive';\nimport { Service } from '@app/core/types';\nimport { SocketState } from '@app/core/store';\nimport { ClusterService } from '@app/core/services/cluster.service';\nimport { ChannelService } from '@app/core/services';\nimport { ServiceService } from '@app/services/service.service';\nimport { DetailsFactory } from '@app/factories/details.factory';\nimport { ConcernEventType } from '@app/models/concern/concern-reason';\n\n@Component({\n selector: 'app-service-details',\n templateUrl: '../../../templates/details.html',\n styleUrls: ['../../../styles/details.scss']\n})\nexport class ServiceDetailsComponent extends DetailAbstractDirective {\n\n entityParam = 'service';\n\n leftMenu = [\n DetailsFactory.labelMenuItem('Main', 'main'),\n DetailsFactory.concernMenuItem('Components', 'component', 'host-component', ConcernEventType.Service, 'service'),\n DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.Service, 'service'),\n DetailsFactory.labelMenuItem('Configuration groups', 'group_config'),\n DetailsFactory.statusMenuItem('Status', 'status', 'service'),\n DetailsFactory.concernMenuItem('Import', 'import', 'import', ConcernEventType.Service, 'service'),\n ];\n\n constructor(\n socket: Store,\n protected route: ActivatedRoute,\n protected service: ClusterService,\n protected channel: ChannelService,\n protected store: Store,\n injector: Injector,\n protected subjectService: ServiceService,\n ) {\n super(socket, route, service, channel, store, injector);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "@import \"node_modules/@angular/material/theming\";\n\n:host {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\nmat-drawer {\n min-width: 240px;\n background-color: transparent;\n padding-left: 10px;\n}\n\n.mat-card {\n flex: 1;\n padding: 10px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n & .mat-card-header {\n min-height: 40px;\n padding: 6px 10px 0;\n\n & .mat-card-title {\n font-size: 26px;\n }\n }\n\n .mat-card-content {\n display: flex;\n flex: 1;\n overflow: auto;\n }\n}\n\n.mat-toolbar {\n height: auto;\n min-height: 50px;\n}\n\n.issue-warning {\n width: 40px;\n height: 40px;\n position: relative;\n cursor: pointer;\n\n .mat-icon {\n margin: 8px 0 0 8px;\n }\n\n div {\n width: 40px;\n height: 40px;\n position: absolute;\n background: mat-color($mat-orange, 500);\n border-radius: 20px;\n top: 0;\n opacity: 0;\n animation: ripple 2s infinite ease-in-out;\n }\n}\n\n\n@keyframes ripple {\n 0% {\n opacity: .5;\n }\n\n 100% {\n opacity: 0;\n }\n}\n", - "styleUrl": "../../../styles/details.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "subjectService", - "type": "ServiceService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 30, - "jsdoctags": [ - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "ClusterService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "subjectService", - "type": "ServiceService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "DetailAbstractDirective", - "templateData": "\n\n \n\n\n\n\n \n \n \n \n \n \n \n {{ currentName }}\n \n \n \n \n \n \n \n \n \n \n\n" - }, - { - "name": "ServiceHostComponent", - "id": "component-ServiceHostComponent-4037fbad8829475aec2c39d891679afa", - "file": "src/app/shared/host-components-map/services2hosts/service-host.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-service-host", - "styleUrls": [ - "./service-host.component.scss" - ], - "styles": [], - "templateUrl": [ - "./service-host.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "actionParameters", - "deprecated": false, - "deprecationMessage": "", - "line": 57, - "type": "IActionParameter[]" - }, - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "line": 42, - "type": "literal type" - }, - { - "name": "fixedButton", - "defaultValue": "true", - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "fixed position buttons for the scrolling", - "description": "

fixed position buttons for the scrolling

\n", - "line": 48, - "type": "boolean" - }, - { - "name": "hideButton", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "hide Save button", - "description": "

hide Save button

\n", - "line": 54, - "type": "boolean" - } - ], - "outputsClass": [ - { - "name": "saveResult", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 59, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "form", - "defaultValue": "new FormGroup({})", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 39 - }, - { - "name": "initFlag", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 62 - }, - { - "name": "loadPost", - "defaultValue": "new StatePost()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 33 - }, - { - "name": "saveFlag", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 61 - }, - { - "name": "scrollEventData", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "optional": false, - "description": "", - "line": 64 - }, - { - "name": "service", - "deprecated": false, - "deprecationMessage": "", - "type": "TakeService", - "optional": false, - "description": "", - "line": 82, - "modifierKind": [ - 122 - ] - }, - { - "name": "showSpinner", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "sourceMap", - "defaultValue": "new Map([\n ['host', []],\n ['compo', []],\n ])", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "statePost", - "defaultValue": "new StatePost()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "socket$", - "defaultValue": "this.socket.pipe(this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object))", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 24, - "inheritance": { - "file": "SocketListenerDirective" - } - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "add", - "args": [ - { - "name": "io", - "type": "IEMObject", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 127, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "io", - "type": "IEMObject", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clearHostFromService", - "args": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 194, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clearServiceFromHost", - "args": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 190, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "data", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "init", - "args": [ - { - "name": "raw", - "type": "IRawHosComponent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 174, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "raw", - "type": "IRawHosComponent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "load", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 162, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 90, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "remove", - "args": [ - { - "name": "io", - "type": "IEMObject", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 155, - "deprecated": false, - "deprecationMessage": "", - "rawdescription": "\nhost only", - "description": "

host only

\n", - "jsdoctags": [ - { - "name": "io", - "type": "IEMObject", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "reset", - "args": [], - "optional": false, - "returnType": "this", - "typeParameters": [], - "line": 113, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "restore", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 228, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "save", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 216, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "selectHost", - "args": [ - { - "name": "host", - "type": "HostTile", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 198, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "host", - "type": "HostTile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "selectService", - "args": [ - { - "name": "component", - "type": "CompTile", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 207, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "component", - "type": "CompTile", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "socketListener", - "args": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 100, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "m", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "SocketListenerDirective" - } - }, - { - "name": "update", - "args": [ - { - "name": "em", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 122, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "em", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "startListenSocket", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "SocketListenerDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { ChannelService } from '@app/core/services';\nimport { keyChannelStrim } from '@app/core/services';\nimport { EventMessage, IEMObject, SocketState } from '@app/core/store';\nimport { IActionParameter } from '@app/core/types';\nimport { Store } from '@ngrx/store';\n\nimport { SocketListenerDirective } from '@app/shared/directives';\nimport { getSelected, TakeService } from '../take.service';\nimport { CompTile, HostTile, IRawHosComponent, Post, StatePost, Tile } from '../types';\n\n@Component({\n selector: 'app-service-host',\n templateUrl: './service-host.component.html',\n styleUrls: ['./service-host.component.scss'],\n})\nexport class ServiceHostComponent extends SocketListenerDirective implements OnInit {\n showSpinner = false;\n\n statePost = new StatePost();\n loadPost = new StatePost();\n sourceMap = new Map([\n ['host', []],\n ['compo', []],\n ]);\n\n form = new FormGroup({});\n\n @Input()\n cluster: { id: number; hostcomponent: string };\n\n /**\n * fixed position buttons for the scrolling\n */\n @Input()\n fixedButton = true;\n\n /**\n * hide Save button\n */\n @Input()\n hideButton = false;\n\n @Input()\n actionParameters: IActionParameter[];\n\n @Output() saveResult = new EventEmitter();\n\n saveFlag = false;\n initFlag = false;\n\n scrollEventData: { direct: 1 | -1 | 0; scrollTop: number };\n\n get Hosts(): HostTile[] {\n return this.sourceMap.get('host');\n }\n\n set Hosts(v: HostTile[]) {\n this.sourceMap.set('host', v);\n }\n\n get Components(): CompTile[] {\n return this.sourceMap.get('compo') as CompTile[];\n }\n\n set Components(v: CompTile[]) {\n this.sourceMap.set('compo', v);\n }\n\n constructor(public service: TakeService, private channel: ChannelService, socket: Store) {\n super(socket);\n }\n\n public get noValid() {\n return /*!!this.service.countConstraint */ !this.form.valid || !this.statePost.data.length;\n }\n\n ngOnInit() {\n this.load();\n super.startListenSocket();\n\n this.channel\n .on(keyChannelStrim.scroll)\n .pipe(this.takeUntil())\n .subscribe((e) => (this.scrollEventData = e));\n }\n\n socketListener(m: EventMessage) {\n const isCurrent = (type: string, id: number) => type === 'cluster' && id === this.cluster.id;\n if (\n (m.event === 'change_hostcomponentmap' || m.event === 'change_state') &&\n isCurrent(m.object.type, m.object.id) &&\n !this.saveFlag\n ) {\n this.reset().load();\n }\n if ((m.event === 'add' || m.event === 'remove') && isCurrent(m.object.details.type, +m.object.details.value))\n this.update(m);\n }\n\n reset() {\n this.Hosts = [];\n this.Components = [];\n this.statePost.clear();\n this.loadPost.clear();\n this.form = new FormGroup({});\n return this;\n }\n\n update(em: EventMessage) {\n if (em.event === 'add') this.add(em.object);\n if (em.event === 'remove') this.remove(em.object);\n }\n\n add(io: IEMObject) {\n const { id, type, details } = io;\n if (details.type === 'cluster' && +details.value === this.cluster.id) {\n this.service\n .load(this.cluster.hostcomponent)\n .pipe(this.takeUntil())\n .subscribe((raw: IRawHosComponent) => {\n if (type === 'host')\n this.Hosts = [\n ...this.Hosts,\n ...this.service.fillHost(\n raw.host.map((h) => new HostTile(h)).filter((h) => h.id === id),\n this.actionParameters\n ),\n ];\n if (type === 'service')\n this.Components = [\n ...this.Components,\n ...this.service.fillComponent(\n raw.component.filter((a) => a.service_id === id && this.Components.every((b) => b.id !== a.id)),\n this.actionParameters\n ),\n ];\n });\n }\n }\n\n /** host only */\n remove(io: IEMObject) {\n if (io.type === 'host') {\n const { id } = io;\n this.Hosts = this.Hosts.filter((a) => a.id !== id);\n }\n }\n\n load() {\n if (this.cluster) {\n if (this.initFlag) return;\n this.initFlag = true;\n\n this.service\n .load(this.cluster.hostcomponent)\n .pipe(this.takeUntil())\n .subscribe((raw: IRawHosComponent) => this.init(raw));\n }\n }\n\n init(raw: IRawHosComponent) {\n if (raw.host) this.Hosts = raw.host.map((h) => new HostTile(h));\n\n if (raw.component)\n this.Components = [...this.Components, ...this.service.fillComponent(raw.component, this.actionParameters)];\n\n if (raw.hc) {\n this.initFlag = false;\n this.statePost.update(raw.hc);\n this.loadPost.update(raw.hc);\n this.service.setRelations(raw.hc, this.Components, this.Hosts, this.actionParameters);\n this.service.fillHost(this.Hosts, this.actionParameters);\n }\n this.service.formFill(this.Components, this.Hosts, this.form);\n }\n\n clearServiceFromHost(data: { relation: CompTile; model: HostTile }) {\n this.service.divorce([data.relation, data.model], this.Components, this.Hosts, this.statePost, this.form);\n }\n\n clearHostFromService(data: { relation: HostTile; model: CompTile }) {\n this.service.divorce([data.model, data.relation], this.Components, this.Hosts, this.statePost, this.form);\n }\n\n selectHost(host: HostTile) {\n const stream = {\n linkSource: this.Components,\n link: getSelected(this.Components),\n selected: getSelected(this.Hosts),\n };\n this.service.next(host, stream, this.Components, this.Hosts, this.statePost, this.loadPost, this.form);\n }\n\n selectService(component: CompTile) {\n const stream = {\n linkSource: this.Hosts,\n link: getSelected(this.Hosts),\n selected: getSelected(this.Components),\n };\n this.service.next(component, stream, this.Components, this.Hosts, this.statePost, this.loadPost, this.form);\n }\n\n save() {\n this.saveFlag = true;\n const { id, hostcomponent } = this.cluster;\n this.service.save(id, hostcomponent, this.statePost.data).subscribe((data) => {\n this.loadPost.update(data);\n this.statePost.update(data);\n this.saveResult.emit(data);\n this.saveFlag = false;\n this.channel.next(keyChannelStrim.notifying, 'Successfully saved.');\n });\n }\n\n restore() {\n const ma = (a: Tile): void => {\n a.isSelected = false;\n a.isLink = false;\n a.relations = [];\n };\n\n this.Hosts.forEach(ma);\n this.Components.forEach(ma);\n\n this.statePost.clear();\n this.statePost.update(this.loadPost.data);\n\n this.service.setRelations(this.loadPost.data, this.Components, this.Hosts, this.actionParameters);\n this.form = new FormGroup({});\n this.service.formFill(this.Components, this.Hosts, this.form);\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".holder {\n display: flex;\n justify-content: space-around;\n margin: 10px 0;\n\n\n h3 {\n margin: 10px;\n line-height: 40px;\n display: flex;\n\n .slide-toggle {\n margin-left: 20px;\n }\n }\n\n div {\n padding: 6px;\n flex: 1 0 auto;\n margin: 0 10px;\n }\n}\n\np {\n padding-right: 40px;\n text-align: right;\n}\n\n.wrapper {\n overflow: auto;\n transition-property: margin-top;\n transition-duration: .5s;\n transition-timing-function: ease-out-cubic;\n margin-top: 0px;\n}\n\n.link {\n font-size: 1em;\n}\n\n.controls {\n top: 130px;\n right: 80px;\n\n .notify {\n opacity: 0;\n\n &>span {\n line-height: 24px;\n vertical-align: text-bottom;\n }\n }\n}\n", - "styleUrl": "./service-host.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "TakeService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 80, - "jsdoctags": [ - { - "name": "service", - "type": "TakeService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "channel", - "type": "ChannelService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "socket", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "SocketListenerDirective", - "implements": [ - "OnInit" - ], - "accessors": { - "Hosts": { - "name": "Hosts", - "setSignature": { - "name": "Hosts", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "v", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 70, - "jsdoctags": [ - { - "name": "v", - "type": "HostTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "Hosts", - "type": "[]", - "returnType": "HostTile[]", - "line": 66 - } - }, - "Components": { - "name": "Components", - "setSignature": { - "name": "Components", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "v", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 78, - "jsdoctags": [ - { - "name": "v", - "type": "CompTile[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "Components", - "type": "[]", - "returnType": "CompTile[]", - "line": 74 - } - }, - "noValid": { - "name": "noValid", - "getSignature": { - "name": "noValid", - "type": "", - "returnType": "", - "line": 86 - } - } - }, - "templateData": "
\n \n \n
\n\n
\n
\n

Components

\n
\n
\n Add services on the services page.\n
\n \n \n
\n
\n
\n

Hosts\n \n

\n
\n
\n Add hosts on the hosts page.\n
\n \n \n
\n
\n
\n" - }, - { - "name": "ServicesComponent", - "id": "component-ServicesComponent-c8be3c53591d2994e00e9662997bcc40", - "file": "src/app/components/cluster/services/services.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-services", - "styleUrls": [], - "styles": [ - ":host { flex: 1; }", - ".add-button {position:fixed; right: 20px;top:120px;}" - ], - "template": "Add services\n\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "eventTypes", - "defaultValue": "[ConcernEventType.Service]", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "optional": false, - "description": "", - "line": 33, - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "listColumns", - "defaultValue": "[\n ListFactory.nameColumn('display_name'),\n {\n label: 'Version',\n value: (row) => row.version,\n },\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.importColumn(this),\n ListFactory.configColumn(this),\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 35 - }, - { - "name": "type", - "defaultValue": "'service2cluster'", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 24, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "route", - "deprecated": false, - "deprecationMessage": "", - "type": "ActivatedRoute", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - }, - { - "name": "router", - "deprecated": false, - "deprecationMessage": "", - "type": "Router", - "optional": false, - "description": "", - "line": 23, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 30, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "ConcernListDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { IColumns } from '@adwp-ui/widgets';\n\nimport { TypeName } from '@app/core/types';\nimport { ListFactory } from '../../../factories/list.factory';\nimport { IClusterService } from '@app/models/cluster-service';\nimport { ConcernListDirective } from '@app/abstract-directives/concern-list.directive';\nimport { ConcernEventType } from '../../../models/concern/concern-reason';\n\n@Component({\n selector: 'app-services',\n template: `\n Add services\n\n \n `,\n styles: [':host { flex: 1; }', '.add-button {position:fixed; right: 20px;top:120px;}'],\n})\nexport class ServicesComponent extends ConcernListDirective {\n\n type: TypeName = 'service2cluster';\n eventTypes = [ConcernEventType.Service];\n\n listColumns = [\n ListFactory.nameColumn('display_name'),\n {\n label: 'Version',\n value: (row) => row.version,\n },\n ListFactory.stateColumn(),\n ListFactory.statusColumn(this),\n ListFactory.actionsButton(this),\n ListFactory.importColumn(this),\n ListFactory.configColumn(this),\n ] as IColumns;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host { flex: 1; }\n.add-button {position:fixed; right: 20px;top:120px;}\n", - "extends": "ConcernListDirective" - }, - { - "name": "ServiceStatusComponent", - "id": "component-ServiceStatusComponent-8f5f1a718b179237de4bf580d5ec8631", - "file": "src/app/components/service/service-status/service-status.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-service-status", - "styleUrls": [ - "../../../styles/status-tree.scss" - ], - "styles": [], - "templateUrl": [ - "../../../templates/status-tree.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "entityService", - "deprecated": false, - "deprecationMessage": "", - "type": "ServiceService", - "optional": false, - "description": "", - "line": 22, - "modifierKind": [ - 122 - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 23, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "entityId", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "optional": false, - "description": "", - "line": 24, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "folding", - "deprecated": false, - "deprecationMessage": "", - "type": "Folding", - "optional": false, - "description": "", - "line": 27, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "loading", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "statusTree", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 25, - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "tree", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 19, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'tree', {static: false}" - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "eventReceived", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 31, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "getEntityIdFromParams", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 68, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "pipeData", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 27, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "expandCollapseAll", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 71, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 55, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "prepareListeners", - "args": [], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "StatusAbstractDirective" - } - }, - { - "name": "prepareStatusTree", - "args": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "StatusTreeType", - "typeParameters": [], - "line": 49, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "input", - "type": "StatusTreeType", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "StatusAbstractDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { fromJS, updateIn } from 'immutable';\n\nimport { StatusAbstractDirective } from '@app/abstract-directives/status.abstract.directive';\nimport { EventMessage, SocketState } from '@app/core/store';\nimport { ServiceService } from '@app/services/service.service';\nimport { ServiceStatusTree } from '@app/models/status-tree';\nimport { Service } from '@app/core/types';\n\n@Component({\n selector: 'app-service-status',\n templateUrl: '../../../templates/status-tree.html',\n styleUrls: ['../../../styles/status-tree.scss']\n})\nexport class ServiceStatusComponent extends StatusAbstractDirective {\n\n constructor(\n protected route: ActivatedRoute,\n protected store: Store,\n public entityService: ServiceService,\n ) {\n super(route, store, entityService);\n }\n\n pipeData(): any {\n return this.entity.cluster_id;\n }\n\n eventReceived(event: EventMessage) {\n let output;\n switch (event.object.type) {\n case 'hostcomponent':\n output = updateIn(fromJS(this.statusTree.value), ['hc'], (components: any[]) =>\n components.map(component => updateIn(component, ['hosts'], (hosts: any[]) =>\n hosts.map((host: any) => {\n if (host.get('id') === event.object.id && component.get('id') === +event.object.details.id) {\n return host.set('status', +event.object.details.value);\n }\n return host;\n })\n ))\n );\n this.statusTree.next(output.toJS() as any as ServiceStatusTree);\n break;\n case 'component':\n output = updateIn(fromJS(this.statusTree.value), ['hc'], (components: any[]) =>\n components.map(component => {\n if (component.get('id') === event.object.id) {\n return component.set('status', +event.object.details.value);\n }\n return component;\n })\n );\n this.statusTree.next(output.toJS() as any as ServiceStatusTree);\n break;\n case 'service':\n output = fromJS(this.statusTree.value);\n if (output.get('id') === event.object.id) {\n output = output.set('status', +event.object.details.value);\n }\n this.statusTree.next(output.toJS() as any as ServiceStatusTree);\n break;\n }\n }\n\n getEntityIdFromParams(): number {\n return +this.route.parent.snapshot.params.service;\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n flex: 1;\n}\n\n.controls {\n position: fixed;\n top: 130px;\n right: 10px;\n\n .notify {\n opacity: 0;\n\n &>span {\n line-height: 24px;\n vertical-align: text-bottom;\n }\n }\n}\n", - "styleUrl": "../../../styles/status-tree.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "entityService", - "type": "ServiceService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 17, - "jsdoctags": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "entityService", - "type": "ServiceService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "StatusAbstractDirective", - "templateData": "\n

Loading...

\n
\n\n\n\n
\n \n
\n\n \n\n
\n" - }, - { - "name": "SettingsComponent", - "id": "component-SettingsComponent-72857ee1013912372108b00169e6acb3", - "file": "src/app/admin/settings.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-settings", - "styleUrls": [], - "styles": [ - ":host {flex:1; display: flex;}" - ], - "template": "", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "set$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 28 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onEvent", - "args": [ - { - "name": "e", - "type": "DynamicEvent", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "e", - "type": "DynamicEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\nimport { Store } from '@ngrx/store';\nimport { Observable } from 'rxjs';\nimport { map, switchMap } from 'rxjs/operators';\n\nimport { ApiService } from '@app/core/api';\nimport { settingsSave, State } from '@app/core/store';\nimport { BaseEntity } from '@app/core/types/api';\nimport { DynamicEvent } from '@app/shared/directives';\n\n@Component({\n selector: 'app-settings',\n template: '',\n styles: [':host {flex:1; display: flex;}'],\n})\nexport class SettingsComponent implements OnInit {\n set$: Observable;\n\n constructor(private api: ApiService, private store: Store) {}\n\n ngOnInit() {\n this.set$ = this.api.root.pipe(\n switchMap((root) => this.api.get(root.adcm)),\n map((adcm) => adcm[0]),\n );\n }\n\n onEvent(e: DynamicEvent) {\n if (e.name === 'send') this.store.dispatch(settingsSave({ isSet: true }));\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {flex:1; display: flex;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 28, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "SimpleTextComponent", - "id": "component-SimpleTextComponent-a70b027f8ca1cb2ef7bd433cd939cbfc", - "file": "src/app/shared/components/tooltip/tooltip.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-simple-text", - "styleUrls": [], - "styles": [], - "template": "{{ current }}", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "line": 39, - "type": "any" - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 41, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import {\n Component,\n ElementRef,\n EventEmitter,\n HostListener,\n Injector,\n Input,\n OnDestroy,\n OnInit,\n Renderer2,\n Type,\n} from '@angular/core';\nimport { Router } from '@angular/router';\nimport { BaseDirective } from '@app/shared/directives';\nimport { delay } from 'rxjs/operators';\n\nimport { IssueInfoComponent } from '../issue-info.component';\nimport { StatusInfoComponent } from '../status-info.component';\nimport { ComponentData, TooltipOptions, TooltipService } from './tooltip.service';\n\nconst POSITION_MARGIN = 16;\n\n@Component({\n selector: 'app-simple-text',\n template: '{{ current }}',\n})\nexport class SimpleTextComponent implements OnInit {\n @Input() current: any;\n constructor(private componentData: ComponentData) {}\n ngOnInit(): void {\n this.current = this.current || this.componentData.current;\n this.componentData.emitter.emit('Done');\n }\n}\n\nconst kit = { issue: IssueInfoComponent, status: StatusInfoComponent };\n@Component({\n selector: 'app-tooltip',\n template: '',\n styleUrls: ['./tooltip.component.scss'],\n})\nexport class TooltipComponent extends BaseDirective implements OnInit, OnDestroy {\n private options: TooltipOptions;\n source: HTMLElement;\n\n CurrentComponent: Type;\n componentInjector: Injector;\n\n constructor(\n private el: ElementRef,\n private service: TooltipService,\n private renderer: Renderer2,\n private router: Router,\n private parentInjector: Injector\n ) {\n super();\n }\n\n @HostListener('mouseenter', ['$event']) menter() {\n this.service.mouseEnterTooltip();\n }\n\n @HostListener('mouseleave') mleave() {\n this.service.mouseLeaveTooltip();\n }\n\n ngOnInit(): void {\n this.service.position$.pipe(this.takeUntil()).subscribe((o) => {\n if (o) {\n this.clear();\n this.buildComponent(o);\n } else this.hide();\n });\n }\n\n hide() {\n this.renderer.setAttribute(this.el.nativeElement, 'style', `opacity: 0; height: auto;`);\n this.clear();\n }\n\n clear() {\n if (this.source) {\n this.source = null;\n this.CurrentComponent = null;\n }\n }\n\n position() {\n const o = this.options;\n const el = this.el.nativeElement;\n const root = document.querySelector('app-root');\n const position = { left: 0, top: 0, bottom: 0, right: 0, height: 0 };\n const offsetParent = (s: HTMLElement) => s.offsetParent as HTMLElement;\n const offset = (s: HTMLElement) => ({ top: s.offsetTop, left: s.offsetLeft });\n const increment = (a: { top: number; left: number }, b: { top: number; left: number }) => ({ top: a.top + b.top, left: a.left + b.left });\n const offsetSum = (s: HTMLElement) => (offsetParent(s) ? increment(offset(s), offsetSum(offsetParent(s))) : offset(s));\n const os = offsetSum(o.source);\n position.top = os.top + o.source.offsetHeight;\n\n // TODO: maybe let's up tooltip?\n // this height for tooltip for scrolling\n position.height = o.event.y > root.offsetHeight - el.offsetHeight ? root.offsetHeight - position.top - POSITION_MARGIN : 0;\n\n switch (o.options.position) {\n case 'bottom':\n if (o.event.x + el.offsetWidth > root.offsetWidth) position.right = POSITION_MARGIN * 2;\n else position.left = os.left + o.source.clientWidth;\n break;\n case 'left':\n position.left = o.event.x < el.clientWidth ? POSITION_MARGIN * 2 : os.left - el.clientWidth;\n break;\n }\n\n this.renderer.setAttribute(el, 'style', `opacity: .9; ${this.getPositionString(position)}`);\n }\n\n getPositionString(po: any) {\n return Object.keys(po).reduce((p, c) => p + (po[c] ? `${c}: ${po[c]}px;` : ''), '');\n }\n\n buildComponent(o: TooltipOptions) {\n this.options = o;\n this.source = this.options.source;\n this.CurrentComponent = kit[this.options.options.componentName] || SimpleTextComponent;\n\n const emitter = new EventEmitter();\n emitter.pipe(delay(100), this.takeUntil()).subscribe(() => this.position());\n\n const parse = (url: string) =>\n url\n .split('/')\n .map((b) => b.split(';')[0])\n .join('/');\n\n this.componentInjector = Injector.create({\n providers: [\n {\n provide: ComponentData,\n useValue: { path: parse(this.router.url), current: this.options.options.content, emitter: emitter },\n },\n ],\n parent: this.parentInjector,\n });\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "componentData", - "type": "ComponentData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 39, - "jsdoctags": [ - { - "name": "componentData", - "type": "ComponentData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "StateColumnComponent", - "id": "component-StateColumnComponent-025e88ffd22afc289eb7e093192f4bdc", - "file": "src/app/components/columns/state-column/state-column.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-state-column", - "styleUrls": [ - "./state-column.component.scss" - ], - "styles": [], - "templateUrl": [ - "./state-column.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "line": 10, - "type": "T" - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\n\n@Component({\n selector: 'app-state-column',\n templateUrl: './state-column.component.html',\n styleUrls: ['./state-column.component.scss']\n})\nexport class StateColumnComponent {\n\n @Input() row: T;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "", - "styleUrl": "./state-column.component.scss" - } - ], - "stylesData": "", - "templateData": "autorenew\n{{ row?.state }}\n" - }, - { - "name": "StatusColumnComponent", - "id": "component-StatusColumnComponent-afb8a8911522db45a368173e82024384", - "file": "src/app/components/columns/status-column/status-column.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-status-column", - "styleUrls": [ - "./status-column.component.scss" - ], - "styles": [], - "templateUrl": [ - "./status-column.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "line": 17, - "type": "T" - } - ], - "outputsClass": [ - { - "name": "onClick", - "defaultValue": "new EventEmitter>()", - "deprecated": false, - "deprecationMessage": "", - "line": 19, - "type": "EventEmitter" - } - ], - "propertiesClass": [], - "methodsClass": [ - { - "name": "clickCell", - "args": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "row", - "type": "T", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 21, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "MouseEvent", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "row", - "type": "T", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, Output, EventEmitter } from '@angular/core';\nimport { AdwpCellComponent } from '@adwp-ui/widgets';\n\nexport interface StatusData {\n event: MouseEvent;\n action: string;\n row: T;\n}\n\n@Component({\n selector: 'app-status-column',\n templateUrl: './status-column.component.html',\n styleUrls: ['./status-column.component.scss']\n})\nexport class StatusColumnComponent implements AdwpCellComponent {\n\n @Input() row: T;\n\n @Output() onClick = new EventEmitter>();\n\n clickCell(event: MouseEvent, action: string, row: T): void {\n this.onClick.emit({ event, action, row });\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "", - "styleUrl": "./status-column.component.scss" - } - ], - "stylesData": "", - "implements": [ - "AdwpCellComponent" - ], - "templateData": "{{ row?.status }}\n\n \n \n\n" - }, - { - "name": "StatusInfoComponent", - "id": "component-StatusInfoComponent-0dabaa5d0526105b87aa689d4354120b", - "file": "src/app/shared/components/status-info.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-status-info", - "styleUrls": [], - "styles": [ - "mat-icon {vertical-align: middle;}", - "a.component {display: block; padding: 6px 8px;}" - ], - "template": "
\n Nothing to display\n \n {{ (c.display_name || c.name || c.component_display_name || c.component).toUpperCase() }} \n \n \n check_circle_outline\n error_outline\n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "cluster", - "deprecated": false, - "deprecationMessage": "", - "type": "ICluster", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "type": "BaseEntity", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "path", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 40 - }, - { - "name": "statusInfo$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 43 - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 47, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onClick", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 78, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\nimport { BaseEntity } from '@app/core/types/api';\nimport { Observable, of } from 'rxjs';\nimport { switchMap, tap, map } from 'rxjs/operators';\n\nimport { StatusService } from './status/status.service';\nimport { ComponentData } from './tooltip/tooltip.service';\nimport { ICluster } from '@app/models/cluster';\n\n@Component({\n selector: 'app-status-info',\n template: `\n
\n Nothing to display\n \n {{ (c.display_name || c.name || c.component_display_name || c.component).toUpperCase() }} \n \n \n check_circle_outline\n error_outline\n \n
\n `,\n styles: ['mat-icon {vertical-align: middle;}', 'a.component {display: block; padding: 6px 8px;}'],\n})\nexport class StatusInfoComponent implements OnInit {\n path: string;\n cluster: ICluster;\n current: BaseEntity;\n statusInfo$: Observable;\n\n constructor(private service: StatusService, private componentData: ComponentData) {}\n\n ngOnInit(): void {\n this.current = this.current || this.componentData.current;\n this.path = this.path || this.componentData.path;\n\n const [name] = this.path.split('/').reverse();\n\n let req$ = of([]);\n\n switch (name) {\n case 'cluster':\n this.cluster = this.current as ICluster;\n req$ = this.service.getServiceComponentsByCluster(this.cluster);\n break;\n case 'service':\n req$ = this.service.getClusterById((this.current).cluster_id).pipe(\n tap((c) => (this.cluster = c)),\n switchMap((cluster) => this.service.getServiceComponentsByCluster(cluster, this.current.id))\n );\n break;\n case 'host':\n if ((this.current).cluster_id)\n req$ = this.service.getClusterById((this.current).cluster_id).pipe(\n tap((c) => (this.cluster = c)),\n switchMap((cluster) => this.service.getStatusInfo(cluster.id, cluster.hostcomponent).pipe(map((a) => this.service.getComponentsOnly(a, this.current.id))))\n );\n break;\n }\n\n this.statusInfo$ = req$.pipe(tap(() => this.componentData.emitter.emit('onLoad')));\n }\n\n onClick(): void {\n this.componentData.emitter.emit('onClose');\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "mat-icon {vertical-align: middle;}\na.component {display: block; padding: 6px 8px;}\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "service", - "type": "StatusService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "componentData", - "type": "ComponentData", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 43, - "jsdoctags": [ - { - "name": "service", - "type": "StatusService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "componentData", - "type": "ComponentData", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ] - }, - { - "name": "StatusMenuItemComponent", - "id": "component-StatusMenuItemComponent-aa2e7ea9f32f2b5b4a0bd14585209968", - "file": "src/app/shared/details/left-menu-items/status-menu-item/status-menu-item.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-status-menu-item", - "styleUrls": [], - "styles": [ - "a span { white-space: nowrap; }" - ], - "template": "\n {{ label }} \n \n \n {{ entity.status === 0 ? 'check_circle_outline' : 'error_outline' }}\n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "entity", - "deprecated": false, - "deprecationMessage": "", - "line": 29, - "type": "", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "data", - "deprecated": false, - "deprecationMessage": "", - "line": 21, - "type": "any", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "label", - "deprecated": false, - "deprecationMessage": "", - "line": 13, - "type": "string", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - }, - { - "name": "link", - "deprecated": false, - "deprecationMessage": "", - "line": 14, - "type": "string", - "inheritance": { - "file": "MenuItemAbstractDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "_entity", - "deprecated": false, - "deprecationMessage": "", - "type": "EntityType", - "optional": false, - "description": "", - "line": 11, - "modifierKind": [ - 121 - ], - "inheritance": { - "file": "MenuItemAbstractDirective" - } - } - ], - "methodsClass": [ - { - "name": "listenToStatusChanges", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 43, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { filter } from 'rxjs/operators';\nimport { Store } from '@ngrx/store';\n\nimport { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive';\nimport { BaseEntity } from '@app/core/types';\nimport { selectMessage, SocketState } from '@app/core/store';\n\n@Component({\n selector: 'app-status-menu-item',\n template: `\n \n {{ label }} \n \n \n {{ entity.status === 0 ? 'check_circle_outline' : 'error_outline' }}\n \n \n \n `,\n styles: ['a span { white-space: nowrap; }'],\n})\nexport class StatusMenuItemComponent extends MenuItemAbstractDirective {\n\n @Input() set entity(entity: BaseEntity) {\n this._entity = entity;\n this.listenToStatusChanges();\n }\n get entity(): BaseEntity {\n return this._entity;\n }\n\n constructor(\n private store: Store,\n ) {\n super();\n }\n\n listenToStatusChanges() {\n this.store.pipe(\n selectMessage,\n filter(event => event?.object?.id && this.entity?.id && event.object.id === this.entity.id),\n filter(event => event?.event === 'change_status'),\n filter(event => event?.object?.type === this.data.entityType),\n this.takeUntil(),\n ).subscribe((event) => this.entity.status = +event.object.details.value);\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "a span { white-space: nowrap; }\n", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 35, - "jsdoctags": [ - { - "name": "store", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "MenuItemAbstractDirective", - "accessors": { - "entity": { - "name": "entity", - "setSignature": { - "name": "entity", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "entity", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 29, - "jsdoctags": [ - { - "name": "entity", - "type": "BaseEntity", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "entity", - "type": "", - "returnType": "BaseEntity", - "line": 33 - } - } - } - }, - { - "name": "StatusTreeComponent", - "id": "component-StatusTreeComponent-91f369d83e4defa92ad4e5e0aa366670", - "file": "src/app/components/status-tree/status-tree.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-status-tree", - "styleUrls": [ - "./status-tree.component.scss" - ], - "styles": [], - "templateUrl": [ - "./status-tree.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "folding", - "deprecated": false, - "deprecationMessage": "", - "line": 99, - "type": "" - }, - { - "name": "tree", - "deprecated": false, - "deprecationMessage": "", - "line": 80, - "type": "[]" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "calcCounts", - "defaultValue": "() => {...}", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 37, - "modifierKind": [ - 120 - ] - }, - { - "name": "dataSource", - "defaultValue": "new MatTreeFlatDataSource(this.treeControl, this.treeFlattener)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 77 - }, - { - "name": "hasChild", - "defaultValue": "() => {...}", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 96 - }, - { - "name": "ownFolding", - "deprecated": false, - "deprecationMessage": "", - "type": "Folding", - "optional": false, - "description": "", - "line": 98, - "modifierKind": [ - 120 - ] - }, - { - "name": "ownTree", - "deprecated": false, - "deprecationMessage": "", - "type": "StatusTree[]", - "optional": false, - "description": "", - "line": 79, - "modifierKind": [ - 120 - ] - }, - { - "name": "transformer", - "defaultValue": "() => {...}", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 56, - "modifierKind": [ - 120 - ] - }, - { - "name": "treeControl", - "defaultValue": "new FlatTreeControl(\n node => node.level,\n node => node.expandable,\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 65 - }, - { - "name": "treeFlattener", - "defaultValue": "new MatTreeFlattener(\n this.transformer,\n node => node.level,\n node => node.expandable,\n node => node.children,\n )", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 70 - }, - { - "name": "treeNode", - "deprecated": false, - "deprecationMessage": "", - "type": "any", - "optional": false, - "description": "", - "line": 35, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'treeNode', {static: true}" - } - ] - } - ], - "methodsClass": [ - { - "name": "collapseAll", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 111, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "expandAll", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 107, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "hasCollapsed", - "args": [], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 115, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input, ViewChild } from '@angular/core';\nimport { FlatTreeControl } from '@angular/cdk/tree';\nimport { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';\n\nimport { StatusTree, StatusTreeSubject } from '@app/models/status-tree';\n\ninterface ExampleFlatNode {\n expandable: boolean;\n subject: StatusTreeSubject;\n level: number;\n}\n\ninterface Counts {\n total: number;\n succeed: number;\n}\n\ninterface CountedStatusTree extends StatusTree {\n counts?: Counts;\n}\n\nexport enum Folding {\n Collapsed,\n Expanded,\n}\n\n@Component({\n selector: 'app-status-tree',\n templateUrl: './status-tree.component.html',\n styleUrls: ['./status-tree.component.scss']\n})\nexport class StatusTreeComponent {\n\n @ViewChild('treeNode', { static: true }) treeNode: any;\n\n private calcCounts = (children: CountedStatusTree[]): Counts => {\n return children.reduce((acc: Counts, child: CountedStatusTree) => {\n acc.total++;\n if ('status' in child.subject) {\n if (child.subject.status === 0) {\n acc.succeed++;\n }\n } else {\n const childrenSucceed = child.children.reduce((accum, item) => item.subject.status === 0 ? accum + 1 : accum, 0);\n if (childrenSucceed === child.children.length) {\n acc.succeed++;\n }\n }\n return acc;\n },\n { total: 0, succeed: 0 } as Counts,\n ) as Counts;\n }\n\n private transformer = (node: StatusTree, level: number) => {\n return {\n expandable: !!node.children && node.children.length > 0,\n subject: node.subject,\n level: level,\n counts: node.children ? this.calcCounts(node.children) : { total: 0, succeed: 0 },\n };\n }\n\n treeControl = new FlatTreeControl(\n node => node.level,\n node => node.expandable,\n );\n\n treeFlattener = new MatTreeFlattener(\n this.transformer,\n node => node.level,\n node => node.expandable,\n node => node.children,\n );\n\n dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);\n\n private ownTree: StatusTree[];\n @Input() set tree(tree: StatusTree[]) {\n this.ownTree = tree;\n this.dataSource.data = tree;\n\n if (this.folding === Folding.Expanded) {\n this.treeControl.expandAll();\n }\n\n if (this.folding === Folding.Collapsed) {\n this.treeControl.collapseAll();\n }\n }\n get tree(): StatusTree[] {\n return this.ownTree;\n }\n\n hasChild = (_: number, node: ExampleFlatNode) => node.expandable;\n\n private ownFolding: Folding;\n @Input() set folding(folding: Folding) {\n this.ownFolding = folding;\n this.tree = this.tree;\n }\n get folding(): Folding {\n return this.ownFolding;\n }\n\n expandAll() {\n this.treeControl.expandAll();\n }\n\n collapseAll() {\n this.treeControl.collapseAll();\n }\n\n hasCollapsed(): boolean {\n for (const item of this.treeControl.dataNodes) {\n if (!this.treeControl.isExpanded(item)) {\n return true;\n }\n }\n return false;\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".expandable {\n font-weight: bold;\n}\n\n.counts {\n color: #ff9800;\n}\n\n.success {\n color: #00e676;\n}\n\nbutton {\n width: 35px;\n height: 35px;\n}\n\nmat-tree-node {\n min-height: 35px;\n}\n", - "styleUrl": "./status-tree.component.scss" - } - ], - "stylesData": "", - "accessors": { - "tree": { - "name": "tree", - "setSignature": { - "name": "tree", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "tree", - "type": "StatusTree[]", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 80, - "jsdoctags": [ - { - "name": "tree", - "type": "StatusTree[]", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "tree", - "type": "[]", - "returnType": "StatusTree[]", - "line": 92 - } - }, - "folding": { - "name": "folding", - "setSignature": { - "name": "folding", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "folding", - "type": "Folding", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 99, - "jsdoctags": [ - { - "name": "folding", - "type": "Folding", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "getSignature": { - "name": "folding", - "type": "", - "returnType": "Folding", - "line": 103 - } - } - }, - "templateData": "\n \n \n\n \n\n \n \n \n\n \n\n \n\n\n\n \n check_circle_outline\n \n error_outline\n \n \n  \n {{node.subject.name}}\n \n \n {{node.subject.name}}\n \n \n  \n \n successful {{node.counts.succeed}}/{{node.counts.total}}\n \n\n" - }, - { - "name": "SubtitleComponent", - "id": "component-SubtitleComponent-4081fb8524bb32b2e846b6a1c81285ac", - "file": "src/app/shared/details/subtitle.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-details-subtitle", - "styleUrls": [], - "styles": [], - "template": "\n \n \n \n \n \n {{ cur.prototype_display_name || cur.prototype_name }}\n {{ cur.prototype_version }}\n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "current", - "deprecated": false, - "deprecationMessage": "", - "line": 34, - "type": "" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "cur", - "deprecated": false, - "deprecationMessage": "", - "type": "IDetails", - "optional": false, - "description": "", - "line": 32 - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { IDetails } from '@app/models/details';\n\n@Component({\n selector: 'app-details-subtitle',\n template: `\n \n \n \n \n \n \n {{ cur.prototype_display_name || cur.prototype_name }}\n {{ cur.prototype_version }}\n \n \n \n `,\n})\nexport class SubtitleComponent {\n cur: IDetails;\n\n @Input() set current(c: IDetails) {\n if (c) {\n this.cur = c;\n }\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "accessors": { - "current": { - "name": "current", - "setSignature": { - "name": "current", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "c", - "type": "IDetails", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 34, - "jsdoctags": [ - { - "name": "c", - "type": "IDetails", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "SupportComponent", - "id": "component-SupportComponent-1d9d62db486fa6e7ded9c7d2abbfd5b9", - "file": "src/app/main/support/support.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-support", - "styleUrls": [ - "./support.component.scss" - ], - "styles": [], - "templateUrl": [ - "./support.component.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\n\n@Component({\n selector: 'app-support',\n templateUrl: './support.component.html',\n styleUrls: ['./support.component.scss']\n})\nexport class SupportComponent implements OnInit {\n\n constructor() { }\n\n ngOnInit() {\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "", - "styleUrl": "./support.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [], - "line": 19 - }, - "implements": [ - "OnInit" - ], - "templateData": "

\n support works!\n

\n" - }, - { - "name": "TaskNameComponent", - "id": "component-TaskNameComponent-ae4563e9e25fed90e46269c10f384aa9", - "file": "src/app/components/columns/task-name/task-name.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-task-name", - "styleUrls": [ - "./task-name.component.scss" - ], - "styles": [], - "template": "\n\n
\n {{ row.action?.display_name || 'unknown' }}\n  \n \n {{ (expandedTask | async) && (expandedTask | async).id === row.id ? 'expand_less' : 'expand_more' }}\n \n
\n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "expandedTask", - "deprecated": false, - "deprecationMessage": "", - "line": 38, - "type": "BehaviorSubject" - }, - { - "name": "toggleExpand", - "deprecated": false, - "deprecationMessage": "", - "line": 39, - "type": "function" - } - ], - "outputsClass": [], - "propertiesClass": [ - { - "name": "linkColumn", - "defaultValue": "{\n label: '',\n type: 'link',\n value: (row) => row.action?.display_name || 'unknown',\n url: (row) => `/job/${row.jobs[0].id}`,\n }", - "deprecated": false, - "deprecationMessage": "", - "type": "ILinkColumn", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "type": "Task", - "optional": false, - "description": "", - "line": 29 - } - ], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { AdwpCellComponent, ILinkColumn } from '@adwp-ui/widgets';\nimport { BehaviorSubject } from 'rxjs';\n\nimport { Task } from '@app/core/types';\n\n@Component({\n selector: 'app-task-name',\n template: `\n \n \n
\n {{ row.action?.display_name || 'unknown' }}\n  \n \n {{ (expandedTask | async) && (expandedTask | async).id === row.id ? 'expand_less' : 'expand_more' }}\n \n
\n
\n `,\n styleUrls: ['./task-name.component.scss']\n})\nexport class TaskNameComponent implements AdwpCellComponent {\n\n row: Task;\n\n linkColumn: ILinkColumn = {\n label: '',\n type: 'link',\n value: (row) => row.action?.display_name || 'unknown',\n url: (row) => `/job/${row.jobs[0].id}`,\n };\n\n @Input() expandedTask: BehaviorSubject;\n @Input() toggleExpand: (row: Task) => void;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n width: 100%;\n}\n\n.multi-title {\n cursor: pointer;\n}\n\n.mat-icon {\n vertical-align: middle;\n font-size: 1.2em;\n width: auto;\n height: auto;\n}\n", - "styleUrl": "./task-name.component.scss" - } - ], - "stylesData": "", - "implements": [ - "AdwpCellComponent" - ] - }, - { - "name": "TaskObjectsComponent", - "id": "component-TaskObjectsComponent-b04ce328b0f09e7c11cfcd792a40e970", - "file": "src/app/components/columns/task-objects/task-objects.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-task-objects", - "styleUrls": [ - "./task-objects.component.scss" - ], - "styles": [], - "templateUrl": [ - "./task-objects.component.html" - ], - "viewProviders": [], - "inputsClass": [ - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "line": 13, - "type": "Task" - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { AdwpCellComponent } from '@adwp-ui/widgets';\n\nimport { Task } from '@app/core/types';\n\n@Component({\n selector: 'app-task-objects',\n templateUrl: './task-objects.component.html',\n styleUrls: ['./task-objects.component.scss']\n})\nexport class TaskObjectsComponent implements AdwpCellComponent {\n\n @Input() row: Task;\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": "adwp-link-cell {\n display: inline;\n}\n\n:host ::ng-deep adwp-link-cell a {\n display: inline !important;\n line-height: 22px;\n}\n", - "styleUrl": "./task-objects.component.scss" - } - ], - "stylesData": "", - "implements": [ - "AdwpCellComponent" - ], - "templateData": "\n \n \n / \n \n\n" - }, - { - "name": "TasksComponent", - "id": "component-TasksComponent-f8644f5018a92a60bc7e36b2a99a93b1", - "file": "src/app/entry/task/tasks.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-tasks", - "styleUrls": [ - "./tasks.component.scss" - ], - "styles": [], - "templateUrl": [ - "./tasks.component.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "data$", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject>", - "optional": false, - "description": "", - "line": 41 - }, - { - "name": "expandedTask", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 39 - }, - { - "name": "JobsComponent", - "defaultValue": "JobsComponent", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 38 - }, - { - "name": "jobsTableInstanceTaken", - "defaultValue": "() => {...}", - "deprecated": false, - "deprecationMessage": "", - "type": "InstanceTakenFunc", - "optional": false, - "description": "", - "line": 91 - }, - { - "name": "listColumns", - "defaultValue": "[\n {\n label: '#',\n value: (row) => row.id,\n className: 'first-child',\n headerClassName: 'first-child',\n },\n {\n type: 'component',\n label: 'Action name',\n component: TaskNameComponent,\n instanceTaken: (componentRef: ComponentRef) => {\n componentRef.instance.expandedTask = this.expandedTask;\n componentRef.instance.toggleExpand = (row) => {\n this.expandedTask.next(\n this.expandedTask.value && this.expandedTask.value.id === row.id ? null : row\n );\n };\n },\n },\n {\n type: 'component',\n label: 'Objects',\n component: TaskObjectsComponent,\n },\n {\n label: 'Start date',\n value: row => DateHelper.short(row.start_date),\n className: 'action_date',\n headerClassName: 'action_date',\n },\n {\n label: 'Finish date',\n value: row => row.status === 'success' || row.status === 'failed' ? DateHelper.short(row.finish_date) : '',\n className: 'action_date',\n headerClassName: 'action_date',\n },\n {\n type: 'component',\n label: 'Status',\n component: TaskStatusColumnComponent,\n className: 'table-end center status',\n headerClassName: 'table-end center status',\n }\n ] as IColumns", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "paging", - "defaultValue": "new BehaviorSubject(null)", - "deprecated": false, - "deprecationMessage": "", - "type": "BehaviorSubject", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "status", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "type": "TaskStatus", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "addTask", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 104, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "changeTask", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 131, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "deleteTask", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 121, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "filterChanged", - "args": [ - { - "name": "event", - "type": "MatButtonToggleChange", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 270, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "MatButtonToggleChange", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getLimit", - "args": [], - "optional": false, - "returnType": "number", - "typeParameters": [], - "line": 247, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "initPaging", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 240, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "jobChanged", - "args": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 143, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "event", - "type": "EventMessage", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 252, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "refreshList", - "args": [ - { - "name": "page", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "limit", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "status", - "type": "TaskStatus", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable>", - "typeParameters": [], - "line": 217, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "page", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "limit", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "status", - "type": "TaskStatus", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "startListen", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 170, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit, ComponentRef } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { filter, tap } from 'rxjs/operators';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { BaseDirective, IColumns, IListResult, InstanceTakenFunc, Paging } from '@adwp-ui/widgets';\nimport { MatButtonToggleChange } from '@angular/material/button-toggle';\n\nimport { DateHelper } from '@app/helpers/date-helper';\nimport { EventMessage } from '@app/core/store';\nimport { JobStatus, Task, Job } from '@app/core/types';\nimport { TaskObjectsComponent } from '@app/components/columns/task-objects/task-objects.component';\nimport { TaskStatusColumnComponent } from '@app/components/columns/task-status-column/task-status-column.component';\nimport { JobsComponent } from '@app/components/job/jobs/jobs.component';\nimport { TaskNameComponent } from '@app/components/columns/task-name/task-name.component';\nimport { TaskService } from '@app/services/task.service';\nimport { JobService } from '@app/services/job.service';\n\ntype TaskStatus = '' | 'running' | 'success' | 'failed';\n\n@Component({\n selector: 'app-tasks',\n templateUrl: './tasks.component.html',\n styleUrls: ['./tasks.component.scss'],\n})\nexport class TasksComponent extends BaseDirective implements OnInit {\n\n JobsComponent = JobsComponent;\n expandedTask = new BehaviorSubject(null);\n\n data$: BehaviorSubject> = new BehaviorSubject(null);\n paging: BehaviorSubject = new BehaviorSubject(null);\n status: TaskStatus = '';\n\n listColumns = [\n {\n label: '#',\n value: (row) => row.id,\n className: 'first-child',\n headerClassName: 'first-child',\n },\n {\n type: 'component',\n label: 'Action name',\n component: TaskNameComponent,\n instanceTaken: (componentRef: ComponentRef) => {\n componentRef.instance.expandedTask = this.expandedTask;\n componentRef.instance.toggleExpand = (row) => {\n this.expandedTask.next(\n this.expandedTask.value && this.expandedTask.value.id === row.id ? null : row\n );\n };\n },\n },\n {\n type: 'component',\n label: 'Objects',\n component: TaskObjectsComponent,\n },\n {\n label: 'Start date',\n value: row => DateHelper.short(row.start_date),\n className: 'action_date',\n headerClassName: 'action_date',\n },\n {\n label: 'Finish date',\n value: row => row.status === 'success' || row.status === 'failed' ? DateHelper.short(row.finish_date) : '',\n className: 'action_date',\n headerClassName: 'action_date',\n },\n {\n type: 'component',\n label: 'Status',\n component: TaskStatusColumnComponent,\n className: 'table-end center status',\n headerClassName: 'table-end center status',\n }\n ] as IColumns;\n\n jobsTableInstanceTaken: InstanceTakenFunc = (componentRef: ComponentRef>) => {\n componentRef.instance.expandedTask = this.expandedTask;\n }\n\n constructor(\n private route: ActivatedRoute,\n private router: Router,\n private taskService: TaskService,\n private jobService: JobService,\n ) {\n super();\n }\n\n addTask(event: EventMessage): void {\n if (this.data$.value.results.some((task) => task.id === event.object.id)) {\n return;\n }\n\n const data: IListResult = Object.assign({}, this.data$.value);\n this.taskService.get(event.object.id).subscribe((task) => {\n if (data.results.length < this.paging.value.pageSize) {\n data.count++;\n } else {\n data.results.splice(data.results.length - 1, 1);\n }\n data.results = [task, ...data.results];\n this.data$.next(data);\n });\n }\n\n deleteTask(event: EventMessage): void {\n const data: IListResult = Object.assign({}, this.data$.value);\n const index = data.results.findIndex((task) => task.id === event.object.id);\n if (index > -1) {\n data.results.splice(index, 1);\n data.count--;\n this.data$.next(data);\n }\n }\n\n changeTask(event: EventMessage): void {\n const data: IListResult = Object.assign({}, this.data$.value);\n const index = data.results.findIndex((a) => a.id === event.object.id);\n if (index > -1) {\n const task: Task = Object.assign({}, data.results[index]);\n task.finish_date = new Date().toISOString();\n task.status = event.object.details.value as JobStatus;\n data.results.splice(index, 1, task);\n this.data$.next(data);\n }\n }\n\n jobChanged(event: EventMessage): void {\n const data: IListResult = Object.assign({}, this.data$.value);\n const taskIndex = data.results.findIndex(\n (item) => item.jobs.some((job) => job.id === event.object.id)\n );\n if (taskIndex > -1) {\n const task: Task = Object.assign({}, data.results[taskIndex]);\n const jobIndex = task.jobs.findIndex((item) => item.id === event.object.id);\n if (jobIndex > -1) {\n const job: Job = Object.assign({}, task.jobs[jobIndex]);\n job.status = event.object.details.value as JobStatus;\n if (event.object.details.type === 'status' && event.object.details.value === 'running') {\n job.start_date = new Date().toISOString();\n }\n if (\n event.object.details.type === 'status'\n && (event.object.details.value === 'success' || event.object.details.value === 'failed')\n ) {\n job.finish_date = new Date().toISOString();\n }\n task.jobs.splice(jobIndex, 1, job);\n data.results.splice(taskIndex, 1, task);\n this.data$.next(data);\n }\n }\n }\n\n startListen() {\n this.taskService.events({ events: ['change_job_status'] })\n .pipe(\n this.takeUntil(),\n )\n .subscribe(event => {\n if (event.object.details.type === 'status') {\n switch (event.object.details.value) {\n case 'created':\n if (['', 'running'].includes(this.status)) {\n this.addTask(event);\n }\n break;\n case 'running':\n if (['', 'running'].includes(this.status)) {\n this.changeTask(event);\n }\n break;\n case 'success':\n if (this.status === '') {\n this.changeTask(event);\n } else if (this.status === 'running') {\n this.deleteTask(event);\n } else if (this.status === 'success') {\n this.addTask(event);\n }\n break;\n case 'failed':\n if (this.status === '') {\n this.changeTask(event);\n } else if (this.status === 'running') {\n this.deleteTask(event);\n } else if (this.status === 'failed') {\n this.addTask(event);\n }\n break;\n }\n } else {\n this.changeTask(event);\n }\n });\n\n this.jobService.events({ events: ['change_job_status'] })\n .pipe(this.takeUntil())\n .subscribe(event => this.jobChanged(event));\n }\n\n refreshList(page: number, limit: number, status: TaskStatus): Observable> {\n const params: any = {\n limit: limit.toString(),\n offset: ((page - 1) * limit).toString(),\n };\n\n if (status) {\n params.status = status.toString();\n }\n\n this.router.navigate([], {\n relativeTo: this.route,\n queryParams: {\n page,\n limit,\n status,\n },\n queryParamsHandling: 'merge',\n });\n\n return this.taskService.list(params).pipe(tap(resp => this.data$.next(resp)));\n }\n\n initPaging() {\n this.paging.pipe(\n this.takeUntil(),\n filter(paging => !!paging),\n ).subscribe((paging) => this.refreshList(paging.pageIndex, paging.pageSize, this.status).subscribe());\n }\n\n getLimit(): number {\n const p = this.route.snapshot.queryParamMap;\n return p.get('limit') ? +p.get('limit') : +localStorage.getItem('limit');\n }\n\n ngOnInit() {\n this.initPaging();\n\n if (!localStorage.getItem('limit')) localStorage.setItem('limit', '10');\n\n this.route.queryParamMap.pipe(this.takeUntil()).subscribe((p) => {\n const page = +p.get('page') ? +p.get('page') : 1;\n const limit = this.getLimit();\n if (limit) {\n localStorage.setItem('limit', limit.toString());\n }\n this.status = (p.get('status') || '') as TaskStatus;\n this.paging.next({ pageIndex: page, pageSize: limit });\n });\n\n this.startListen();\n }\n\n filterChanged(event: MatButtonToggleChange) {\n this.status = event.value;\n this.paging.next({ pageIndex: 1, pageSize: this.getLimit() });\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n flex: 1;\n}\n\n.multi-title {\n cursor: pointer;\n}\n\n.mat-icon {\n vertical-align: middle;\n font-size: 1.2em;\n width: auto;\n height: auto;\n}\n\ntable.main {\n width: 100%;\n}\n\n:host ::ng-deep .first-child {\n width: 35px;\n padding-right: 10px;\n flex-grow: 0;\n flex-basis: 35px;\n}\n\n:host ::ng-deep .action_date {\n width: 200px;\n flex-basis: 200px;\n flex-grow: 0;\n}\n\n:host ::ng-deep .regular-table {\n mat-row:not(:hover) {\n background-color: #303030 !important;\n }\n mat-cell {\n cursor: auto;\n }\n adwp-link-cell {\n cursor: pointer;\n }\n}\n\n:host ::ng-deep .expandedRow > mat-cell {\n padding: 0;\n}\n\n.padding20 {\n padding-right: 20px;\n}\n\n:host ::ng-deep .parent-end {\n width: 84px;\n flex-basis: 84px;\n flex-grow: 0;\n}\n\n:host ::ng-deep .table-end {\n width: 50px;\n flex-basis: 50px;\n flex-grow: 0;\n}\n\n.end {\n width: 40px;\n padding-left: 30px !important;\n}\n\n:host ::ng-deep .center {\n text-align: center;\n}\n\n:host ::ng-deep .status {\n display: flex;\n justify-content: center;\n}\n\ntable.inner {\n width: 100%;\n margin-bottom: 10px;\n\n & tr:last-child td {\n border-bottom-width: 0;\n }\n}\n\ntd.mat-cell,\nth.mat-header-cell {\n white-space: nowrap;\n padding: 0 10px;\n}\n\ntr.jobs-row {\n height: 0;\n}\n\n.expand-jobs {\n overflow: hidden;\n padding: 0 12px;\n}\n\n.toggle {\n font-size: small;\n}\n\n:host ::ng-deep .toggle .mat-button-toggle-label-content {\n line-height: 36px;\n}\n", - "styleUrl": "./tasks.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "taskService", - "type": "TaskService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "jobService", - "type": "JobService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 93, - "jsdoctags": [ - { - "name": "route", - "type": "ActivatedRoute", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "taskService", - "type": "TaskService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "jobService", - "type": "JobService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "OnInit" - ], - "templateData": "\n \n\n \n All\n In progress\n Success\n Failed\n \n\n\n
\n
\n\n \n\n
\n
\n" - }, - { - "name": "TaskStatusColumnComponent", - "id": "component-TaskStatusColumnComponent-e760b35cbde144fe3ff0bb1b88b318a4", - "file": "src/app/components/columns/task-status-column/task-status-column.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-task-status-column", - "styleUrls": [ - "./task-status-column.component.scss" - ], - "styles": [], - "templateUrl": [ - "./task-status-column.component.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "dialog", - "deprecated": false, - "deprecationMessage": "", - "type": "MatDialog", - "optional": false, - "description": "", - "line": 18, - "modifierKind": [ - 122 - ] - }, - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "type": "Task", - "optional": false, - "description": "", - "line": 22 - } - ], - "methodsClass": [ - { - "name": "cancelTask", - "args": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 24, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "url", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { AdwpCellComponent } from '@adwp-ui/widgets';\nimport { filter, switchMap } from 'rxjs/operators';\nimport { MatDialog } from '@angular/material/dialog';\n\nimport { Task } from '@app/core/types';\nimport { DialogComponent } from '@app/shared/components';\nimport { ApiService } from '@app/core/api';\n\n@Component({\n selector: 'app-task-status-column',\n templateUrl: './task-status-column.component.html',\n styleUrls: ['./task-status-column.component.scss']\n})\nexport class TaskStatusColumnComponent implements AdwpCellComponent {\n\n constructor(\n public dialog: MatDialog,\n private api: ApiService,\n ) {}\n\n row: Task;\n\n cancelTask(url: string) {\n this.dialog\n .open(DialogComponent, {\n data: {\n text: 'Are you sure?',\n controls: ['Yes', 'No'],\n },\n })\n .beforeClosed()\n .pipe(\n filter((yes) => yes),\n switchMap(() => this.api.put(url, {}))\n )\n .subscribe();\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".mat-icon {\n vertical-align: middle;\n font-size: 1.2em;\n width: auto;\n height: auto;\n}\n", - "styleUrl": "./task-status-column.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 15, - "jsdoctags": [ - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "AdwpCellComponent" - ], - "templateData": "\n \n autorenew\n \n \n autorenew\n \n\n\n \n block\n \n done_all\n \n \n\n" - }, - { - "name": "TextareaComponent", - "id": "component-TextareaComponent-aa1c7244c01c6c4e479df6f78459af29", - "file": "src/app/shared/form-elements/textarea.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-fields-textarea", - "styleUrls": [], - "styles": [], - "template": "\n \n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\n\nimport { FieldDirective } from './field.directive';\n\n@Component({\n selector: 'app-fields-textarea',\n template: `\n \n \n \n \n \n \n `,\n})\nexport class TextareaComponent extends FieldDirective {}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": "FieldDirective" - }, - { - "name": "TextBoxComponent", - "id": "component-TextBoxComponent-4b4acc84982e7580cd38f672c9e4ee69", - "file": "src/app/shared/form-elements/text-box.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-fields-textbox", - "styleUrls": [], - "styles": [], - "template": "\n \n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 25, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\n\nimport { FieldDirective } from './field.directive';\n\n@Component({\n selector: 'app-fields-textbox',\n template: `\n \n \n \n \n \n \n `\n})\nexport class TextBoxComponent extends FieldDirective {}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": "FieldDirective" - }, - { - "name": "TextComponent", - "id": "component-TextComponent-ec779dd686b8b0b425c29ed4b719ba4f", - "file": "src/app/entry/job/log/text.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-log-text", - "styleUrls": [], - "styles": [ - "\n :host {\n display: flex;\n flex: 1;\n flex-direction: column;\n }\n .tools {\n position: fixed;\n right: 60px;\n top: 150px;\n }\n textarea {\n background-color: #424242;\n border: 0;\n color: #fff;\n flex: 1;\n }\n " - ], - "template": "
\n \n \n \n \n
\n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "content", - "deprecated": false, - "deprecationMessage": "", - "line": 59, - "type": "string" - }, - { - "name": "status", - "deprecated": false, - "deprecationMessage": "", - "line": 60, - "type": "JobStatus" - } - ], - "outputsClass": [ - { - "name": "refresh", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 61, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "isRun", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 56 - }, - { - "name": "isScroll", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 55 - }, - { - "name": "isWatch", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 57 - }, - { - "name": "textarea", - "deprecated": false, - "deprecationMessage": "", - "type": "ElementRef", - "optional": false, - "description": "", - "line": 63, - "decorators": [ - { - "name": "ViewChild", - "stringifiedArguments": "'tea', {read: ElementRef}" - } - ] - }, - { - "name": "watch", - "deprecated": false, - "deprecationMessage": "", - "type": "Subscription", - "optional": false, - "description": "", - "line": 58 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "down", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 86, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngDoCheck", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 70, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 65, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "read", - "args": [ - { - "name": "stop", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 101, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "stop", - "type": "literal type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "startWatch", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 109, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "top", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 92, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "update", - "args": [ - { - "name": "status", - "type": "JobStatus", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 78, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "status", - "type": "JobStatus", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, DoCheck, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';\nimport { interval, Subscription } from 'rxjs';\nimport { BaseDirective } from '@adwp-ui/widgets';\n\nimport { JobStatus } from '@app/core/types/task-job';\n\n@Component({\n selector: 'app-log-text',\n styles: [\n `\n :host {\n display: flex;\n flex: 1;\n flex-direction: column;\n }\n .tools {\n position: fixed;\n right: 60px;\n top: 150px;\n }\n textarea {\n background-color: #424242;\n border: 0;\n color: #fff;\n flex: 1;\n }\n `,\n ],\n template: `\n
\n \n \n \n \n
\n \n `,\n})\nexport class TextComponent extends BaseDirective implements OnInit, DoCheck {\n isScroll = false;\n isRun = false;\n isWatch = false;\n watch: Subscription;\n @Input() content: string;\n @Input() status: JobStatus;\n @Output() refresh = new EventEmitter();\n\n @ViewChild('tea', { read: ElementRef }) textarea: ElementRef;\n\n ngOnInit(): void {\n this.isRun = this.status === 'running';\n if (this.isRun) this.startWatch();\n }\n\n ngDoCheck(): void {\n if (this.textarea) {\n const el = this.textarea.nativeElement;\n this.isScroll = el.offsetHeight < el.scrollHeight;\n if (this.isScroll && this.isWatch) this.down();\n }\n }\n\n update(status: JobStatus) {\n this.isRun = status === 'running';\n if (!this.isRun && this.isWatch) {\n this.isWatch = false;\n this.watch.unsubscribe();\n }\n }\n\n down() {\n const el = this.textarea.nativeElement;\n el.scrollTop = el.scrollHeight;\n if (this.isRun && !this.isWatch) this.startWatch();\n }\n\n top() {\n const el = this.textarea.nativeElement;\n el.scrollTop = 0;\n if (this.isRun && this.isWatch) {\n this.isWatch = false;\n this.watch.unsubscribe();\n }\n }\n\n read(stop: { direct: -1 | 1 | 0 }) {\n if (this.isRun && this.isWatch && stop.direct === -1) {\n this.isWatch = false;\n this.watch.unsubscribe();\n }\n if (this.isRun && !this.isWatch && !stop.direct) this.startWatch();\n }\n\n startWatch() {\n this.isWatch = true;\n this.watch = interval(5000)\n .pipe(this.takeUntil())\n .subscribe(_ => this.refresh.emit());\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n :host {\n display: flex;\n flex: 1;\n flex-direction: column;\n }\n .tools {\n position: fixed;\n right: 60px;\n top: 150px;\n }\n textarea {\n background-color: #424242;\n border: 0;\n color: #fff;\n flex: 1;\n }\n \n", - "extends": "BaseDirective", - "implements": [ - "OnInit", - "DoCheck" - ] - }, - { - "name": "ToolsComponent", - "id": "component-ToolsComponent-73a34d103ccaf596fec58838d6cc3cfb", - "file": "src/app/shared/configuration/tools/tools.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-tools", - "styleUrls": [], - "styles": [ - ":host {display: flex;justify-content: space-between;align-items: baseline; margin: 10px 20px 0;}", - ".form_config_button_save { margin: 0 16px 0 30px;}", - ".description {flex: 0}" - ], - "template": "\n \n\n\nAdvanced\n
\n \n \n
\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "disabledHistory", - "defaultValue": "true", - "deprecated": false, - "deprecationMessage": "", - "line": 47, - "type": "boolean" - }, - { - "name": "disabledSave", - "defaultValue": "true", - "deprecated": false, - "deprecationMessage": "", - "line": 46, - "type": "boolean" - } - ], - "outputsClass": [ - { - "name": "applyFilter", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 49, - "type": "EventEmitter" - }, - { - "name": "save", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 50, - "type": "EventEmitter" - }, - { - "name": "showHistory", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 51, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "description", - "defaultValue": "new FormControl()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 45 - }, - { - "name": "filter$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 41, - "modifierKind": [ - 120 - ] - }, - { - "name": "filterParams", - "defaultValue": "{ advanced: false, search: '' }", - "deprecated": false, - "deprecationMessage": "", - "type": "ISearchParam", - "optional": false, - "description": "", - "line": 42 - }, - { - "name": "historyShow", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 43 - }, - { - "name": "isAdvanced", - "deprecated": false, - "deprecationMessage": "", - "type": "boolean", - "optional": false, - "description": "", - "line": 44 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 53, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "onSave", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 72, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "search", - "args": [ - { - "name": "search", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 62, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "search", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "toggleHistory", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 67, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';\nimport { FormControl } from '@angular/forms';\nimport { BaseDirective } from '@app/shared/directives';\nimport { Subject } from 'rxjs';\n\nimport { ISearchParam } from '../main/main.service';\n\n@Component({\n selector: 'app-tools',\n template: `\n \n \n \n \n Advanced\n
\n \n \n
\n `,\n styles: [\n ':host {display: flex;justify-content: space-between;align-items: baseline; margin: 10px 20px 0;}',\n '.form_config_button_save { margin: 0 16px 0 30px;}',\n '.description {flex: 0}',\n ],\n})\nexport class ToolsComponent extends BaseDirective implements OnInit {\n private filter$ = new Subject();\n filterParams: ISearchParam = { advanced: false, search: '' };\n historyShow = false;\n isAdvanced: boolean;\n description = new FormControl();\n @Input() disabledSave = true;\n @Input() disabledHistory = true;\n\n @Output() applyFilter = new EventEmitter();\n @Output() save = new EventEmitter();\n @Output() showHistory = new EventEmitter();\n\n ngOnInit() {\n this.filter$.pipe(this.takeUntil()).subscribe(() => this.applyFilter.emit(this.filterParams));\n }\n\n set advanced(advanced: boolean) {\n this.filterParams.advanced = advanced;\n this.filter$.next();\n }\n\n search(search: string) {\n this.filterParams.search = search;\n this.filter$.next();\n }\n\n toggleHistory() {\n this.historyShow = !this.historyShow;\n this.showHistory.emit(this.historyShow);\n }\n\n onSave() {\n this.save.emit();\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": ":host {display: flex;justify-content: space-between;align-items: baseline; margin: 10px 20px 0;}\n.form_config_button_save { margin: 0 16px 0 30px;}\n.description {flex: 0}\n", - "extends": "BaseDirective", - "implements": [ - "OnInit" - ], - "accessors": { - "advanced": { - "name": "advanced", - "setSignature": { - "name": "advanced", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "advanced", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 57, - "jsdoctags": [ - { - "name": "advanced", - "type": "boolean", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "TooltipComponent", - "id": "component-TooltipComponent-a70b027f8ca1cb2ef7bd433cd939cbfc", - "file": "src/app/shared/components/tooltip/tooltip.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-tooltip", - "styleUrls": [ - "./tooltip.component.scss" - ], - "styles": [], - "template": "", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "componentInjector", - "deprecated": false, - "deprecationMessage": "", - "type": "Injector", - "optional": false, - "description": "", - "line": 58 - }, - { - "name": "CurrentComponent", - "deprecated": false, - "deprecationMessage": "", - "type": "Type", - "optional": false, - "description": "", - "line": 57 - }, - { - "name": "options", - "deprecated": false, - "deprecationMessage": "", - "type": "TooltipOptions", - "optional": false, - "description": "", - "line": 54, - "modifierKind": [ - 120 - ] - }, - { - "name": "source", - "deprecated": false, - "deprecationMessage": "", - "type": "HTMLElement", - "optional": false, - "description": "", - "line": 55 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "buildComponent", - "args": [ - { - "name": "o", - "type": "TooltipOptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 132, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "o", - "type": "TooltipOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clear", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 92, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "getPositionString", - "args": [ - { - "name": "po", - "type": "any", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 128, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "po", - "type": "any", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "hide", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 87, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "menter", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 70, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseenter', ['$event']" - } - ] - }, - { - "name": "mleave", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 74, - "deprecated": false, - "deprecationMessage": "", - "decorators": [ - { - "name": "HostListener", - "stringifiedArguments": "'mouseleave'" - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 78, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "position", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 99, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [ - { - "name": "mouseenter", - "args": [], - "argsDecorator": [ - "$event" - ], - "deprecated": false, - "deprecationMessage": "", - "line": 70 - }, - { - "name": "mouseleave", - "args": [], - "argsDecorator": [], - "deprecated": false, - "deprecationMessage": "", - "line": 74 - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import {\n Component,\n ElementRef,\n EventEmitter,\n HostListener,\n Injector,\n Input,\n OnDestroy,\n OnInit,\n Renderer2,\n Type,\n} from '@angular/core';\nimport { Router } from '@angular/router';\nimport { BaseDirective } from '@app/shared/directives';\nimport { delay } from 'rxjs/operators';\n\nimport { IssueInfoComponent } from '../issue-info.component';\nimport { StatusInfoComponent } from '../status-info.component';\nimport { ComponentData, TooltipOptions, TooltipService } from './tooltip.service';\n\nconst POSITION_MARGIN = 16;\n\n@Component({\n selector: 'app-simple-text',\n template: '{{ current }}',\n})\nexport class SimpleTextComponent implements OnInit {\n @Input() current: any;\n constructor(private componentData: ComponentData) {}\n ngOnInit(): void {\n this.current = this.current || this.componentData.current;\n this.componentData.emitter.emit('Done');\n }\n}\n\nconst kit = { issue: IssueInfoComponent, status: StatusInfoComponent };\n@Component({\n selector: 'app-tooltip',\n template: '',\n styleUrls: ['./tooltip.component.scss'],\n})\nexport class TooltipComponent extends BaseDirective implements OnInit, OnDestroy {\n private options: TooltipOptions;\n source: HTMLElement;\n\n CurrentComponent: Type;\n componentInjector: Injector;\n\n constructor(\n private el: ElementRef,\n private service: TooltipService,\n private renderer: Renderer2,\n private router: Router,\n private parentInjector: Injector\n ) {\n super();\n }\n\n @HostListener('mouseenter', ['$event']) menter() {\n this.service.mouseEnterTooltip();\n }\n\n @HostListener('mouseleave') mleave() {\n this.service.mouseLeaveTooltip();\n }\n\n ngOnInit(): void {\n this.service.position$.pipe(this.takeUntil()).subscribe((o) => {\n if (o) {\n this.clear();\n this.buildComponent(o);\n } else this.hide();\n });\n }\n\n hide() {\n this.renderer.setAttribute(this.el.nativeElement, 'style', `opacity: 0; height: auto;`);\n this.clear();\n }\n\n clear() {\n if (this.source) {\n this.source = null;\n this.CurrentComponent = null;\n }\n }\n\n position() {\n const o = this.options;\n const el = this.el.nativeElement;\n const root = document.querySelector('app-root');\n const position = { left: 0, top: 0, bottom: 0, right: 0, height: 0 };\n const offsetParent = (s: HTMLElement) => s.offsetParent as HTMLElement;\n const offset = (s: HTMLElement) => ({ top: s.offsetTop, left: s.offsetLeft });\n const increment = (a: { top: number; left: number }, b: { top: number; left: number }) => ({ top: a.top + b.top, left: a.left + b.left });\n const offsetSum = (s: HTMLElement) => (offsetParent(s) ? increment(offset(s), offsetSum(offsetParent(s))) : offset(s));\n const os = offsetSum(o.source);\n position.top = os.top + o.source.offsetHeight;\n\n // TODO: maybe let's up tooltip?\n // this height for tooltip for scrolling\n position.height = o.event.y > root.offsetHeight - el.offsetHeight ? root.offsetHeight - position.top - POSITION_MARGIN : 0;\n\n switch (o.options.position) {\n case 'bottom':\n if (o.event.x + el.offsetWidth > root.offsetWidth) position.right = POSITION_MARGIN * 2;\n else position.left = os.left + o.source.clientWidth;\n break;\n case 'left':\n position.left = o.event.x < el.clientWidth ? POSITION_MARGIN * 2 : os.left - el.clientWidth;\n break;\n }\n\n this.renderer.setAttribute(el, 'style', `opacity: .9; ${this.getPositionString(position)}`);\n }\n\n getPositionString(po: any) {\n return Object.keys(po).reduce((p, c) => p + (po[c] ? `${c}: ${po[c]}px;` : ''), '');\n }\n\n buildComponent(o: TooltipOptions) {\n this.options = o;\n this.source = this.options.source;\n this.CurrentComponent = kit[this.options.options.componentName] || SimpleTextComponent;\n\n const emitter = new EventEmitter();\n emitter.pipe(delay(100), this.takeUntil()).subscribe(() => this.position());\n\n const parse = (url: string) =>\n url\n .split('/')\n .map((b) => b.split(';')[0])\n .join('/');\n\n this.componentInjector = Injector.create({\n providers: [\n {\n provide: ComponentData,\n useValue: { path: parse(this.router.url), current: this.options.options.content, emitter: emitter },\n },\n ],\n parent: this.parentInjector,\n });\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n line-height: normal;\n text-align: left;\n font-family: Roboto, \"Helvetica Neue\", sans-serif;\n color: #fff;\n font-size: 14px;\n position: absolute;\n display: block;\n border: solid 1px #455A64;\n padding: 8px 14px;\n background-color: #37474F;\n border-radius: 5px;\n box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2),\n 0px 2px 2px 0px rgba(0, 0, 0, 0.14),\n 0px 1px 5px 0px rgba(0, 0, 0, 0.12);\n opacity: 0;\n height: auto;\n // -webkit-transition: .2s ease-in-out;\n // -moz-transition: .2s ease-in-out;\n // -o-transition: .2s ease-in-out;\n //transition: .2s ease-in-out;\n z-index: 1100;\n overflow: auto;\n}\n", - "styleUrl": "./tooltip.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "service", - "type": "TooltipService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "parentInjector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 58, - "jsdoctags": [ - { - "name": "el", - "type": "ElementRef", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "service", - "type": "TooltipService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "renderer", - "type": "Renderer2", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "parentInjector", - "type": "Injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "implements": [ - "OnInit", - "OnDestroy" - ] - }, - { - "name": "TopComponent", - "id": "component-TopComponent-80e20dc06909003d8740fc7b9a082fc4", - "file": "src/app/main/top/top.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-top", - "styleUrls": [ - "./top.component.scss" - ], - "styles": [], - "templateUrl": [ - "./top.component.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "isAuth$", - "defaultValue": "of(false)", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 25 - } - ], - "methodsClass": [ - { - "name": "logout", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 40, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 32, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "profile", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 36, - "deprecated": false, - "deprecationMessage": "" - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { Store } from '@ngrx/store';\nimport { Observable, of } from 'rxjs';\n\nimport { authLogout, AuthState, isAuthenticated } from '@app/core/store';\n\n@Component({\n selector: 'app-top',\n templateUrl: './top.component.html',\n styleUrls: ['./top.component.scss'],\n})\nexport class TopComponent implements OnInit {\n isAuth$: Observable = of(false);\n\n constructor(\n private router: Router,\n private authStore: Store,\n ) {}\n\n ngOnInit() {\n this.isAuth$ = this.authStore.select(isAuthenticated);\n }\n\n profile() {\n this.router.navigate(['profile']);\n }\n\n logout() {\n this.authStore.dispatch(authLogout());\n }\n\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ".mat-toolbar {\n height: auto !important;\n padding: 6px 16px !important;\n background-color: #333c47 !important;\n margin-bottom: 0;\n display: block;\n}\n\n.right-panel {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n}\n\napp-bell {\n margin-right: 8px;\n}\n\na {\n display: flex;\n align-items: center;\n margin: 5px 0;\n\n img {\n height: 40px;\n vertical-align: bottom;\n }\n\n &:hover {\n text-decoration: none;\n }\n}\n\n.top-menu {\n display: flex;\n justify-content: center;\n height: 50px;\n justify-items: baseline;\n\n & a {\n font-size: 14px;\n }\n}\n\n.job-status {\n display: inline-block;\n margin: 0 4px;\n\n & .mat-mini-fab {\n margin: 0 4px;\n width: 24px;\n height: 24px;\n line-height: 12px;\n }\n}\n", - "styleUrl": "./top.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "authStore", - "type": "Store", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 25, - "jsdoctags": [ - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "authStore", - "type": "Store", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ], - "templateData": "\n \n \"Arenadata\n \n\n \n \n CLUSTERS\n \n \n HOSTPROVIDERS\n \n \n HOSTS\n \n JOBS\n \n BUNDLES\n \n \n\n \n \n \n\n \n\n \n \n contact_support\n Ask for help\n \n\n \n event_seat\n Documentation\n \n\n \n\n \n \n \n settings_applications\n Settings\n \n \n \n \n \n \n\n" - }, - { - "name": "UpgradeComponent", - "id": "component-UpgradeComponent-34c36605396243e8465a70ce623de60b", - "file": "src/app/shared/components/upgrade.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-upgrade", - "styleUrls": [], - "styles": [], - "template": "\n\n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "row", - "deprecated": false, - "deprecationMessage": "", - "line": 81, - "type": "" - }, - { - "name": "xPosition", - "defaultValue": "'before'", - "deprecated": false, - "deprecationMessage": "", - "line": 78, - "type": "string" - } - ], - "outputsClass": [ - { - "name": "refresh", - "defaultValue": "new EventEmitter()", - "deprecated": false, - "deprecationMessage": "", - "line": 87, - "type": "EventEmitter" - } - ], - "propertiesClass": [ - { - "name": "EventHelper", - "defaultValue": "EventHelper", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 73 - }, - { - "name": "list$", - "deprecated": false, - "deprecationMessage": "", - "type": "Observable", - "optional": false, - "description": "", - "line": 75 - }, - { - "name": "pRow", - "defaultValue": "{ upgradable: false, upgrade: '', issue: null }", - "deprecated": false, - "deprecationMessage": "", - "type": "UpgradeItem", - "optional": false, - "description": "", - "line": 76 - }, - { - "name": "destroy$", - "defaultValue": "new Subject()", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 21, - "inheritance": { - "file": "BaseDirective" - } - } - ], - "methodsClass": [ - { - "name": "checkIssue", - "args": [], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 93, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "fork", - "args": [ - { - "name": "item", - "type": "Upgrade", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 126, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "Upgrade", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getUpgrades", - "args": [ - { - "name": "upgrade", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "Observable", - "typeParameters": [], - "line": 131, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "upgrade", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "runUpgrade", - "args": [ - { - "name": "item", - "type": "Upgrade", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 97, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "item", - "type": "Upgrade", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnDestroy", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 23, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - }, - { - "name": "takeUntil", - "args": [], - "optional": false, - "returnType": "MonoTypeOperatorFunction", - "typeParameters": [ - "T" - ], - "line": 28, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "BaseDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { MatDialog } from '@angular/material/dialog';\nimport { ApiService } from '@app/core/api';\nimport { EmmitRow } from '@app/core/types';\nimport { concat, Observable, of } from 'rxjs';\nimport { filter, map, switchMap } from 'rxjs/operators';\nimport { EventHelper } from '@adwp-ui/widgets';\n\nimport { BaseDirective } from '../directives';\nimport { DialogComponent } from './dialog.component';\nimport { IIssues } from '@app/models/issue';\nimport { IssueHelper } from '@app/helpers/issue-helper';\n\nexport interface UpgradeItem {\n upgradable: boolean;\n upgrade: string;\n issue: IIssues;\n}\n\nexport interface Upgrade {\n id: number;\n bundle_id: number;\n name: string;\n description: string;\n do: string;\n upgradable: boolean;\n from_edition: string[];\n license: 'unaccepted' | 'absent';\n license_url: string;\n max_strict: boolean;\n max_version: string;\n min_strict: boolean;\n min_version: string;\n state_available: string;\n state_on_success: string;\n url: string;\n}\n\n@Component({\n selector: 'app-upgrade',\n template: `\n \n \n \n \n \n \n `\n})\nexport class UpgradeComponent extends BaseDirective {\n EventHelper = EventHelper;\n\n list$: Observable;\n pRow: UpgradeItem = { upgradable: false, upgrade: '', issue: null };\n\n @Input() xPosition = 'before';\n\n @Input()\n set row(row: UpgradeItem) {\n this.pRow = row;\n this.list$ = this.getUpgrades(this.pRow.upgrade);\n }\n\n @Output()\n refresh: EventEmitter = new EventEmitter();\n\n constructor(private api: ApiService, private dialog: MatDialog) {\n super();\n }\n\n checkIssue() {\n return this.pRow.upgradable && !IssueHelper.isIssue(this.pRow.issue);\n }\n\n runUpgrade(item: Upgrade) {\n const license$ = item.license === 'unaccepted' ? this.api.put(`${item.license_url}accept/`, {}) : of();\n const do$ = this.api.post<{ id: number }>(item.do, {});\n this.fork(item)\n .pipe(\n switchMap(text =>\n this.dialog\n .open(DialogComponent, {\n data: {\n title: 'Are you sure you want to upgrade?',\n text,\n disabled: !item.upgradable,\n controls: item.license === 'unaccepted' ? {\n label: 'Do you accept the license agreement?',\n buttons: ['Yes', 'No']\n } : ['Yes', 'No']\n }\n })\n .beforeClosed()\n .pipe(\n this.takeUntil(),\n filter(yes => yes),\n switchMap(() => concat(license$, do$))\n )\n )\n )\n .subscribe(row => this.refresh.emit({ cmd: 'refresh', row }));\n }\n\n fork(item: Upgrade) {\n const flag = item.license === 'unaccepted';\n return flag ? this.api.get<{ text: string }>(item.license_url).pipe(map(a => a.text)) : of(item.description);\n }\n\n getUpgrades(upgrade: string): Observable {\n return this.api.get(`${upgrade}?ordering=-name`).pipe(\n filter((list: Upgrade[]) => !!list.length)\n );\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 87, - "jsdoctags": [ - { - "name": "api", - "type": "ApiService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "extends": "BaseDirective", - "accessors": { - "row": { - "name": "row", - "setSignature": { - "name": "row", - "type": "void", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "row", - "type": "UpgradeItem", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "void", - "line": 81, - "jsdoctags": [ - { - "name": "row", - "type": "UpgradeItem", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - } - } - }, - { - "name": "UsersComponent", - "id": "component-UsersComponent-ea1fe3d6dc908d036a0a83d472ae080f", - "file": "src/app/admin/users/users.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [ - { - "name": "UsersService" - } - ], - "selector": "app-users", - "styleUrls": [ - "users.component.scss" - ], - "styles": [], - "templateUrl": [ - "./users.component.html" - ], - "viewProviders": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [ - { - "name": "addForm", - "defaultValue": "new FormGroup({\n username: new FormControl('', [Validators.required, Validators.pattern('[a-zA-Z0-9]*')]),\n xxx: this.chPassword,\n })", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 39 - }, - { - "name": "chPassword", - "defaultValue": "new FormGroup({\n password: new FormControl('', [Validators.required]),\n cpassword: new FormControl('', [Validators.required]),\n })", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 34 - }, - { - "name": "currentUserName", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "optional": false, - "description": "", - "line": 32 - }, - { - "name": "hideLeft", - "defaultValue": "true", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 30 - }, - { - "name": "showChangePassword", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "optional": false, - "description": "", - "line": 31 - }, - { - "name": "users", - "deprecated": false, - "deprecationMessage": "", - "type": "User[]", - "optional": false, - "description": "", - "line": 29 - } - ], - "methodsClass": [ - { - "name": "addUser", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 66, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "changePassword", - "args": [ - { - "name": "user", - "type": "User", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 95, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "user", - "type": "User", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clearUser", - "args": [ - { - "name": "user", - "type": "User", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 75, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "user", - "type": "User", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 58, - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "validRow", - "args": [ - { - "name": "pass", - "type": "NgModel", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cpass", - "type": "NgModel", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "boolean", - "typeParameters": [], - "line": 91, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "pass", - "type": "NgModel", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cpass", - "type": "NgModel", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\nimport { FormControl, FormGroup, NgModel, Validators } from '@angular/forms';\nimport { map } from 'rxjs/operators';\nimport { Router } from '@angular/router';\nimport { MatDialog } from '@angular/material/dialog';\n\nimport { AuthService } from '../../core/auth/auth.service';\nimport { DialogComponent } from '@app/shared/components';\nimport { User, UsersService } from './users.service';\n\n@Component({\n selector: 'app-users',\n templateUrl: './users.component.html',\n styleUrls: ['users.component.scss'],\n providers: [UsersService],\n})\nexport class UsersComponent implements OnInit {\n users: User[];\n hideLeft = true;\n showChangePassword = false;\n currentUserName: string;\n\n chPassword = new FormGroup({\n password: new FormControl('', [Validators.required]),\n cpassword: new FormControl('', [Validators.required]),\n });\n\n addForm = new FormGroup({\n username: new FormControl('', [Validators.required, Validators.pattern('[a-zA-Z0-9]*')]),\n xxx: this.chPassword,\n });\n\n constructor(private us: UsersService, private auth: AuthService, private router: Router, private dialog: MatDialog) {}\n\n get username() {\n return this.addForm.get('username');\n }\n\n get password() {\n return this.addForm.get('xxx').get('password');\n }\n\n get cpassword() {\n return this.addForm.get('xxx').get('cpassword');\n }\n\n ngOnInit() {\n this.currentUserName = this.auth.auth.login;\n this.us\n .getUsers()\n .pipe(map((u) => u.filter((a) => a.username !== 'status')))\n .subscribe((users) => (this.users = users));\n }\n\n addUser() {\n if (this.addForm.valid)\n this.us.addUser(this.addForm.get('username').value, this.addForm.get('xxx').get('password').value).subscribe((user) => {\n this.users = this.users.concat(user);\n this.addForm.reset();\n this.hideLeft = true;\n });\n }\n\n clearUser(user: User) {\n const dialogRef = this.dialog.open(DialogComponent, {\n width: '250px',\n data: {\n text: `Delete [ ${user.username} ]? Are you sure?`,\n controls: ['Yes', 'No'],\n },\n });\n\n dialogRef.beforeClosed().subscribe((yes) => {\n if (yes) {\n this.us.clearUser(user).subscribe((_) => (this.users = this.users.filter((u) => u !== user)));\n }\n });\n }\n\n validRow(pass: NgModel, cpass: NgModel): boolean {\n return pass.valid && cpass.valid && pass.value === cpass.value;\n }\n\n changePassword(user: User) {\n this.us.changePassword(user.password, user.change_password).subscribe((_) => {\n user.password = '';\n user.confirm = '';\n if (user.username === this.currentUserName) this.router.navigate(['/login']);\n });\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": [ - { - "data": ":host {\n flex: 1;\n width: 100%;\n}\n\n.users-add-card {\n position: fixed;\n right: 20px;\n width: 250px;\n}\n\n.add-button {\n position: absolute;\n right: 40px;\n top: 10px;\n}\n", - "styleUrl": "users.component.scss" - } - ], - "stylesData": "", - "constructorObj": { - "name": "constructor", - "description": "", - "deprecated": false, - "deprecationMessage": "", - "args": [ - { - "name": "us", - "type": "UsersService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "auth", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "" - } - ], - "line": 42, - "jsdoctags": [ - { - "name": "us", - "type": "UsersService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "auth", - "type": "AuthService", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "router", - "type": "Router", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "dialog", - "type": "MatDialog", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - "implements": [ - "OnInit" - ], - "accessors": { - "username": { - "name": "username", - "getSignature": { - "name": "username", - "type": "", - "returnType": "", - "line": 46 - } - }, - "password": { - "name": "password", - "getSignature": { - "name": "password", - "type": "", - "returnType": "", - "line": 50 - } - }, - "cpassword": { - "name": "cpassword", - "getSignature": { - "name": "cpassword", - "type": "", - "returnType": "", - "line": 54 - } - } - }, - "templateData": "\n\n\n \n
\n
\n \n \n \n \n Username is\n required\n \n \n Username is\n not valid\n \n \n \n
\n
\n
\n
\n \n \n \n \n Password is\n required\n \n \n \n
\n
\n \n \n \n \n Confirm password is\n required\n \n \n Password and confirm password does not match\n \n \n \n
\n
\n

\n \n

\n
\n
\n
\n
\n\n\n\n \n \n\n \n UserName \n \n
{{ row.username }}
\n
\n
\n\n \n Password \n \n \n \n \n  \n \n \n \n \n \n \n\n \n \n \n \n \n \n
\n" - }, - { - "name": "VariantComponent", - "id": "component-VariantComponent-96e04dde587f6ca6d6bad4ae8672bff9", - "file": "src/app/shared/form-elements/variant.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-fields-variant", - "styleUrls": [], - "styles": [], - "template": "\n \n \n \n {{ option }}\n \n \n \n \n \n \n {{ option }}\n \n \n \n \n \n\n", - "templateUrl": [], - "viewProviders": [], - "inputsClass": [ - { - "name": "field", - "deprecated": false, - "deprecationMessage": "", - "line": 23, - "type": "IFieldOptions", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "form", - "deprecated": false, - "deprecationMessage": "", - "line": 22, - "type": "FormGroup", - "inheritance": { - "file": "FieldDirective" - } - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [ - { - "name": "ngOnInit", - "args": [], - "optional": false, - "returnType": "void", - "typeParameters": [], - "line": 40, - "deprecated": false, - "deprecationMessage": "", - "inheritance": { - "file": "FieldDirective" - } - }, - { - "name": "hasError", - "args": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "any", - "typeParameters": [], - "line": 39, - "deprecated": false, - "deprecationMessage": "", - "jsdoctags": [ - { - "name": "name", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ], - "inheritance": { - "file": "FieldDirective" - } - } - ], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, OnInit } from '@angular/core';\n\nimport { FieldDirective } from './field.directive';\n\n@Component({\n selector: 'app-fields-variant',\n template: `\n \n \n \n \n {{ option }}\n \n \n \n \n \n \n {{ option }}\n \n \n \n \n \n \n `,\n})\nexport class VariantComponent extends FieldDirective implements OnInit {\n ngOnInit() {\n if (this.field.read_only) {\n this.control.disable();\n }\n }\n}\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": "FieldDirective", - "implements": [ - "OnInit" - ] - } - ], - "modules": [ - { - "name": "AddingModule", - "id": "module-AddingModule-887fb60bdbbbfb0b64a62b421f2efb15", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/add-component/adding.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { FormElementsModule } from '@app/shared/form-elements/form-elements.module';\nimport { MaterialModule } from '@app/shared/material.module';\nimport { StuffModule } from '@app/shared/stuff.module';\n\nimport { AddButtonComponent } from './add-button.component';\nimport { AddFormComponent } from './add-form.component';\nimport { BaseFormDirective } from './base-form.directive';\nimport { AddClusterComponent } from './add-cluster.component';\nimport { HostComponent } from './host.component';\nimport { Host2clusterComponent } from './host2cluster.component';\nimport { ProviderComponent } from './provider.component';\nimport { ServiceComponent } from './service.component';\nimport { ControlsComponent } from './controls.component';\n\n@NgModule({\n declarations: [\n AddButtonComponent,\n AddFormComponent,\n AddClusterComponent,\n HostComponent,\n Host2clusterComponent,\n ProviderComponent,\n ServiceComponent,\n BaseFormDirective,\n ControlsComponent,\n ],\n imports: [CommonModule, MaterialModule, StuffModule, FormsModule, ReactiveFormsModule, FormElementsModule],\n exports: [\n AddButtonComponent,\n ProviderComponent,\n AddClusterComponent,\n HostComponent,\n ServiceComponent,\n Host2clusterComponent,\n BaseFormDirective,\n ControlsComponent,\n ],\n entryComponents: [AddFormComponent]\n})\nexport class AddingModule {\n}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "AddButtonComponent" - }, - { - "name": "AddClusterComponent" - }, - { - "name": "AddFormComponent" - }, - { - "name": "BaseFormDirective" - }, - { - "name": "ControlsComponent" - }, - { - "name": "Host2clusterComponent" - }, - { - "name": "HostComponent" - }, - { - "name": "ProviderComponent" - }, - { - "name": "ServiceComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "FormElementsModule" - }, - { - "name": "MaterialModule" - }, - { - "name": "StuffModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "AddButtonComponent" - }, - { - "name": "AddClusterComponent" - }, - { - "name": "BaseFormDirective" - }, - { - "name": "ControlsComponent" - }, - { - "name": "Host2clusterComponent" - }, - { - "name": "HostComponent" - }, - { - "name": "ProviderComponent" - }, - { - "name": "ServiceComponent" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "AdminModule", - "id": "module-AdminModule-da5818e7048922becdfd0770abb303a0", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/admin/admin.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { RouterModule, Routes } from '@angular/router';\nimport { AuthGuard } from '../core/auth/auth.guard';\nimport { SharedModule } from '@app/shared/shared.module';\n\nimport { IntroComponent } from './intro.component';\nimport { PatternComponent } from './pattern.component';\nimport { SettingsComponent } from './settings.component';\nimport { UsersComponent } from './users/users.component';\n\nconst routes: Routes = [\n {\n path: '',\n component: PatternComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n {\n path: '',\n redirectTo: 'intro',\n pathMatch: 'full',\n },\n {\n path: 'intro',\n component: IntroComponent,\n },\n {\n path: 'settings',\n component: SettingsComponent,\n },\n {\n path: 'users',\n component: UsersComponent,\n },\n ],\n },\n];\n\n@NgModule({\n imports: [RouterModule.forChild(routes)],\n exports: [RouterModule],\n})\nexport class AdminRoutingModule {}\n\n@NgModule({\n imports: [CommonModule, AdminRoutingModule, SharedModule],\n declarations: [IntroComponent, SettingsComponent, UsersComponent, PatternComponent],\n})\nexport class AdminModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "IntroComponent" - }, - { - "name": "PatternComponent" - }, - { - "name": "SettingsComponent" - }, - { - "name": "UsersComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "AdminRoutingModule" - }, - { - "name": "SharedModule" - } - ] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "AdminRoutingModule", - "id": "module-AdminRoutingModule-da5818e7048922becdfd0770abb303a0", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/admin/admin.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { RouterModule, Routes } from '@angular/router';\nimport { AuthGuard } from '../core/auth/auth.guard';\nimport { SharedModule } from '@app/shared/shared.module';\n\nimport { IntroComponent } from './intro.component';\nimport { PatternComponent } from './pattern.component';\nimport { SettingsComponent } from './settings.component';\nimport { UsersComponent } from './users/users.component';\n\nconst routes: Routes = [\n {\n path: '',\n component: PatternComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n {\n path: '',\n redirectTo: 'intro',\n pathMatch: 'full',\n },\n {\n path: 'intro',\n component: IntroComponent,\n },\n {\n path: 'settings',\n component: SettingsComponent,\n },\n {\n path: 'users',\n component: UsersComponent,\n },\n ],\n },\n];\n\n@NgModule({\n imports: [RouterModule.forChild(routes)],\n exports: [RouterModule],\n})\nexport class AdminRoutingModule {}\n\n@NgModule({\n imports: [CommonModule, AdminRoutingModule, SharedModule],\n declarations: [IntroComponent, SettingsComponent, UsersComponent, PatternComponent],\n})\nexport class AdminModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [] - }, - { - "type": "imports", - "elements": [] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "AppModule", - "id": "module-AppModule-c9a4a31c4d9a4832e6a9213654ef2274", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/app.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { APP_INITIALIZER, Injector, NgModule } from '@angular/core';\nimport { BrowserModule } from '@angular/platform-browser';\nimport { BrowserAnimationsModule } from '@angular/platform-browser/animations';\nimport { EffectsModule } from '@ngrx/effects';\nimport { StoreModule } from '@ngrx/store';\nimport { StoreDevtoolsModule } from '@ngrx/store-devtools';\nimport { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';\nimport { HttpClient } from '@angular/common/http';\nimport { AdwpUiWidgetsModule } from '@adwp-ui/widgets';\n\nimport { CoreModule } from '@app/core/core.module';\nimport { ConfigService } from '@app/core/services';\nimport { reducers, StoreEffects } from '@app/core/store';\nimport { environment } from '@env/environment';\nimport { AppComponent } from './app.component';\nimport { EntryModule } from './entry/entry.module';\nimport { MainModule } from './main/main.module';\nimport { SharedModule } from './shared/shared.module';\nimport { LogComponent } from './ws-logs/log.component';\nimport { appInitializer, translateLoader } from '@app/shared/translate/intializer';\nimport { AppRoutingModule } from '@app/app-routing.module';\nimport { ListService } from '@app/shared/components/list/list.service';\nimport { LIST_SERVICE_PROVIDER } from '@app/shared/components/list/list-service-token';\nimport { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model';\nimport { AddService } from '@app/shared/add-component/add.service';\n\n@NgModule({\n declarations: [\n AppComponent,\n LogComponent,\n ],\n imports: [\n BrowserModule,\n BrowserAnimationsModule,\n CoreModule,\n SharedModule,\n EntryModule,\n MainModule,\n AppRoutingModule,\n StoreModule.forRoot(reducers),\n EffectsModule.forRoot(StoreEffects),\n !environment.production ? StoreDevtoolsModule.instrument() : [],\n TranslateModule.forRoot({\n defaultLanguage: 'en',\n loader: {\n provide: TranslateLoader,\n useFactory: translateLoader,\n deps: [HttpClient]\n }\n }),\n AdwpUiWidgetsModule,\n ],\n bootstrap: [AppComponent],\n providers: [\n {\n provide: APP_INITIALIZER,\n useFactory: (appConfig: ConfigService) => () => appConfig.load(),\n deps: [ConfigService],\n multi: true,\n },\n {\n provide: APP_INITIALIZER,\n useFactory: appInitializer,\n deps: [TranslateService, Injector],\n multi: true\n },\n {\n provide: LIST_SERVICE_PROVIDER,\n useClass: ListService\n },\n {\n provide: ADD_SERVICE_PROVIDER,\n useClass: AddService\n },\n ],\n})\nexport class AppModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "AppComponent" - }, - { - "name": "LogComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "!environment" - }, - { - "name": "AppRoutingModule" - }, - { - "name": "CoreModule" - }, - { - "name": "EntryModule" - }, - { - "name": "MainModule" - }, - { - "name": "SharedModule" - } - ] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [ - { - "name": "AppComponent" - } - ] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "AppRoutingModule", - "id": "module-AppRoutingModule-7a949d7d14777f47367cc9c37f405275", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/app-routing.module.ts", - "methods": [], - "sourceCode": "import { NgModule } from '@angular/core';\nimport { RouterModule, Routes } from '@angular/router';\n\nimport { LogComponent } from '@app/ws-logs/log.component';\nimport { AuthGuard } from '@app/core/auth/auth.guard';\nimport { LoginComponent } from '@app/main/login/login.component';\nimport { ProfileComponent } from '@app/main/profile/profile.component';\nimport { SupportComponent } from '@app/main/support/support.component';\nimport { FatalErrorComponent, GatewayTimeoutComponent, PageNotFoundComponent } from '@app/main/server-status.component';\nimport { HostListComponent } from '@app/components/host/host-list/host-list.component';\nimport { MainInfoComponent } from '@app/shared/components';\nimport { ConfigComponent } from '@app/shared/configuration/main/config.component';\nimport { HostproviderComponent } from '@app/components/hostprovider/hostprovider.component';\nimport { ConfigGroupHostListComponent, ConfigGroupListComponent } from '@app/config-groups';\nimport { HostDetailsComponent } from '@app/components/host/host-details/host-details.component';\nimport { ProviderDetailsComponent } from '@app/components/hostprovider/provider-details/provider-details.component';\nimport { GroupConfigDetailsComponent } from '@app/components/hostprovider/group-config-details/group-config-details.component';\nimport { HostStatusComponent } from '@app/components/host/host-status/host-status.component';\n\nconst routes: Routes = [\n {\n path: 'cluster',\n loadChildren: () => \"import('app/entry/cluster/cluster.module').then(m => m.ClusterModule)\",\n },\n {\n path: 'job',\n loadChildren: () => \"import('app/entry/job/job.module').then(m => m.JobModule)\",\n },\n {\n path: 'task',\n loadChildren: () => \"import('app/entry/task/task.module').then(m => m.TaskModule)\",\n },\n {\n path: 'bundle',\n loadChildren: () => \"import('app/entry/bundle/bundle.module').then(m => m.BundleModule)\",\n },\n {\n path: 'host',\n children: [\n {\n path: '',\n pathMatch: 'full',\n component: HostListComponent,\n }, {\n path: ':host',\n component: HostDetailsComponent,\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'status', component: HostStatusComponent },\n ],\n }\n ],\n canActivate: [AuthGuard],\n },\n {\n path: 'provider',\n children: [\n {\n path: '',\n pathMatch: 'full',\n component: HostproviderComponent,\n }, {\n path: ':provider',\n component: ProviderDetailsComponent,\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'group_config', component: ConfigGroupListComponent },\n ]\n }\n ],\n canActivate: [AuthGuard],\n },\n {\n path: 'provider/:provider/group_config/:group_config',\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n component: GroupConfigDetailsComponent,\n children: [\n { path: '', redirectTo: 'host', pathMatch: 'full' },\n { path: 'host', component: ConfigGroupHostListComponent },\n { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } },\n ],\n },\n\n {\n path: 'cluster/:cluster/host/:host/provider/:provider',\n redirectTo: 'provider/:provider',\n },\n {\n path: 'host/:host/provider/:provider',\n redirectTo: 'provider/:provider',\n },\n { path: '', redirectTo: 'admin', pathMatch: 'full' },\n { path: 'log', component: LogComponent, canActivate: [AuthGuard] },\n { path: 'login', component: LoginComponent },\n { path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] },\n { path: 'support', component: SupportComponent },\n { path: '404', component: PageNotFoundComponent },\n { path: '500', component: FatalErrorComponent },\n { path: '504', component: GatewayTimeoutComponent },\n {\n path: 'admin',\n loadChildren: () => \"import('app/admin/admin.module').then(m => m.AdminModule)\",\n },\n { path: '**', component: PageNotFoundComponent },\n];\n\n@NgModule({\n imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],\n exports: [RouterModule]\n})\nexport class AppRoutingModule {\n}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [] - }, - { - "type": "imports", - "elements": [] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "AttributesModule", - "id": "module-AttributesModule-dad1aecbe468c094ca4af775ddde34c8", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/configuration/attributes/attributes.module.ts", - "methods": [ - { - "name": "forRoot", - "args": [ - { - "name": "attributeConfig", - "type": "AttributesOptions", - "deprecated": false, - "deprecationMessage": "" - } - ], - "optional": false, - "returnType": "ModuleWithProviders", - "typeParameters": [], - "line": 35, - "deprecated": false, - "deprecationMessage": "", - "modifierKind": [ - 123 - ], - "jsdoctags": [ - { - "name": "attributeConfig", - "type": "AttributesOptions", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "sourceCode": "import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { MatTooltipModule } from '@angular/material/tooltip';\nimport { MatPseudoCheckboxModule } from '@angular/material/core';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\n\nimport { ATTRIBUTES_OPTIONS, AttributeService, AttributesOptions } from './attribute.service';\nimport { GroupKeysWrapperComponent } from './attributes/group-keys/group-keys-wrapper.component';\nimport { ConfigFieldMarker } from './config-field.directive';\nimport { ConfigFieldAttributeProviderComponent } from './attribute-provider.component';\nimport { TooltipModule } from '@app/shared/components/tooltip/tooltip.module';\n\n@NgModule({\n declarations: [\n GroupKeysWrapperComponent,\n ConfigFieldMarker,\n ConfigFieldAttributeProviderComponent,\n ],\n imports: [\n CommonModule,\n MatPseudoCheckboxModule,\n MatCheckboxModule,\n MatTooltipModule,\n TooltipModule,\n ReactiveFormsModule,\n ],\n exports: [\n ConfigFieldAttributeProviderComponent,\n ConfigFieldMarker\n ],\n providers: [AttributeService]\n})\nexport class AttributesModule {\n static forRoot(attributeConfig: AttributesOptions): ModuleWithProviders {\n return {\n ngModule: AttributesModule,\n providers: [{ provide: ATTRIBUTES_OPTIONS, useValue: attributeConfig }]\n };\n }\n}\n", - "children": [ - { - "type": "providers", - "elements": [ - { - "name": "AttributeService" - } - ] - }, - { - "type": "declarations", - "elements": [ - { - "name": "ConfigFieldAttributeProviderComponent" - }, - { - "name": "ConfigFieldMarker" - }, - { - "name": "GroupKeysWrapperComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "TooltipModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "ConfigFieldAttributeProviderComponent" - }, - { - "name": "ConfigFieldMarker" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "BundleModule", - "id": "module-BundleModule-81d62190aa9216e6cc3e41727e48e342", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/entry/bundle/bundle.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Routes, RouterModule } from '@angular/router';\n\nimport { AuthGuard } from '../../core/auth/auth.guard';\nimport { BundleListComponent, MainComponent, LicenseComponent } from './bundle-list.component';\nimport { SharedModule } from '@app/shared/shared.module';\nimport { BundleDetailsComponent } from '../../components/bundle/bundle-details/bundle-details.component';\n\nconst routes: Routes = [\n {\n path: '',\n canActivate: [AuthGuard],\n component: BundleListComponent,\n },\n {\n path: ':bundle',\n canActivate: [AuthGuard],\n component: BundleDetailsComponent,\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainComponent },\n { path: 'license', component: LicenseComponent },\n ],\n },\n];\n\n@NgModule({\n imports: [RouterModule.forChild(routes)],\n exports: [RouterModule],\n})\nexport class BundleRoutingModule {}\n\n@NgModule({\n declarations: [BundleListComponent, MainComponent, LicenseComponent],\n imports: [CommonModule, SharedModule, BundleRoutingModule, RouterModule, BundleRoutingModule],\n})\nexport class BundleModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "BundleListComponent" - }, - { - "name": "LicenseComponent" - }, - { - "name": "MainComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "BundleRoutingModule" - }, - { - "name": "BundleRoutingModule" - }, - { - "name": "SharedModule" - } - ] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "BundleRoutingModule", - "id": "module-BundleRoutingModule-81d62190aa9216e6cc3e41727e48e342", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/entry/bundle/bundle.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Routes, RouterModule } from '@angular/router';\n\nimport { AuthGuard } from '../../core/auth/auth.guard';\nimport { BundleListComponent, MainComponent, LicenseComponent } from './bundle-list.component';\nimport { SharedModule } from '@app/shared/shared.module';\nimport { BundleDetailsComponent } from '../../components/bundle/bundle-details/bundle-details.component';\n\nconst routes: Routes = [\n {\n path: '',\n canActivate: [AuthGuard],\n component: BundleListComponent,\n },\n {\n path: ':bundle',\n canActivate: [AuthGuard],\n component: BundleDetailsComponent,\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainComponent },\n { path: 'license', component: LicenseComponent },\n ],\n },\n];\n\n@NgModule({\n imports: [RouterModule.forChild(routes)],\n exports: [RouterModule],\n})\nexport class BundleRoutingModule {}\n\n@NgModule({\n declarations: [BundleListComponent, MainComponent, LicenseComponent],\n imports: [CommonModule, SharedModule, BundleRoutingModule, RouterModule, BundleRoutingModule],\n})\nexport class BundleModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [] - }, - { - "type": "imports", - "elements": [] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "ClusterModule", - "id": "module-ClusterModule-7c9fa6b4346b911c43e60d28977a8364", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/entry/cluster/cluster.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { RouterModule, Routes } from '@angular/router';\n\n\nimport { ConfigComponent } from '../../shared/configuration/main/config.component';\nimport { ImportComponent, MainInfoComponent } from '@app/shared/components';\nimport { SharedModule } from '@app/shared/shared.module';\n\nimport { ClusterListComponent } from './cluster.component';\nimport { HcmapComponent } from '@app/components/cluster/hcmap/hcmap.component';\nimport { ClusterHostComponent } from '../../components/cluster/host/cluster-host.component';\nimport { ServicesComponent } from '@app/components/cluster/services/services.component';\nimport { AuthGuard } from '../../core/auth/auth.guard';\nimport { ServiceComponentsComponent } from '../../components/service-component/service-components.component';\nimport {\n ConfigGroupHostListComponent,\n ConfigGroupListComponent,\n ConfigGroupModule\n} from '../../config-groups';\nimport { ClusterDetailsComponent } from '../../components/cluster/cluster-details/cluster-details.component';\nimport { GroupConfigDetailsComponent } from '../../components/hostprovider/group-config-details/group-config-details.component';\nimport { ServiceDetailsComponent } from '../../components/service/service-details/service-details.component';\nimport { ServiceComponentDetailsComponent } from '../../components/service-component/service-component-details/service-component-details.component';\nimport { HostDetailsComponent } from '../../components/host/host-details/host-details.component';\nimport { ClusterStatusComponent } from '../../components/cluster/cluster-status/cluster-status.component';\nimport { ServiceStatusComponent } from '../../components/service/service-status/service-status.component';\nimport { ServiceComponentStatusComponent } from '../../components/service-component/service-component-status/service-component-status.component';\nimport { HostStatusComponent } from '../../components/host/host-status/host-status.component';\n\nconst clusterRoutes: Routes = [\n {\n path: '',\n component: ClusterListComponent,\n canActivate: [AuthGuard],\n },\n {\n path: ':cluster',\n component: ClusterDetailsComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'service', component: ServicesComponent },\n { path: 'host', component: ClusterHostComponent },\n { path: 'host_component', component: HcmapComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'group_config', component: ConfigGroupListComponent },\n { path: 'status', component: ClusterStatusComponent },\n { path: 'import', component: ImportComponent },\n ],\n },\n {\n path: ':cluster/group_config/:group_config',\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n component: GroupConfigDetailsComponent,\n children: [\n { path: '', redirectTo: 'host', pathMatch: 'full' },\n { path: 'host', component: ConfigGroupHostListComponent },\n { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } },\n ],\n },\n {\n path: ':cluster/service/:service',\n component: ServiceDetailsComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'group_config', component: ConfigGroupListComponent },\n { path: 'status', component: ServiceStatusComponent },\n { path: 'import', component: ImportComponent },\n { path: 'component', component: ServiceComponentsComponent },\n ],\n },\n {\n path: ':cluster/service/:service/group_config/:group_config',\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n component: GroupConfigDetailsComponent,\n children: [\n { path: '', redirectTo: 'host', pathMatch: 'full' },\n { path: 'host', component: ConfigGroupHostListComponent },\n { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } },\n ],\n },\n {\n path: ':cluster/service/:service/component/:servicecomponent',\n component: ServiceComponentDetailsComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'group_config', component: ConfigGroupListComponent },\n { path: 'status', component: ServiceComponentStatusComponent },\n ],\n },\n {\n path: ':cluster/service/:service/component/:component/group_config/:group_config',\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n component: GroupConfigDetailsComponent,\n children: [\n { path: '', redirectTo: 'host', pathMatch: 'full' },\n { path: 'host', component: ConfigGroupHostListComponent },\n { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } },\n ],\n },\n {\n path: ':cluster/host/:host',\n component: HostDetailsComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'status', component: HostStatusComponent },\n ],\n },\n];\n\n@NgModule({\n imports: [\n RouterModule.forChild(clusterRoutes),\n ],\n exports: [RouterModule],\n})\nexport class ClusterRoutingModule {\n}\n\n@NgModule({\n imports: [\n CommonModule,\n SharedModule,\n RouterModule,\n ConfigGroupModule,\n ClusterRoutingModule,\n ],\n declarations: [\n ClusterListComponent,\n ServicesComponent,\n ClusterHostComponent,\n HcmapComponent,\n ClusterStatusComponent,\n ],\n})\nexport class ClusterModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "ClusterHostComponent" - }, - { - "name": "ClusterListComponent" - }, - { - "name": "ClusterStatusComponent" - }, - { - "name": "HcmapComponent" - }, - { - "name": "ServicesComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "ClusterRoutingModule" - }, - { - "name": "ConfigGroupModule" - }, - { - "name": "SharedModule" - } - ] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "ClusterRoutingModule", - "id": "module-ClusterRoutingModule-7c9fa6b4346b911c43e60d28977a8364", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/entry/cluster/cluster.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { RouterModule, Routes } from '@angular/router';\n\n\nimport { ConfigComponent } from '../../shared/configuration/main/config.component';\nimport { ImportComponent, MainInfoComponent } from '@app/shared/components';\nimport { SharedModule } from '@app/shared/shared.module';\n\nimport { ClusterListComponent } from './cluster.component';\nimport { HcmapComponent } from '@app/components/cluster/hcmap/hcmap.component';\nimport { ClusterHostComponent } from '../../components/cluster/host/cluster-host.component';\nimport { ServicesComponent } from '@app/components/cluster/services/services.component';\nimport { AuthGuard } from '../../core/auth/auth.guard';\nimport { ServiceComponentsComponent } from '../../components/service-component/service-components.component';\nimport {\n ConfigGroupHostListComponent,\n ConfigGroupListComponent,\n ConfigGroupModule\n} from '../../config-groups';\nimport { ClusterDetailsComponent } from '../../components/cluster/cluster-details/cluster-details.component';\nimport { GroupConfigDetailsComponent } from '../../components/hostprovider/group-config-details/group-config-details.component';\nimport { ServiceDetailsComponent } from '../../components/service/service-details/service-details.component';\nimport { ServiceComponentDetailsComponent } from '../../components/service-component/service-component-details/service-component-details.component';\nimport { HostDetailsComponent } from '../../components/host/host-details/host-details.component';\nimport { ClusterStatusComponent } from '../../components/cluster/cluster-status/cluster-status.component';\nimport { ServiceStatusComponent } from '../../components/service/service-status/service-status.component';\nimport { ServiceComponentStatusComponent } from '../../components/service-component/service-component-status/service-component-status.component';\nimport { HostStatusComponent } from '../../components/host/host-status/host-status.component';\n\nconst clusterRoutes: Routes = [\n {\n path: '',\n component: ClusterListComponent,\n canActivate: [AuthGuard],\n },\n {\n path: ':cluster',\n component: ClusterDetailsComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'service', component: ServicesComponent },\n { path: 'host', component: ClusterHostComponent },\n { path: 'host_component', component: HcmapComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'group_config', component: ConfigGroupListComponent },\n { path: 'status', component: ClusterStatusComponent },\n { path: 'import', component: ImportComponent },\n ],\n },\n {\n path: ':cluster/group_config/:group_config',\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n component: GroupConfigDetailsComponent,\n children: [\n { path: '', redirectTo: 'host', pathMatch: 'full' },\n { path: 'host', component: ConfigGroupHostListComponent },\n { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } },\n ],\n },\n {\n path: ':cluster/service/:service',\n component: ServiceDetailsComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'group_config', component: ConfigGroupListComponent },\n { path: 'status', component: ServiceStatusComponent },\n { path: 'import', component: ImportComponent },\n { path: 'component', component: ServiceComponentsComponent },\n ],\n },\n {\n path: ':cluster/service/:service/group_config/:group_config',\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n component: GroupConfigDetailsComponent,\n children: [\n { path: '', redirectTo: 'host', pathMatch: 'full' },\n { path: 'host', component: ConfigGroupHostListComponent },\n { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } },\n ],\n },\n {\n path: ':cluster/service/:service/component/:servicecomponent',\n component: ServiceComponentDetailsComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'group_config', component: ConfigGroupListComponent },\n { path: 'status', component: ServiceComponentStatusComponent },\n ],\n },\n {\n path: ':cluster/service/:service/component/:component/group_config/:group_config',\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n component: GroupConfigDetailsComponent,\n children: [\n { path: '', redirectTo: 'host', pathMatch: 'full' },\n { path: 'host', component: ConfigGroupHostListComponent },\n { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } },\n ],\n },\n {\n path: ':cluster/host/:host',\n component: HostDetailsComponent,\n canActivate: [AuthGuard],\n canActivateChild: [AuthGuard],\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainInfoComponent },\n { path: 'config', component: ConfigComponent },\n { path: 'status', component: HostStatusComponent },\n ],\n },\n];\n\n@NgModule({\n imports: [\n RouterModule.forChild(clusterRoutes),\n ],\n exports: [RouterModule],\n})\nexport class ClusterRoutingModule {\n}\n\n@NgModule({\n imports: [\n CommonModule,\n SharedModule,\n RouterModule,\n ConfigGroupModule,\n ClusterRoutingModule,\n ],\n declarations: [\n ClusterListComponent,\n ServicesComponent,\n ClusterHostComponent,\n HcmapComponent,\n ClusterStatusComponent,\n ],\n})\nexport class ClusterModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [] - }, - { - "type": "imports", - "elements": [] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "ConfigGroupModule", - "id": "module-ConfigGroupModule-2391140ab0d20e99ac04738b678dd093", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/config-groups/config-group.module.ts", - "methods": [], - "sourceCode": "import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { ConfigGroupHostListComponent, ConfigGroupListComponent } from './pages';\nimport { AdwpListModule } from '@adwp-ui/widgets';\nimport { AddConfigGroupComponent, AddHostToConfigGroupComponent } from './components';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { MatListModule } from '@angular/material/list';\nimport { AddingModule } from '@app/shared/add-component/adding.module';\nimport { FormElementsModule } from '@app/shared/form-elements/form-elements.module';\nimport { ListService } from '../shared/components/list/list.service';\nimport { LIST_SERVICE_PROVIDER } from '../shared/components/list/list-service-token';\nimport { MatPaginatorModule } from '@angular/material/paginator';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\n\n\n@NgModule({\n declarations: [\n ConfigGroupListComponent,\n AddConfigGroupComponent,\n ConfigGroupHostListComponent,\n AddHostToConfigGroupComponent,\n ],\n imports: [\n CommonModule,\n ReactiveFormsModule,\n AdwpListModule,\n MatListModule,\n AddingModule,\n FormElementsModule,\n MatPaginatorModule,\n MatCheckboxModule\n ],\n exports: [\n AddConfigGroupComponent,\n ],\n providers: [\n {\n provide: LIST_SERVICE_PROVIDER,\n useClass: ListService\n }\n ]\n})\nexport class ConfigGroupModule {\n}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "AddConfigGroupComponent" - }, - { - "name": "AddHostToConfigGroupComponent" - }, - { - "name": "ConfigGroupHostListComponent" - }, - { - "name": "ConfigGroupListComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "AddingModule" - }, - { - "name": "FormElementsModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "AddConfigGroupComponent" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "ConfigurationModule", - "id": "module-ConfigurationModule-d03285dec9a658c607cb46aa60d877b8", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/configuration/configuration.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\nimport { MatOptionModule } from '@angular/material/core';\nimport { MatExpansionModule } from '@angular/material/expansion';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatListModule } from '@angular/material/list';\nimport { MatSelectModule } from '@angular/material/select';\nimport { MatSlideToggleModule } from '@angular/material/slide-toggle';\nimport { MatToolbarModule } from '@angular/material/toolbar';\nimport { MatTooltipModule } from '@angular/material/tooltip';\n\nimport { FormElementsModule } from '../form-elements/form-elements.module';\nimport { StuffModule } from '../stuff.module';\nimport { FieldService } from './services/field.service';\nimport { FieldComponent } from './field/field.component';\nimport { ConfigFieldsComponent } from './fields/fields.component';\nimport { GroupFieldsComponent } from './group-fields/group-fields.component';\nimport { ConfigComponent } from './main/config.component';\nimport { ItemComponent } from './scheme/item.component';\nimport { RootComponent } from './scheme/root.component';\nimport { SchemeComponent } from './scheme/scheme.component';\nimport { SchemeService } from './scheme/scheme.service';\nimport { ColorOptionDirective } from './tools/color-option.directive';\nimport { HistoryComponent } from './tools/history.component';\nimport { SearchComponent } from './tools/search.component';\nimport { ToolsComponent } from './tools/tools.component';\nimport { YspecService } from './yspec/yspec.service';\nimport { AdwpListModule } from '@adwp-ui/widgets';\nimport { AddingModule } from '@app/shared/add-component/adding.module';\nimport { ConfigService } from '@app/shared/configuration/services/config.service';\nimport { ConfigGroupModule } from '@app/config-groups';\nimport { AttributesModule } from '@app/shared/configuration/attributes/attributes.module';\nimport { ConfigAttributeNames } from '@app/shared/configuration/attributes/attribute.service';\nimport { GroupKeysWrapperComponent } from '@app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component';\n\nconst material = [\n MatIconModule,\n MatInputModule,\n MatButtonModule,\n MatSelectModule,\n MatOptionModule,\n MatCheckboxModule,\n MatTooltipModule,\n MatToolbarModule,\n MatFormFieldModule,\n MatExpansionModule,\n MatSlideToggleModule,\n MatListModule,\n];\n\n@NgModule({\n declarations: [\n FieldComponent,\n ConfigFieldsComponent,\n GroupFieldsComponent,\n ConfigComponent,\n HistoryComponent,\n SearchComponent,\n ColorOptionDirective,\n ToolsComponent,\n SchemeComponent,\n RootComponent,\n ItemComponent,\n ],\n imports: [\n CommonModule,\n FormsModule,\n ReactiveFormsModule,\n StuffModule,\n FormElementsModule,\n ...material,\n AdwpListModule,\n AddingModule,\n ConfigGroupModule,\n AttributesModule.forRoot({\n group_keys: {\n name: ConfigAttributeNames.GROUP_KEYS,\n wrapper: GroupKeysWrapperComponent,\n options: {\n tooltipText: 'Group parameter'\n }\n },\n custom_group_keys: {\n name: ConfigAttributeNames.CUSTOM_GROUP_KEYS,\n options: {\n tooltipText: 'This parameter can not be added to config group'\n }\n }\n })\n ],\n exports: [ConfigComponent, ConfigFieldsComponent],\n providers: [FieldService, YspecService, SchemeService, ConfigService],\n})\nexport class ConfigurationModule {\n}\n", - "children": [ - { - "type": "providers", - "elements": [ - { - "name": "ConfigService" - }, - { - "name": "FieldService" - }, - { - "name": "SchemeService" - }, - { - "name": "YspecService" - } - ] - }, - { - "type": "declarations", - "elements": [ - { - "name": "ColorOptionDirective" - }, - { - "name": "ConfigComponent" - }, - { - "name": "ConfigFieldsComponent" - }, - { - "name": "FieldComponent" - }, - { - "name": "GroupFieldsComponent" - }, - { - "name": "HistoryComponent" - }, - { - "name": "ItemComponent" - }, - { - "name": "RootComponent" - }, - { - "name": "SchemeComponent" - }, - { - "name": "SearchComponent" - }, - { - "name": "ToolsComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "AddingModule" - }, - { - "name": "AttributesModule" - }, - { - "name": "ConfigGroupModule" - }, - { - "name": "FormElementsModule" - }, - { - "name": "StuffModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "ConfigComponent" - }, - { - "name": "ConfigFieldsComponent" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "CoreModule", - "id": "module-CoreModule-2299f688192757b5ffaae80fb15cf6f6", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/core/core.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';\nimport { NgModule } from '@angular/core';\n\nimport { ApiService } from '@app/core/api';\nimport { AuthGuard } from './auth/auth.guard';\nimport { AuthService } from './auth/auth.service';\nimport { RequestCacheService, RequestCache } from '@app/core/http-interseptors/request-cache.service';\nimport { CachingInterseptor } from '@app/core/http-interseptors/caching-interseptor';\nimport { AuthInterceptor } from '@app/core/http-interseptors/auth-interseptor';\n\n@NgModule({\n imports: [HttpClientModule],\n providers: [\n ApiService,\n { provide: RequestCache, useClass: RequestCacheService },\n { provide: HTTP_INTERCEPTORS, useClass: CachingInterseptor, multi: true },\n { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },\n AuthGuard,\n AuthService\n ],\n})\nexport class CoreModule {}\n", - "children": [ - { - "type": "providers", - "elements": [ - { - "name": "ApiService" - }, - { - "name": "AuthInterceptor" - }, - { - "name": "AuthService" - }, - { - "name": "CachingInterseptor" - } - ] - }, - { - "type": "declarations", - "elements": [] - }, - { - "type": "imports", - "elements": [] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "DetailsModule", - "id": "module-DetailsModule-d480eedd93d23f48d0052c623f547382", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/details/details.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatCardModule } from '@angular/material/card';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatListModule } from '@angular/material/list';\nimport { MatSidenavModule } from '@angular/material/sidenav';\nimport { MatToolbarModule } from '@angular/material/toolbar';\nimport { RouterModule } from '@angular/router';\nimport { AdwpListModule } from '@adwp-ui/widgets';\n\nimport { StuffModule } from '../stuff.module';\nimport { SubtitleComponent } from './subtitle.component';\nimport { NavigationComponent } from '@app/components/navigation/navigation.component';\nimport { ActionsButtonComponent } from '@app/components/actions-button/actions-button.component';\n\nimport { NavItemPipe } from '@app/pipes/nav-item.pipe';\nimport { MatTooltipModule } from '@angular/material/tooltip';\nimport { ObjectLinkColumnPipe } from '@app/pipes/object-link-column.pipe';\nimport { SortObjectsPipe } from '@app/pipes/sort-objects.pipe';\nimport { TaskObjectsComponent } from '@app/components/columns/task-objects/task-objects.component';\nimport { HostDetailsComponent } from '@app/components/host/host-details/host-details.component';\nimport { LeftMenuComponent } from './left-menu/left-menu.component';\nimport { LabelMenuItemComponent } from './left-menu-items/label-menu-item/label-menu-item.component';\nimport { StatusMenuItemComponent } from './left-menu-items/status-menu-item/status-menu-item.component';\nimport { ProviderDetailsComponent } from '@app/components/hostprovider/provider-details/provider-details.component';\nimport { GroupConfigDetailsComponent } from '@app/components/hostprovider/group-config-details/group-config-details.component';\nimport { BundleDetailsComponent } from '@app/components/bundle/bundle-details/bundle-details.component';\nimport { ServiceDetailsComponent } from '@app/components/service/service-details/service-details.component';\nimport { ServiceComponentDetailsComponent } from '@app/components/service-component/service-component-details/service-component-details.component';\nimport { JobDetailsComponent } from '@app/components/job/job-details/job-details.component';\nimport { ClusterDetailsComponent } from '@app/components/cluster/cluster-details/cluster-details.component';\nimport { LogMenuItemComponent } from './left-menu-items/log-menu-item/log-menu-item.component';\nimport { ConcernMenuItemComponent } from '@app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.component';\nimport { ConcernMenuItemPipe } from './left-menu-items/concern-menu-item/concern-menu-item.pipe';\n\n@NgModule({\n imports: [\n CommonModule,\n RouterModule,\n StuffModule,\n MatCardModule,\n MatToolbarModule,\n MatSidenavModule,\n MatListModule,\n MatIconModule,\n MatButtonModule,\n MatTooltipModule,\n AdwpListModule.forRoot({\n itemsPerPage: [10, 25, 50, 100],\n }),\n ],\n exports: [\n ServiceDetailsComponent,\n HostDetailsComponent,\n ProviderDetailsComponent,\n GroupConfigDetailsComponent,\n ServiceComponentDetailsComponent,\n ClusterDetailsComponent,\n BundleDetailsComponent,\n JobDetailsComponent,\n ActionsButtonComponent,\n ObjectLinkColumnPipe,\n SortObjectsPipe,\n AdwpListModule,\n TaskObjectsComponent,\n ],\n declarations: [\n ServiceDetailsComponent,\n HostDetailsComponent,\n ProviderDetailsComponent,\n GroupConfigDetailsComponent,\n ServiceComponentDetailsComponent,\n ClusterDetailsComponent,\n BundleDetailsComponent,\n JobDetailsComponent,\n SubtitleComponent,\n NavigationComponent,\n ActionsButtonComponent,\n\n NavItemPipe,\n ObjectLinkColumnPipe,\n SortObjectsPipe,\n TaskObjectsComponent,\n LeftMenuComponent,\n LabelMenuItemComponent,\n StatusMenuItemComponent,\n LogMenuItemComponent,\n ConcernMenuItemComponent,\n ConcernMenuItemPipe,\n ],\n})\nexport class DetailsModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "ActionsButtonComponent" - }, - { - "name": "BundleDetailsComponent" - }, - { - "name": "ClusterDetailsComponent" - }, - { - "name": "ConcernMenuItemComponent" - }, - { - "name": "ConcernMenuItemPipe" - }, - { - "name": "GroupConfigDetailsComponent" - }, - { - "name": "HostDetailsComponent" - }, - { - "name": "JobDetailsComponent" - }, - { - "name": "LabelMenuItemComponent" - }, - { - "name": "LeftMenuComponent" - }, - { - "name": "LogMenuItemComponent" - }, - { - "name": "NavItemPipe" - }, - { - "name": "NavigationComponent" - }, - { - "name": "ObjectLinkColumnPipe" - }, - { - "name": "ProviderDetailsComponent" - }, - { - "name": "ServiceComponentDetailsComponent" - }, - { - "name": "ServiceDetailsComponent" - }, - { - "name": "SortObjectsPipe" - }, - { - "name": "StatusMenuItemComponent" - }, - { - "name": "SubtitleComponent" - }, - { - "name": "TaskObjectsComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "StuffModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "ActionsButtonComponent" - }, - { - "name": "BundleDetailsComponent" - }, - { - "name": "ClusterDetailsComponent" - }, - { - "name": "GroupConfigDetailsComponent" - }, - { - "name": "HostDetailsComponent" - }, - { - "name": "JobDetailsComponent" - }, - { - "name": "ObjectLinkColumnPipe" - }, - { - "name": "ProviderDetailsComponent" - }, - { - "name": "ServiceComponentDetailsComponent" - }, - { - "name": "ServiceDetailsComponent" - }, - { - "name": "SortObjectsPipe" - }, - { - "name": "TaskObjectsComponent" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "EntryModule", - "id": "module-EntryModule-6ca66d8433e3a12eb253c4ab801d95b0", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/entry/entry.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\n\nimport { SharedModule } from '@app/shared/shared.module';\nimport { HostproviderComponent } from '@app/components/hostprovider/hostprovider.component';\nimport { HostListComponent } from '@app/components/host/host-list/host-list.component';\n\n@NgModule({\n imports: [CommonModule, SharedModule],\n declarations: [HostproviderComponent, HostListComponent],\n})\nexport class EntryModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "HostListComponent" - }, - { - "name": "HostproviderComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "SharedModule" - } - ] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "FormElementsModule", - "id": "module-FormElementsModule-c2b6308ea70cef328de93ef271dab8f9", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/form-elements/form-elements.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\n\nimport { MaterialModule } from '../material.module';\nimport { StuffModule } from '../stuff.module';\nimport { BooleanComponent } from './boolean.component';\nimport { BundlesComponent } from './bundles.component';\nimport { ButtonUploaderComponent } from './button-uploader.component';\nimport { ConfirmEqualValidatorDirective } from './confirm-equal-validator.directive';\nimport { DropdownComponent } from './dropdown.component';\nimport { ErrorInfoComponent } from './error-info.component';\nimport { FieldDirective } from './field.directive';\nimport { InputComponent } from './input.component';\nimport { JsonComponent } from './json.component';\nimport { BaseMapListDirective, FieldListComponent, FieldMapComponent } from './map.component';\nimport { PasswordComponent } from './password/password.component';\nimport { TextBoxComponent } from './text-box.component';\nimport { TextareaComponent } from './textarea.component';\nimport { VariantComponent } from './variant.component';\nimport { SecretTextComponent } from './secret-text/secret-text.component';\n\n@NgModule({\n declarations: [\n PasswordComponent,\n BooleanComponent,\n TextBoxComponent,\n TextareaComponent,\n JsonComponent,\n DropdownComponent,\n BundlesComponent,\n ButtonUploaderComponent,\n FieldListComponent,\n FieldMapComponent,\n InputComponent,\n BaseMapListDirective,\n ConfirmEqualValidatorDirective,\n FieldDirective,\n ErrorInfoComponent,\n VariantComponent,\n SecretTextComponent\n ],\n imports: [CommonModule, FormsModule, ReactiveFormsModule, MaterialModule, StuffModule],\n exports: [\n FieldListComponent,\n FieldMapComponent,\n PasswordComponent,\n BooleanComponent,\n TextBoxComponent,\n TextareaComponent,\n JsonComponent,\n DropdownComponent,\n BundlesComponent,\n InputComponent,\n ButtonUploaderComponent,\n VariantComponent,\n ConfirmEqualValidatorDirective,\n SecretTextComponent\n ],\n})\nexport class FormElementsModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "BaseMapListDirective" - }, - { - "name": "BooleanComponent" - }, - { - "name": "BundlesComponent" - }, - { - "name": "ButtonUploaderComponent" - }, - { - "name": "ConfirmEqualValidatorDirective" - }, - { - "name": "DropdownComponent" - }, - { - "name": "ErrorInfoComponent" - }, - { - "name": "FieldDirective" - }, - { - "name": "FieldListComponent" - }, - { - "name": "FieldMapComponent" - }, - { - "name": "InputComponent" - }, - { - "name": "JsonComponent" - }, - { - "name": "PasswordComponent" - }, - { - "name": "SecretTextComponent" - }, - { - "name": "TextBoxComponent" - }, - { - "name": "TextareaComponent" - }, - { - "name": "VariantComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "MaterialModule" - }, - { - "name": "StuffModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "BooleanComponent" - }, - { - "name": "BundlesComponent" - }, - { - "name": "ButtonUploaderComponent" - }, - { - "name": "ConfirmEqualValidatorDirective" - }, - { - "name": "DropdownComponent" - }, - { - "name": "FieldListComponent" - }, - { - "name": "FieldMapComponent" - }, - { - "name": "InputComponent" - }, - { - "name": "JsonComponent" - }, - { - "name": "PasswordComponent" - }, - { - "name": "SecretTextComponent" - }, - { - "name": "TextBoxComponent" - }, - { - "name": "TextareaComponent" - }, - { - "name": "VariantComponent" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "HostComponentsMapModule", - "id": "module-HostComponentsMapModule-69a9aa35c7f0d939a536ed1cb5bfd527", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/host-components-map/host-components-map.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\n\nimport { MaterialModule } from '../material.module';\nimport { StuffModule } from '../stuff.module';\nimport { HolderDirective } from './holder.directive';\nimport { Much2ManyComponent } from './much-2-many/much-2-many.component';\nimport { ServiceHostComponent } from './services2hosts/service-host.component';\nimport { TakeService } from './take.service';\nimport { AddingModule } from '../add-component/adding.module';\nimport { DependenciesComponent } from './dependencies.component';\n\n@NgModule({\n declarations: [HolderDirective, ServiceHostComponent, Much2ManyComponent, DependenciesComponent],\n imports: [CommonModule, MaterialModule, RouterModule, StuffModule, AddingModule],\n exports: [ServiceHostComponent],\n providers: [TakeService]\n})\nexport class HostComponentsMapModule {}\n", - "children": [ - { - "type": "providers", - "elements": [ - { - "name": "TakeService" - } - ] - }, - { - "type": "declarations", - "elements": [ - { - "name": "DependenciesComponent" - }, - { - "name": "HolderDirective" - }, - { - "name": "Much2ManyComponent" - }, - { - "name": "ServiceHostComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "AddingModule" - }, - { - "name": "MaterialModule" - }, - { - "name": "StuffModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "ServiceHostComponent" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "JobModule", - "id": "module-JobModule-7ffd2f97e77e9a469480e89131a04009", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/entry/job/job.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\n\nimport { SharedModule } from '@app/shared/shared.module';\nimport { JobInfoComponent } from './job-info.component';\nimport { JobRoutingModule } from './job-routing.module';\nimport { MainComponent } from './job.component';\nimport { LogComponent } from './log/log.component';\nimport { CheckComponent } from './log/check.component';\nimport { TextComponent } from './log/text.component';\n\n\n@NgModule({\n declarations: [\n MainComponent,\n LogComponent,\n JobInfoComponent,\n CheckComponent,\n TextComponent,\n ],\n imports: [\n CommonModule,\n SharedModule,\n RouterModule,\n JobRoutingModule,\n ]\n})\nexport class JobModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "CheckComponent" - }, - { - "name": "JobInfoComponent" - }, - { - "name": "LogComponent" - }, - { - "name": "MainComponent" - }, - { - "name": "TextComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "JobRoutingModule" - }, - { - "name": "SharedModule" - } - ] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "JobRoutingModule", - "id": "module-JobRoutingModule-66db9b0e3b72ad9112e4172b0837037e", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/entry/job/job-routing.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { NgModule } from '@angular/core';\nimport { RouterModule, Routes } from '@angular/router';\n\nimport { AuthGuard } from '@app/core/auth/auth.guard';\nimport { MainComponent } from './job.component';\nimport { LogComponent } from './log/log.component';\nimport { JobDetailsComponent } from '../../components/job/job-details/job-details.component';\n\nconst routes: Routes = [\n {\n path: ':job',\n canActivate: [AuthGuard],\n component: JobDetailsComponent,\n children: [\n { path: '', redirectTo: 'main', pathMatch: 'full' },\n { path: 'main', component: MainComponent },\n { path: ':log', component: LogComponent }\n ]\n }\n];\n\n@NgModule({\n imports: [RouterModule.forChild(routes)],\n exports: [RouterModule]\n})\nexport class JobRoutingModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [] - }, - { - "type": "imports", - "elements": [] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "MainModule", - "id": "module-MainModule-fdbba2cbab2bb6d3d4180f2f37ded576", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/main/main.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RouterModule } from '@angular/router';\n\nimport { SharedModule } from '@app/shared/shared.module';\nimport { LoginComponent } from './login/login.component';\nimport { ProfileComponent } from './profile/profile.component';\nimport { SupportComponent } from './support/support.component';\nimport { TopComponent } from './top/top.component';\nimport { ProgressComponent } from './progress.component';\nimport { PageNotFoundComponent, FatalErrorComponent, GatewayTimeoutComponent } from './server-status.component';\nimport { BellComponent } from '@app/components/bell/bell.component';\nimport { NotificationsComponent } from '@app/components/notifications/notifications.component';\nimport { BellTaskLinkPipe } from '@app/pipes/bell-task-link.pipe';\n\n@NgModule({\n imports: [\n CommonModule,\n SharedModule,\n RouterModule,\n ],\n declarations: [\n LoginComponent,\n ProfileComponent,\n SupportComponent,\n FatalErrorComponent,\n GatewayTimeoutComponent,\n PageNotFoundComponent,\n TopComponent,\n ProgressComponent,\n BellComponent,\n NotificationsComponent,\n BellTaskLinkPipe,\n ],\n exports: [\n TopComponent,\n BellComponent,\n ProgressComponent,\n ],\n})\nexport class MainModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "BellComponent" - }, - { - "name": "BellTaskLinkPipe" - }, - { - "name": "FatalErrorComponent" - }, - { - "name": "GatewayTimeoutComponent" - }, - { - "name": "LoginComponent" - }, - { - "name": "NotificationsComponent" - }, - { - "name": "PageNotFoundComponent" - }, - { - "name": "ProfileComponent" - }, - { - "name": "ProgressComponent" - }, - { - "name": "SupportComponent" - }, - { - "name": "TopComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "SharedModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "BellComponent" - }, - { - "name": "ProgressComponent" - }, - { - "name": "TopComponent" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "MaterialModule", - "id": "module-MaterialModule-44163574f2b107a457519c1ad2ba9c37", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/material.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CdkTableModule } from '@angular/cdk/table';\nimport { NgModule } from '@angular/core';\nimport { MatAutocompleteModule } from '@angular/material/autocomplete';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatCardModule } from '@angular/material/card';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\nimport { MatDialogModule } from '@angular/material/dialog';\nimport { MatExpansionModule } from '@angular/material/expansion';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatListModule } from '@angular/material/list';\nimport { MatMenuModule } from '@angular/material/menu';\nimport { MatPaginatorModule } from '@angular/material/paginator';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { MatProgressSpinnerModule } from '@angular/material/progress-spinner';\nimport { MatSelectModule } from '@angular/material/select';\nimport { MatSidenavModule } from '@angular/material/sidenav';\nimport { MatSlideToggleModule } from '@angular/material/slide-toggle';\nimport { MatSliderModule } from '@angular/material/slider';\nimport { MatSnackBarModule } from '@angular/material/snack-bar';\nimport { MatSortModule } from '@angular/material/sort';\nimport { MatStepperModule } from '@angular/material/stepper';\nimport { MatTableModule } from '@angular/material/table';\nimport { MatToolbarModule } from '@angular/material/toolbar';\nimport { MatTooltipModule } from '@angular/material/tooltip';\nimport { MatButtonToggleModule } from '@angular/material/button-toggle';\n\n@NgModule({\n exports: [\n MatStepperModule,\n CdkTableModule,\n MatSlideToggleModule,\n MatToolbarModule,\n MatSidenavModule,\n MatMenuModule,\n MatCardModule,\n MatExpansionModule,\n MatFormFieldModule,\n MatSelectModule,\n MatInputModule,\n MatCheckboxModule,\n MatButtonModule,\n MatAutocompleteModule,\n MatDialogModule,\n MatTooltipModule,\n MatSnackBarModule,\n MatProgressSpinnerModule,\n MatProgressBarModule,\n MatIconModule,\n MatListModule,\n MatTableModule,\n MatPaginatorModule,\n MatSortModule,\n MatSliderModule,\n MatButtonToggleModule,\n ],\n})\nexport class MaterialModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [] - }, - { - "type": "imports", - "elements": [] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "SharedModule", - "id": "module-SharedModule-5f20077c68342310fb4a7191435f4095", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/shared.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { RouterModule } from '@angular/router';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { MatTreeModule } from '@angular/material/tree';\n\nimport { AddingModule } from './add-component/adding.module';\nimport {\n ActionMasterComponent,\n ButtonSpinnerComponent,\n DialogComponent,\n ExportComponent,\n ImportComponent,\n IssueInfoComponent,\n MainInfoComponent,\n StatusInfoComponent,\n UpgradeComponent,\n} from './components';\nimport { ActionMasterConfigComponent } from './components/actions/master/action-master-config.component';\nimport { MultiSortDirective } from './components/list/multi-sort.directive';\nimport { ConfigurationModule } from './configuration/configuration.module';\nimport { DetailsModule } from './details/details.module';\nimport { DynamicDirective, HoverDirective } from './directives';\nimport { FormElementsModule } from './form-elements/form-elements.module';\nimport { HostComponentsMapModule } from './host-components-map/host-components-map.module';\nimport { MaterialModule } from './material.module';\nimport { BreakRowPipe, TagEscPipe } from './pipes';\nimport { StuffModule } from './stuff.module';\nimport { StatusColumnComponent } from '@app/components/columns/status-column/status-column.component';\nimport { StateColumnComponent } from '@app/components/columns/state-column/state-column.component';\nimport { EditionColumnComponent } from '@app/components/columns/edition-column/edition-column.component';\nimport { ClusterColumnComponent } from '@app/components/columns/cluster-column/cluster-column.component';\nimport { ServiceComponentsComponent } from '@app/components/service-component/service-components.component';\nimport { JobService } from '@app/services/job.service';\nimport { TaskService } from '@app/services/task.service';\nimport { ToDataSourcePipe } from '@app/pipes/to-data-source.pipe';\nimport { PickKeysPipe } from '@app/pipes/pick-keys.pipe';\nimport { TranslateKeysPipe } from '@app/pipes/translate-object-keys.pipe';\nimport { TooltipModule } from '@app/shared/components/tooltip/tooltip.module';\nimport { StatusTreeComponent } from '@app/components/status-tree/status-tree.component';\nimport { HostStatusComponent } from '@app/components/host/host-status/host-status.component';\nimport { EntityStatusToStatusTreePipe } from '@app/pipes/entity-status-to-status-tree.pipe';\nimport { ServiceStatusComponent } from '@app/components/service/service-status/service-status.component';\nimport { ServiceComponentStatusComponent } from '@app/components/service-component/service-component-status/service-component-status.component';\nimport { StatusTreeLinkPipe } from '@app/pipes/status-tree-link.pipe';\n\n@NgModule({\n imports: [\n CommonModule,\n MaterialModule,\n FormsModule,\n ReactiveFormsModule,\n RouterModule,\n StuffModule,\n FormElementsModule,\n ConfigurationModule,\n AddingModule,\n HostComponentsMapModule,\n DetailsModule,\n TranslateModule,\n TooltipModule,\n MatTreeModule,\n ],\n declarations: [\n DialogComponent,\n BreakRowPipe,\n HoverDirective,\n DynamicDirective,\n ButtonSpinnerComponent,\n TagEscPipe,\n IssueInfoComponent,\n HostStatusComponent,\n ServiceStatusComponent,\n StatusInfoComponent,\n MainInfoComponent,\n MultiSortDirective,\n ImportComponent,\n ExportComponent,\n ActionMasterComponent,\n ActionMasterConfigComponent,\n StatusColumnComponent,\n StateColumnComponent,\n EditionColumnComponent,\n ClusterColumnComponent,\n ServiceComponentsComponent,\n ServiceComponentStatusComponent,\n ToDataSourcePipe,\n PickKeysPipe,\n TranslateKeysPipe,\n StatusTreeComponent,\n EntityStatusToStatusTreePipe,\n StatusTreeLinkPipe,\n ],\n exports: [\n FormsModule,\n ReactiveFormsModule,\n MaterialModule,\n StuffModule,\n FormElementsModule,\n ConfigurationModule,\n AddingModule,\n HostComponentsMapModule,\n DetailsModule,\n DialogComponent,\n BreakRowPipe,\n HoverDirective,\n DynamicDirective,\n ButtonSpinnerComponent,\n UpgradeComponent,\n TagEscPipe,\n HostStatusComponent,\n ServiceStatusComponent,\n StatusInfoComponent,\n MainInfoComponent,\n ImportComponent,\n ExportComponent,\n StatusColumnComponent,\n StateColumnComponent,\n EditionColumnComponent,\n ClusterColumnComponent,\n ServiceComponentsComponent,\n ServiceComponentStatusComponent,\n ToDataSourcePipe,\n PickKeysPipe,\n TranslateKeysPipe,\n TooltipModule,\n StatusTreeComponent,\n EntityStatusToStatusTreePipe,\n StatusTreeLinkPipe,\n ],\n providers: [\n JobService,\n TaskService,\n ],\n})\nexport class SharedModule {\n}\n", - "children": [ - { - "type": "providers", - "elements": [ - { - "name": "JobService" - }, - { - "name": "TaskService" - } - ] - }, - { - "type": "declarations", - "elements": [ - { - "name": "ActionMasterComponent" - }, - { - "name": "ActionMasterConfigComponent" - }, - { - "name": "BreakRowPipe" - }, - { - "name": "ButtonSpinnerComponent" - }, - { - "name": "ClusterColumnComponent" - }, - { - "name": "DialogComponent" - }, - { - "name": "DynamicDirective" - }, - { - "name": "EditionColumnComponent" - }, - { - "name": "EntityStatusToStatusTreePipe" - }, - { - "name": "ExportComponent" - }, - { - "name": "HostStatusComponent" - }, - { - "name": "HoverDirective" - }, - { - "name": "ImportComponent" - }, - { - "name": "IssueInfoComponent" - }, - { - "name": "MainInfoComponent" - }, - { - "name": "MultiSortDirective" - }, - { - "name": "PickKeysPipe" - }, - { - "name": "ServiceComponentStatusComponent" - }, - { - "name": "ServiceComponentsComponent" - }, - { - "name": "ServiceStatusComponent" - }, - { - "name": "StateColumnComponent" - }, - { - "name": "StatusColumnComponent" - }, - { - "name": "StatusInfoComponent" - }, - { - "name": "StatusTreeComponent" - }, - { - "name": "StatusTreeLinkPipe" - }, - { - "name": "TagEscPipe" - }, - { - "name": "ToDataSourcePipe" - }, - { - "name": "TranslateKeysPipe" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "AddingModule" - }, - { - "name": "ConfigurationModule" - }, - { - "name": "DetailsModule" - }, - { - "name": "FormElementsModule" - }, - { - "name": "MaterialModule" - }, - { - "name": "StuffModule" - }, - { - "name": "TooltipModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "AddingModule" - }, - { - "name": "BreakRowPipe" - }, - { - "name": "ButtonSpinnerComponent" - }, - { - "name": "ClusterColumnComponent" - }, - { - "name": "ConfigurationModule" - }, - { - "name": "DetailsModule" - }, - { - "name": "DialogComponent" - }, - { - "name": "DynamicDirective" - }, - { - "name": "EditionColumnComponent" - }, - { - "name": "EntityStatusToStatusTreePipe" - }, - { - "name": "ExportComponent" - }, - { - "name": "FormElementsModule" - }, - { - "name": "HostStatusComponent" - }, - { - "name": "HoverDirective" - }, - { - "name": "ImportComponent" - }, - { - "name": "MainInfoComponent" - }, - { - "name": "MaterialModule" - }, - { - "name": "PickKeysPipe" - }, - { - "name": "ServiceComponentStatusComponent" - }, - { - "name": "ServiceComponentsComponent" - }, - { - "name": "ServiceStatusComponent" - }, - { - "name": "StateColumnComponent" - }, - { - "name": "StatusColumnComponent" - }, - { - "name": "StatusInfoComponent" - }, - { - "name": "StatusTreeComponent" - }, - { - "name": "StatusTreeLinkPipe" - }, - { - "name": "StuffModule" - }, - { - "name": "TagEscPipe" - }, - { - "name": "ToDataSourcePipe" - }, - { - "name": "TooltipModule" - }, - { - "name": "TranslateKeysPipe" - }, - { - "name": "UpgradeComponent" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "StuffModule", - "id": "module-StuffModule-6c018707ee0761b1cbb0e96a9cc34442", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/stuff.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\n\nimport { ActionsComponent, CrumbsComponent, UpgradeComponent } from './components';\nimport { ActionListComponent } from './components/actions/action-list/action-list.component';\nimport { ActionsDirective } from './components/actions/actions.directive';\nimport { TooltipDirective } from '@app/shared/components/tooltip';\nimport { PopoverDirective } from '@app/directives/popover.directive';\nimport {\n BaseDirective,\n ForTestDirective,\n InfinityScrollDirective,\n MTextareaDirective,\n ScrollDirective,\n SocketListenerDirective\n} from './directives';\nimport { MaterialModule } from './material.module';\nimport { MenuItemComponent } from './components/actions/action-list/menu-item/menu-item.component';\nimport { PopoverComponent } from '@app/components/popover/popover.component';\nimport { KeysPipe } from '@app/pipes/keys.pipe';\nimport { IsArrayPipe } from '@app/pipes/is-array.pipe';\nimport { IssuePathPipe } from '@app/pipes/issue-path.pipe';\nimport { ConcernComponent } from '@app/components/concern/concern.component';\nimport { ConcernService } from '@app/services/concern.service';\nimport { ConcernItemComponent } from '@app/components/concern/concern-item/concern-item.component';\nimport { IssueMessagePlaceholderPipe } from '@app/pipes/issue-message-placeholder.pipe';\nimport { ConcernListComponent } from '@app/components/concern/concern-list/concern-list.component';\nimport { ConcernListRefComponent } from '@app/components/concern/concern-list-ref/concern-list-ref.component';\nimport { TooltipModule } from '@app/shared/components/tooltip/tooltip.module';\n\n@NgModule({\n declarations: [\n ForTestDirective,\n MTextareaDirective,\n BaseDirective,\n SocketListenerDirective,\n CrumbsComponent,\n UpgradeComponent,\n ScrollDirective,\n InfinityScrollDirective,\n ActionsComponent,\n ActionsDirective,\n ActionListComponent,\n MenuItemComponent,\n PopoverDirective,\n PopoverComponent,\n ConcernComponent,\n ConcernItemComponent,\n IssueMessagePlaceholderPipe,\n ConcernListComponent,\n ConcernListRefComponent,\n KeysPipe,\n IsArrayPipe,\n IssuePathPipe,\n ],\n imports: [\n CommonModule,\n MaterialModule,\n RouterModule,\n TooltipModule\n ],\n exports: [\n ForTestDirective,\n TooltipDirective,\n MTextareaDirective,\n BaseDirective,\n SocketListenerDirective,\n CrumbsComponent,\n UpgradeComponent,\n ScrollDirective,\n InfinityScrollDirective,\n ActionsComponent,\n ActionsDirective,\n ActionListComponent,\n MenuItemComponent,\n PopoverDirective,\n PopoverComponent,\n ConcernComponent,\n ConcernItemComponent,\n IssueMessagePlaceholderPipe,\n ConcernListComponent,\n KeysPipe,\n IsArrayPipe,\n IssuePathPipe,\n ConcernListRefComponent,\n TooltipModule\n ],\n providers: [\n ConcernService,\n ],\n})\nexport class StuffModule {}\n", - "children": [ - { - "type": "providers", - "elements": [ - { - "name": "ConcernService" - } - ] - }, - { - "type": "declarations", - "elements": [ - { - "name": "ActionListComponent" - }, - { - "name": "ActionsComponent" - }, - { - "name": "ActionsDirective" - }, - { - "name": "BaseDirective" - }, - { - "name": "ConcernComponent" - }, - { - "name": "ConcernItemComponent" - }, - { - "name": "ConcernListComponent" - }, - { - "name": "ConcernListRefComponent" - }, - { - "name": "CrumbsComponent" - }, - { - "name": "ForTestDirective" - }, - { - "name": "InfinityScrollDirective" - }, - { - "name": "IsArrayPipe" - }, - { - "name": "IssueMessagePlaceholderPipe" - }, - { - "name": "IssuePathPipe" - }, - { - "name": "KeysPipe" - }, - { - "name": "MTextareaDirective" - }, - { - "name": "MenuItemComponent" - }, - { - "name": "PopoverComponent" - }, - { - "name": "PopoverDirective" - }, - { - "name": "ScrollDirective" - }, - { - "name": "SocketListenerDirective" - }, - { - "name": "UpgradeComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "MaterialModule" - }, - { - "name": "TooltipModule" - } - ] - }, - { - "type": "exports", - "elements": [ - { - "name": "ActionListComponent" - }, - { - "name": "ActionsComponent" - }, - { - "name": "ActionsDirective" - }, - { - "name": "BaseDirective" - }, - { - "name": "ConcernComponent" - }, - { - "name": "ConcernItemComponent" - }, - { - "name": "ConcernListComponent" - }, - { - "name": "ConcernListRefComponent" - }, - { - "name": "CrumbsComponent" - }, - { - "name": "ForTestDirective" - }, - { - "name": "InfinityScrollDirective" - }, - { - "name": "IsArrayPipe" - }, - { - "name": "IssueMessagePlaceholderPipe" - }, - { - "name": "IssuePathPipe" - }, - { - "name": "KeysPipe" - }, - { - "name": "MTextareaDirective" - }, - { - "name": "MenuItemComponent" - }, - { - "name": "PopoverComponent" - }, - { - "name": "PopoverDirective" - }, - { - "name": "ScrollDirective" - }, - { - "name": "SocketListenerDirective" - }, - { - "name": "TooltipDirective" - }, - { - "name": "TooltipModule" - }, - { - "name": "UpgradeComponent" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "TaskModule", - "id": "module-TaskModule-378babf3a59c15abcccd708605a303c1", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/entry/task/task.module.ts", - "methods": [], - "sourceCode": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { RouterModule, Routes } from '@angular/router';\nimport { AuthGuard } from '../../core/auth/auth.guard';\nimport { SharedModule } from '@app/shared/shared.module';\n\nimport { HoverDirective } from './hover.directive';\nimport { TasksComponent } from './tasks.component';\nimport { TaskStatusColumnComponent } from '@app/components/columns/task-status-column/task-status-column.component';\nimport { JobsComponent } from '@app/components/job/jobs/jobs.component';\nimport { JobStatusColumnComponent } from '@app/components/columns/job-status-column/job-status-column.component';\nimport { TaskNameComponent } from '@app/components/columns/task-name/task-name.component';\nimport { JobNameComponent } from '@app/components/columns/job-name/job-name.component';\n\nconst routes: Routes = [\n {\n path: '',\n canActivate: [AuthGuard],\n component: TasksComponent\n }\n];\n\n@NgModule({\n imports: [\n CommonModule,\n SharedModule,\n RouterModule.forChild(routes),\n ],\n declarations: [\n TasksComponent,\n HoverDirective,\n TaskStatusColumnComponent,\n TaskNameComponent,\n JobNameComponent,\n JobsComponent,\n JobStatusColumnComponent,\n ],\n})\nexport class TaskModule {}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "HoverDirective" - }, - { - "name": "JobNameComponent" - }, - { - "name": "JobStatusColumnComponent" - }, - { - "name": "JobsComponent" - }, - { - "name": "TaskNameComponent" - }, - { - "name": "TaskStatusColumnComponent" - }, - { - "name": "TasksComponent" - } - ] - }, - { - "type": "imports", - "elements": [ - { - "name": "SharedModule" - } - ] - }, - { - "type": "exports", - "elements": [] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - }, - { - "name": "TooltipModule", - "id": "module-TooltipModule-66c93f74ae899548f9d04b6aa647eb5c", - "description": "", - "deprecationMessage": "", - "deprecated": false, - "file": "src/app/shared/components/tooltip/tooltip.module.ts", - "methods": [], - "sourceCode": "import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { SimpleTextComponent, TooltipComponent } from './tooltip.component';\nimport { TooltipDirective } from './tooltip.directive';\n\n\n@NgModule({\n declarations: [TooltipComponent, SimpleTextComponent, TooltipDirective],\n imports: [\n CommonModule\n ],\n exports: [TooltipComponent, SimpleTextComponent, TooltipDirective]\n})\nexport class TooltipModule {\n}\n", - "children": [ - { - "type": "providers", - "elements": [] - }, - { - "type": "declarations", - "elements": [ - { - "name": "SimpleTextComponent" - }, - { - "name": "TooltipComponent" - }, - { - "name": "TooltipDirective" - } - ] - }, - { - "type": "imports", - "elements": [] - }, - { - "type": "exports", - "elements": [ - { - "name": "SimpleTextComponent" - }, - { - "name": "TooltipComponent" - }, - { - "name": "TooltipDirective" - } - ] - }, - { - "type": "bootstrap", - "elements": [] - }, - { - "type": "classes", - "elements": [] - } - ] - } - ], - "miscellaneous": { - "variables": [ - { - "name": "__karma__", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/test.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "any" - }, - { - "name": "accord", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IActionParameter): ((b: CompTile) => boolean) => (b: CompTile): boolean =>\n b.component === `${a.service}/${a.component}`" - }, - { - "name": "ACKNOWLEDGE_EVENT", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/components/notifications/notifications.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'acknowledge'" - }, - { - "name": "ADD_SERVICE_PROVIDER", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/add-service-model.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken('AddService')" - }, - { - "name": "adjectives", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/naming.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "defaultValue": "[\n 'Ancient',\n 'Beautiful',\n 'Big',\n 'Blue',\n 'Broad',\n 'Clear',\n 'Cold',\n 'Dark',\n 'Deep',\n 'Distant',\n 'Down',\n 'Dry',\n 'Famous',\n 'Fear',\n 'Flowing',\n 'Frozen',\n 'Great',\n 'Holy',\n 'Huge',\n 'Icy',\n 'Large',\n 'Latter',\n 'Longest',\n 'Lovely',\n 'Lower',\n 'Mad',\n 'Magnificent',\n 'Majestic',\n 'Middle',\n 'Mighty',\n 'Muddy',\n 'Narrow',\n 'Noble',\n 'North',\n 'Placid',\n 'Polluted',\n 'Quiet',\n 'Rapid',\n 'Sacred',\n 'Shallow',\n 'Slow',\n 'Sluggish',\n 'Small',\n 'Swift',\n 'Tidal',\n 'Tributary',\n 'Turbulent',\n 'Wide',\n 'Wild',\n]" - }, - { - "name": "ATTRIBUTES_OPTIONS", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken('Attributes options')" - }, - { - "name": "authCheck", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] Check')" - }, - { - "name": "authFaled", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] LoginFaled', props<{ message: string }>())" - }, - { - "name": "authLogin", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] Login', props<{ login: string; password: string }>())" - }, - { - "name": "authLogout", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] Logout')" - }, - { - "name": "authSuccess", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] LoginSuccess', props<{ login: string }>())" - }, - { - "name": "BACK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'[Router] Back'" - }, - { - "name": "Bell", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/bell.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() => ({ })" - }, - { - "name": "checkActions", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(host_id: number, com: CompTile, action: 'add' | 'remove', load: StatePost): boolean => {\n if (com.actions?.length) {\n if (action === 'remove') return flag(host_id, com, load) ? com.actions.some((a) => a === 'remove') : true;\n if (action === 'add') return flag(host_id, com, load) ? true : com.actions.some((a) => a === 'add');\n } else return true;\n}" - }, - { - "name": "checkConstraint", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(c: TConstraint, r: number): boolean => {\n if (!c?.length) return true;\n const v = c[c.length - 1];\n return v === '+' || v === 'odd' || v > r || v === 'depend';\n}" - }, - { - "name": "checkDependencies", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(c: CompTile, cs: CompTile[]): void =>\n findDependencies(c, cs).forEach((a) => (a.limit = a.limit ? [...a.limit, 'depend'] : ['depend']))" - }, - { - "name": "checkIssue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getIssueSelector,\n state => state\n)" - }, - { - "name": "checkRequires", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(component: CompTile, cs: CompTile[]): IRequires[] =>\n component.requires.reduce(\n (p, c) => (c.components.every((a) => cs.some((b) => b.prototype_id === a.prototype_id)) ? p : [...p, c]),\n []\n )" - }, - { - "name": "clearMessages", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Clear messages')" - }, - { - "name": "clearProfile", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] ClearProfile')" - }, - { - "name": "COLUMNS_SET", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/list/list.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n cluster: ['name', 'prototype_version', 'description', 'state', 'status', 'actions', 'import', 'upgrade', 'config', 'controls'],\n host2cluster: ['fqdn', 'provider_name', 'state', 'status', 'actions', 'config', 'remove'],\n service2cluster: ['display_name', 'version_no_sort', 'state', 'status', 'actions', 'import', 'config'],\n host: ['fqdn', 'provider_name', 'host2cluster', 'state', 'status', 'actions', 'config', 'controls'],\n provider: ['name', 'prototype_version', 'state', 'actions', 'upgrade', 'config', 'controls'],\n job: ['action', 'objects', 'start_date', 'finish_date', 'status'],\n task: ['id', 'start_date', 'finish_date', 'status'],\n bundle: ['name', 'version', 'edition', 'description', 'controls'],\n}" - }, - { - "name": "ComponentFactory", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/test/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(count: number, service_id: number): IComponent[] =>\n newArray(count, (_, i) => new HCmComponent(i + 1, service_id) as IComponent)", - "rawdescription": "Array with specific service id and components with id by index [1, count]\nsee: class HCmComponent", - "description": "

Array with specific service id and components with id by index [1, count]\nsee: class HCmComponent

\n" - }, - { - "name": "CONFIG_FIELD", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/field/field.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken('Config field')" - }, - { - "name": "CONFIG_GROUP_LIST_SERVICE", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/config-groups/service/config-group-list.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken>('EntityService')" - }, - { - "name": "CONFIG_URL", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/services/config.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'/assets/config.json'" - }, - { - "name": "context", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/test.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "require.context('./', true, /\\.spec\\.ts$/)" - }, - { - "name": "createFormForAttribute", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(fb: FormBuilder, json: ConfigAttributesJSON, attr: ConfigAttributeNames, disabled: boolean = false): FormGroup => {\n const buildFormGroup = (json: boolean | ConfigAttributesJSON) => {\n const data = Object.entries(json).map(([key, value]) => [key, value]).reduce((acc, [key, value]: [string, boolean | ConfigAttributesJSON]) => {\n\n if (isBoolean(value) || isEmptyObject(value)) {\n return {\n ...acc,\n [key]: { value, disabled }\n };\n } else if (!isEmptyObject(value)) {\n return { ...acc, [key]: buildFormGroup(value) };\n }\n\n }, {});\n\n return fb.group(data);\n };\n\n return buildFormGroup(json[attr]);\n}" - }, - { - "name": "disableHost", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(h: HostTile, ap: IActionParameter[]): boolean =>\n ap ? (isExist(h.relations as CompTile[], ap) ? isExpand(ap) : isShrink(ap)) : false" - }, - { - "name": "EntityNames", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/models/entity-names.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName[]", - "defaultValue": "['servicecomponent', 'group_config', 'component', 'host', 'service', 'cluster', 'provider', 'job', 'task', 'bundle']" - }, - { - "name": "environment", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/environments/environment.prod.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n production: true,\n apiRoot: '/api/v1/',\n SERVER_URL_EVENT: `${p === 'https:' ? 'wss' : 'ws'}://${location.host}/ws/event/`,\n SERVER_URL_STATUS: `${p === 'https:' ? 'wss' : 'ws'}://${location.host}/ws/status/`\n}" - }, - { - "name": "environment", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/environments/environment.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n production: false,\n apiRoot: '/api/v1/',\n SERVER_URL_EVENT: `${p === 'https:' ? 'wss' : 'ws'}://localhost:8000/ws/event/`,\n SERVER_URL_STATUS: `${p === 'https:' ? 'wss' : 'ws'}://localhost:8000/ws/status/`\n}" - }, - { - "name": "EXCLUDE_URLS", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/http-interseptors/auth-interseptor.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "defaultValue": "['/api/v1/token/', '/assets/config.json']" - }, - { - "name": "FAILED_COLOR", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/components/bell/bell.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'#FF8A80'" - }, - { - "name": "fillIssue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Issue] FillIssue', props<{ value: IIssues; url: string }>())" - }, - { - "name": "findAttrValue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(obj: T, key: string): boolean => {\n let value;\n for (let i in obj) {\n if (!obj.hasOwnProperty(i)) continue;\n if (typeof obj[i] === 'object') {\n value = findAttrValue(obj[i], key);\n } else if (i === key) {\n value = obj[i];\n }\n }\n return value;\n}" - }, - { - "name": "findDependencies", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(c: CompTile, cs: CompTile[]): CompTile[] => {\n const r =\n c.requires?.reduce<{ prototype_id: number }[]>(\n (p, a) => [...p, ...a.components.map((b) => ({ prototype_id: b.prototype_id }))],\n []\n ) || [];\n return cs.filter((a) => r.some((b) => b.prototype_id === a.prototype_id));\n}" - }, - { - "name": "flag", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(host_id: number, com: CompTile, load: StatePost): boolean =>\n load.data.some((a) => a.component_id === com.id && a.service_id === com.service_id && a.host_id === host_id)" - }, - { - "name": "fn", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n boolean: (v: boolean | null, d: boolean | null, r: boolean): boolean | null => (String(v) === 'true' || String(v) === 'false' || String(v) === 'null' ? v : r ? d : null),\n json: (v: string): string => (v === null ? '' : JSON.stringify(v, undefined, 4)),\n map: (v: object, d: object): object => (!v ? d : v),\n list: (v: string[], d: string[]): string[] => (!v ? d : v),\n structure: (v: any): any => v,\n}" - }, - { - "name": "fo", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(n: string) => (b: IFieldStack) => b.type !== 'group' && b.subname && b.name === n" - }, - { - "name": "FORWARD", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'[Router] Forward'" - }, - { - "name": "fromBundle", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/add.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() =>\n new FormGroup({\n prototype_id: new FormControl('', Validators.required),\n name: new FormControl('', Validators.required),\n description: new FormControl(),\n })" - }, - { - "name": "getApiState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('api')" - }, - { - "name": "getAuthState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('auth')" - }, - { - "name": "getConnectStatus", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(getSocketState, (state: SocketState) => state.status)" - }, - { - "name": "getControlType", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(t: TNForm): controlType => typeToControl[t] || (t as controlType)" - }, - { - "name": "getField", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(item: IFieldStack): IFieldOptions => {\n return {\n ...item,\n key: getKey(item.name, item.subname),\n value: getValue(item.type)(item.value, item.default, item.required),\n validator: getValidator(item.required, item.limits?.min, item.limits?.max, item.type),\n controlType: getControlType(item.type),\n hidden: item.name === '__main_info' || isHidden(item),\n compare: []\n };\n}" - }, - { - "name": "getFirstAdminLogin", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getProfileSelector,\n state => state.username === 'admin' && !state.profile.settingsSaved\n)" - }, - { - "name": "getIssueSelector", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('issue')" - }, - { - "name": "getKey", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(name: string, subname: string): string => (subname ? `${subname}/${name}` : name)" - }, - { - "name": "getMessage", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(getSocketState, (state) => state.message)" - }, - { - "name": "getNavigationPath", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getNavigationState,\n state => state.path\n)" - }, - { - "name": "getNavigationState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('navigation')" - }, - { - "name": "getOptions", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack, d: IConfig) =>\n d.config\n .filter(fo(a.name))\n .map((f) => getField(f))\n // switch off validation for field if !(activatable: true && active: false) - line: 146\n .map((c) => ({ ...c, name: c.subname, activatable: a.activatable && !isActive(d.attr, a.name) }))" - }, - { - "name": "getPanel", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack, d: IConfig): IPanelOptions => ({\n ...a,\n hidden: isHidden(a),\n active: a.activatable ? isActive(d.attr, a.name) : true,\n options: getOptions(a, d),\n})" - }, - { - "name": "getPattern", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(t: TNForm): RegExp => (patternFn[t] ? patternFn[t]() : null)" - }, - { - "name": "getProfile", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getProfileSelector,\n state => state.profile\n)" - }, - { - "name": "getProfileSelector", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('profile')" - }, - { - "name": "getRoot", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getApiState,\n (state: ApiState) => state.root\n)" - }, - { - "name": "getSelected", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(from: Tile[]): Tile => from.find((a) => a.isSelected)" - }, - { - "name": "getSocketState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('socket')" - }, - { - "name": "getStack", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getApiState,\n (state: ApiState) => state.stack\n)" - }, - { - "name": "getValidator", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(required: boolean, min: number, max: number, type: TNForm) => ({\n required,\n min,\n max,\n pattern: getPattern(type),\n})" - }, - { - "name": "getValue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(t: TNForm) => {\n const def = (value: number | string) => (value === null || value === undefined ? '' : String(value));\n return fn[t] ? fn[t] : def;\n}" - }, - { - "name": "GO", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'[Router] Go'" - }, - { - "name": "handleTree", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(c: ISearchParam): ((a: TFormOptions) => TFormOptions) => (a: TFormOptions): TFormOptions => {\n if ('options' in a) {\n a.options = a.options.map(handleTree(c));\n if (c.search) a.hidden = a.options.filter((b) => !b.hidden).length === 0;\n else a.hidden = isAdvancedField(a) ? !c.advanced : false;\n } else if (isVisibleField(a)) {\n a.hidden = !(a.display_name.toLowerCase().includes(c.search.toLowerCase()) || String(a.value).toLocaleLowerCase().includes(c.search.toLocaleLowerCase()));\n if (!a.hidden && isAdvancedField(a)) a.hidden = !c.advanced;\n }\n return a;\n}" - }, - { - "name": "HCFactory", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/test/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(host_id: number, service_id: number, components: number): Post[] =>\n newArray(components, (_, i) => new Post(host_id, service_id, i + 1, i + 1))" - }, - { - "name": "historyAnime", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/main/main.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "defaultValue": "[\n trigger('history', [\n state('hide', style({ top: '70px' })),\n state('show', style({ top: '134px' })),\n state('hideTools', style({ opacity: 0 })),\n state('showTools', style({ opacity: 0.8 })),\n transition('hideTools => showTools', animate('.5s .3s ease-in')),\n transition('showTools => hideTools', animate('.2s ease-out')),\n transition('hide <=> show', animate('.3s')),\n ]),\n]" - }, - { - "name": "initialState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "AuthState", - "defaultValue": "{\n isValid: false,\n message: '',\n}" - }, - { - "name": "initialState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "NavigationState", - "defaultValue": "{\n path: [],\n}" - }, - { - "name": "initialState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "SocketState", - "defaultValue": "{\n status: null,\n message: null,\n}" - }, - { - "name": "InitState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "ApiState", - "defaultValue": "{\n root: null,\n stack: null,\n}" - }, - { - "name": "InitState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n value: null,\n url: '',\n}" - }, - { - "name": "InitState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n username: '',\n change_password: '',\n profile: {\n textarea: {},\n settingsSaved: false,\n },\n}" - }, - { - "name": "intPattern", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() => new RegExp(/^[-]?\\d+$/)" - }, - { - "name": "isActive", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IConfigAttr, n: string) => a[n]?.active" - }, - { - "name": "isAdvancedField", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: TFormOptions) => isVisibleField(a) && a.ui_options?.advanced" - }, - { - "name": "isAuthenticated", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getAuthState,\n state => state.isValid\n)" - }, - { - "name": "isBoolean", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(x: any) => typeof x === 'boolean'" - }, - { - "name": "isEmptyObject", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(x: any) => isObject(x) && !Object.keys(x).length" - }, - { - "name": "isExist", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(rel: CompTile[], ap: IActionParameter[]): boolean =>\n isShrink(ap) ? ap.some((a) => rel.some(accord(a))) : ap.every((a) => rel.some(accord(a)))" - }, - { - "name": "isExpand", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(ap: IActionParameter[]): boolean => ap.every((a) => a.action === 'add')" - }, - { - "name": "isHidden", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack) => !!(a.ui_options?.invisible || a.ui_options?.advanced)" - }, - { - "name": "isNumber", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(x: any) => typeof x === 'number' && !isNaN(x)" - }, - { - "name": "isObject", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(x: any) => x !== null && typeof x === 'object'" - }, - { - "name": "isShrink", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(ap: IActionParameter[]): boolean => ap.every((a) => a.action === 'remove')" - }, - { - "name": "ISSUE_MESSAGES_DEFAULT_MOCK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n concern: ISSUE_MESSAGES_FIRST_MESSAGE,\n}" - }, - { - "name": "ISSUE_MESSAGES_FIRST_MESSAGE", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern", - "defaultValue": "{\n id: 2039,\n blocking: true,\n type: 'issue',\n cause: 'config',\n reason: {\n message: 'Run ${action1} action on ${component1}.',\n placeholder: {\n action1: {\n type: IMPlaceholderItemType.ComponentActionRun,\n ids : {\n cluster: 1,\n service: 2,\n component: 2,\n action: 22\n },\n name: 'Restart'\n },\n component1: {\n type: IMPlaceholderItemType.ComponentConfig,\n ids : {\n cluster: 1,\n service: 2,\n component: 2\n },\n name: 'My Component'\n }\n }\n }\n}" - }, - { - "name": "ISSUE_MESSAGES_LIST_MOCK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n concerns: [\n ISSUE_MESSAGES_FIRST_MESSAGE,\n ISSUE_MESSAGES_SECOND_MESSAGE,\n ISSUE_MESSAGES_VERY_LONG_MESSAGE,\n ],\n}" - }, - { - "name": "ISSUE_MESSAGES_SECOND_MESSAGE", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern", - "defaultValue": "{\n id: 2040,\n blocking: true,\n type: 'issue',\n cause: 'config',\n reason: {\n message: 'Run the following ${action2} action on this ${component2}.',\n placeholder: {\n action2: {\n type: IMPlaceholderItemType.ComponentActionRun,\n ids : {\n cluster: 1,\n service: 2,\n component: 2,\n action: 22\n },\n name: 'Restart'\n },\n component2: {\n type: IMPlaceholderItemType.ComponentConfig,\n ids : {\n cluster: 1,\n service: 2,\n component: 2\n },\n name: 'My Component'\n }\n }\n }\n}" - }, - { - "name": "ISSUE_MESSAGES_VERY_LONG_MESSAGE", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern", - "defaultValue": "{\n id: 2041,\n blocking: true,\n type: 'issue',\n cause: 'config',\n reason: {\n message: 'Run ${action1} action on ${component1}. This is a very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' long message. Bonus ${action2}!',\n placeholder: {\n action1: {\n type: IMPlaceholderItemType.ComponentActionRun,\n ids : {\n cluster: 1,\n service: 2,\n component: 2,\n action: 22\n },\n name: 'Restart'\n },\n component1: {\n type: IMPlaceholderItemType.ComponentConfig,\n ids : {\n cluster: 1,\n service: 2,\n component: 2\n },\n name: 'My Component'\n },\n action2: {\n type: IMPlaceholderItemType.ComponentActionRun,\n ids: {\n cluster: 1,\n service: 2,\n component: 2,\n action: 22\n },\n name: ''\n }\n }\n }\n}" - }, - { - "name": "ISSUE_MESSAGES_VERY_LONG_MOCK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n concern: ISSUE_MESSAGES_VERY_LONG_MESSAGE,\n}" - }, - { - "name": "isVisibleField", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: TFormOptions) => !a.ui_options?.invisible" - }, - { - "name": "kit", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/tooltip/tooltip.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{ issue: IssueInfoComponent, status: StatusInfoComponent }" - }, - { - "name": "LIST_SERVICE_PROVIDER", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/list/list-service-token.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken>('ListService')" - }, - { - "name": "ListOfMessages", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern-list.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - }, - { - "name": "ListOfMessagesPopup", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern-list-popup.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - }, - { - "name": "loadConfigGroup", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/config-groups/loader.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() => import('./config-group.module').then((m) => m.ConfigGroupModule)" - }, - { - "name": "loadIssue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Issue] LoadIssue')" - }, - { - "name": "loadProfile", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] Load')" - }, - { - "name": "loadProfileSuccess", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] LoadSuccess', props<{ profile: IUser }>())" - }, - { - "name": "loadRoot", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadRoot')" - }, - { - "name": "loadStack", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadStack')" - }, - { - "name": "material", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/configuration.module.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "defaultValue": "[\n MatIconModule,\n MatInputModule,\n MatButtonModule,\n MatSelectModule,\n MatOptionModule,\n MatCheckboxModule,\n MatTooltipModule,\n MatToolbarModule,\n MatFormFieldModule,\n MatExpansionModule,\n MatSlideToggleModule,\n MatListModule,\n]" - }, - { - "name": "maxAge", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/http-interseptors/request-cache.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Number.MAX_VALUE" - }, - { - "name": "metaReducers", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "MetaReducer[]", - "defaultValue": "!environment.production ? [] : []" - }, - { - "name": "MODELS", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/add.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "defaultValue": "{\n provider: {\n name: 'provider',\n form: fromBundle(),\n },\n host: {\n name: 'host',\n form: new FormGroup({\n fqdn: new FormControl('', [Validators.required, Validators.pattern(new RegExp(/^[A-Za-z0-9_\\.\\-]+$/))]),\n cluster_id: new FormControl(),\n provider_id: new FormControl('', Validators.required),\n }),\n },\n cluster: {\n name: 'cluster',\n form: fromBundle(),\n },\n service: {\n name: 'service',\n title: 'services'\n },\n host2cluster: {\n name: 'host2cluster',\n title: 'hosts',\n },\n}" - }, - { - "name": "newConfigGroupForm", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/config-groups/service/config-group-add.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(): FormGroup =>\n new FormGroup({\n name: new FormControl('', [Validators.required, Validators.maxLength(30)]),\n description: new FormControl(),\n })" - }, - { - "name": "newConfigGroupHostForm", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/config-groups/service/config-group-host-add.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() =>\n new FormGroup({\n name: new FormControl('', Validators.required),\n description: new FormControl(),\n })" - }, - { - "name": "notify", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/animations/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "trigger('notify', [\n state('show', style({ opacity: 1 })),\n state('hide', style({ opacity: 0 })),\n transition('hide => show', [animate('.2s')]),\n transition('show => hide', [animate('2s')]),\n])" - }, - { - "name": "OnlyMessage", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - }, - { - "name": "openClose", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/animations/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "trigger('openClose', [\n state('true', style({ height: '*', opacity: 1 })),\n state('false', style({ height: '0px', opacity: 0 })),\n transition('true <=> false', [animate('0.5s')]),\n])" - }, - { - "name": "options", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/form-elements/boolean.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{ clickAction: 'noop', color: 'accent' }" - }, - { - "name": "p", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/environments/environment.prod.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "location.protocol" - }, - { - "name": "p", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/environments/environment.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "location.protocol" - }, - { - "name": "PADDING_TOP_BOTTOM", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/directives/m-textarea.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "defaultValue": "16" - }, - { - "name": "patternFn", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n integer: intPattern,\n int: intPattern,\n float: () => new RegExp(/^[-]?[0-9]+(\\.[0-9]+)?$/),\n}" - }, - { - "name": "POINT_WHEN_EMMIT", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/directives/infinity-scroll.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "defaultValue": "100" - }, - { - "name": "POSITION_MARGIN", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/tooltip/tooltip.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "defaultValue": "16" - }, - { - "name": "PROFILE_LINK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/profile.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "`${environment.apiRoot}profile/`" - }, - { - "name": "randomInteger", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(max: number, min: number = 0): number =>\n Math.floor(min + Math.random() * (max + 1 - min))" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n InitState,\n on(rootSuccess, (state, { root }) => ({ ...state, root })),\n on(rootError, state => ({ root: null, stack: null })),\n on(stackSuccess, (state, { stack }) => ({ ...state, stack }))\n)" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n initialState,\n on(authSuccess, state => ({ isValid: true, message: 'Auth is success.' })),\n on(authFaled, (state, { message }) => ({ isValid: false, message })),\n on(authLogout, state => ({ isValid: false, message: '' }))\n)" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(InitState, on(loadIssue, state => ({ ...state })), on(fillIssue, (state, { value, url }) => ({ value, url })))" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n initialState,\n on(setPath, (state, { path }) => ({ path })),\n)" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n InitState,\n on(loadProfileSuccess, (state, { profile }) => ({ ...profile })),\n on(setTextareaHeight, state => ({ ...state })),\n on(settingsSave, (state, { isSet }) => ({ ...state, isSet })),\n on(clearProfile, () => InitState)\n)" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n initialState,\n on(socketInit, (state) => ({ ...state })),\n on(socketOpen, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketClose, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketResponse, (state, { message }) => ({\n ...state,\n message,\n })),\n on(clearMessages, (state) => ({ ...state, message: null }))\n)" - }, - { - "name": "reducers", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "ActionReducerMap", - "defaultValue": "{\n auth: authReducer,\n socket: socketReducer,\n api: apiReducer,\n profile: profileReducer,\n issue: issueReducer,\n navigation: navigationReducer,\n}" - }, - { - "name": "RegularTree", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/status-tree/status-tree.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - }, - { - "name": "require", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/test.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "any" - }, - { - "name": "requiredObject", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/import/import.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(): ValidatorFn => (control: AbstractControl): { [key: string]: boolean } | null =>\n Object.keys(control.value).some((key) => control.value[key]) ? null : { requiered: true }" - }, - { - "name": "rivers", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/naming.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "defaultValue": "[\n 'Amur',\n 'Anadyr',\n 'Angara',\n 'Colorado',\n 'Congo',\n 'Desna',\n 'Dnieper',\n 'Don',\n 'Itrysh',\n 'Kama',\n 'Limpopo',\n 'Mekong',\n 'Mississippi',\n 'Nile',\n 'Ob',\n 'Oka',\n 'Pechora',\n 'Rhine',\n 'Ural',\n 'Volga',\n 'Yangtze',\n 'Yenisei',\n 'Yukon',\n 'Zambezi',\n]" - }, - { - "name": "rootError", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadRootError')" - }, - { - "name": "rootSuccess", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadRootSuccess', props<{ root: IRoot }>())" - }, - { - "name": "RUNNING_COLOR", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/components/bell/bell.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'#FFEA00'" - }, - { - "name": "selectMessage", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "pipe(\n select(getMessage),\n skip(1),\n)" - }, - { - "name": "setPath", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Navigation] Set path', props<{ path: AdcmTypedEntity[] }>())" - }, - { - "name": "setPathOfRoute", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Navigation] Set path', props<{ params: ParamMap }>())" - }, - { - "name": "setTextareaHeight", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] SetTextareaHeight', props<{ key: string; value: number }>())" - }, - { - "name": "settingsSave", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] SettingsSave', props<{ isSet: boolean }>())" - }, - { - "name": "setValue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n )" - }, - { - "name": "socketClose", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Close', props<{ status: StatusType }>())" - }, - { - "name": "socketInit", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Init')" - }, - { - "name": "socketOpen", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Open', props<{ status: StatusType }>())" - }, - { - "name": "socketResponse", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Response', props<{ message: EventMessage }>())" - }, - { - "name": "stackSuccess", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadStackSuccess', props<{ stack: IRoot }>())" - }, - { - "name": "StoreEffects", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "defaultValue": "[AuthEffects, ApiEffects, ProfileEffects, IssueEffect, SocketEffect, NavigationEffects]" - }, - { - "name": "styleCSS", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/main/server-status.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'div { font-weight:bold; margin: 40px auto; width: 400px;}'" - }, - { - "name": "SUCCESS_COLOR", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/components/bell/bell.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'#1EE564'" - }, - { - "name": "Template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern-list-popup.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "(args) => ({\n props: args,\n template: ``,\n})" - }, - { - "name": "Template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern-list.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "(args) => ({\n props: args,\n template: ``,\n})" - }, - { - "name": "Template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "args => ({\n props: {\n ...args,\n }\n})" - }, - { - "name": "Template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/status-tree/status-tree.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "args => ({\n props: {\n ...args,\n },\n})" - }, - { - "name": "TemporaryEntityNameConverter", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/list/base-list.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(currentName: Partial): string => {\n\n if (currentName === 'group_config') return 'group-config';\n if (currentName === 'group_config_hosts') return 'group-config-hosts';\n\n return currentName;\n}" - }, - { - "name": "toField", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n})" - }, - { - "name": "toFormOptions", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n}" - }, - { - "name": "toPanel", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n})" - }, - { - "name": "trueOnly", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/import/import.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (control.value ? null : { trueOnly: !control.value })" - }, - { - "name": "typeToControl", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Partial", - "defaultValue": "{\n bool: 'boolean',\n int: 'textbox',\n integer: 'textbox',\n float: 'textbox',\n string: 'textbox',\n file: 'textarea',\n text: 'textarea',\n}" - }, - { - "name": "UPLOAD_URL", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/services/stack.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "`${environment.apiRoot}stack/upload/`" - }, - { - "name": "USER_LINK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/admin/users/users.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "`${environment.apiRoot}user/`" - }, - { - "name": "VeryLongMessage", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - } - ], - "functions": [ - { - "name": "apiReducer", - "file": "src/app/core/api/api.reducer.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "appInitializer", - "file": "src/app/shared/translate/intializer.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "translate", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "translate", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "authReducer", - "file": "src/app/core/auth/auth.store.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "clearEmptyField", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Remove empty, null, undefined properties

\n", - "args": [ - { - "name": "input", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Object", - "jsdoctags": [ - { - "name": "input", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "flatten", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Utility function for a array,\nflattening an array of arrays

\n", - "args": [ - { - "name": "a", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": { - "pos": 2281, - "end": 2282, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "a" - }, - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "pos": 2275, - "end": 2280, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "" - } - ] - }, - { - "name": "getEventEntityType", - "file": "src/app/store/navigation/navigation.store.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "TypeName", - "jsdoctags": [ - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getPath", - "file": "src/app/store/navigation/navigation.store.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "getters", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Observable", - "jsdoctags": [ - { - "name": "getters", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getRandomColor", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [], - "returnType": "string", - "jsdoctags": [ - { - "tagName": { - "pos": 2681, - "end": 2688, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "returns" - }, - "comment": "

16-bit hex string

\n" - }, - { - "tagName": { - "pos": 2711, - "end": 2718, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "example" - }, - "comment": "

'#110C2E'

\n" - } - ] - }, - { - "name": "isCachable", - "file": "src/app/core/http-interseptors/caching-interseptor.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "req", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "req", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "issueReducer", - "file": "src/app/core/store/issue.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "navigationReducer", - "file": "src/app/store/navigation/navigation.store.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "newArray", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "count", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "fn", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": { - "pos": 2490, - "end": 2495, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "count" - }, - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "pos": 2475, - "end": 2480, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "", - "typeExpression": { - "pos": 2481, - "end": 2489, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 302, - "type": { - "pos": 2482, - "end": 2488, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 144 - } - } - }, - { - "name": { - "pos": 2535, - "end": 2537, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "fn" - }, - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "pos": 2500, - "end": 2505, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "", - "typeExpression": { - "pos": 2506, - "end": 2534, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 302, - "type": { - "pos": 2507, - "end": 2533, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 175, - "parameters": [ - { - "pos": 2508, - "end": 2516, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 161, - "name": { - "pos": 2508, - "end": 2509, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "_" - }, - "type": { - "pos": 2510, - "end": 2516, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 141 - } - }, - { - "pos": 2517, - "end": 2527, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 161, - "name": { - "pos": 2517, - "end": 2519, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "i" - }, - "type": { - "pos": 2520, - "end": 2527, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 144 - } - } - ], - "type": { - "pos": 2531, - "end": 2533, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 174, - "typeName": { - "pos": 2531, - "end": 2533, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "T" - } - } - } - } - }, - { - "tagName": { - "pos": 2542, - "end": 2549, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "returns" - }, - "comment": "" - } - ] - }, - { - "name": "nullEmptyField", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": true, - "deprecationMessage": "", - "description": "

Support nullable value in object properties,\nif value input field is empty return null.

\n", - "args": [ - { - "name": "input", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Object", - "jsdoctags": [ - { - "name": "input", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "profileReducer", - "file": "src/app/core/store/profile/index.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "sendRequest", - "file": "src/app/core/http-interseptors/caching-interseptor.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "req", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "next", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cache", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Observable>", - "jsdoctags": [ - { - "name": "req", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "next", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cache", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "socketReducer", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "translateLoader", - "file": "src/app/shared/translate/intializer.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "http", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "http", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "uniqid", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "prefix", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "isFloat", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "string", - "jsdoctags": [ - { - "name": "prefix", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "isFloat", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "typealiases": [ - { - "name": "ActionParam", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"add\" | \"remove\"", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "Attributes", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "Map", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 174 - }, - { - "name": "AttributesOptions", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "Record", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 174 - }, - { - "name": "ComponentName", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"issue\" | \"status\" | undefined", - "file": "src/app/shared/components/tooltip/tooltip.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "ConcernType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"issue\" | \"lock\"", - "file": "src/app/models/concern/concern.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "ConfigAttribute", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - }, - { - "name": "controlType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"boolean\" | \"textbox\" | \"textarea\" | \"json\" | \"password\" | \"list\" | \"map\" | \"dropdown\" | \"file\" | \"text\" | \"structure\" | \"secrettext\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "

Mark for rendering required component

\n", - "kind": 183 - }, - { - "name": "Entities", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "ICluster | Service | Host | Provider | Job | Task | Bundle", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "EntityEvent", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"add\" | \"add_job_log\" | \"create\" | \"delete\" | \"remove\" | \"change_config\" | \"change_state\" | \"change_status\" | \"change_job_status\" | \"change_hostcomponentmap\" | \"upgrade\" | \"concern\"", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "IssueType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"cluster\" | \"service\" | \"servicecomponent\" | \"component\"", - "file": "src/app/models/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "Job", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - }, - { - "name": "JobStatus", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"created\" | \"running\" | \"failed\" | \"success\" | \"aborted\"", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "JobType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"component\" | \"service\" | \"cluster\" | \"host\" | \"provider\"", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "PopoverEventFunc", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "function", - "file": "src/app/abstract-directives/popover-content.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 175 - }, - { - "name": "PositionType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"top\" | \"right\" | \"bottom\" | \"left\"", - "file": "src/app/shared/components/tooltip/tooltip.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "ProfileState", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "IUser", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 174 - }, - { - "name": "Prototype", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/core/types/stack.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - }, - { - "name": "resultTypes", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "simpleTypes | simpleTypes[] | object", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "RouterActionsUnion", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "Go | Back | Forward", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "ServicePrototype", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/core/types/stack.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - }, - { - "name": "simpleTypes", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "string | number | boolean", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "StackInfo", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"cluster\" | \"host\" | \"provider\" | \"service\" | \"bundle\"", - "file": "src/app/core/services/stack.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "stateType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"created\" | \"locked\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "StatusTreeLinkFunc", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "function", - "file": "src/app/models/status-tree.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 175 - }, - { - "name": "StatusType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"open\" | \"close\" | \"re-open\"", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "Task", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - }, - { - "name": "TaskStatus", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "string | \"running\" | \"success\" | \"failed\"", - "file": "src/app/entry/task/tasks.component.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TConstraint", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "TConstraintValue[]", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 179 - }, - { - "name": "TConstraintValue", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "number | \"+\" | \"odd\" | \"depend\"", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TFormOptions", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "IFieldOptions | IPanelOptions", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TMatch", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "TNBase | TNReq", - "file": "src/app/shared/configuration/yspec/yspec.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TNBase", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"string\" | \"integer\" | \"int\" | \"boolean\" | \"bool\" | \"float\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TNForm", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "TNBase | TNReq | TNSpec", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TNReq", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"dict\" | \"list\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TNSpec", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"structure\" | \"group\" | \"option\" | \"json\" | \"map\" | \"file\" | \"text\" | \"password\" | \"secrettext\" | \"variant\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TValue", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "string | number | boolean | object | any[]", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TypeName", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"bundle\" | \"cluster\" | \"host\" | \"provider\" | \"service\" | \"job\" | \"task\" | \"user\" | \"profile\" | \"adcm\" | \"stats\" | \"hostcomponent\" | \"service2cluster\" | \"host2cluster\" | \"servicecomponent\" | \"component\" | \"group_config\" | \"group_config_hosts\"", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "enumerations": [ - { - "name": "ConcernEventType", - "childs": [ - { - "name": "Cluster", - "deprecated": false, - "deprecationMessage": "", - "value": "cluster-concerns" - }, - { - "name": "Service", - "deprecated": false, - "deprecationMessage": "", - "value": "cluster-object-concerns" - }, - { - "name": "Host", - "deprecated": false, - "deprecationMessage": "", - "value": "host-concerns" - }, - { - "name": "HostProvider", - "deprecated": false, - "deprecationMessage": "", - "value": "host-provider-concerns" - }, - { - "name": "ServiceComponent", - "deprecated": false, - "deprecationMessage": "", - "value": "service-component-concerns" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/models/concern/concern-reason.ts" - }, - { - "name": "ConfigAttributeNames", - "childs": [ - { - "name": "GROUP_KEYS", - "deprecated": false, - "deprecationMessage": "", - "value": "group_keys" - }, - { - "name": "CUSTOM_GROUP_KEYS", - "deprecated": false, - "deprecationMessage": "", - "value": "custom_group_keys" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/shared/configuration/attributes/attribute.service.ts" - }, - { - "name": "Direction", - "childs": [ - { - "name": "", - "deprecated": false, - "deprecationMessage": "", - "value": "" - }, - { - "name": "asc", - "deprecated": false, - "deprecationMessage": "", - "value": "" - }, - { - "name": "desc", - "deprecated": false, - "deprecationMessage": "", - "value": "-" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/abstract-directives/list.directive.ts" - }, - { - "name": "DisplayMode", - "childs": [ - { - "name": "default", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "inHost", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "noCluster", - "deprecated": false, - "deprecationMessage": "" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/shared/add-component/provider.component.ts" - }, - { - "name": "flagForConsole", - "childs": [ - { - "name": "profile", - "deprecated": false, - "deprecationMessage": "", - "value": "profile" - }, - { - "name": "socket", - "deprecated": false, - "deprecationMessage": "", - "value": "socket" - }, - { - "name": "load_complete", - "deprecated": false, - "deprecationMessage": "", - "value": "load_complete" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "

Magic strings for marking loading stages and other, for ci tests

\n", - "file": "src/app/app.component.ts" - }, - { - "name": "Folding", - "childs": [ - { - "name": "Collapsed", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "Expanded", - "deprecated": false, - "deprecationMessage": "" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/components/status-tree/status-tree.component.ts" - }, - { - "name": "IMPlaceholderItemType", - "childs": [ - { - "name": "ComponentActionRun", - "deprecated": false, - "deprecationMessage": "", - "value": "component_action_run" - }, - { - "name": "ComponentConfig", - "deprecated": false, - "deprecationMessage": "", - "value": "component_config" - }, - { - "name": "Cluster", - "deprecated": false, - "deprecationMessage": "", - "value": "cluster" - }, - { - "name": "Service", - "deprecated": false, - "deprecationMessage": "", - "value": "service" - }, - { - "name": "Component", - "deprecated": false, - "deprecationMessage": "", - "value": "component" - }, - { - "name": "HostProvider", - "deprecated": false, - "deprecationMessage": "", - "value": "provider" - }, - { - "name": "Host", - "deprecated": false, - "deprecationMessage": "", - "value": "host" - }, - { - "name": "Job", - "deprecated": false, - "deprecationMessage": "", - "value": "job" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/models/concern/concern-reason.ts" - }, - { - "name": "keyChannelStrim", - "childs": [ - { - "name": "scroll", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "notifying", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "load_complete", - "deprecated": false, - "deprecationMessage": "" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/core/services/channel.service.ts" - }, - { - "name": "whatShow", - "childs": [ - { - "name": "none", - "deprecated": false, - "deprecationMessage": "", - "value": "none" - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "value": "config" - }, - { - "name": "hostMap", - "deprecated": false, - "deprecationMessage": "", - "value": "hostmap" - }, - { - "name": "stepper", - "deprecated": false, - "deprecationMessage": "", - "value": "stepper" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/shared/components/actions/master/master.service.ts" - } - ], - "groupedVariables": { - "src/test.ts": [ - { - "name": "__karma__", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/test.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "any" - }, - { - "name": "context", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/test.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "require.context('./', true, /\\.spec\\.ts$/)" - }, - { - "name": "require", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/test.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "any" - } - ], - "src/app/shared/host-components-map/take.service.ts": [ - { - "name": "accord", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IActionParameter): ((b: CompTile) => boolean) => (b: CompTile): boolean =>\n b.component === `${a.service}/${a.component}`" - }, - { - "name": "checkActions", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(host_id: number, com: CompTile, action: 'add' | 'remove', load: StatePost): boolean => {\n if (com.actions?.length) {\n if (action === 'remove') return flag(host_id, com, load) ? com.actions.some((a) => a === 'remove') : true;\n if (action === 'add') return flag(host_id, com, load) ? true : com.actions.some((a) => a === 'add');\n } else return true;\n}" - }, - { - "name": "checkConstraint", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(c: TConstraint, r: number): boolean => {\n if (!c?.length) return true;\n const v = c[c.length - 1];\n return v === '+' || v === 'odd' || v > r || v === 'depend';\n}" - }, - { - "name": "checkDependencies", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(c: CompTile, cs: CompTile[]): void =>\n findDependencies(c, cs).forEach((a) => (a.limit = a.limit ? [...a.limit, 'depend'] : ['depend']))" - }, - { - "name": "checkRequires", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(component: CompTile, cs: CompTile[]): IRequires[] =>\n component.requires.reduce(\n (p, c) => (c.components.every((a) => cs.some((b) => b.prototype_id === a.prototype_id)) ? p : [...p, c]),\n []\n )" - }, - { - "name": "disableHost", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(h: HostTile, ap: IActionParameter[]): boolean =>\n ap ? (isExist(h.relations as CompTile[], ap) ? isExpand(ap) : isShrink(ap)) : false" - }, - { - "name": "findDependencies", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(c: CompTile, cs: CompTile[]): CompTile[] => {\n const r =\n c.requires?.reduce<{ prototype_id: number }[]>(\n (p, a) => [...p, ...a.components.map((b) => ({ prototype_id: b.prototype_id }))],\n []\n ) || [];\n return cs.filter((a) => r.some((b) => b.prototype_id === a.prototype_id));\n}" - }, - { - "name": "flag", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(host_id: number, com: CompTile, load: StatePost): boolean =>\n load.data.some((a) => a.component_id === com.id && a.service_id === com.service_id && a.host_id === host_id)" - }, - { - "name": "getSelected", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(from: Tile[]): Tile => from.find((a) => a.isSelected)" - }, - { - "name": "isExist", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(rel: CompTile[], ap: IActionParameter[]): boolean =>\n isShrink(ap) ? ap.some((a) => rel.some(accord(a))) : ap.every((a) => rel.some(accord(a)))" - }, - { - "name": "isExpand", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(ap: IActionParameter[]): boolean => ap.every((a) => a.action === 'add')" - }, - { - "name": "isShrink", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/take.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(ap: IActionParameter[]): boolean => ap.every((a) => a.action === 'remove')" - } - ], - "src/app/components/notifications/notifications.component.ts": [ - { - "name": "ACKNOWLEDGE_EVENT", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/components/notifications/notifications.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'acknowledge'" - } - ], - "src/app/shared/add-component/add-service-model.ts": [ - { - "name": "ADD_SERVICE_PROVIDER", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/add-service-model.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken('AddService')" - } - ], - "src/app/shared/add-component/naming.ts": [ - { - "name": "adjectives", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/naming.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "defaultValue": "[\n 'Ancient',\n 'Beautiful',\n 'Big',\n 'Blue',\n 'Broad',\n 'Clear',\n 'Cold',\n 'Dark',\n 'Deep',\n 'Distant',\n 'Down',\n 'Dry',\n 'Famous',\n 'Fear',\n 'Flowing',\n 'Frozen',\n 'Great',\n 'Holy',\n 'Huge',\n 'Icy',\n 'Large',\n 'Latter',\n 'Longest',\n 'Lovely',\n 'Lower',\n 'Mad',\n 'Magnificent',\n 'Majestic',\n 'Middle',\n 'Mighty',\n 'Muddy',\n 'Narrow',\n 'Noble',\n 'North',\n 'Placid',\n 'Polluted',\n 'Quiet',\n 'Rapid',\n 'Sacred',\n 'Shallow',\n 'Slow',\n 'Sluggish',\n 'Small',\n 'Swift',\n 'Tidal',\n 'Tributary',\n 'Turbulent',\n 'Wide',\n 'Wild',\n]" - }, - { - "name": "rivers", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/naming.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string[]", - "defaultValue": "[\n 'Amur',\n 'Anadyr',\n 'Angara',\n 'Colorado',\n 'Congo',\n 'Desna',\n 'Dnieper',\n 'Don',\n 'Itrysh',\n 'Kama',\n 'Limpopo',\n 'Mekong',\n 'Mississippi',\n 'Nile',\n 'Ob',\n 'Oka',\n 'Pechora',\n 'Rhine',\n 'Ural',\n 'Volga',\n 'Yangtze',\n 'Yenisei',\n 'Yukon',\n 'Zambezi',\n]" - } - ], - "src/app/shared/configuration/attributes/attribute.service.ts": [ - { - "name": "ATTRIBUTES_OPTIONS", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken('Attributes options')" - }, - { - "name": "createFormForAttribute", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(fb: FormBuilder, json: ConfigAttributesJSON, attr: ConfigAttributeNames, disabled: boolean = false): FormGroup => {\n const buildFormGroup = (json: boolean | ConfigAttributesJSON) => {\n const data = Object.entries(json).map(([key, value]) => [key, value]).reduce((acc, [key, value]: [string, boolean | ConfigAttributesJSON]) => {\n\n if (isBoolean(value) || isEmptyObject(value)) {\n return {\n ...acc,\n [key]: { value, disabled }\n };\n } else if (!isEmptyObject(value)) {\n return { ...acc, [key]: buildFormGroup(value) };\n }\n\n }, {});\n\n return fb.group(data);\n };\n\n return buildFormGroup(json[attr]);\n}" - } - ], - "src/app/core/auth/auth.store.ts": [ - { - "name": "authCheck", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] Check')" - }, - { - "name": "authFaled", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] LoginFaled', props<{ message: string }>())" - }, - { - "name": "authLogin", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] Login', props<{ login: string; password: string }>())" - }, - { - "name": "authLogout", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] Logout')" - }, - { - "name": "authSuccess", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Auth] LoginSuccess', props<{ login: string }>())" - }, - { - "name": "getAuthState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('auth')" - }, - { - "name": "initialState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "AuthState", - "defaultValue": "{\n isValid: false,\n message: '',\n}" - }, - { - "name": "isAuthenticated", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getAuthState,\n state => state.isValid\n)" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/auth/auth.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n initialState,\n on(authSuccess, state => ({ isValid: true, message: 'Auth is success.' })),\n on(authFaled, (state, { message }) => ({ isValid: false, message })),\n on(authLogout, state => ({ isValid: false, message: '' }))\n)" - } - ], - "src/app/core/store/router/router.actions.ts": [ - { - "name": "BACK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'[Router] Back'" - }, - { - "name": "FORWARD", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'[Router] Forward'" - }, - { - "name": "GO", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'[Router] Go'" - } - ], - "src/stories/bell.stories.ts": [ - { - "name": "Bell", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/bell.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() => ({ })" - } - ], - "src/app/core/store/issue.ts": [ - { - "name": "checkIssue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getIssueSelector,\n state => state\n)" - }, - { - "name": "fillIssue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Issue] FillIssue', props<{ value: IIssues; url: string }>())" - }, - { - "name": "getIssueSelector", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('issue')" - }, - { - "name": "InitState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n value: null,\n url: '',\n}" - }, - { - "name": "loadIssue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Issue] LoadIssue')" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(InitState, on(loadIssue, state => ({ ...state })), on(fillIssue, (state, { value, url }) => ({ value, url })))" - } - ], - "src/app/core/store/sockets/socket.reducer.ts": [ - { - "name": "clearMessages", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Clear messages')" - }, - { - "name": "getConnectStatus", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(getSocketState, (state: SocketState) => state.status)" - }, - { - "name": "getMessage", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(getSocketState, (state) => state.message)" - }, - { - "name": "getSocketState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('socket')" - }, - { - "name": "initialState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "SocketState", - "defaultValue": "{\n status: null,\n message: null,\n}" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n initialState,\n on(socketInit, (state) => ({ ...state })),\n on(socketOpen, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketClose, (state, { status }) => ({\n ...state,\n status,\n })),\n on(socketResponse, (state, { message }) => ({\n ...state,\n message,\n })),\n on(clearMessages, (state) => ({ ...state, message: null }))\n)" - }, - { - "name": "selectMessage", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "pipe(\n select(getMessage),\n skip(1),\n)" - }, - { - "name": "socketClose", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Close', props<{ status: StatusType }>())" - }, - { - "name": "socketInit", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Init')" - }, - { - "name": "socketOpen", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Open', props<{ status: StatusType }>())" - }, - { - "name": "socketResponse", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Socket] Response', props<{ message: EventMessage }>())" - } - ], - "src/app/core/store/profile/index.ts": [ - { - "name": "clearProfile", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] ClearProfile')" - }, - { - "name": "getFirstAdminLogin", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getProfileSelector,\n state => state.username === 'admin' && !state.profile.settingsSaved\n)" - }, - { - "name": "getProfile", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getProfileSelector,\n state => state.profile\n)" - }, - { - "name": "getProfileSelector", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('profile')" - }, - { - "name": "InitState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n username: '',\n change_password: '',\n profile: {\n textarea: {},\n settingsSaved: false,\n },\n}" - }, - { - "name": "loadProfile", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] Load')" - }, - { - "name": "loadProfileSuccess", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] LoadSuccess', props<{ profile: IUser }>())" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n InitState,\n on(loadProfileSuccess, (state, { profile }) => ({ ...profile })),\n on(setTextareaHeight, state => ({ ...state })),\n on(settingsSave, (state, { isSet }) => ({ ...state, isSet })),\n on(clearProfile, () => InitState)\n)" - }, - { - "name": "setTextareaHeight", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] SetTextareaHeight', props<{ key: string; value: number }>())" - }, - { - "name": "settingsSave", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Profile] SettingsSave', props<{ isSet: boolean }>())" - } - ], - "src/app/shared/components/list/list.service.ts": [ - { - "name": "COLUMNS_SET", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/list/list.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n cluster: ['name', 'prototype_version', 'description', 'state', 'status', 'actions', 'import', 'upgrade', 'config', 'controls'],\n host2cluster: ['fqdn', 'provider_name', 'state', 'status', 'actions', 'config', 'remove'],\n service2cluster: ['display_name', 'version_no_sort', 'state', 'status', 'actions', 'import', 'config'],\n host: ['fqdn', 'provider_name', 'host2cluster', 'state', 'status', 'actions', 'config', 'controls'],\n provider: ['name', 'prototype_version', 'state', 'actions', 'upgrade', 'config', 'controls'],\n job: ['action', 'objects', 'start_date', 'finish_date', 'status'],\n task: ['id', 'start_date', 'finish_date', 'status'],\n bundle: ['name', 'version', 'edition', 'description', 'controls'],\n}" - } - ], - "src/app/shared/host-components-map/test/index.ts": [ - { - "name": "ComponentFactory", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/test/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(count: number, service_id: number): IComponent[] =>\n newArray(count, (_, i) => new HCmComponent(i + 1, service_id) as IComponent)", - "rawdescription": "Array with specific service id and components with id by index [1, count]\nsee: class HCmComponent", - "description": "

Array with specific service id and components with id by index [1, count]\nsee: class HCmComponent

\n" - }, - { - "name": "HCFactory", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/host-components-map/test/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(host_id: number, service_id: number, components: number): Post[] =>\n newArray(components, (_, i) => new Post(host_id, service_id, i + 1, i + 1))" - } - ], - "src/app/shared/configuration/field/field.component.ts": [ - { - "name": "CONFIG_FIELD", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/field/field.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken('Config field')" - } - ], - "src/app/config-groups/service/config-group-list.service.ts": [ - { - "name": "CONFIG_GROUP_LIST_SERVICE", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/config-groups/service/config-group-list.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken>('EntityService')" - } - ], - "src/app/core/services/config.service.ts": [ - { - "name": "CONFIG_URL", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/services/config.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'/assets/config.json'" - } - ], - "src/app/models/entity-names.ts": [ - { - "name": "EntityNames", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/models/entity-names.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "TypeName[]", - "defaultValue": "['servicecomponent', 'group_config', 'component', 'host', 'service', 'cluster', 'provider', 'job', 'task', 'bundle']" - } - ], - "src/environments/environment.prod.ts": [ - { - "name": "environment", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/environments/environment.prod.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n production: true,\n apiRoot: '/api/v1/',\n SERVER_URL_EVENT: `${p === 'https:' ? 'wss' : 'ws'}://${location.host}/ws/event/`,\n SERVER_URL_STATUS: `${p === 'https:' ? 'wss' : 'ws'}://${location.host}/ws/status/`\n}" - }, - { - "name": "p", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/environments/environment.prod.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "location.protocol" - } - ], - "src/environments/environment.ts": [ - { - "name": "environment", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/environments/environment.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n production: false,\n apiRoot: '/api/v1/',\n SERVER_URL_EVENT: `${p === 'https:' ? 'wss' : 'ws'}://localhost:8000/ws/event/`,\n SERVER_URL_STATUS: `${p === 'https:' ? 'wss' : 'ws'}://localhost:8000/ws/status/`\n}" - }, - { - "name": "p", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/environments/environment.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "location.protocol" - } - ], - "src/app/core/http-interseptors/auth-interseptor.ts": [ - { - "name": "EXCLUDE_URLS", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/http-interseptors/auth-interseptor.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "defaultValue": "['/api/v1/token/', '/assets/config.json']" - } - ], - "src/app/components/bell/bell.component.ts": [ - { - "name": "FAILED_COLOR", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/components/bell/bell.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'#FF8A80'" - }, - { - "name": "RUNNING_COLOR", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/components/bell/bell.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'#FFEA00'" - }, - { - "name": "SUCCESS_COLOR", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/components/bell/bell.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'#1EE564'" - } - ], - "src/app/shared/configuration/services/field.service.ts": [ - { - "name": "findAttrValue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(obj: T, key: string): boolean => {\n let value;\n for (let i in obj) {\n if (!obj.hasOwnProperty(i)) continue;\n if (typeof obj[i] === 'object') {\n value = findAttrValue(obj[i], key);\n } else if (i === key) {\n value = obj[i];\n }\n }\n return value;\n}" - }, - { - "name": "fn", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n boolean: (v: boolean | null, d: boolean | null, r: boolean): boolean | null => (String(v) === 'true' || String(v) === 'false' || String(v) === 'null' ? v : r ? d : null),\n json: (v: string): string => (v === null ? '' : JSON.stringify(v, undefined, 4)),\n map: (v: object, d: object): object => (!v ? d : v),\n list: (v: string[], d: string[]): string[] => (!v ? d : v),\n structure: (v: any): any => v,\n}" - }, - { - "name": "fo", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(n: string) => (b: IFieldStack) => b.type !== 'group' && b.subname && b.name === n" - }, - { - "name": "getControlType", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(t: TNForm): controlType => typeToControl[t] || (t as controlType)" - }, - { - "name": "getField", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(item: IFieldStack): IFieldOptions => {\n return {\n ...item,\n key: getKey(item.name, item.subname),\n value: getValue(item.type)(item.value, item.default, item.required),\n validator: getValidator(item.required, item.limits?.min, item.limits?.max, item.type),\n controlType: getControlType(item.type),\n hidden: item.name === '__main_info' || isHidden(item),\n compare: []\n };\n}" - }, - { - "name": "getKey", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(name: string, subname: string): string => (subname ? `${subname}/${name}` : name)" - }, - { - "name": "getOptions", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack, d: IConfig) =>\n d.config\n .filter(fo(a.name))\n .map((f) => getField(f))\n // switch off validation for field if !(activatable: true && active: false) - line: 146\n .map((c) => ({ ...c, name: c.subname, activatable: a.activatable && !isActive(d.attr, a.name) }))" - }, - { - "name": "getPanel", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack, d: IConfig): IPanelOptions => ({\n ...a,\n hidden: isHidden(a),\n active: a.activatable ? isActive(d.attr, a.name) : true,\n options: getOptions(a, d),\n})" - }, - { - "name": "getPattern", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(t: TNForm): RegExp => (patternFn[t] ? patternFn[t]() : null)" - }, - { - "name": "getValidator", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(required: boolean, min: number, max: number, type: TNForm) => ({\n required,\n min,\n max,\n pattern: getPattern(type),\n})" - }, - { - "name": "getValue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(t: TNForm) => {\n const def = (value: number | string) => (value === null || value === undefined ? '' : String(value));\n return fn[t] ? fn[t] : def;\n}" - }, - { - "name": "handleTree", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(c: ISearchParam): ((a: TFormOptions) => TFormOptions) => (a: TFormOptions): TFormOptions => {\n if ('options' in a) {\n a.options = a.options.map(handleTree(c));\n if (c.search) a.hidden = a.options.filter((b) => !b.hidden).length === 0;\n else a.hidden = isAdvancedField(a) ? !c.advanced : false;\n } else if (isVisibleField(a)) {\n a.hidden = !(a.display_name.toLowerCase().includes(c.search.toLowerCase()) || String(a.value).toLocaleLowerCase().includes(c.search.toLocaleLowerCase()));\n if (!a.hidden && isAdvancedField(a)) a.hidden = !c.advanced;\n }\n return a;\n}" - }, - { - "name": "intPattern", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() => new RegExp(/^[-]?\\d+$/)" - }, - { - "name": "isActive", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IConfigAttr, n: string) => a[n]?.active" - }, - { - "name": "isAdvancedField", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: TFormOptions) => isVisibleField(a) && a.ui_options?.advanced" - }, - { - "name": "isHidden", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack) => !!(a.ui_options?.invisible || a.ui_options?.advanced)" - }, - { - "name": "isVisibleField", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: TFormOptions) => !a.ui_options?.invisible" - }, - { - "name": "patternFn", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n integer: intPattern,\n int: intPattern,\n float: () => new RegExp(/^[-]?[0-9]+(\\.[0-9]+)?$/),\n}" - }, - { - "name": "typeToControl", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Partial", - "defaultValue": "{\n bool: 'boolean',\n int: 'textbox',\n integer: 'textbox',\n float: 'textbox',\n string: 'textbox',\n file: 'textarea',\n text: 'textarea',\n}" - } - ], - "src/app/shared/add-component/add.service.ts": [ - { - "name": "fromBundle", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/add.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() =>\n new FormGroup({\n prototype_id: new FormControl('', Validators.required),\n name: new FormControl('', Validators.required),\n description: new FormControl(),\n })" - }, - { - "name": "MODELS", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/add-component/add.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "literal type", - "defaultValue": "{\n provider: {\n name: 'provider',\n form: fromBundle(),\n },\n host: {\n name: 'host',\n form: new FormGroup({\n fqdn: new FormControl('', [Validators.required, Validators.pattern(new RegExp(/^[A-Za-z0-9_\\.\\-]+$/))]),\n cluster_id: new FormControl(),\n provider_id: new FormControl('', Validators.required),\n }),\n },\n cluster: {\n name: 'cluster',\n form: fromBundle(),\n },\n service: {\n name: 'service',\n title: 'services'\n },\n host2cluster: {\n name: 'host2cluster',\n title: 'hosts',\n },\n}" - } - ], - "src/app/core/api/api.reducer.ts": [ - { - "name": "getApiState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('api')" - }, - { - "name": "getRoot", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getApiState,\n (state: ApiState) => state.root\n)" - }, - { - "name": "getStack", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getApiState,\n (state: ApiState) => state.stack\n)" - }, - { - "name": "InitState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "ApiState", - "defaultValue": "{\n root: null,\n stack: null,\n}" - }, - { - "name": "loadRoot", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadRoot')" - }, - { - "name": "loadStack", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadStack')" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n InitState,\n on(rootSuccess, (state, { root }) => ({ ...state, root })),\n on(rootError, state => ({ root: null, stack: null })),\n on(stackSuccess, (state, { stack }) => ({ ...state, stack }))\n)" - }, - { - "name": "rootError", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadRootError')" - }, - { - "name": "rootSuccess", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadRootSuccess', props<{ root: IRoot }>())" - }, - { - "name": "stackSuccess", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/api/api.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[API] LoadStackSuccess', props<{ stack: IRoot }>())" - } - ], - "src/app/store/navigation/navigation.store.ts": [ - { - "name": "getNavigationPath", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createSelector(\n getNavigationState,\n state => state.path\n)" - }, - { - "name": "getNavigationState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createFeatureSelector('navigation')" - }, - { - "name": "initialState", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "NavigationState", - "defaultValue": "{\n path: [],\n}" - }, - { - "name": "reducer", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createReducer(\n initialState,\n on(setPath, (state, { path }) => ({ path })),\n)" - }, - { - "name": "setPath", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Navigation] Set path', props<{ path: AdcmTypedEntity[] }>())" - }, - { - "name": "setPathOfRoute", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/store/navigation/navigation.store.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "createAction('[Navigation] Set path', props<{ params: ParamMap }>())" - } - ], - "src/app/shared/configuration/main/main.service.ts": [ - { - "name": "historyAnime", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/main/main.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "defaultValue": "[\n trigger('history', [\n state('hide', style({ top: '70px' })),\n state('show', style({ top: '134px' })),\n state('hideTools', style({ opacity: 0 })),\n state('showTools', style({ opacity: 0.8 })),\n transition('hideTools => showTools', animate('.5s .3s ease-in')),\n transition('showTools => hideTools', animate('.2s ease-out')),\n transition('hide <=> show', animate('.3s')),\n ]),\n]" - } - ], - "src/app/core/types/func.ts": [ - { - "name": "isBoolean", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(x: any) => typeof x === 'boolean'" - }, - { - "name": "isEmptyObject", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(x: any) => isObject(x) && !Object.keys(x).length" - }, - { - "name": "isNumber", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(x: any) => typeof x === 'number' && !isNaN(x)" - }, - { - "name": "isObject", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(x: any) => x !== null && typeof x === 'object'" - }, - { - "name": "randomInteger", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/types/func.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(max: number, min: number = 0): number =>\n Math.floor(min + Math.random() * (max + 1 - min))" - } - ], - "src/stories/concern/mock.ts": [ - { - "name": "ISSUE_MESSAGES_DEFAULT_MOCK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n concern: ISSUE_MESSAGES_FIRST_MESSAGE,\n}" - }, - { - "name": "ISSUE_MESSAGES_FIRST_MESSAGE", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern", - "defaultValue": "{\n id: 2039,\n blocking: true,\n type: 'issue',\n cause: 'config',\n reason: {\n message: 'Run ${action1} action on ${component1}.',\n placeholder: {\n action1: {\n type: IMPlaceholderItemType.ComponentActionRun,\n ids : {\n cluster: 1,\n service: 2,\n component: 2,\n action: 22\n },\n name: 'Restart'\n },\n component1: {\n type: IMPlaceholderItemType.ComponentConfig,\n ids : {\n cluster: 1,\n service: 2,\n component: 2\n },\n name: 'My Component'\n }\n }\n }\n}" - }, - { - "name": "ISSUE_MESSAGES_LIST_MOCK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n concerns: [\n ISSUE_MESSAGES_FIRST_MESSAGE,\n ISSUE_MESSAGES_SECOND_MESSAGE,\n ISSUE_MESSAGES_VERY_LONG_MESSAGE,\n ],\n}" - }, - { - "name": "ISSUE_MESSAGES_SECOND_MESSAGE", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern", - "defaultValue": "{\n id: 2040,\n blocking: true,\n type: 'issue',\n cause: 'config',\n reason: {\n message: 'Run the following ${action2} action on this ${component2}.',\n placeholder: {\n action2: {\n type: IMPlaceholderItemType.ComponentActionRun,\n ids : {\n cluster: 1,\n service: 2,\n component: 2,\n action: 22\n },\n name: 'Restart'\n },\n component2: {\n type: IMPlaceholderItemType.ComponentConfig,\n ids : {\n cluster: 1,\n service: 2,\n component: 2\n },\n name: 'My Component'\n }\n }\n }\n}" - }, - { - "name": "ISSUE_MESSAGES_VERY_LONG_MESSAGE", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Concern", - "defaultValue": "{\n id: 2041,\n blocking: true,\n type: 'issue',\n cause: 'config',\n reason: {\n message: 'Run ${action1} action on ${component1}. This is a very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' very very very very very very very very very very very very very very very very very very very very very very very' +\n ' long message. Bonus ${action2}!',\n placeholder: {\n action1: {\n type: IMPlaceholderItemType.ComponentActionRun,\n ids : {\n cluster: 1,\n service: 2,\n component: 2,\n action: 22\n },\n name: 'Restart'\n },\n component1: {\n type: IMPlaceholderItemType.ComponentConfig,\n ids : {\n cluster: 1,\n service: 2,\n component: 2\n },\n name: 'My Component'\n },\n action2: {\n type: IMPlaceholderItemType.ComponentActionRun,\n ids: {\n cluster: 1,\n service: 2,\n component: 2,\n action: 22\n },\n name: ''\n }\n }\n }\n}" - }, - { - "name": "ISSUE_MESSAGES_VERY_LONG_MOCK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/mock.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{\n concern: ISSUE_MESSAGES_VERY_LONG_MESSAGE,\n}" - } - ], - "src/app/shared/components/tooltip/tooltip.component.ts": [ - { - "name": "kit", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/tooltip/tooltip.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{ issue: IssueInfoComponent, status: StatusInfoComponent }" - }, - { - "name": "POSITION_MARGIN", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/tooltip/tooltip.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "defaultValue": "16" - } - ], - "src/app/shared/components/list/list-service-token.ts": [ - { - "name": "LIST_SERVICE_PROVIDER", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/list/list-service-token.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "new InjectionToken>('ListService')" - } - ], - "src/stories/concern/concern-list.stories.ts": [ - { - "name": "ListOfMessages", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern-list.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - }, - { - "name": "Template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern-list.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "(args) => ({\n props: args,\n template: ``,\n})" - } - ], - "src/stories/concern/concern-list-popup.stories.ts": [ - { - "name": "ListOfMessagesPopup", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern-list-popup.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - }, - { - "name": "Template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern-list-popup.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "(args) => ({\n props: args,\n template: ``,\n})" - } - ], - "src/app/config-groups/loader.ts": [ - { - "name": "loadConfigGroup", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/config-groups/loader.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() => import('./config-group.module').then((m) => m.ConfigGroupModule)" - } - ], - "src/app/shared/configuration/configuration.module.ts": [ - { - "name": "material", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/configuration.module.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "defaultValue": "[\n MatIconModule,\n MatInputModule,\n MatButtonModule,\n MatSelectModule,\n MatOptionModule,\n MatCheckboxModule,\n MatTooltipModule,\n MatToolbarModule,\n MatFormFieldModule,\n MatExpansionModule,\n MatSlideToggleModule,\n MatListModule,\n]" - } - ], - "src/app/core/http-interseptors/request-cache.service.ts": [ - { - "name": "maxAge", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/http-interseptors/request-cache.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Number.MAX_VALUE" - } - ], - "src/app/core/store/index.ts": [ - { - "name": "metaReducers", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "MetaReducer[]", - "defaultValue": "!environment.production ? [] : []" - }, - { - "name": "reducers", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "ActionReducerMap", - "defaultValue": "{\n auth: authReducer,\n socket: socketReducer,\n api: apiReducer,\n profile: profileReducer,\n issue: issueReducer,\n navigation: navigationReducer,\n}" - }, - { - "name": "StoreEffects", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "[]", - "defaultValue": "[AuthEffects, ApiEffects, ProfileEffects, IssueEffect, SocketEffect, NavigationEffects]" - } - ], - "src/app/config-groups/service/config-group-add.service.ts": [ - { - "name": "newConfigGroupForm", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/config-groups/service/config-group-add.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(): FormGroup =>\n new FormGroup({\n name: new FormControl('', [Validators.required, Validators.maxLength(30)]),\n description: new FormControl(),\n })" - } - ], - "src/app/config-groups/service/config-group-host-add.service.ts": [ - { - "name": "newConfigGroupHostForm", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/config-groups/service/config-group-host-add.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "() =>\n new FormGroup({\n name: new FormControl('', Validators.required),\n description: new FormControl(),\n })" - } - ], - "src/app/core/animations/index.ts": [ - { - "name": "notify", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/animations/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "trigger('notify', [\n state('show', style({ opacity: 1 })),\n state('hide', style({ opacity: 0 })),\n transition('hide => show', [animate('.2s')]),\n transition('show => hide', [animate('2s')]),\n])" - }, - { - "name": "openClose", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/animations/index.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "trigger('openClose', [\n state('true', style({ height: '*', opacity: 1 })),\n state('false', style({ height: '0px', opacity: 0 })),\n transition('true <=> false', [animate('0.5s')]),\n])" - } - ], - "src/stories/concern/concern.stories.ts": [ - { - "name": "OnlyMessage", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - }, - { - "name": "Template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "args => ({\n props: {\n ...args,\n }\n})" - }, - { - "name": "VeryLongMessage", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/concern/concern.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - } - ], - "src/app/shared/form-elements/boolean.component.ts": [ - { - "name": "options", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/form-elements/boolean.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "object", - "defaultValue": "{ clickAction: 'noop', color: 'accent' }" - } - ], - "src/app/shared/directives/m-textarea.directive.ts": [ - { - "name": "PADDING_TOP_BOTTOM", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/directives/m-textarea.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "defaultValue": "16" - } - ], - "src/app/shared/directives/infinity-scroll.directive.ts": [ - { - "name": "POINT_WHEN_EMMIT", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/directives/infinity-scroll.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "number", - "defaultValue": "100" - } - ], - "src/app/core/store/profile/profile.service.ts": [ - { - "name": "PROFILE_LINK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/store/profile/profile.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "`${environment.apiRoot}profile/`" - } - ], - "src/stories/status-tree/status-tree.stories.ts": [ - { - "name": "RegularTree", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/status-tree/status-tree.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "Template.bind({})" - }, - { - "name": "Template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/status-tree/status-tree.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "args => ({\n props: {\n ...args,\n },\n})" - } - ], - "src/app/shared/components/import/import.component.ts": [ - { - "name": "requiredObject", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/import/import.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(): ValidatorFn => (control: AbstractControl): { [key: string]: boolean } | null =>\n Object.keys(control.value).some((key) => control.value[key]) ? null : { requiered: true }" - }, - { - "name": "trueOnly", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/import/import.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (control.value ? null : { trueOnly: !control.value })" - } - ], - "src/app/shared/configuration/tests/configuration.ts": [ - { - "name": "setValue", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(data: IFieldStack[], v: TValue): IOutput =>\n data\n .filter((a) => !a.subname)\n .reduce(\n (p, c, i) => ({\n ...p,\n [c.name]:\n c.type === 'group'\n ? data\n .filter((a) => a.name === c.name && a.type !== 'group')\n .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {})\n : v\n ? v[i]\n : null,\n }),\n {}\n )" - }, - { - "name": "toField", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack): IFieldOptions => ({\n ...a,\n controlType: getControlType(a.type),\n validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type),\n compare: [],\n key: getKey(a.name, a.subname),\n hidden: false,\n value: getValue(a.type)(a.value, a.default, a.required),\n})" - }, - { - "name": "toFormOptions", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(data: IConfig): TFormOptions[] => {\n return data.config.reduce((p, c) => {\n if (c.subname) return p;\n if (c.type !== 'group') return [...p, toField(c)];\n else return [...p, toPanel(c, data)];\n }, []);\n}" - }, - { - "name": "toPanel", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/configuration/tests/configuration.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(a: IFieldStack, data: IConfig): IPanelOptions => ({\n ...a,\n options: getOptions(a, data),\n active: true,\n hidden: false,\n})" - } - ], - "src/app/main/server-status.component.ts": [ - { - "name": "styleCSS", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/main/server-status.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "'div { font-weight:bold; margin: 40px auto; width: 400px;}'" - } - ], - "src/app/shared/components/list/base-list.directive.ts": [ - { - "name": "TemporaryEntityNameConverter", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/shared/components/list/base-list.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "(currentName: Partial): string => {\n\n if (currentName === 'group_config') return 'group-config';\n if (currentName === 'group_config_hosts') return 'group-config-hosts';\n\n return currentName;\n}" - } - ], - "src/app/core/services/stack.service.ts": [ - { - "name": "UPLOAD_URL", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/core/services/stack.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "`${environment.apiRoot}stack/upload/`" - } - ], - "src/app/admin/users/users.service.ts": [ - { - "name": "USER_LINK", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/admin/users/users.service.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "", - "defaultValue": "`${environment.apiRoot}user/`" - } - ] - }, - "groupedFunctions": { - "src/app/core/api/api.reducer.ts": [ - { - "name": "apiReducer", - "file": "src/app/core/api/api.reducer.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "src/app/shared/translate/intializer.ts": [ - { - "name": "appInitializer", - "file": "src/app/shared/translate/intializer.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "translate", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "injector", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "translate", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "injector", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "translateLoader", - "file": "src/app/shared/translate/intializer.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "http", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "http", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "src/app/core/auth/auth.store.ts": [ - { - "name": "authReducer", - "file": "src/app/core/auth/auth.store.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "src/app/core/types/func.ts": [ - { - "name": "clearEmptyField", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Remove empty, null, undefined properties

\n", - "args": [ - { - "name": "input", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Object", - "jsdoctags": [ - { - "name": "input", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "flatten", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Utility function for a array,\nflattening an array of arrays

\n", - "args": [ - { - "name": "a", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": { - "pos": 2281, - "end": 2282, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "a" - }, - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "pos": 2275, - "end": 2280, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "" - } - ] - }, - { - "name": "getRandomColor", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [], - "returnType": "string", - "jsdoctags": [ - { - "tagName": { - "pos": 2681, - "end": 2688, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "returns" - }, - "comment": "

16-bit hex string

\n" - }, - { - "tagName": { - "pos": 2711, - "end": 2718, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "example" - }, - "comment": "

'#110C2E'

\n" - } - ] - }, - { - "name": "newArray", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "count", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "fn", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": { - "pos": 2490, - "end": 2495, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "count" - }, - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "pos": 2475, - "end": 2480, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "", - "typeExpression": { - "pos": 2481, - "end": 2489, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 302, - "type": { - "pos": 2482, - "end": 2488, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 144 - } - } - }, - { - "name": { - "pos": 2535, - "end": 2537, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "fn" - }, - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "pos": 2500, - "end": 2505, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "param" - }, - "comment": "", - "typeExpression": { - "pos": 2506, - "end": 2534, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 302, - "type": { - "pos": 2507, - "end": 2533, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 175, - "parameters": [ - { - "pos": 2508, - "end": 2516, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 161, - "name": { - "pos": 2508, - "end": 2509, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "_" - }, - "type": { - "pos": 2510, - "end": 2516, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 141 - } - }, - { - "pos": 2517, - "end": 2527, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 161, - "name": { - "pos": 2517, - "end": 2519, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "i" - }, - "type": { - "pos": 2520, - "end": 2527, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 144 - } - } - ], - "type": { - "pos": 2531, - "end": 2533, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 1, - "kind": 174, - "typeName": { - "pos": 2531, - "end": 2533, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "T" - } - } - } - } - }, - { - "tagName": { - "pos": 2542, - "end": 2549, - "flags": 4194304, - "modifierFlagsCache": 0, - "transformFlags": 0, - "kind": 78, - "escapedText": "returns" - }, - "comment": "" - } - ] - }, - { - "name": "nullEmptyField", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": true, - "deprecationMessage": "", - "description": "

Support nullable value in object properties,\nif value input field is empty return null.

\n", - "args": [ - { - "name": "input", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Object", - "jsdoctags": [ - { - "name": "input", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "uniqid", - "file": "src/app/core/types/func.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "prefix", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "isFloat", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "string", - "jsdoctags": [ - { - "name": "prefix", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "isFloat", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "src/app/store/navigation/navigation.store.ts": [ - { - "name": "getEventEntityType", - "file": "src/app/store/navigation/navigation.store.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "type", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "TypeName", - "jsdoctags": [ - { - "name": "type", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "getPath", - "file": "src/app/store/navigation/navigation.store.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "getters", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Observable", - "jsdoctags": [ - { - "name": "getters", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "navigationReducer", - "file": "src/app/store/navigation/navigation.store.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "src/app/core/http-interseptors/caching-interseptor.ts": [ - { - "name": "isCachable", - "file": "src/app/core/http-interseptors/caching-interseptor.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "req", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "req", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "sendRequest", - "file": "src/app/core/http-interseptors/caching-interseptor.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "req", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "next", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cache", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Observable>", - "jsdoctags": [ - { - "name": "req", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "next", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cache", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "src/app/core/store/issue.ts": [ - { - "name": "issueReducer", - "file": "src/app/core/store/issue.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "src/app/core/store/profile/index.ts": [ - { - "name": "profileReducer", - "file": "src/app/core/store/profile/index.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], - "src/app/core/store/sockets/socket.reducer.ts": [ - { - "name": "socketReducer", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "" - } - ], - "jsdoctags": [ - { - "name": "state", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "action", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ] - }, - "groupedEnumerations": { - "src/app/models/concern/concern-reason.ts": [ - { - "name": "ConcernEventType", - "childs": [ - { - "name": "Cluster", - "deprecated": false, - "deprecationMessage": "", - "value": "cluster-concerns" - }, - { - "name": "Service", - "deprecated": false, - "deprecationMessage": "", - "value": "cluster-object-concerns" - }, - { - "name": "Host", - "deprecated": false, - "deprecationMessage": "", - "value": "host-concerns" - }, - { - "name": "HostProvider", - "deprecated": false, - "deprecationMessage": "", - "value": "host-provider-concerns" - }, - { - "name": "ServiceComponent", - "deprecated": false, - "deprecationMessage": "", - "value": "service-component-concerns" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/models/concern/concern-reason.ts" - }, - { - "name": "IMPlaceholderItemType", - "childs": [ - { - "name": "ComponentActionRun", - "deprecated": false, - "deprecationMessage": "", - "value": "component_action_run" - }, - { - "name": "ComponentConfig", - "deprecated": false, - "deprecationMessage": "", - "value": "component_config" - }, - { - "name": "Cluster", - "deprecated": false, - "deprecationMessage": "", - "value": "cluster" - }, - { - "name": "Service", - "deprecated": false, - "deprecationMessage": "", - "value": "service" - }, - { - "name": "Component", - "deprecated": false, - "deprecationMessage": "", - "value": "component" - }, - { - "name": "HostProvider", - "deprecated": false, - "deprecationMessage": "", - "value": "provider" - }, - { - "name": "Host", - "deprecated": false, - "deprecationMessage": "", - "value": "host" - }, - { - "name": "Job", - "deprecated": false, - "deprecationMessage": "", - "value": "job" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/models/concern/concern-reason.ts" - } - ], - "src/app/shared/configuration/attributes/attribute.service.ts": [ - { - "name": "ConfigAttributeNames", - "childs": [ - { - "name": "GROUP_KEYS", - "deprecated": false, - "deprecationMessage": "", - "value": "group_keys" - }, - { - "name": "CUSTOM_GROUP_KEYS", - "deprecated": false, - "deprecationMessage": "", - "value": "custom_group_keys" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/shared/configuration/attributes/attribute.service.ts" - } - ], - "src/app/abstract-directives/list.directive.ts": [ - { - "name": "Direction", - "childs": [ - { - "name": "", - "deprecated": false, - "deprecationMessage": "", - "value": "" - }, - { - "name": "asc", - "deprecated": false, - "deprecationMessage": "", - "value": "" - }, - { - "name": "desc", - "deprecated": false, - "deprecationMessage": "", - "value": "-" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/abstract-directives/list.directive.ts" - } - ], - "src/app/shared/add-component/provider.component.ts": [ - { - "name": "DisplayMode", - "childs": [ - { - "name": "default", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "inHost", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "noCluster", - "deprecated": false, - "deprecationMessage": "" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/shared/add-component/provider.component.ts" - } - ], - "src/app/app.component.ts": [ - { - "name": "flagForConsole", - "childs": [ - { - "name": "profile", - "deprecated": false, - "deprecationMessage": "", - "value": "profile" - }, - { - "name": "socket", - "deprecated": false, - "deprecationMessage": "", - "value": "socket" - }, - { - "name": "load_complete", - "deprecated": false, - "deprecationMessage": "", - "value": "load_complete" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "

Magic strings for marking loading stages and other, for ci tests

\n", - "file": "src/app/app.component.ts" - } - ], - "src/app/components/status-tree/status-tree.component.ts": [ - { - "name": "Folding", - "childs": [ - { - "name": "Collapsed", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "Expanded", - "deprecated": false, - "deprecationMessage": "" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/components/status-tree/status-tree.component.ts" - } - ], - "src/app/core/services/channel.service.ts": [ - { - "name": "keyChannelStrim", - "childs": [ - { - "name": "scroll", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "notifying", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "load_complete", - "deprecated": false, - "deprecationMessage": "" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/core/services/channel.service.ts" - } - ], - "src/app/shared/components/actions/master/master.service.ts": [ - { - "name": "whatShow", - "childs": [ - { - "name": "none", - "deprecated": false, - "deprecationMessage": "", - "value": "none" - }, - { - "name": "config", - "deprecated": false, - "deprecationMessage": "", - "value": "config" - }, - { - "name": "hostMap", - "deprecated": false, - "deprecationMessage": "", - "value": "hostmap" - }, - { - "name": "stepper", - "deprecated": false, - "deprecationMessage": "", - "value": "stepper" - } - ], - "ctype": "miscellaneous", - "subtype": "enum", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "file": "src/app/shared/components/actions/master/master.service.ts" - } - ] - }, - "groupedTypeAliases": { - "src/app/shared/host-components-map/types.ts": [ - { - "name": "ActionParam", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"add\" | \"remove\"", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TConstraint", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "TConstraintValue[]", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 179 - }, - { - "name": "TConstraintValue", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "number | \"+\" | \"odd\" | \"depend\"", - "file": "src/app/shared/host-components-map/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/shared/configuration/attributes/attribute.service.ts": [ - { - "name": "Attributes", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "Map", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 174 - }, - { - "name": "AttributesOptions", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "Record", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 174 - }, - { - "name": "ConfigAttribute", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/shared/configuration/attributes/attribute.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - } - ], - "src/app/shared/components/tooltip/tooltip.service.ts": [ - { - "name": "ComponentName", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"issue\" | \"status\" | undefined", - "file": "src/app/shared/components/tooltip/tooltip.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "PositionType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"top\" | \"right\" | \"bottom\" | \"left\"", - "file": "src/app/shared/components/tooltip/tooltip.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/models/concern/concern.ts": [ - { - "name": "ConcernType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"issue\" | \"lock\"", - "file": "src/app/models/concern/concern.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/shared/configuration/types.ts": [ - { - "name": "controlType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"boolean\" | \"textbox\" | \"textarea\" | \"json\" | \"password\" | \"list\" | \"map\" | \"dropdown\" | \"file\" | \"text\" | \"structure\" | \"secrettext\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "

Mark for rendering required component

\n", - "kind": 183 - }, - { - "name": "resultTypes", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "simpleTypes | simpleTypes[] | object", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "simpleTypes", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "string | number | boolean", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "stateType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"created\" | \"locked\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TNBase", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"string\" | \"integer\" | \"int\" | \"boolean\" | \"bool\" | \"float\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TNForm", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "TNBase | TNReq | TNSpec", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TNReq", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"dict\" | \"list\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TNSpec", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"structure\" | \"group\" | \"option\" | \"json\" | \"map\" | \"file\" | \"text\" | \"password\" | \"secrettext\" | \"variant\"", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TValue", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "string | number | boolean | object | any[]", - "file": "src/app/shared/configuration/types.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/core/types/api.ts": [ - { - "name": "Entities", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "ICluster | Service | Host | Provider | Job | Task | Bundle", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "TypeName", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"bundle\" | \"cluster\" | \"host\" | \"provider\" | \"service\" | \"job\" | \"task\" | \"user\" | \"profile\" | \"adcm\" | \"stats\" | \"hostcomponent\" | \"service2cluster\" | \"host2cluster\" | \"servicecomponent\" | \"component\" | \"group_config\" | \"group_config_hosts\"", - "file": "src/app/core/types/api.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/core/store/sockets/socket.reducer.ts": [ - { - "name": "EntityEvent", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"add\" | \"add_job_log\" | \"create\" | \"delete\" | \"remove\" | \"change_config\" | \"change_state\" | \"change_status\" | \"change_job_status\" | \"change_hostcomponentmap\" | \"upgrade\" | \"concern\"", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "StatusType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"open\" | \"close\" | \"re-open\"", - "file": "src/app/core/store/sockets/socket.reducer.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/models/issue.ts": [ - { - "name": "IssueType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"cluster\" | \"service\" | \"servicecomponent\" | \"component\"", - "file": "src/app/models/issue.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/core/types/task-job.ts": [ - { - "name": "Job", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - }, - { - "name": "JobStatus", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"created\" | \"running\" | \"failed\" | \"success\" | \"aborted\"", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "JobType", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"component\" | \"service\" | \"cluster\" | \"host\" | \"provider\"", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - }, - { - "name": "Task", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/core/types/task-job.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - } - ], - "src/app/abstract-directives/popover-content.directive.ts": [ - { - "name": "PopoverEventFunc", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "function", - "file": "src/app/abstract-directives/popover-content.directive.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 175 - } - ], - "src/app/core/store/profile/index.ts": [ - { - "name": "ProfileState", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "IUser", - "file": "src/app/core/store/profile/index.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 174 - } - ], - "src/app/core/types/stack.ts": [ - { - "name": "Prototype", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/core/types/stack.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - }, - { - "name": "ServicePrototype", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "", - "file": "src/app/core/types/stack.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - } - ], - "src/app/core/store/router/router.actions.ts": [ - { - "name": "RouterActionsUnion", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "Go | Back | Forward", - "file": "src/app/core/store/router/router.actions.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/core/services/stack.service.ts": [ - { - "name": "StackInfo", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"cluster\" | \"host\" | \"provider\" | \"service\" | \"bundle\"", - "file": "src/app/core/services/stack.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/models/status-tree.ts": [ - { - "name": "StatusTreeLinkFunc", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "function", - "file": "src/app/models/status-tree.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 175 - } - ], - "src/app/entry/task/tasks.component.ts": [ - { - "name": "TaskStatus", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "string | \"running\" | \"success\" | \"failed\"", - "file": "src/app/entry/task/tasks.component.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/shared/configuration/services/field.service.ts": [ - { - "name": "TFormOptions", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "IFieldOptions | IPanelOptions", - "file": "src/app/shared/configuration/services/field.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ], - "src/app/shared/configuration/yspec/yspec.service.ts": [ - { - "name": "TMatch", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "TNBase | TNReq", - "file": "src/app/shared/configuration/yspec/yspec.service.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 183 - } - ] - } - }, - "routes": { - "name": "", - "kind": "module", - "className": "AppModule", - "children": [ - { - "name": "routes", - "filename": "src/app/app-routing.module.ts", - "module": "AppRoutingModule", - "children": [ - { - "path": "cluster", - "loadChildren": "app/entry/cluster/cluster.module#ClusterModule", - "children": [ - { - "kind": "module", - "children": [ - { - "name": "clusterRoutes", - "filename": "src/app/entry/cluster/cluster.module.ts", - "module": "ClusterRoutingModule", - "children": [ - { - "path": "", - "component": "ClusterListComponent", - "canActivate": [ - "AuthGuard" - ] - }, - { - "path": ":cluster", - "component": "ClusterDetailsComponent", - "canActivate": [ - "AuthGuard" - ], - "canActivateChild": [ - "AuthGuard" - ], - "children": [ - { - "path": "", - "redirectTo": "main", - "pathMatch": "full" - }, - { - "path": "main", - "component": "MainInfoComponent" - }, - { - "path": "service", - "component": "ServicesComponent" - }, - { - "path": "host", - "component": "ClusterHostComponent" - }, - { - "path": "host_component", - "component": "HcmapComponent" - }, - { - "path": "config", - "component": "ConfigComponent" - }, - { - "path": "group_config", - "component": "ConfigGroupListComponent" - }, - { - "path": "status", - "component": "ClusterStatusComponent" - }, - { - "path": "import", - "component": "ImportComponent" - } - ] - }, - { - "path": ":cluster/group_config/:group_config", - "canActivate": [ - "AuthGuard" - ], - "canActivateChild": [ - "AuthGuard" - ], - "component": "GroupConfigDetailsComponent", - "children": [ - { - "path": "", - "redirectTo": "host", - "pathMatch": "full" - }, - { - "path": "host", - "component": "ConfigGroupHostListComponent" - }, - { - "path": "config", - "component": "ConfigComponent", - "data": { - "isGroupConfig": true - } - } - ] - }, - { - "path": ":cluster/service/:service", - "component": "ServiceDetailsComponent", - "canActivate": [ - "AuthGuard" - ], - "canActivateChild": [ - "AuthGuard" - ], - "children": [ - { - "path": "", - "redirectTo": "main", - "pathMatch": "full" - }, - { - "path": "main", - "component": "MainInfoComponent" - }, - { - "path": "config", - "component": "ConfigComponent" - }, - { - "path": "group_config", - "component": "ConfigGroupListComponent" - }, - { - "path": "status", - "component": "ServiceStatusComponent" - }, - { - "path": "import", - "component": "ImportComponent" - }, - { - "path": "component", - "component": "ServiceComponentsComponent" - } - ] - }, - { - "path": ":cluster/service/:service/group_config/:group_config", - "canActivate": [ - "AuthGuard" - ], - "canActivateChild": [ - "AuthGuard" - ], - "component": "GroupConfigDetailsComponent", - "children": [ - { - "path": "", - "redirectTo": "host", - "pathMatch": "full" - }, - { - "path": "host", - "component": "ConfigGroupHostListComponent" - }, - { - "path": "config", - "component": "ConfigComponent", - "data": { - "isGroupConfig": true - } - } - ] - }, - { - "path": ":cluster/service/:service/component/:servicecomponent", - "component": "ServiceComponentDetailsComponent", - "canActivate": [ - "AuthGuard" - ], - "canActivateChild": [ - "AuthGuard" - ], - "children": [ - { - "path": "", - "redirectTo": "main", - "pathMatch": "full" - }, - { - "path": "main", - "component": "MainInfoComponent" - }, - { - "path": "config", - "component": "ConfigComponent" - }, - { - "path": "group_config", - "component": "ConfigGroupListComponent" - }, - { - "path": "status", - "component": "ServiceComponentStatusComponent" - } - ] - }, - { - "path": ":cluster/service/:service/component/:component/group_config/:group_config", - "canActivate": [ - "AuthGuard" - ], - "canActivateChild": [ - "AuthGuard" - ], - "component": "GroupConfigDetailsComponent", - "children": [ - { - "path": "", - "redirectTo": "host", - "pathMatch": "full" - }, - { - "path": "host", - "component": "ConfigGroupHostListComponent" - }, - { - "path": "config", - "component": "ConfigComponent", - "data": { - "isGroupConfig": true - } - } - ] - }, - { - "path": ":cluster/host/:host", - "component": "HostDetailsComponent", - "canActivate": [ - "AuthGuard" - ], - "canActivateChild": [ - "AuthGuard" - ], - "children": [ - { - "path": "", - "redirectTo": "main", - "pathMatch": "full" - }, - { - "path": "main", - "component": "MainInfoComponent" - }, - { - "path": "config", - "component": "ConfigComponent" - }, - { - "path": "status", - "component": "HostStatusComponent" - } - ] - } - ], - "kind": "module" - } - ], - "module": "ClusterModule" - } - ] - }, - { - "path": "job", - "loadChildren": "app/entry/job/job.module#JobModule", - "children": [ - { - "kind": "module", - "children": [ - { - "name": "routes", - "filename": "src/app/entry/job/job-routing.module.ts", - "module": "JobRoutingModule", - "children": [ - { - "path": ":job", - "canActivate": [ - "AuthGuard" - ], - "component": "JobDetailsComponent", - "children": [ - { - "path": "", - "redirectTo": "main", - "pathMatch": "full" - }, - { - "path": "main", - "component": "MainComponent" - }, - { - "path": ":log", - "component": "LogComponent" - } - ] - } - ], - "kind": "module" - } - ], - "module": "JobModule" - } - ] - }, - { - "path": "task", - "loadChildren": "app/entry/task/task.module#TaskModule", - "children": [ - { - "kind": "module", - "children": [], - "module": "TaskModule" - } - ] - }, - { - "path": "bundle", - "loadChildren": "app/entry/bundle/bundle.module#BundleModule", - "children": [ - { - "kind": "module", - "children": [ - { - "name": "routes", - "filename": "src/app/entry/bundle/bundle.module.ts", - "module": "BundleRoutingModule", - "children": [ - { - "path": "", - "canActivate": [ - "AuthGuard" - ], - "component": "BundleListComponent" - }, - { - "path": ":bundle", - "canActivate": [ - "AuthGuard" - ], - "component": "BundleDetailsComponent", - "children": [ - { - "path": "", - "redirectTo": "main", - "pathMatch": "full" - }, - { - "path": "main", - "component": "MainComponent" - }, - { - "path": "license", - "component": "LicenseComponent" - } - ] - } - ], - "kind": "module" - } - ], - "module": "BundleModule" - } - ] - }, - { - "path": "host", - "children": [ - { - "path": "", - "pathMatch": "full", - "component": "HostListComponent" - }, - { - "path": ":host", - "component": "HostDetailsComponent", - "children": [ - { - "path": "", - "redirectTo": "main", - "pathMatch": "full" - }, - { - "path": "main", - "component": "MainInfoComponent" - }, - { - "path": "config", - "component": "ConfigComponent" - }, - { - "path": "status", - "component": "HostStatusComponent" - } - ] - } - ], - "canActivate": [ - "AuthGuard" - ] - }, - { - "path": "provider", - "children": [ - { - "path": "", - "pathMatch": "full", - "component": "HostproviderComponent" - }, - { - "path": ":provider", - "component": "ProviderDetailsComponent", - "children": [ - { - "path": "", - "redirectTo": "main", - "pathMatch": "full" - }, - { - "path": "main", - "component": "MainInfoComponent" - }, - { - "path": "config", - "component": "ConfigComponent" - }, - { - "path": "group_config", - "component": "ConfigGroupListComponent" - } - ] - } - ], - "canActivate": [ - "AuthGuard" - ] - }, - { - "path": "provider/:provider/group_config/:group_config", - "canActivate": [ - "AuthGuard" - ], - "canActivateChild": [ - "AuthGuard" - ], - "component": "GroupConfigDetailsComponent", - "children": [ - { - "path": "", - "redirectTo": "host", - "pathMatch": "full" - }, - { - "path": "host", - "component": "ConfigGroupHostListComponent" - }, - { - "path": "config", - "component": "ConfigComponent", - "data": { - "isGroupConfig": true - } - } - ] - }, - { - "path": "cluster/:cluster/host/:host/provider/:provider", - "redirectTo": "provider/:provider" - }, - { - "path": "host/:host/provider/:provider", - "redirectTo": "provider/:provider" - }, - { - "path": "", - "redirectTo": "admin", - "pathMatch": "full" - }, - { - "path": "log", - "component": "LogComponent", - "canActivate": [ - "AuthGuard" - ] - }, - { - "path": "login", - "component": "LoginComponent" - }, - { - "path": "profile", - "component": "ProfileComponent", - "canActivate": [ - "AuthGuard" - ] - }, - { - "path": "support", - "component": "SupportComponent" - }, - { - "path": "404", - "component": "PageNotFoundComponent" - }, - { - "path": "500", - "component": "FatalErrorComponent" - }, - { - "path": "504", - "component": "GatewayTimeoutComponent" - }, - { - "path": "admin", - "loadChildren": "app/admin/admin.module#AdminModule", - "children": [ - { - "kind": "module", - "children": [ - { - "name": "routes", - "filename": "src/app/admin/admin.module.ts", - "module": "AdminRoutingModule", - "children": [ - { - "path": "", - "component": "PatternComponent", - "canActivate": [ - "AuthGuard" - ], - "canActivateChild": [ - "AuthGuard" - ], - "children": [ - { - "path": "", - "redirectTo": "intro", - "pathMatch": "full" - }, - { - "path": "intro", - "component": "IntroComponent" - }, - { - "path": "settings", - "component": "SettingsComponent" - }, - { - "path": "users", - "component": "UsersComponent" - } - ] - } - ], - "kind": "module" - } - ], - "module": "AdminModule" - } - ] - }, - { - "path": "**", - "component": "PageNotFoundComponent" - } - ], - "kind": "module" - } - ] - }, - "coverage": { - "count": 1, - "status": "low", - "files": [ - { - "filePath": "e2e/app.po.ts", - "type": "class", - "linktype": "classe", - "name": "AppPage", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "e2e/login/login.po.ts", - "type": "class", - "linktype": "classe", - "name": "LoginPage", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "e2e/start/start.po.ts", - "type": "class", - "linktype": "classe", - "name": "StartPage", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/abstract-directives/adwp-base-list.directive.ts", - "type": "class", - "linktype": "classe", - "name": "AdwpBaseListDirective", - "coveragePercent": 0, - "coverageCount": "0/31", - "status": "low" - }, - { - "filePath": "src/app/abstract-directives/adwp-list.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "AdwpListDirective", - "coveragePercent": 0, - "coverageCount": "0/19", - "status": "low" - }, - { - "filePath": "src/app/abstract-directives/base-detail.abstract.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "BaseDetailAbstractDirective", - "coveragePercent": 0, - "coverageCount": "0/18", - "status": "low" - }, - { - "filePath": "src/app/abstract-directives/concern-list.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "ConcernListDirective", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/abstract-directives/detail.abstract.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "DetailAbstractDirective", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/abstract-directives/list.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "ListDirective", - "coveragePercent": 0, - "coverageCount": "0/29", - "status": "low" - }, - { - "filePath": "src/app/abstract-directives/menu-item.abstract.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "MenuItemAbstractDirective", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/abstract-directives/popover-content.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "PopoverContentDirective", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/abstract-directives/status.abstract.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "StatusAbstractDirective", - "coveragePercent": 0, - "coverageCount": "0/16", - "status": "low" - }, - { - "filePath": "src/app/abstract/entity-service.ts", - "type": "class", - "linktype": "classe", - "name": "EntityService", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/abstract/having-status-tree.abstract.service.ts", - "type": "class", - "linktype": "classe", - "name": "HavingStatusTreeAbstractService", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/admin/intro.component.ts", - "type": "component", - "linktype": "component", - "name": "IntroComponent", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/admin/pattern.component.ts", - "type": "component", - "linktype": "component", - "name": "PatternComponent", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/admin/settings.component.ts", - "type": "component", - "linktype": "component", - "name": "SettingsComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/admin/users/users.component.ts", - "type": "component", - "linktype": "component", - "name": "UsersComponent", - "coveragePercent": 0, - "coverageCount": "0/13", - "status": "low" - }, - { - "filePath": "src/app/admin/users/users.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "UsersService", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/admin/users/users.service.ts", - "type": "interface", - "linktype": "interface", - "name": "User", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/admin/users/users.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "USER_LINK", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/app.component.ts", - "type": "component", - "linktype": "component", - "name": "AppComponent", - "coveragePercent": 16, - "coverageCount": "1/6", - "status": "low" - }, - { - "filePath": "src/app/components/actions-button/actions-button.component.ts", - "type": "component", - "linktype": "component", - "name": "ActionsButtonComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/bell/bell.component.ts", - "type": "component", - "linktype": "component", - "name": "BellComponent", - "coveragePercent": 0, - "coverageCount": "0/29", - "status": "low" - }, - { - "filePath": "src/app/components/bell/bell.component.ts", - "type": "interface", - "linktype": "interface", - "name": "NotificationsData", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/components/bell/bell.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "FAILED_COLOR", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/components/bell/bell.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "RUNNING_COLOR", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/components/bell/bell.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "SUCCESS_COLOR", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/components/bundle/bundle-details/bundle-details.component.ts", - "type": "component", - "linktype": "component", - "name": "BundleDetailsComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/cluster/cluster-details/cluster-details.component.ts", - "type": "component", - "linktype": "component", - "name": "ClusterDetailsComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/cluster/cluster-status/cluster-status.component.ts", - "type": "component", - "linktype": "component", - "name": "ClusterStatusComponent", - "coveragePercent": 0, - "coverageCount": "0/16", - "status": "low" - }, - { - "filePath": "src/app/components/cluster/hcmap/hcmap.component.ts", - "type": "component", - "linktype": "component", - "name": "HcmapComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/components/cluster/host/cluster-host.component.ts", - "type": "component", - "linktype": "component", - "name": "ClusterHostComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/cluster/services/services.component.ts", - "type": "component", - "linktype": "component", - "name": "ServicesComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/columns/cluster-column/cluster-column.component.ts", - "type": "component", - "linktype": "component", - "name": "ClusterColumnComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/components/columns/cluster-column/cluster-column.component.ts", - "type": "interface", - "linktype": "interface", - "name": "AddClusterEventData", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/components/columns/edition-column/edition-column.component.ts", - "type": "component", - "linktype": "component", - "name": "EditionColumnComponent", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/components/columns/job-name/job-name.component.ts", - "type": "component", - "linktype": "component", - "name": "JobNameComponent", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/components/columns/job-status-column/job-status-column.component.ts", - "type": "component", - "linktype": "component", - "name": "JobStatusColumnComponent", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/components/columns/state-column/state-column.component.ts", - "type": "component", - "linktype": "component", - "name": "StateColumnComponent", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/components/columns/status-column/status-column.component.ts", - "type": "component", - "linktype": "component", - "name": "StatusColumnComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/components/columns/status-column/status-column.component.ts", - "type": "interface", - "linktype": "interface", - "name": "StatusData", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/components/columns/task-name/task-name.component.ts", - "type": "component", - "linktype": "component", - "name": "TaskNameComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/components/columns/task-objects/task-objects.component.ts", - "type": "component", - "linktype": "component", - "name": "TaskObjectsComponent", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/components/columns/task-status-column/task-status-column.component.ts", - "type": "component", - "linktype": "component", - "name": "TaskStatusColumnComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/components/concern/concern-item/concern-item.component.ts", - "type": "component", - "linktype": "component", - "name": "ConcernItemComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/components/concern/concern-list-ref/concern-list-ref.component.ts", - "type": "component", - "linktype": "component", - "name": "ConcernListRefComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/components/concern/concern-list/concern-list.component.ts", - "type": "component", - "linktype": "component", - "name": "ConcernListComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/components/concern/concern.component.ts", - "type": "component", - "linktype": "component", - "name": "ConcernComponent", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/components/host/host-details/host-details.component.ts", - "type": "component", - "linktype": "component", - "name": "HostDetailsComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/host/host-list/host-list.component.ts", - "type": "component", - "linktype": "component", - "name": "HostListComponent", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/components/host/host-status/host-status.component.ts", - "type": "component", - "linktype": "component", - "name": "HostStatusComponent", - "coveragePercent": 0, - "coverageCount": "0/16", - "status": "low" - }, - { - "filePath": "src/app/components/hostprovider/group-config-details/group-config-details.component.ts", - "type": "component", - "linktype": "component", - "name": "GroupConfigDetailsComponent", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/components/hostprovider/hostprovider.component.ts", - "type": "component", - "linktype": "component", - "name": "HostproviderComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/hostprovider/provider-details/provider-details.component.ts", - "type": "component", - "linktype": "component", - "name": "ProviderDetailsComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/job/job-details/job-details.component.ts", - "type": "component", - "linktype": "component", - "name": "JobDetailsComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/components/job/jobs/jobs.component.ts", - "type": "component", - "linktype": "component", - "name": "JobsComponent", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/components/navigation/navigation.component.ts", - "type": "component", - "linktype": "component", - "name": "NavigationComponent", - "coveragePercent": 0, - "coverageCount": "0/13", - "status": "low" - }, - { - "filePath": "src/app/components/notifications/notifications.component.ts", - "type": "component", - "linktype": "component", - "name": "NotificationsComponent", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/components/notifications/notifications.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ACKNOWLEDGE_EVENT", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/components/popover/popover.component.ts", - "type": "component", - "linktype": "component", - "name": "PopoverComponent", - "coveragePercent": 0, - "coverageCount": "0/12", - "status": "low" - }, - { - "filePath": "src/app/components/service-component/service-component-details/service-component-details.component.ts", - "type": "component", - "linktype": "component", - "name": "ServiceComponentDetailsComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/service-component/service-component-status/service-component-status.component.ts", - "type": "component", - "linktype": "component", - "name": "ServiceComponentStatusComponent", - "coveragePercent": 0, - "coverageCount": "0/16", - "status": "low" - }, - { - "filePath": "src/app/components/service-component/service-components.component.ts", - "type": "component", - "linktype": "component", - "name": "ServiceComponentsComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/service/service-details/service-details.component.ts", - "type": "component", - "linktype": "component", - "name": "ServiceDetailsComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/components/service/service-status/service-status.component.ts", - "type": "component", - "linktype": "component", - "name": "ServiceStatusComponent", - "coveragePercent": 0, - "coverageCount": "0/16", - "status": "low" - }, - { - "filePath": "src/app/components/status-tree/status-tree.component.ts", - "type": "component", - "linktype": "component", - "name": "StatusTreeComponent", - "coveragePercent": 0, - "coverageCount": "0/15", - "status": "low" - }, - { - "filePath": "src/app/components/status-tree/status-tree.component.ts", - "type": "interface", - "linktype": "interface", - "name": "CountedStatusTree", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/components/status-tree/status-tree.component.ts", - "type": "interface", - "linktype": "interface", - "name": "Counts", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/components/status-tree/status-tree.component.ts", - "type": "interface", - "linktype": "interface", - "name": "ExampleFlatNode", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/config-groups/components/config-group-add/config-group-add.component.ts", - "type": "component", - "linktype": "component", - "name": "AddConfigGroupComponent", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/config-groups/components/config-group-host-add/config-group-host-add.component.ts", - "type": "component", - "linktype": "component", - "name": "AddHostToConfigGroupComponent", - "coveragePercent": 0, - "coverageCount": "0/16", - "status": "low" - }, - { - "filePath": "src/app/config-groups/loader.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "loadConfigGroup", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/config-groups/model/config-group.model.ts", - "type": "interface", - "linktype": "interface", - "name": "ConfigGroup", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/config-groups/pages/group-list/group-list.component.ts", - "type": "component", - "linktype": "component", - "name": "ConfigGroupListComponent", - "coveragePercent": 0, - "coverageCount": "0/21", - "status": "low" - }, - { - "filePath": "src/app/config-groups/pages/host-list/host-list.component.ts", - "type": "component", - "linktype": "component", - "name": "ConfigGroupHostListComponent", - "coveragePercent": 0, - "coverageCount": "0/21", - "status": "low" - }, - { - "filePath": "src/app/config-groups/service/config-group-add.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ConfigGroupAddService", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/config-groups/service/config-group-add.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "newConfigGroupForm", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/config-groups/service/config-group-host-add.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ConfigGroupHostAddService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/config-groups/service/config-group-host-add.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "newConfigGroupHostForm", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/config-groups/service/config-group-host-list.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ConfigGroupHostListService", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/config-groups/service/config-group-list.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ConfigGroupListService", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/config-groups/service/config-group-list.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "CONFIG_GROUP_LIST_SERVICE", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/config-groups/service/config-group.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ConfigGroupService", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/core/animations/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "notify", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/animations/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "openClose", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.effects.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ApiEffects", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "interface", - "linktype": "interface", - "name": "ApiState", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "apiReducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getApiState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getRoot", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getStack", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "InitState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "loadRoot", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "loadStack", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "reducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "rootError", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "rootSuccess", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "stackSuccess", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/api/api.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ApiService", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.guard.ts", - "type": "guard", - "linktype": "guard", - "name": "AuthGuard", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "AuthService", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "injectable", - "linktype": "injectable", - "name": "AuthEffects", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "interface", - "linktype": "interface", - "name": "AuthState", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "authReducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "authCheck", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "authFaled", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "authLogin", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "authLogout", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "authSuccess", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getAuthState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "initialState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isAuthenticated", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/auth/auth.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "reducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/http-interseptors/auth-interseptor.ts", - "type": "interceptor", - "linktype": "interceptor", - "name": "AuthInterceptor", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/http-interseptors/auth-interseptor.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "EXCLUDE_URLS", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/http-interseptors/caching-interseptor.ts", - "type": "interceptor", - "linktype": "interceptor", - "name": "CachingInterseptor", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/http-interseptors/caching-interseptor.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "isCachable", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/http-interseptors/caching-interseptor.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "sendRequest", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/http-interseptors/request-cache.service.ts", - "type": "class", - "linktype": "classe", - "name": "RequestCache", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/http-interseptors/request-cache.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "RequestCacheService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/http-interseptors/request-cache.service.ts", - "type": "interface", - "linktype": "interface", - "name": "RequestCacheEntry", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/http-interseptors/request-cache.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "maxAge", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/services/app/app.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "AppService", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/core/services/channel.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ChannelService", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/services/channel.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IBroadcast", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/services/cluster.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ClusterService", - "coveragePercent": 8, - "coverageCount": "2/25", - "status": "low" - }, - { - "filePath": "src/app/core/services/cluster.service.ts", - "type": "interface", - "linktype": "interface", - "name": "WorkerInstance", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/services/config.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ConfigService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/services/config.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IVersionInfo", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/services/config.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "CONFIG_URL", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/services/dom.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "DomService", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/services/fully-rendered.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "FullyRenderedService", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/services/preloader.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "PreloaderService", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/core/services/stack.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "StackService", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/services/stack.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "UPLOAD_URL", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/index.ts", - "type": "interface", - "linktype": "interface", - "name": "State", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/core/store/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "metaReducers", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "reducers", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "StoreEffects", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/issue.ts", - "type": "injectable", - "linktype": "injectable", - "name": "IssueEffect", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/store/issue.ts", - "type": "interface", - "linktype": "interface", - "name": "IssueState", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/store/issue.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "issueReducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/issue.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "checkIssue", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/issue.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "fillIssue", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/issue.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getIssueSelector", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/issue.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "InitState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/issue.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "loadIssue", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/issue.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "reducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ProfileEffects", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "profileReducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "clearProfile", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getFirstAdminLogin", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getProfile", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getProfileSelector", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "InitState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "loadProfile", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "loadProfileSuccess", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "reducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "setTextareaHeight", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "settingsSave", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/profile.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ProfileService", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/profile.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IProfile", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/profile.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IUser", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/profile.service.ts", - "type": "interface", - "linktype": "interface", - "name": "LastViewedTask", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/core/store/profile/profile.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "PROFILE_LINK", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/router/route-serializer.ts", - "type": "class", - "linktype": "classe", - "name": "RouteSerializer", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/core/store/router/route-serializer.ts", - "type": "interface", - "linktype": "interface", - "name": "RouterStateUrl", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/store/router/router.actions.ts", - "type": "class", - "linktype": "classe", - "name": "Back", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/core/store/router/router.actions.ts", - "type": "class", - "linktype": "classe", - "name": "Forward", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/core/store/router/router.actions.ts", - "type": "class", - "linktype": "classe", - "name": "Go", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/store/router/router.actions.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "BACK", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/router/router.actions.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "FORWARD", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/router/router.actions.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "GO", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/router/router.effects.ts", - "type": "injectable", - "linktype": "injectable", - "name": "RouterEffects", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.effect.ts", - "type": "injectable", - "linktype": "injectable", - "name": "SocketEffect", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "interface", - "linktype": "interface", - "name": "EventMessage", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "interface", - "linktype": "interface", - "name": "IEMObject", - "coveragePercent": 25, - "coverageCount": "1/4", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "interface", - "linktype": "interface", - "name": "SocketState", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "socketReducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "clearMessages", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getConnectStatus", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getMessage", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getSocketState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "initialState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "reducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "selectMessage", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "socketClose", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "socketInit", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "socketOpen", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.reducer.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "socketResponse", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/store/sockets/socket.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "SocketService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/types/actions.ts", - "type": "interface", - "linktype": "interface", - "name": "IAction", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/core/types/actions.ts", - "type": "interface", - "linktype": "interface", - "name": "IActionParameter", - "coveragePercent": 25, - "coverageCount": "1/4", - "status": "low" - }, - { - "filePath": "src/app/core/types/actions.ts", - "type": "interface", - "linktype": "interface", - "name": "IUIOptions", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/core/types/api.ts", - "type": "interface", - "linktype": "interface", - "name": "ApiFlat", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/types/api.ts", - "type": "interface", - "linktype": "interface", - "name": "BaseEntity", - "coveragePercent": 0, - "coverageCount": "0/17", - "status": "low" - }, - { - "filePath": "src/app/core/types/api.ts", - "type": "interface", - "linktype": "interface", - "name": "Bundle", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/types/api.ts", - "type": "interface", - "linktype": "interface", - "name": "CanLicensed", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/core/types/api.ts", - "type": "interface", - "linktype": "interface", - "name": "Host", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/core/types/api.ts", - "type": "interface", - "linktype": "interface", - "name": "IRoot", - "coveragePercent": 100, - "coverageCount": "1/1", - "status": "very-good" - }, - { - "filePath": "src/app/core/types/api.ts", - "type": "interface", - "linktype": "interface", - "name": "License", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/types/api.ts", - "type": "interface", - "linktype": "interface", - "name": "Provider", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/core/types/api.ts", - "type": "interface", - "linktype": "interface", - "name": "Service", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/core/types/context-manager.ts", - "type": "class", - "linktype": "classe", - "name": "ContextManager", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "clearEmptyField", - "coveragePercent": 100, - "coverageCount": "1/1", - "status": "very-good" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "flatten", - "coveragePercent": 100, - "coverageCount": "1/1", - "status": "very-good" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "getRandomColor", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "newArray", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "nullEmptyField", - "coveragePercent": 100, - "coverageCount": "1/1", - "status": "very-good" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "uniqid", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isBoolean", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isEmptyObject", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isNumber", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isObject", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/types/func.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "randomInteger", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/core/types/host-component.ts", - "type": "interface", - "linktype": "interface", - "name": "HostComponent", - "coveragePercent": 18, - "coverageCount": "3/16", - "status": "low" - }, - { - "filePath": "src/app/core/types/host-component.ts", - "type": "interface", - "linktype": "interface", - "name": "IComponent", - "coveragePercent": 8, - "coverageCount": "1/12", - "status": "low" - }, - { - "filePath": "src/app/core/types/host-component.ts", - "type": "interface", - "linktype": "interface", - "name": "IRequires", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/types/import-export.ts", - "type": "interface", - "linktype": "interface", - "name": "IExport", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/core/types/import-export.ts", - "type": "interface", - "linktype": "interface", - "name": "IImport", - "coveragePercent": 16, - "coverageCount": "1/6", - "status": "low" - }, - { - "filePath": "src/app/core/types/stack.ts", - "type": "interface", - "linktype": "interface", - "name": "StackBase", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/core/types/task-job.ts", - "type": "interface", - "linktype": "interface", - "name": "CheckLog", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/core/types/task-job.ts", - "type": "interface", - "linktype": "interface", - "name": "JobAction", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/types/task-job.ts", - "type": "interface", - "linktype": "interface", - "name": "JobObject", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/core/types/task-job.ts", - "type": "interface", - "linktype": "interface", - "name": "JobRaw", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/types/task-job.ts", - "type": "interface", - "linktype": "interface", - "name": "LogFile", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/core/types/task-job.ts", - "type": "interface", - "linktype": "interface", - "name": "TaskBase", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/core/types/task-job.ts", - "type": "interface", - "linktype": "interface", - "name": "TaskRaw", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/core/types/utils.ts", - "type": "interface", - "linktype": "interface", - "name": "EmmitRow", - "coveragePercent": 25, - "coverageCount": "1/4", - "status": "low" - }, - { - "filePath": "src/app/core/types/utils.ts", - "type": "interface", - "linktype": "interface", - "name": "IError", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/core/types/utils.ts", - "type": "interface", - "linktype": "interface", - "name": "SelectOption", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/directives/popover.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "PopoverDirective", - "coveragePercent": 0, - "coverageCount": "0/21", - "status": "low" - }, - { - "filePath": "src/app/directives/popover.directive.ts", - "type": "interface", - "linktype": "interface", - "name": "PopoverInput", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/entry/bundle/bundle-list.component.ts", - "type": "component", - "linktype": "component", - "name": "BundleListComponent", - "coveragePercent": 0, - "coverageCount": "0/27", - "status": "low" - }, - { - "filePath": "src/app/entry/bundle/bundle-list.component.ts", - "type": "component", - "linktype": "component", - "name": "LicenseComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/entry/bundle/bundle-list.component.ts", - "type": "component", - "linktype": "component", - "name": "MainComponent", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/entry/cluster/cluster.component.ts", - "type": "component", - "linktype": "component", - "name": "ClusterListComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/entry/job/job-info.component.ts", - "type": "component", - "linktype": "component", - "name": "JobInfoComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/entry/job/job.component.ts", - "type": "component", - "linktype": "component", - "name": "MainComponent", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/entry/job/log/check.component.ts", - "type": "component", - "linktype": "component", - "name": "CheckComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/entry/job/log/log.component.ts", - "type": "component", - "linktype": "component", - "name": "LogComponent", - "coveragePercent": 0, - "coverageCount": "0/14", - "status": "low" - }, - { - "filePath": "src/app/entry/job/log/log.component.ts", - "type": "interface", - "linktype": "interface", - "name": "ITimeInfo", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/entry/job/log/text.component.ts", - "type": "component", - "linktype": "component", - "name": "TextComponent", - "coveragePercent": 0, - "coverageCount": "0/19", - "status": "low" - }, - { - "filePath": "src/app/entry/task/hover.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "HoverDirective", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/entry/task/tasks.component.ts", - "type": "component", - "linktype": "component", - "name": "TasksComponent", - "coveragePercent": 0, - "coverageCount": "0/22", - "status": "low" - }, - { - "filePath": "src/app/factories/details.factory.ts", - "type": "class", - "linktype": "classe", - "name": "DetailsFactory", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/factories/list.factory.ts", - "type": "class", - "linktype": "classe", - "name": "ListFactory", - "coveragePercent": 0, - "coverageCount": "0/15", - "status": "low" - }, - { - "filePath": "src/app/helpers/date-helper.ts", - "type": "class", - "linktype": "classe", - "name": "DateHelper", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/helpers/issue-helper.ts", - "type": "class", - "linktype": "classe", - "name": "IssueHelper", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/helpers/objects-helper.ts", - "type": "class", - "linktype": "classe", - "name": "ObjectsHelper", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/main/login/login.component.ts", - "type": "component", - "linktype": "component", - "name": "LoginComponent", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/main/profile/profile.component.ts", - "type": "component", - "linktype": "component", - "name": "ProfileComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/main/progress.component.ts", - "type": "component", - "linktype": "component", - "name": "ProgressComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/main/server-status.component.ts", - "type": "component", - "linktype": "component", - "name": "FatalErrorComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/main/server-status.component.ts", - "type": "component", - "linktype": "component", - "name": "GatewayTimeoutComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/main/server-status.component.ts", - "type": "component", - "linktype": "component", - "name": "PageNotFoundComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/main/server-status.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styleCSS", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/main/support/support.component.ts", - "type": "component", - "linktype": "component", - "name": "SupportComponent", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/main/top/top.component.ts", - "type": "component", - "linktype": "component", - "name": "TopComponent", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/models/action.ts", - "type": "interface", - "linktype": "interface", - "name": "IAction", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/models/action.ts", - "type": "interface", - "linktype": "interface", - "name": "IActionConfig", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/bundle.ts", - "type": "interface", - "linktype": "interface", - "name": "IBundle", - "coveragePercent": 0, - "coverageCount": "0/14", - "status": "low" - }, - { - "filePath": "src/app/models/cluster-service.ts", - "type": "interface", - "linktype": "interface", - "name": "IClusterService", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/models/cluster.ts", - "type": "interface", - "linktype": "interface", - "name": "ICluster", - "coveragePercent": 0, - "coverageCount": "0/15", - "status": "low" - }, - { - "filePath": "src/app/models/component.ts", - "type": "interface", - "linktype": "interface", - "name": "IComponent", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "ConcernReason", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholder", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholderActionRun", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholderCluster", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholderComponent", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholderComponentConfig", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholderHost", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholderHostProvider", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholderItem", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholderJob", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern-reason.ts", - "type": "interface", - "linktype": "interface", - "name": "IMPlaceholderService", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/concern/concern.ts", - "type": "interface", - "linktype": "interface", - "name": "Concern", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/models/details.ts", - "type": "interface", - "linktype": "interface", - "name": "IDetails", - "coveragePercent": 5, - "coverageCount": "1/20", - "status": "low" - }, - { - "filePath": "src/app/models/details.ts", - "type": "interface", - "linktype": "interface", - "name": "INavItem", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/models/details.ts", - "type": "interface", - "linktype": "interface", - "name": "IStyledNavItem", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/entity-names.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "EntityNames", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/models/entity.ts", - "type": "interface", - "linktype": "interface", - "name": "AdcmEntity", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/models/entity.ts", - "type": "interface", - "linktype": "interface", - "name": "AdcmTypedEntity", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/eventable-service.ts", - "type": "interface", - "linktype": "interface", - "name": "ConcernEventFilter", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/eventable-service.ts", - "type": "interface", - "linktype": "interface", - "name": "EventableService", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/eventable-service.ts", - "type": "interface", - "linktype": "interface", - "name": "EventFilter", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/host.ts", - "type": "interface", - "linktype": "interface", - "name": "IHost", - "coveragePercent": 0, - "coverageCount": "0/12", - "status": "low" - }, - { - "filePath": "src/app/models/issue.ts", - "type": "interface", - "linktype": "interface", - "name": "IIssues", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/models/issue.ts", - "type": "interface", - "linktype": "interface", - "name": "IssueEntity", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/list-result.ts", - "type": "interface", - "linktype": "interface", - "name": "ListResult", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/models/service-component.ts", - "type": "interface", - "linktype": "interface", - "name": "IServiceComponent", - "coveragePercent": 0, - "coverageCount": "0/17", - "status": "low" - }, - { - "filePath": "src/app/models/status-tree.ts", - "type": "interface", - "linktype": "interface", - "name": "ClusterStatusTree", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/status-tree.ts", - "type": "interface", - "linktype": "interface", - "name": "HostComponentStatusTree", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/status-tree.ts", - "type": "interface", - "linktype": "interface", - "name": "HostStatusTree", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/status-tree.ts", - "type": "interface", - "linktype": "interface", - "name": "ServiceStatusTree", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/status-tree.ts", - "type": "interface", - "linktype": "interface", - "name": "ServiceStatusTree", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/models/status-tree.ts", - "type": "interface", - "linktype": "interface", - "name": "StatusTree", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/models/status-tree.ts", - "type": "interface", - "linktype": "interface", - "name": "StatusTreeSubject", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/models/universal-adcm-event-data.ts", - "type": "interface", - "linktype": "interface", - "name": "UniversalAdcmEventData", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/pipes/bell-task-link.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "BellTaskLinkPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/entity-status-to-status-tree.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "EntityStatusToStatusTreePipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/is-array.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "IsArrayPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/issue-message-placeholder.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "IssueMessagePlaceholderPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/issue-path.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "IssuePathPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/keys.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "KeysPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/nav-item.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "NavItemPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/object-link-column.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "ObjectLinkColumnPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/pick-keys.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "PickKeysPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/sort-objects.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "SortObjectsPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/status-tree-link.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "StatusTreeLinkPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/to-data-source.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "ToDataSourcePipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/pipes/translate-object-keys.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "TranslateKeysPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/services/bundle.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "BundleService", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/services/cluster-entity.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ClusterEntityService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/services/concern.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ConcernService", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/services/host.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "HostService", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/services/job.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "JobService", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/services/provider.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ProviderService", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/services/service-component.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ServiceComponentService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/services/service.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ServiceService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/services/stats.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "StatsService", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/services/stats.service.ts", - "type": "interface", - "linktype": "interface", - "name": "Stats", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/services/task.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "TaskService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/add-button.component.ts", - "type": "component", - "linktype": "component", - "name": "AddButtonComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/add-cluster.component.ts", - "type": "component", - "linktype": "component", - "name": "AddClusterComponent", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/add-form.component.ts", - "type": "component", - "linktype": "component", - "name": "AddFormComponent", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/add-service-model.ts", - "type": "interface", - "linktype": "interface", - "name": "FormModel", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/add-service-model.ts", - "type": "interface", - "linktype": "interface", - "name": "IAddService", - "coveragePercent": 0, - "coverageCount": "0/12", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/add-service-model.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ADD_SERVICE_PROVIDER", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/add.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "AddService", - "coveragePercent": 0, - "coverageCount": "0/16", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/add.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "fromBundle", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/add.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "MODELS", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/base-form.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "BaseFormDirective", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/controls.component.ts", - "type": "component", - "linktype": "component", - "name": "ControlsComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/host.component.ts", - "type": "component", - "linktype": "component", - "name": "HostComponent", - "coveragePercent": 0, - "coverageCount": "0/25", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/host2cluster.component.ts", - "type": "component", - "linktype": "component", - "name": "Host2clusterComponent", - "coveragePercent": 0, - "coverageCount": "0/22", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/naming.ts", - "type": "class", - "linktype": "classe", - "name": "GenName", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/naming.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "adjectives", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/naming.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "rivers", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/provider.component.ts", - "type": "component", - "linktype": "component", - "name": "ProviderComponent", - "coveragePercent": 0, - "coverageCount": "0/13", - "status": "low" - }, - { - "filePath": "src/app/shared/add-component/service.component.ts", - "type": "component", - "linktype": "component", - "name": "ServiceComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/action-list/action-list.component.ts", - "type": "component", - "linktype": "component", - "name": "ActionListComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/action-list/menu-item/menu-item.component.ts", - "type": "component", - "linktype": "component", - "name": "MenuItemComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/actions.component.ts", - "type": "component", - "linktype": "component", - "name": "ActionsComponent", - "coveragePercent": 0, - "coverageCount": "0/19", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/actions.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "ActionsDirective", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/actions.directive.ts", - "type": "interface", - "linktype": "interface", - "name": "ActionParameters", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/actions.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ActionsService", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/master/action-master-config.component.ts", - "type": "component", - "linktype": "component", - "name": "ActionMasterConfigComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/master/master.component.ts", - "type": "component", - "linktype": "component", - "name": "ActionMasterComponent", - "coveragePercent": 0, - "coverageCount": "0/17", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/master/master.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "MasterService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/master/master.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IMasterData", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/components/actions/master/master.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IValue", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/components/button-spinner.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonSpinnerComponent", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/shared/components/crumbs.component.ts", - "type": "component", - "linktype": "component", - "name": "CrumbsComponent", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/components/dialog.component.ts", - "type": "component", - "linktype": "component", - "name": "DialogComponent", - "coveragePercent": 0, - "coverageCount": "0/14", - "status": "low" - }, - { - "filePath": "src/app/shared/components/dialog.component.ts", - "type": "interface", - "linktype": "interface", - "name": "DialogData", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/shared/components/import/import.component.ts", - "type": "component", - "linktype": "component", - "name": "ExportComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/components/import/import.component.ts", - "type": "component", - "linktype": "component", - "name": "ImportComponent", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/shared/components/import/import.component.ts", - "type": "interface", - "linktype": "interface", - "name": "IComposite", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/components/import/import.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "requiredObject", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/components/import/import.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "trueOnly", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/components/issue-info.component.ts", - "type": "component", - "linktype": "component", - "name": "IssueInfoComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/shared/components/issue-info.component.ts", - "type": "interface", - "linktype": "interface", - "name": "IIssueInfo", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/components/list/base-list.directive.ts", - "type": "class", - "linktype": "classe", - "name": "BaseListDirective", - "coveragePercent": 0, - "coverageCount": "0/29", - "status": "low" - }, - { - "filePath": "src/app/shared/components/list/base-list.directive.ts", - "type": "interface", - "linktype": "interface", - "name": "IRowHost", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/components/list/base-list.directive.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "TemporaryEntityNameConverter", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/components/list/list-service-token.ts", - "type": "interface", - "linktype": "interface", - "name": "IListService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/components/list/list-service-token.ts", - "type": "interface", - "linktype": "interface", - "name": "ListInstance", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/components/list/list-service-token.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "LIST_SERVICE_PROVIDER", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/components/list/list.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ListService", - "coveragePercent": 0, - "coverageCount": "0/12", - "status": "low" - }, - { - "filePath": "src/app/shared/components/list/list.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "COLUMNS_SET", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/components/list/multi-sort.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "MultiSortDirective", - "coveragePercent": 0, - "coverageCount": "0/14", - "status": "low" - }, - { - "filePath": "src/app/shared/components/main-info.component.ts", - "type": "component", - "linktype": "component", - "name": "MainInfoComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/components/status-info.component.ts", - "type": "component", - "linktype": "component", - "name": "StatusInfoComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/shared/components/status/status.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "StatusService", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/shared/components/status/status.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IAllStatus", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/components/status/status.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IStatus", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/components/tooltip/tooltip.component.ts", - "type": "component", - "linktype": "component", - "name": "SimpleTextComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/components/tooltip/tooltip.component.ts", - "type": "component", - "linktype": "component", - "name": "TooltipComponent", - "coveragePercent": 0, - "coverageCount": "0/19", - "status": "low" - }, - { - "filePath": "src/app/shared/components/tooltip/tooltip.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "kit", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/components/tooltip/tooltip.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "POSITION_MARGIN", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/components/tooltip/tooltip.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "TooltipDirective", - "coveragePercent": 8, - "coverageCount": "1/12", - "status": "low" - }, - { - "filePath": "src/app/shared/components/tooltip/tooltip.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ComponentData", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/components/tooltip/tooltip.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "TooltipService", - "coveragePercent": 11, - "coverageCount": "1/9", - "status": "low" - }, - { - "filePath": "src/app/shared/components/tooltip/tooltip.service.ts", - "type": "interface", - "linktype": "interface", - "name": "TooltipDisplayOptions", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/components/tooltip/tooltip.service.ts", - "type": "interface", - "linktype": "interface", - "name": "TooltipOptions", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/components/upgrade.component.ts", - "type": "component", - "linktype": "component", - "name": "UpgradeComponent", - "coveragePercent": 0, - "coverageCount": "0/15", - "status": "low" - }, - { - "filePath": "src/app/shared/components/upgrade.component.ts", - "type": "interface", - "linktype": "interface", - "name": "Upgrade", - "coveragePercent": 0, - "coverageCount": "0/17", - "status": "low" - }, - { - "filePath": "src/app/shared/components/upgrade.component.ts", - "type": "interface", - "linktype": "interface", - "name": "UpgradeItem", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attribute-provider.component.ts", - "type": "component", - "linktype": "component", - "name": "ConfigFieldAttributeProviderComponent", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attribute.service.ts", - "type": "class", - "linktype": "classe", - "name": "ConfigAttributeFactory", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attribute.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "AttributeService", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attribute.service.ts", - "type": "interface", - "linktype": "interface", - "name": "AttributeOptions", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attribute.service.ts", - "type": "interface", - "linktype": "interface", - "name": "AttributeWrapper", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attribute.service.ts", - "type": "interface", - "linktype": "interface", - "name": "ConfigAttributeOptions", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attribute.service.ts", - "type": "interface", - "linktype": "interface", - "name": "ConfigAttributesJSON", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attribute.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ATTRIBUTES_OPTIONS", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attribute.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "createFormForAttribute", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.ts", - "type": "component", - "linktype": "component", - "name": "GroupKeysWrapperComponent", - "coveragePercent": 0, - "coverageCount": "0/19", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/attributes/config-field.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "ConfigFieldMarker", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/configuration.module.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "material", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/field/field.component.ts", - "type": "component", - "linktype": "component", - "name": "FieldComponent", - "coveragePercent": 6, - "coverageCount": "1/16", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/field/field.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "CONFIG_FIELD", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/fields/fields.component.ts", - "type": "component", - "linktype": "component", - "name": "ConfigFieldsComponent", - "coveragePercent": 5, - "coverageCount": "1/17", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/group-fields/group-fields.component.ts", - "type": "component", - "linktype": "component", - "name": "GroupFieldsComponent", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/main/config.component.ts", - "type": "component", - "linktype": "component", - "name": "ConfigComponent", - "coveragePercent": 0, - "coverageCount": "0/34", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/main/main.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "MainService", - "coveragePercent": 0, - "coverageCount": "0/15", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/main/main.service.ts", - "type": "interface", - "linktype": "interface", - "name": "ISearchParam", - "coveragePercent": 33, - "coverageCount": "1/3", - "status": "medium" - }, - { - "filePath": "src/app/shared/configuration/main/main.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "historyAnime", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/scheme/item.component.ts", - "type": "component", - "linktype": "component", - "name": "ItemComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/scheme/root.component.ts", - "type": "component", - "linktype": "component", - "name": "RootComponent", - "coveragePercent": 0, - "coverageCount": "0/13", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/scheme/scheme.component.ts", - "type": "component", - "linktype": "component", - "name": "SchemeComponent", - "coveragePercent": 18, - "coverageCount": "2/11", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/scheme/scheme.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "SchemeService", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/scheme/scheme.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IControl", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/scheme/scheme.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IValue", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/config.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "ConfigService", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/config.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IConfigListResponse", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/config.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IConfigResponse", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/config.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IConfigService", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "FieldService", - "coveragePercent": 38, - "coverageCount": "5/13", - "status": "medium" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IOutput", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "interface", - "linktype": "interface", - "name": "ISource", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IToolsEvent", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "findAttrValue", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "fn", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "fo", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getControlType", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getField", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getKey", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getOptions", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getPanel", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getPattern", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getValidator", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getValue", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "handleTree", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "intPattern", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isActive", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isAdvancedField", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isHidden", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isVisibleField", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "patternFn", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/services/field.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "typeToControl", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "class", - "linktype": "classe", - "name": "Configuration", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "class", - "linktype": "classe", - "name": "FieldFactory", - "coveragePercent": 33, - "coverageCount": "1/3", - "status": "medium" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "class", - "linktype": "classe", - "name": "FieldStack", - "coveragePercent": 0, - "coverageCount": "0/14", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "class", - "linktype": "classe", - "name": "Limits", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "class", - "linktype": "classe", - "name": "UIOptions", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "class", - "linktype": "classe", - "name": "YContainer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "class", - "linktype": "classe", - "name": "YField", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "class", - "linktype": "classe", - "name": "Yspec", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "setValue", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "toField", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "toFormOptions", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tests/configuration.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "toPanel", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tools/color-option.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "ColorOptionDirective", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tools/history.component.ts", - "type": "component", - "linktype": "component", - "name": "HistoryComponent", - "coveragePercent": 0, - "coverageCount": "0/12", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tools/search.component.ts", - "type": "component", - "linktype": "component", - "name": "SearchComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/tools/tools.component.ts", - "type": "component", - "linktype": "component", - "name": "ToolsComponent", - "coveragePercent": 0, - "coverageCount": "0/18", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "CompareConfig", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "ICanGroup", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "ICompare", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IConfig", - "coveragePercent": 14, - "coverageCount": "1/7", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IConfigAttr", - "coveragePercent": 33, - "coverageCount": "1/3", - "status": "medium" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IFieldOptions", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IFieldStack", - "coveragePercent": 7, - "coverageCount": "1/13", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IFormOptions", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "ILimits", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IPanelOptions", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IUIoptions", - "coveragePercent": 25, - "coverageCount": "1/4", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IValidator", - "coveragePercent": 20, - "coverageCount": "1/5", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IVariantSet", - "coveragePercent": 20, - "coverageCount": "1/5", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/yspec/yspec.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "YspecService", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/yspec/yspec.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IStructure", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/yspec/yspec.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IYContainer", - "coveragePercent": 25, - "coverageCount": "1/4", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/yspec/yspec.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IYField", - "coveragePercent": 16, - "coverageCount": "1/6", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/yspec/yspec.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IYRoot", - "coveragePercent": 12, - "coverageCount": "1/8", - "status": "low" - }, - { - "filePath": "src/app/shared/configuration/yspec/yspec.service.ts", - "type": "interface", - "linktype": "interface", - "name": "IYspec", - "coveragePercent": 100, - "coverageCount": "1/1", - "status": "very-good" - }, - { - "filePath": "src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.component.ts", - "type": "component", - "linktype": "component", - "name": "ConcernMenuItemComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "ConcernMenuItemPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.ts", - "type": "component", - "linktype": "component", - "name": "LabelMenuItemComponent", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.ts", - "type": "component", - "linktype": "component", - "name": "LogMenuItemComponent", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/shared/details/left-menu-items/status-menu-item/status-menu-item.component.ts", - "type": "component", - "linktype": "component", - "name": "StatusMenuItemComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/shared/details/left-menu/left-menu.component.ts", - "type": "component", - "linktype": "component", - "name": "LeftMenuComponent", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/shared/details/left-menu/left-menu.component.ts", - "type": "interface", - "linktype": "interface", - "name": "LeftMenuItem", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/details/subtitle.component.ts", - "type": "component", - "linktype": "component", - "name": "SubtitleComponent", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/base.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "BaseDirective", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/base.directive.ts", - "type": "interface", - "linktype": "interface", - "name": "ISocketListener", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/dynamic.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "DynamicDirective", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/dynamic.directive.ts", - "type": "interface", - "linktype": "interface", - "name": "DynamicComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/dynamic.directive.ts", - "type": "interface", - "linktype": "interface", - "name": "DynamicEvent", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/for-test.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "ForTestDirective", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/hover.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "HoverDirective", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/infinity-scroll.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "InfinityScrollDirective", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/infinity-scroll.directive.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "POINT_WHEN_EMMIT", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/m-textarea.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "MTextareaDirective", - "coveragePercent": 0, - "coverageCount": "0/7", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/m-textarea.directive.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "PADDING_TOP_BOTTOM", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/scroll.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "ScrollDirective", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/socketListener.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "SocketListenerDirective", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/directives/socketListener.directive.ts", - "type": "injectable", - "linktype": "injectable", - "name": "SocketListenerDirective", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/boolean.component.ts", - "type": "component", - "linktype": "component", - "name": "BooleanComponent", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/boolean.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "options", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/bundles.component.ts", - "type": "component", - "linktype": "component", - "name": "BundlesComponent", - "coveragePercent": 0, - "coverageCount": "0/26", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/button-uploader.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonUploaderComponent", - "coveragePercent": 0, - "coverageCount": "0/8", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/confirm-equal-validator.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "ConfirmEqualValidatorDirective", - "coveragePercent": 0, - "coverageCount": "0/3", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/dropdown.component.ts", - "type": "component", - "linktype": "component", - "name": "DropdownComponent", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/error-info.component.ts", - "type": "component", - "linktype": "component", - "name": "ErrorInfoComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/field.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "FieldDirective", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/input.component.ts", - "type": "component", - "linktype": "component", - "name": "InputComponent", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/json.component.ts", - "type": "component", - "linktype": "component", - "name": "JsonComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/map.component.ts", - "type": "component", - "linktype": "component", - "name": "FieldListComponent", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/map.component.ts", - "type": "component", - "linktype": "component", - "name": "FieldMapComponent", - "coveragePercent": 0, - "coverageCount": "0/9", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/map.component.ts", - "type": "directive", - "linktype": "directive", - "name": "BaseMapListDirective", - "coveragePercent": 0, - "coverageCount": "0/10", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/password/password.component.ts", - "type": "component", - "linktype": "component", - "name": "PasswordComponent", - "coveragePercent": 0, - "coverageCount": "0/21", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/secret-text/secret-text.component.ts", - "type": "component", - "linktype": "component", - "name": "SecretTextComponent", - "coveragePercent": 0, - "coverageCount": "0/12", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/text-box.component.ts", - "type": "component", - "linktype": "component", - "name": "TextBoxComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/textarea.component.ts", - "type": "component", - "linktype": "component", - "name": "TextareaComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/form-elements/variant.component.ts", - "type": "component", - "linktype": "component", - "name": "VariantComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/dependencies.component.ts", - "type": "component", - "linktype": "component", - "name": "DependenciesComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/holder.directive.ts", - "type": "directive", - "linktype": "directive", - "name": "HolderDirective", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/much-2-many/much-2-many.component.ts", - "type": "component", - "linktype": "component", - "name": "Much2ManyComponent", - "coveragePercent": 0, - "coverageCount": "0/13", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/services2hosts/service-host.component.ts", - "type": "component", - "linktype": "component", - "name": "ServiceHostComponent", - "coveragePercent": 8, - "coverageCount": "3/35", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "injectable", - "linktype": "injectable", - "name": "TakeService", - "coveragePercent": 13, - "coverageCount": "2/15", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "accord", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "checkActions", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "checkConstraint", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "checkDependencies", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "checkRequires", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "disableHost", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "findDependencies", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "flag", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getSelected", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isExist", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isExpand", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/take.service.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "isShrink", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/test/index.ts", - "type": "class", - "linktype": "classe", - "name": "HCmComponent", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/test/index.ts", - "type": "class", - "linktype": "classe", - "name": "HcmHost", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/test/index.ts", - "type": "class", - "linktype": "classe", - "name": "HCmRequires", - "coveragePercent": 0, - "coverageCount": "0/6", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/test/index.ts", - "type": "class", - "linktype": "classe", - "name": "HostComponent", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/test/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ComponentFactory", - "coveragePercent": 100, - "coverageCount": "1/1", - "status": "very-good" - }, - { - "filePath": "src/app/shared/host-components-map/test/index.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "HCFactory", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/types.ts", - "type": "class", - "linktype": "classe", - "name": "CompTile", - "coveragePercent": 0, - "coverageCount": "0/16", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/types.ts", - "type": "class", - "linktype": "classe", - "name": "HostTile", - "coveragePercent": 0, - "coverageCount": "0/12", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/types.ts", - "type": "class", - "linktype": "classe", - "name": "StatePost", - "coveragePercent": 12, - "coverageCount": "1/8", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/types.ts", - "type": "class", - "linktype": "classe", - "name": "Tile", - "coveragePercent": 9, - "coverageCount": "1/11", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IRawHosComponent", - "coveragePercent": 0, - "coverageCount": "0/4", - "status": "low" - }, - { - "filePath": "src/app/shared/host-components-map/types.ts", - "type": "interface", - "linktype": "interface", - "name": "IStream", - "coveragePercent": 25, - "coverageCount": "1/4", - "status": "low" - }, - { - "filePath": "src/app/shared/pipes/break-row.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "BreakRowPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/pipes/tag-esc.pipe.ts", - "type": "pipe", - "linktype": "pipe", - "name": "TagEscPipe", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/translate/intializer.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "appInitializer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/shared/translate/intializer.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "translateLoader", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation-effects.ts", - "type": "injectable", - "linktype": "injectable", - "name": "NavigationEffects", - "coveragePercent": 0, - "coverageCount": "0/5", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "interface", - "linktype": "interface", - "name": "NavigationState", - "coveragePercent": 0, - "coverageCount": "0/2", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "getEventEntityType", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "getPath", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "function", - "linktype": "miscellaneous", - "linksubtype": "function", - "name": "navigationReducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getNavigationPath", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "getNavigationState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "initialState", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "reducer", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "setPath", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/store/navigation/navigation.store.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "setPathOfRoute", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/app/ws-logs/log.component.ts", - "type": "component", - "linktype": "component", - "name": "LogComponent", - "coveragePercent": 0, - "coverageCount": "0/14", - "status": "low" - }, - { - "filePath": "src/environments/environment.prod.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "environment", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/environments/environment.prod.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "p", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/environments/environment.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "environment", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/environments/environment.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "p", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/bell.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Bell", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/concern-list-popup.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ListOfMessagesPopup", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/concern-list-popup.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/concern-list.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ListOfMessages", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/concern-list.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/concern.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "OnlyMessage", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/concern.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/concern.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "VeryLongMessage", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/mock.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ISSUE_MESSAGES_DEFAULT_MOCK", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/mock.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ISSUE_MESSAGES_FIRST_MESSAGE", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/mock.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ISSUE_MESSAGES_LIST_MOCK", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/mock.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ISSUE_MESSAGES_SECOND_MESSAGE", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/mock.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ISSUE_MESSAGES_VERY_LONG_MESSAGE", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/concern/mock.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ISSUE_MESSAGES_VERY_LONG_MOCK", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/status-tree/status-tree.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "RegularTree", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/status-tree/status-tree.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/test.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "__karma__", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/test.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "context", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/test.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "require", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - } - ] - } -} \ No newline at end of file diff --git a/web/e2e/app.e2e-spec.ts b/web/e2e/app.e2e-spec.ts deleted file mode 100644 index 85e358ffc5..0000000000 --- a/web/e2e/app.e2e-spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed 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 { AppPage } from './app.po'; -import { LoginPage } from './login/login.po'; - -describe('ad App', () => { - let page: AppPage; - let login: LoginPage; - - beforeEach(() => { - page = new AppPage(); - login = new LoginPage(); - }); - - - it('should display login page', async () => { - await page.navigateTo(); - expect(login.getButton().isPresent()).toEqual('Login'); - }); -}); diff --git a/web/e2e/app.po.ts b/web/e2e/app.po.ts deleted file mode 100644 index def5d2601e..0000000000 --- a/web/e2e/app.po.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Licensed 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 { browser } from 'protractor'; - -export class AppPage { - navigateTo() { - return browser.get('/'); - } -} diff --git a/web/e2e/login/login.e2e-spec.ts b/web/e2e/login/login.e2e-spec.ts deleted file mode 100644 index 42b969b8e5..0000000000 --- a/web/e2e/login/login.e2e-spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed 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 { StartPage } from '../start/start.po'; -import { LoginPage } from './login.po'; - -describe('Login page', () => { - let page: LoginPage; - let startPage: StartPage; - - const wrongCredentials = { - username: 'fake', - password: 'fake', - }; - - beforeEach(() => { - page = new LoginPage(); - startPage = new StartPage(); - }); - - it('when user trying to login with wrong credentials', async () => { - page.navigateTo(); - await page.fillCredentials(wrongCredentials); - expect(page.getErrorMessage()).toEqual('Incorrect password or user.'); - }); - - it('when login is successful — he should redirect to default page', async () => { - page.navigateTo(); - await page.fillCredentials(); - expect(startPage.getPageTitleText()).toEqual('Hi there!'); - }); - -}); diff --git a/web/e2e/login/login.po.ts b/web/e2e/login/login.po.ts deleted file mode 100644 index 11197e5b95..0000000000 --- a/web/e2e/login/login.po.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed 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 { browser, by, element } from 'protractor'; - -export class LoginPage { - private credentials = { - username: 'admin', - password: 'admin', - }; - - navigateTo() { - return browser.get('/login'); - } - - fillCredentials(credentials: any = this.credentials) { - element(by.css('[placeholder="Login"]')).sendKeys(credentials.username); - element(by.css('[placeholder="Password"]')).sendKeys(credentials.password); - this.getButton().click(); - } - - getErrorMessage() { - return element(by.css('.warn')).getText(); - } - - getButton() { - return element(by.tagName('button')); - } -} diff --git a/web/e2e/start/start.e2e-spec.ts b/web/e2e/start/start.e2e-spec.ts deleted file mode 100644 index cd00156df7..0000000000 --- a/web/e2e/start/start.e2e-spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed 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 { StartPage } from './start.po'; -import { LoginPage } from '../login/login.po'; -import { browser } from 'protractor'; - -describe('Start page', () => { - let page: StartPage; - let login: LoginPage; - - beforeEach(() => { - page = new StartPage(); - login = new LoginPage(); - }); - - it('when user is authorize', () => { - login.navigateTo(); - login.fillCredentials(); - browser.sleep(1); - page.navigateTo(); - expect(page.getPageTitleText()).toEqual('Hi there!'); - }); -}); diff --git a/web/e2e/start/start.po.ts b/web/e2e/start/start.po.ts deleted file mode 100644 index 460f1ce951..0000000000 --- a/web/e2e/start/start.po.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed 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 { browser, element, by } from 'protractor'; - -export class StartPage { - navigateTo() { - return browser.get('/admin/intro'); - } - - getPageTitleText() { - return element(by.css('.mat-card-title')).getText(); - } -} diff --git a/web/e2e/tsconfig.e2e.json b/web/e2e/tsconfig.e2e.json deleted file mode 100644 index 8cc9c0dfc9..0000000000 --- a/web/e2e/tsconfig.e2e.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "compilerOptions": { - "outDir": "../out-tsc/e2e", - "baseUrl": "./", - "module": "commonjs", - "target": "es5", - "types": [ - "jasmine", - "jasminewd2", - "node" - ] - } -} diff --git a/web/export/src/uml/host.png b/web/export/src/uml/host.png deleted file mode 100644 index 2b6afee35e8e9ab4e9ce1ca613700660463d1fc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76270 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 diff --git a/web/karma.conf.js b/web/karma.conf.js deleted file mode 100644 index ed23987a8c..0000000000 --- a/web/karma.conf.js +++ /dev/null @@ -1,42 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), - require('@angular-devkit/build-angular/plugins/karma') - ], - client:{ - clearContext: false // leave Jasmine Spec Runner output visible in browser - }, - coverageIstanbulReporter: { - dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ], - fixWebpackSourcePaths: true, - thresholds: { - statements: 80, - lines: 80, - branches: 80, - functions: 80 - } - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['ChromeHeadlessNoSandbox'], - customLaunchers: { - ChromeHeadlessNoSandbox: { - base: 'ChromeHeadless', - flags: ['--no-sandbox'] - } - }, - singleRun: false - }); -}; diff --git a/web/ng_test.sh b/web/ng_test.sh deleted file mode 100755 index 65bf1333b6..0000000000 --- a/web/ng_test.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env sh -set -eu - -yarn config set registry https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ -export CHROME_BIN=/usr/bin/google-chrome -yarn install -yarn test -- --watch=false diff --git a/web/package.json b/web/package.json deleted file mode 100644 index 25db2e12d0..0000000000 --- a/web/package.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "name": "adcm", - "version": "0.0.1", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve --proxyConfig=proxy.conf.json", - "build": "ng build", - "test": "ng test", - "lint": "ng lint", - "e2e": "ng e2e", - "bundle-report": "ng build --prod --stats-json && webpack-bundle-analyzer ./dist/stats-es2015.json", - "docs:json": "compodoc -p ./tsconfig.base.json -e json -d .", - "storybook": "yarn run docs:json && start-storybook -p 6006", - "build-storybook": "yarn run docs:json && build-storybook" - }, - "private": true, - "dependencies": { - "@angular/animations": "^11.2.14", - "@angular/cdk": "^11.2.13", - "@angular/common": "^11.2.14", - "@angular/compiler": "^11.2.14", - "@angular/core": "^11.2.14", - "@angular/forms": "^11.2.14", - "@angular/material": "^11.2.13", - "@angular/platform-browser": "^11.2.14", - "@angular/platform-browser-dynamic": "^11.2.14", - "@angular/router": "^11.2.14", - "@ng-web-apis/common": "^1.12.1", - "@ngrx/effects": "^10.1.2", - "@ngrx/entity": "^10.1.2", - "@ngrx/router-store": "^10.1.2", - "@ngrx/store": "^10.1.2", - "@ngrx/store-devtools": "^10.1.2", - "@ngx-translate/core": "^13.0.0", - "@ngx-translate/http-loader": "^6.0.0", - "@storybook/preset-scss": "^1.0.3", - "@tinkoff/ng-polymorpheus": "^3.1.12", - "deepmerge": "^4.2.2", - "immutable": "^4.0.0", - "luxon": "^1.25.0", - "ngx-mat-select-search": "^3.3.3", - "rxjs": "^6.5.5", - "sass": "^1.32.8", - "tslib": "^2.0.0", - "zone.js": "~0.10.3" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~0.1102.14", - "@angular/cli": "^11.2.14", - "@angular/compiler-cli": "11.2.14", - "@angular/elements": "^12.1.2", - "@angular/language-service": "11.2.14", - "@babel/core": "^7.14.6", - "@compodoc/compodoc": "^1.1.14", - "@ngrx/schematics": "^10.0.0", - "@storybook/addon-actions": "^6.3.8", - "@storybook/addon-essentials": "^6.3.8", - "@storybook/addon-links": "^6.3.8", - "@storybook/angular": "^6.3.8", - "@types/jasmine": "~3.6.0", - "@types/jasminewd2": "~2.0.8", - "@types/luxon": "^1.25.0", - "@types/node": "^14.0.13", - "@webcomponents/custom-elements": "^1.4.3", - "babel-loader": "^8.2.2", - "codelyzer": "^6.0.0", - "css-loader": "^5.2.7", - "eslint": "^7.2.0", - "jasmine-core": "~3.6.0", - "jasmine-spec-reporter": "~5.0.0", - "karma": "~5.2.1", - "karma-chrome-launcher": "~3.1.0", - "karma-cli": "~2.0.0", - "karma-coverage-istanbul-reporter": "~3.0.2", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", - "ng-packagr": "^11.2.4", - "protractor": "~7.0.0", - "react-dom": "^17.0.2", - "sass-loader": "^10.0.1", - "style-loader": "^2.0.0", - "ts-node": "~9.0.0", - "tslint": "~6.1.0", - "typescript": "~4.0.2", - "webpack-bundle-analyzer": "^4.1.0" - } -} diff --git a/web/protractor.conf.js b/web/protractor.conf.js deleted file mode 100644 index 2d0fcd1973..0000000000 --- a/web/protractor.conf.js +++ /dev/null @@ -1,31 +0,0 @@ -// Protractor configuration file, see link for more information -// https://github.com/angular/protractor/blob/master/lib/config.ts - -const { SpecReporter } = require('jasmine-spec-reporter'); - -exports.config = { - allScriptsTimeout: 11000, - specs: [ - './e2e/**/*.e2e-spec.ts' - ], - capabilities: { - 'browserName': 'chrome' - }, - directConnect: true, - baseUrl: 'http://localhost:4400/', - framework: 'jasmine', - - SELENIUM_PROMISE_MANAGER: false, - - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 30000, - print: function() {} - }, - onPrepare() { - require('ts-node').register({ - project: 'e2e/tsconfig.e2e.json' - }); - jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); - } -}; diff --git a/web/proxy.conf.json b/web/proxy.conf.json deleted file mode 100644 index fe5995314e..0000000000 --- a/web/proxy.conf.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "/social/login/google-oauth2/": { - "target": "http://localhost:8000", - "secure": false - }, - - "/api/v1/*": { - "target": "http://localhost:8000", - "secure": false - }, - "/api/ui/*": { - "target": "http://localhost:8000", - "secure": false - }, - "/status/api/v1/*": { - "target": "http://localhost:8000", - "secure": false - }, - "http://localhost:8000/api/v1/*": { - "secure": false, - "changeOrigin": true - }, - "http://localhost:8000/status/api/v1/*": { - "secure": false, - "changeOrigin": true - } -} diff --git a/web/src/_mixins.scss b/web/src/_mixins.scss deleted file mode 100644 index 3fbecde136..0000000000 --- a/web/src/_mixins.scss +++ /dev/null @@ -1,5 +0,0 @@ -@mixin read-only-field { - background-color: #484848; - font-style: italic; - color: #a7a7a7; -} diff --git a/web/src/adcm-theme.scss b/web/src/adcm-theme.scss deleted file mode 100644 index 6ec7106c5e..0000000000 --- a/web/src/adcm-theme.scss +++ /dev/null @@ -1,143 +0,0 @@ -@import '~@angular/material/theming'; -@include mat-core(); - -$app-primary: mat-palette($mat-blue-grey, A400); -$app-secondary: mat-palette($mat-light-green, A500); -$app-accent: mat-palette($mat-green, A400); -$app-warn: mat-palette($mat-orange); -$app-theme: mat-dark-theme($app-primary, $app-accent, $app-warn); - -@include angular-material-theme($app-theme); - -a { - color: mat-color($mat-blue, 200); - text-decoration: none; - - &:hover { - color: mat-color($mat-blue, 300); - text-decoration: underline; - } -} - -.select-table-item { - background-color: mat-color($mat-blue-grey, 500)!important; - - & button:not(.mm-button).mat-icon-button.mat-primary { - color: mat-color($mat-green, A400); - } -} - -.primary { - color: mat-color($app-primary); - border-color: mat-color($app-primary); -} - -.secondary { - color: mat-color($app-secondary); - border-color: mat-color($app-secondary); -} - -.accent { - color: mat-color($mat-green, A400); -} - -.warn { - color: mat-color($mat-orange, 500); -} - -.running { - color: mat-color($mat-yellow, 500); -} - -.success { - color: mat-color($mat-green, A400); -} - -.failed { - color: mat-color($mat-red, A100); -} - -.created { - color: mat-color($mat-blue-grey, 200); -} - -.aborted { - color: mat-color($mat-deep-orange, 200); -} - -.mat-list-item.primary { - border: solid 1px mat-color($mat-blue-grey, A400); -} - -.mat-list-item.accent { - border: solid 1px mat-color($mat-green, A400); -} - -.mat-list-item.warn { - border: solid 1px mat-color($mat-orange, 500); -} - -.mat-list-item.mat-warn { - color: mat-color($mat-orange, 500)!important; -} - -//.mat-list-item.mat-accent { -// color: mat-color($mat-green, A400); -//} - -a.active .mat-list-item-content { - // font-weight: bold; - text-decoration: none; - color: mat-color($mat-green, A400); -} - -.mat-nav-list a:not(.top, .issue) { - color: mat-color($mat-blue-grey, 200) !important; - - &:hover { - color: mat-color($mat-blue-grey, 50) !important; - } -} - -.top-menu.mat-list-base .mat-list-item { - color: mat-color($mat-green, A400); - width: auto; - height: 40px; -} - -// BEGIN: Paginator - -@mixin paginator { - font-size: 14px; - margin: 0 6px; - color: #bbb; -} - -.page-button { - @include paginator; - cursor: pointer; -} - -.page-button:hover { - text-decoration: none; - color: #ccc; -} - -.page-button.current { - color: mat-color($mat-orange, 500); -} - -.page-additional { - @include paginator; -} - -// END: Paginator - -.choice-column { - max-width: 40px; -} - -.reset-column { - display: flex; - justify-content: flex-end; -} diff --git a/web/src/adcm2.scss b/web/src/adcm2.scss deleted file mode 100644 index f0d7134b04..0000000000 --- a/web/src/adcm2.scss +++ /dev/null @@ -1,40 +0,0 @@ -mat-header-cell.list-control, mat-cell.list-control { - flex-grow: 0; - flex-basis: 60px; - text-align: center; -} - -.width100 { - flex-grow: 0; - flex-basis: 100px; -} - -.width30pr { - flex-grow: 1; - flex-basis: 30%; - width: 100px -} - -.text-ellipsed { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* BEGIN: Material header arrow crutch */ -.mat-header-cell .mat-sort-header-container.mat-sort-header-sorted .mat-sort-header-arrow { - opacity: 1 !important; -} -/* END: Material header arrow crutch */ - -mat-cell { - padding: 0 2px; -} - -mat-header-cell { - padding: 0 2px; -} - -.expandedRow { - min-height: 0; -} diff --git a/web/src/app/abstract-directives/adwp-base-list.directive.ts b/web/src/app/abstract-directives/adwp-base-list.directive.ts deleted file mode 100644 index acc22c17bf..0000000000 --- a/web/src/app/abstract-directives/adwp-base-list.directive.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { BehaviorSubject } from 'rxjs'; -import { Paging } from '@app/adwp'; -import { Sort } from '@angular/material/sort'; -import { ParamMap } from '@angular/router'; -import { Store } from '@ngrx/store'; - -import { BaseListDirective } from '@app/shared/components/list/base-list.directive'; -import { TypeName } from '@app/core/types'; -import { ListDirective } from '@app/abstract-directives/list.directive'; -import { ListService } from '@app/shared/components/list/list.service'; -import { SocketState } from '@app/core/store'; - -export class AdwpBaseListDirective extends BaseListDirective { - - paging: BehaviorSubject; - sorting: BehaviorSubject = new BehaviorSubject(null); - - constructor( - protected parent: ListDirective, - protected service: ListService, - protected store: Store, - ) { - super(parent, service, store); - } - - checkType(typeName: string, referenceTypeName: TypeName): boolean { - if (referenceTypeName === 'servicecomponent') { - return typeName === 'component'; - } - - return (referenceTypeName ? referenceTypeName.split('2')[0] : referenceTypeName) === typeName; - } - - routeListener(limit: number, page: number, ordering: string, params: ParamMap) { - this.paging.next({ pageIndex: page + 1, pageSize: limit }); - if (ordering) { - const direction = ordering[0] === '-' ? 'desc' : 'asc'; - const active = ordering[0] === '-' ? ordering.substr(1) : ordering; - this.sorting.next({ direction, active }); - } - - this.listParams = params; - this.refresh(); - } - -} diff --git a/web/src/app/abstract-directives/adwp-list.directive.ts b/web/src/app/abstract-directives/adwp-list.directive.ts deleted file mode 100644 index 29b6c6d284..0000000000 --- a/web/src/app/abstract-directives/adwp-list.directive.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Directive, OnInit } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { IColumns, IListResult, Paging, RowEventData } from '@app/adwp'; -import { Sort } from '@angular/material/sort'; -import { PageEvent } from '@angular/material/paginator'; - -import { ListDirective } from './list.directive'; -import { AdwpBaseListDirective } from './adwp-base-list.directive'; -import { BaseEntity, Entities } from '@app/core/types'; - -@Directive({ - selector: '[appAdwpList]', -}) -export abstract class AdwpListDirective extends ListDirective implements OnInit { - - abstract listColumns: IColumns; - - data$: BehaviorSubject> = new BehaviorSubject(null); - - paging: BehaviorSubject = new BehaviorSubject(null); - sorting: BehaviorSubject = new BehaviorSubject(null); - - defaultSort: Sort = { active: 'id', direction: 'desc' }; - - reload(data: IListResult) { - this.data$.next(data as any); - } - - initBaseListDirective() { - this.baseListDirective = new AdwpBaseListDirective(this, this.service, this.store); - this.baseListDirective.typeName = this.type; - this.baseListDirective.reload = this.reload.bind(this); - (this.baseListDirective as AdwpBaseListDirective).paging = this.paging; - (this.baseListDirective as AdwpBaseListDirective).sorting = this.sorting; - this.baseListDirective.init(); - } - - ngOnInit() { - this.initBaseListDirective(); - } - - clickRow(data: RowEventData) { - this.clickCell(data.event, 'title', data.row); - } - - auxclickRow(data: RowEventData) { - this.clickCell(data.event, 'new-tab', data.row); - } - - changeCount(count: number) {} - - getPageIndex(): number { - return this.paging.value.pageIndex - 1; - } - - getPageSize(): number { - return this.paging.value.pageSize; - } - - onChangePaging(paging: Paging): void { - this.paging.next(paging); - - const pageEvent = new PageEvent(); - pageEvent.pageIndex = this.getPageIndex(); - pageEvent.length = this.data$.value.count; - pageEvent.pageSize = this.getPageSize(); - - this.pageHandler(pageEvent); - } - - onChangeSort(sort: Sort): void { - this.sorting.next(sort); - this.changeSorting(sort); - } - - getSort(): Sort { - return this.sorting.value; - } - - rewriteRow(row: BaseEntity) { - this.service.checkItem(row).subscribe((item) => Object.keys(row).map((a) => (row[a] = item[a]))); - } - - findRow(id: number): BaseEntity { - return this.data.data.find((item) => item.id === id); - } - -} diff --git a/web/src/app/abstract-directives/base-detail.abstract.directive.ts b/web/src/app/abstract-directives/base-detail.abstract.directive.ts deleted file mode 100644 index 111c193f3c..0000000000 --- a/web/src/app/abstract-directives/base-detail.abstract.directive.ts +++ /dev/null @@ -1,176 +0,0 @@ -// Licensed 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 { Directive, Injector, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute, convertToParamMap, ParamMap } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { Observable, Subscription } from 'rxjs'; -import { switchMap, tap } from 'rxjs/operators'; - -import { ChannelService, keyChannelStrim } from '../core/services'; -import { ClusterService, WorkerInstance } from '../core/services/cluster.service'; -import { EventMessage, getNavigationPath, setPathOfRoute, SocketState } from '../core/store'; -import { EmmitRow, Host, IAction, Job } from '../core/types'; -import { SocketListenerDirective } from '@app/shared/directives'; -import { IDetails } from '@app/models/details'; -import { AdcmEntity } from '../models/entity'; -import { IIssues } from '../models/issue'; -import { IssueHelper } from '../helpers/issue-helper'; -import { ICluster } from '../models/cluster'; - -@Directive({ - selector: '[appBaseDetailAbstract]', -}) -export abstract class BaseDetailAbstractDirective extends SocketListenerDirective implements OnInit, OnDestroy { - subscription$: Subscription; - upgradable = false; - actions: IAction[] = []; - status: number | string; - issue: IIssues; - current: IDetails; - currentName = ''; - - navigationPath: Observable = this.store.select(getNavigationPath).pipe(this.takeUntil()); - - constructor( - socket: Store, - protected route: ActivatedRoute, - protected service: ClusterService, - protected channel: ChannelService, - protected store: Store, - injector: Injector, - ) { - super(socket); - } - - get Current() { - return this.service.Current; - } - - initContext(param: ParamMap): Observable { - return this.service.getContext(param); - } - - ngOnInit(): void { - this.subscription$ = this.route.paramMap.pipe( - switchMap((param) => this.initContext(param)), - tap((w) => this.run(w)), - this.takeUntil(), - ).subscribe(); - - super.startListenSocket(); - } - - ngOnDestroy(): void { - this.service.clearWorker(); - } - - get isIssue() { - return IssueHelper.isIssue(this.issue); - } - - run(w: WorkerInstance) { - const { - id, - name, - typeName, - action, - actions, - issue, - status, - prototype_name, - prototype_display_name, - prototype_version, - bundle_id, - state, - } = w.current; - const { upgradable, upgrade, hostcomponent } = w.current as ICluster; - const { log_files, objects } = w.current as Job; - const { provider_id, provider_name } = w.current as Host; - - this.currentName = name; - this.actions = actions; - this.upgradable = upgradable; - this.status = status; - - const parent = w.current.typeName === 'cluster' ? null : w.cluster; - this.issue = issue; - - this.current = { - parent, - id, - name, - typeName, - actions, - action, - issue, - upgradable, - upgrade, - status, - state, - log_files, - objects, - prototype_name, - prototype_display_name, - prototype_version, - provider_id, - provider_name, - bundle_id, - hostcomponent, - }; - } - - scroll(stop: { direct: -1 | 1 | 0; screenTop: number }) { - this.channel.next(keyChannelStrim.scroll, stop); - } - - reset() { - if (this.subscription$) { - this.subscription$.unsubscribe(); - } - this.subscription$ = this.service.reset().pipe( - this.takeUntil(), - tap((a) => this.run(a)), - this.takeUntil(), - ).subscribe(); - } - - socketListener(m: EventMessage) { - if ((m.event === 'create' || m.event === 'delete') && m.object.type === 'bundle') { - this.reset(); - return; - } - - const type = m.object.type === 'component' ? 'servicecomponent' : m.object.type; - if (this.Current?.typeName === type && this.Current?.id === m.object.id) { - if (this.service.Current.typeName === 'job' && (m.event === 'change_job_status' || m.event === 'add_job_log')) { - this.reset(); - return; - } - - if (m.event === 'change_state' || m.event === 'upgrade') { - this.reset(); - return; - } - - if (m.event === 'change_status') this.status = +m.object.details.value; - } - - } - - refresh(event: EmmitRow): void { - const { row } = event; - - const params: ParamMap = convertToParamMap({ cluster: row.id }); - this.store.dispatch(setPathOfRoute({ params })); - - } -} diff --git a/web/src/app/abstract-directives/concern-list.directive.ts b/web/src/app/abstract-directives/concern-list.directive.ts deleted file mode 100644 index e83fc1f922..0000000000 --- a/web/src/app/abstract-directives/concern-list.directive.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Directive, OnInit } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material/dialog'; -import { Store } from '@ngrx/store'; - -import { AdwpListDirective } from './adwp-list.directive'; -import { ListService } from '../shared/components/list/list.service'; -import { SocketState } from '../core/store'; -import { ConcernService } from '../services/concern.service'; -import { ConcernEventType } from '../models/concern/concern-reason'; - -@Directive({ - selector: '[appConcernList]', -}) -export abstract class ConcernListDirective extends AdwpListDirective implements OnInit { - - abstract eventTypes: ConcernEventType[]; - - constructor( - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - protected concernService: ConcernService, - ) { - super(service, store, route, router, dialog); - } - - ngOnInit() { - super.ngOnInit(); - - this.concernService.events({ types: this.eventTypes }) - .pipe(this.takeUntil()) - .subscribe(resp => { - if (resp.event !== 'delete') { - const row = this.findRow(resp.object.id); - if (row) { - this.rewriteRow(row); - } - } - }); - } - -} diff --git a/web/src/app/abstract-directives/detail.abstract.directive.ts b/web/src/app/abstract-directives/detail.abstract.directive.ts deleted file mode 100644 index fa83ee8313..0000000000 --- a/web/src/app/abstract-directives/detail.abstract.directive.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { switchMap } from 'rxjs/operators'; -import { Directive, OnInit } from '@angular/core'; - -import { BaseDetailAbstractDirective } from './base-detail.abstract.directive'; -import { LeftMenuItem } from '@app/shared/details/left-menu/left-menu.component'; -import { AdcmEntity } from '@app/models/entity'; -import { EntityService } from '@app/abstract/entity-service'; - -@Directive({ - selector: '[appDetailAbstract]', -}) -export abstract class DetailAbstractDirective extends BaseDetailAbstractDirective implements OnInit { - - entity: EntityType; - - abstract leftMenu: LeftMenuItem[]; - protected abstract subjectService: EntityService; - abstract entityParam: string; - - entityReceived(entity: EntityType): void { - this.entity = entity; - } - - ngOnInit() { - super.ngOnInit(); - - this.updateEntity(); - } - - updateEntity() { - this.route.params.pipe( - switchMap((params) => this.subjectService.get(params[this.entityParam])), - this.takeUntil(), - ).subscribe((entity) => this.entityReceived(entity)); - } - -} diff --git a/web/src/app/abstract-directives/list.directive.ts b/web/src/app/abstract-directives/list.directive.ts deleted file mode 100644 index 9f7f30f4ac..0000000000 --- a/web/src/app/abstract-directives/list.directive.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { Directive, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { filter } from 'rxjs/operators'; -import { Store } from '@ngrx/store'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; -import { MatSort, Sort } from '@angular/material/sort'; -import { MatTableDataSource } from '@angular/material/table'; -import { MatDialog } from '@angular/material/dialog'; -import { BaseDirective, EventHelper } from '@app/adwp'; - -import { EmmitRow, TypeName } from '@app/core/types'; -import { BaseListDirective } from '@app/shared/components/list/base-list.directive'; -import { SocketState } from '@app/core/store'; -import { ListService } from '@app/shared/components/list/list.service'; -import { DialogComponent } from '@app/shared/components'; -import { StatusData } from '@app/components/columns/status-column/status-column.component'; -import { ICluster } from '@app/models/cluster'; -import { LIST_SERVICE_PROVIDER } from '@app/shared/components/list/list-service-token'; - -enum Direction { - '' = '', - 'asc' = '', - 'desc' = '-', -} - -@Directive({ - selector: '[appAbstractList]', -}) -export abstract class ListDirective extends BaseDirective implements OnInit, OnDestroy { - - @Input() type: TypeName; - - baseListDirective: BaseListDirective; - - current: any = {}; - - @Input() - columns: Array; - - @Output() - listItemEvt = new EventEmitter(); - - paginator: MatPaginator; - - sort: MatSort; - - data: MatTableDataSource = new MatTableDataSource([]); - - @Output() pageEvent = new EventEmitter(); - - addToSorting = false; - - @Input() - set dataSource(data: { results: any; count: number; previous: any }) { - if (data) { - const list = data.results; - const isListBlank = list.length === 0; - const hasPreviousPage = data.previous !== null; - this.data = new MatTableDataSource(list); - this.changeCount(data.count); - if (Array.isArray(list)) { - this.listItemEvt.emit({ cmd: 'onLoad', row: list[0] }); - } - - if (hasPreviousPage && isListBlank) { - const url = this.router.url; - const urlHasSubdomain = url.includes('admin'); - const path = this.route.snapshot.routeConfig.path; - - const urlParams = { - page: this.getPageIndex() < 1 ? '0' : String(this.getPageIndex() - 1), - limit: this.getPageSize(), - filter: this.baseListDirective.listParams.get('filter'), - ordering: this.getSortParam(this.getSort()), - } - - if (urlHasSubdomain && path) { - this.router.navigate(['./admin', path, urlParams]); - } else { - const { page } = urlParams; - this.updateLocalStorage('page', page); - history.back(); - } - } - } - } - - sortParam = ''; - - constructor( - @Inject(LIST_SERVICE_PROVIDER) protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - ) { - super(); - } - - changeCount(count: number): void { - this.paginator.length = count; - } - - clickCell($e: MouseEvent, cmd?: string, row?: any, item?: any): void { - EventHelper.stopPropagation($e); - this.current = row; - this.listItemEvt.emit({ cmd, row, item }); - } - - ngOnInit(): void { - this.baseListDirective = new BaseListDirective(this, this.service, this.store); - this.baseListDirective.typeName = this.type; - this.baseListDirective.init(); - } - - ngOnDestroy(): void { - this.baseListDirective.destroy(); - super.ngOnDestroy(); - } - - delete($event: MouseEvent, row: any): void { - EventHelper.stopPropagation($event); - this.dialog - .open(DialogComponent, { - data: { - title: `Deleting "${row.name || row.fqdn}"`, - text: 'Are you sure?', - controls: ['Yes', 'No'], - }, - }) - .beforeClosed() - .pipe(filter((yes) => yes)) - .subscribe(() => this.listItemEvt.emit({ cmd: 'delete', row })); - } - - maintenanceModeToggle($event: MouseEvent, row: any): void { - this.listItemEvt.emit({ cmd: 'maintenanceModeToggle', row} ) - } - - getPageIndex(): number { - return this.paginator.pageIndex; - } - - getPageSize(): number { - return this.paginator.pageSize; - } - - changeSorting(sort: Sort): void { - const _filter = this.route.snapshot.paramMap.get('filter') || ''; - const pageIndex = this.getPageIndex(); - const pageSize = this.getPageSize(); - const ordering = this.getSortParam(sort); - this.updateLocalStorage('ordering', ordering); - - this.router.navigate( - [ - './', - { - page: pageIndex, - limit: pageSize, - filter: _filter, - ordering, - }, - ], - { relativeTo: this.route } - ); - - this.sortParam = ordering; - } - - getSortParam(a: Sort): string { - const params: { [key: string]: string[] } = { - prototype_version: ['prototype_display_name', 'prototype_version'], - }; - - if (a) { - const dumb = params[a.active] ? params[a.active] : [a.active], - active = dumb.map((b: string) => `${Direction[a.direction]}${b}`).join(','); - - const current = this.sortParam; - if (current && this.addToSorting) { - const result = current - .split(',') - .filter((b) => dumb.every((d) => d !== b.replace('-', ''))) - .join(','); - return [result, a.direction ? active : ''].filter((e) => e).join(','); - } - - return a.direction ? active : ''; - } else { - return ''; - } - } - - getSort(): Sort { - return this.sort; - } - - pageHandler(pageEvent: PageEvent): void { - this.pageEvent.emit(pageEvent); - - const f = this.route.snapshot.paramMap.get('filter') || ''; - const ordering = this.getSortParam(this.getSort()); - const ls = localStorage.getItem('list:param'); - let listParam = ls ? JSON.parse(ls) : null; - - listParam = { - ...listParam, - [this.type]: { - ...listParam?.[this.type], - limit: String(pageEvent.pageSize), - page: String(pageEvent.pageIndex), - filter: f, ordering - } - } - localStorage.setItem('list:param', JSON.stringify(listParam)); - localStorage.setItem('limit', String(pageEvent.pageSize)); - - this.router.navigate(['./', listParam?.[this.type]], { - relativeTo: this.route, - }); - } - - gotoStatus(data: StatusData): void { - this.clickCell(data.event, data.action, data.row); - } - - updateLocalStorage(key: string, value: string) { - const ls = localStorage.getItem('list:param'); - let listParam = ls ? JSON.parse(ls) : null; - - listParam = { - ...listParam, - [this.type]: { - ...listParam?.[this.type], - [key]: value - } - } - - localStorage.setItem('list:param', JSON.stringify(listParam)); - } -} diff --git a/web/src/app/abstract-directives/menu-item.abstract.directive.ts b/web/src/app/abstract-directives/menu-item.abstract.directive.ts deleted file mode 100644 index 9795bad6a1..0000000000 --- a/web/src/app/abstract-directives/menu-item.abstract.directive.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Directive, Input } from '@angular/core'; -import { BaseDirective } from '@app/adwp'; -import { AdcmEntity } from '../models/entity'; - -@Directive({ - selector: '[appMenuItemAbstract]', -}) -export abstract class MenuItemAbstractDirective extends BaseDirective { - - protected _entity: EntityType; - - @Input() label: string; - @Input() link: string; - @Input() get entity(): EntityType { - return this._entity; - } - set entity(value: EntityType) { - this._entity = value; - } - @Input() data: any; - -} diff --git a/web/src/app/abstract-directives/popover-content.directive.ts b/web/src/app/abstract-directives/popover-content.directive.ts deleted file mode 100644 index 090812a3a8..0000000000 --- a/web/src/app/abstract-directives/popover-content.directive.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Directive } from '@angular/core'; -import { BaseDirective } from '@app/adwp'; - -import { PopoverInput } from '../directives/popover.directive'; - -export type PopoverEventFunc = (event: any) => void; - -@Directive({ - selector: '[appAbstractPopoverContent]', -}) -export abstract class PopoverContentDirective extends BaseDirective { - - abstract data: PopoverInput; - - event?: PopoverEventFunc; - -} diff --git a/web/src/app/abstract-directives/rbac-entity-list.directive.ts b/web/src/app/abstract-directives/rbac-entity-list.directive.ts deleted file mode 100644 index 4f2d78f9d5..0000000000 --- a/web/src/app/abstract-directives/rbac-entity-list.directive.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Directive } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { MatDialog } from '@angular/material/dialog'; -import { MatCheckboxChange } from '@angular/material/checkbox'; -import { Entity, IListResult, RowEventData, IChoiceColumn } from '@app/adwp'; -import * as Immutable from 'immutable'; -import { filter } from 'rxjs/operators'; -import { zip } from 'rxjs'; - -import { ListService } from '@app/shared/components/list/list.service'; -import { SocketState } from '@app/core/store'; -import { DialogComponent } from '@app/shared/components'; -import { AdwpListDirective } from './adwp-list.directive'; -import { AddButtonComponent, AddButtonDialogConfig } from '../shared/add-component'; -import { EntityAbstractService } from '../abstract/entity.abstract.service'; - -const ADCM_RBAC_ADD_DIALOG_CONFIG: AddButtonDialogConfig = { - width: '75%', - maxWidth: '1000px' -}; - -@Directive({ - selector: '[appRbacEntityList]', -}) -export abstract class RbacEntityListDirective extends AdwpListDirective { - - abstract getTitle(row: T): string; - - abstract addButton: AddButtonComponent; - - dialogConfig: AddButtonDialogConfig = ADCM_RBAC_ADD_DIALOG_CONFIG; - - constructor( - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - protected entityService: EntityAbstractService, - ) { - super(service, store, route, router, dialog); - } - - chooseAll(event: MatCheckboxChange): void { - const { disabled = (row: any) => false } = (this.listColumns.find(({ type }) => type === 'choice') || {}) as IChoiceColumn; - const value: IListResult = Immutable.fromJS(this.data$.value).toJS() as any; - value.results.forEach((row: any) => { - if (!disabled(row)) { - row.checked = event.checked - } - }); - this.data$.next(value); - } - - deleteEntities(): void { - const checkedItems = this.data$.value.results.filter((item: any) => item.checked); - this.dialog - .open(DialogComponent, { - data: { - title: checkedItems.length > 1 ? 'Deleting selected entries' : `Deleting "${this.getTitle(checkedItems[0])}"`, - text: 'Are you sure?', - controls: ['Yes', 'No'], - }, - }) - .beforeClosed() - .pipe(filter((yes) => yes)) - .subscribe(() => { - const rowsToDelete = this.data$.value.results.filter((row: any) => row.checked).map(row => this.entityService.delete(row.id)); - zip(...rowsToDelete).subscribe(() => this.baseListDirective.refresh()); - }); - } - - clickRow(data: RowEventData): void { - this.showForm(data); - } - - showForm(data: RowEventData): void { - const { url } = data.row; - if (url) { - this.entityService.getByUrl(data.row.url) - .pipe(this.takeUntil()) - .subscribe((entity) => { - this.addButton.showForm(this.entityService.model(entity)); - }); - } - } - -} diff --git a/web/src/app/abstract-directives/rbac-options.directive.ts b/web/src/app/abstract-directives/rbac-options.directive.ts deleted file mode 100644 index a05b420e93..0000000000 --- a/web/src/app/abstract-directives/rbac-options.directive.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Directive, OnChanges, SimpleChange, SimpleChanges } from '@angular/core'; -import { Params } from '@angular/router'; -import { BehaviorSubject, merge, Observable } from 'rxjs'; -import { RbacRoleModel } from '../models/rbac/rbac-role.model'; -import { debounceTime, filter, first, skip, switchMap } from 'rxjs/operators'; -import { EntityAbstractService } from '../abstract/entity.abstract.service'; -import { clearEmptyField } from '../core/types'; - -const RBAC_ROLES_FILTERS_DEBOUNCE_TIME = 300; - -@Directive() -export class RbacOptionsDirective implements OnChanges { - private _params$: BehaviorSubject; - - options$: Observable; - - initialParams: Params = {}; - - params: Params; - - constructor(service: EntityAbstractService) { - this._params$ = new BehaviorSubject(this.initialParams); - const paramsWithOrdering$ = this._params$.asObservable().pipe( - // the ordering is s required param for options requests - filter((params) => params['ordering']) - ); - - const initial$ = paramsWithOrdering$.pipe(first()); - - const debounced$ = paramsWithOrdering$.pipe( - skip(1), - debounceTime(RBAC_ROLES_FILTERS_DEBOUNCE_TIME) - ); - - this.options$ = merge(initial$, debounced$).pipe( - switchMap((params) => service.getList(params)), - filter((v) => !!v) - ); - } - - ngOnChanges(changes: SimpleChanges): void { - this.handleParamsChanges(changes['params']); - } - - private handleParamsChanges(params: SimpleChange): void { - if (params && params.currentValue) { - this._params$.next({ - ...this.initialParams, - ...clearEmptyField(params.currentValue) - }); - } - } -} diff --git a/web/src/app/abstract-directives/status.abstract.directive.ts b/web/src/app/abstract-directives/status.abstract.directive.ts deleted file mode 100644 index b26832338b..0000000000 --- a/web/src/app/abstract-directives/status.abstract.directive.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Directive, OnInit, ViewChild } from '@angular/core'; -import { BaseDirective } from '@app/adwp'; -import { BehaviorSubject } from 'rxjs'; -import { Store } from '@ngrx/store'; -import { ActivatedRoute, Params } from '@angular/router'; -import { filter, switchMap, tap } from 'rxjs/operators'; - -import { StatusTreeSubject } from '../models/status-tree'; -import { Folding } from '../components/status-tree/status-tree.component'; -import { EventMessage, selectMessage, SocketState } from '../core/store'; -import { HavingStatusTreeAbstractService } from '../abstract/having-status-tree.abstract.service'; -import { AdcmEntity } from '@app/models/entity'; - -@Directive({ - selector: '[appStatusAbstract]', -}) -export abstract class StatusAbstractDirective extends BaseDirective implements OnInit { - - @ViewChild('tree', { static: false }) tree: any; - - loading = false; - - entity: EntityType; - entityId: number; - statusTree = new BehaviorSubject(null); - - folding: Folding; - - abstract getEntityIdFromParams(params: Params): number; - - constructor( - protected route: ActivatedRoute, - protected store: Store, - public entityService: HavingStatusTreeAbstractService, - ) { - super(); - } - - eventReceived(event: EventMessage): void {} - - prepareListeners() { - return this.store.pipe( - selectMessage, - this.takeUntil(), - filter(event => event.event === 'change_status'), - ).subscribe((event: EventMessage) => this.eventReceived(event)); - } - - prepareStatusTree(input: StatusTreeType): StatusTreeType { - return input; - } - - pipeData(): any {} - - ngOnInit(): void { - this.route.params.pipe( - this.takeUntil(), - tap(() => this.loading = true), - tap(() => this.folding = Folding.Expanded), - tap((params) => this.entityId = this.getEntityIdFromParams(params)), - switchMap(() => this.entityService.get(this.entityId)), - tap(entity => this.entity = entity), - switchMap(() => this.entityService.getStatusTree(this.entityId)), - ).subscribe((resp) => { - this.loading = false; - this.statusTree.next(this.prepareStatusTree(resp)); - this.prepareListeners(); - }); - } - - expandCollapseAll() { - if (this.tree.hasCollapsed()) { - this.tree.expandAll(); - } else { - this.tree.collapseAll(); - } - } - -} diff --git a/web/src/app/abstract/deletable-entity.abstract.service.ts b/web/src/app/abstract/deletable-entity.abstract.service.ts deleted file mode 100644 index 035e82bd51..0000000000 --- a/web/src/app/abstract/deletable-entity.abstract.service.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Observable } from 'rxjs'; - -export abstract class DeletableEntityAbstractService { - - abstract delete(id: number): Observable; - -} diff --git a/web/src/app/abstract/entity-service.ts b/web/src/app/abstract/entity-service.ts deleted file mode 100644 index 05677b2889..0000000000 --- a/web/src/app/abstract/entity-service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Observable } from 'rxjs'; - -import { ApiService } from '@app/core/api'; - -export abstract class EntityService { - - constructor( - protected api: ApiService, - ) { - } - - abstract get(id: number, params?: { [key: string]: string }): Observable; - -} diff --git a/web/src/app/abstract/entity.abstract.service.ts b/web/src/app/abstract/entity.abstract.service.ts deleted file mode 100644 index 5c0df81cb7..0000000000 --- a/web/src/app/abstract/entity.abstract.service.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Observable } from 'rxjs'; -import { Params } from '@angular/router'; -import { FormModel } from '@app/shared/add-component/add-service-model'; - -export abstract class EntityAbstractService { - abstract model?(value?: any): FormModel; - - abstract delete?(id: number): Observable; - - abstract add?(param: any): Observable; - - abstract get?(id: number): Observable; - - abstract getByUrl?(url: string): Observable; - - abstract update?(url: string, params?: Partial): Observable; - - abstract getList?(param?: Params): Observable; -} diff --git a/web/src/app/abstract/having-status-tree.abstract.service.ts b/web/src/app/abstract/having-status-tree.abstract.service.ts deleted file mode 100644 index 63ec64c36f..0000000000 --- a/web/src/app/abstract/having-status-tree.abstract.service.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Observable } from 'rxjs'; - -import { StatusTree, StatusTreeSubject } from '../models/status-tree'; -import { EntityService } from '@app/abstract/entity-service'; -import { AdcmEntity } from '@app/models/entity'; - -export abstract class HavingStatusTreeAbstractService extends EntityService { - - abstract getStatusTree(id: number): Observable; - abstract entityStatusTreeToStatusTree(input: StatusTreeType, ...args): StatusTree[]; - -} diff --git a/web/src/app/admin/admin.module.ts b/web/src/app/admin/admin.module.ts deleted file mode 100644 index a0c8054e32..0000000000 --- a/web/src/app/admin/admin.module.ts +++ /dev/null @@ -1,124 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { AuthGuard } from '@app/core/auth/auth.guard'; -import { IntroComponent } from './intro.component'; -import { PatternComponent } from './pattern.component'; -import { SettingsComponent } from './settings.component'; -import { UsersComponent } from './users/users.component'; -import { RbacGroupFormModule } from '../components/rbac/group-form/rbac-group-form.module'; -import { RbacUserFormModule } from '../components/rbac/user-form/rbac-user-form.module'; -import { RbacRoleFormModule } from '../components/rbac/role-form/rbac-role-form.module'; -import { GroupsComponent } from './groups/groups.component'; -import { RolesComponent } from './roles/roles.component'; -import { PoliciesComponent } from './policies/policies.component'; -import { AuditOperationsComponent } from './audit-operations/audit-operations.component'; -import { AdwpListModule } from '@app/adwp'; -import { MatToolbarModule } from '@angular/material/toolbar'; -import { MatSidenavModule } from '@angular/material/sidenav'; -import { MatListModule } from '@angular/material/list'; -import { MatCardModule } from '@angular/material/card'; -import { StuffModule } from '../shared/stuff.module'; -import { AddingModule } from '../shared/add-component/adding.module'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { RbacPolicyFormModule } from '../components/rbac/policy-form/rbac-policy-form.module'; -import { ConfigurationModule } from '../shared/configuration/configuration.module'; -import { - RbacAuditOperationsHistoryFormComponent -} from "../components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component"; -import { AuditLoginComponent } from './audit-login/audit-login.component'; - -const routes: Routes = [ - { - path: '', - component: PatternComponent, - canActivate: [AuthGuard], - canActivateChild: [AuthGuard], - children: [ - { - path: '', - redirectTo: 'intro', - pathMatch: 'full', - }, - { - path: 'intro', - component: IntroComponent, - }, - { - path: 'settings', - component: SettingsComponent, - }, - { - path: 'users', - component: UsersComponent, - }, - { - path: 'groups', - component: GroupsComponent, - }, - { - path: 'roles', - component: RolesComponent, - }, - { - path: 'policies', - component: PoliciesComponent, - }, - { - path: 'audit/operations', - component: AuditOperationsComponent, - }, - { - path: 'audit/logins', - component: AuditLoginComponent, - } - ], - }, -]; - -@NgModule({ - imports: [ - CommonModule, - RouterModule.forChild(routes), - AdwpListModule, - RbacGroupFormModule, - RbacRoleFormModule, - RbacUserFormModule, - RbacPolicyFormModule, - MatToolbarModule, - MatSidenavModule, - MatListModule, - MatCardModule, - StuffModule, - AddingModule, - MatButtonModule, - MatIconModule, - ConfigurationModule - ], - declarations: [ - IntroComponent, - SettingsComponent, - UsersComponent, - PatternComponent, - GroupsComponent, - RolesComponent, - PoliciesComponent, - AuditOperationsComponent, - RbacAuditOperationsHistoryFormComponent, - AuditLoginComponent - ], -}) -export class AdminModule { -} diff --git a/web/src/app/admin/audit-login/audit-login.component.html b/web/src/app/admin/audit-login/audit-login.component.html deleted file mode 100644 index cfc02daf12..0000000000 --- a/web/src/app/admin/audit-login/audit-login.component.html +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/web/src/app/admin/audit-login/audit-login.component.scss b/web/src/app/admin/audit-login/audit-login.component.scss deleted file mode 100644 index 3490a52051..0000000000 --- a/web/src/app/admin/audit-login/audit-login.component.scss +++ /dev/null @@ -1,10 +0,0 @@ -:host { - flex: 1; - width: 100%; -} - -.controls { - position: absolute; - right: 40px; - top: 16px; -} diff --git a/web/src/app/admin/audit-login/audit-login.component.ts b/web/src/app/admin/audit-login/audit-login.component.ts deleted file mode 100644 index d39e6ccd55..0000000000 --- a/web/src/app/admin/audit-login/audit-login.component.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { Component, ComponentRef, ViewChild } from '@angular/core'; -import { ADD_SERVICE_PROVIDER } from "../../shared/add-component/add-service-model"; -import { IColumns } from "@app/adwp"; -import { TypeName } from "../../core/types"; -import { ListService } from "../../shared/components/list/list.service"; -import { Store } from "@ngrx/store"; -import { SocketState } from "../../core/store"; -import { ActivatedRoute, Router } from "@angular/router"; -import { MatDialog } from "@angular/material/dialog"; -import { RbacEntityListDirective } from "../../abstract-directives/rbac-entity-list.directive"; -import { RbacAuditLoginModel } from "../../models/rbac/rbac-audit-login.model"; -import { AddButtonComponent } from "../../shared/add-component"; -import { RbacAuditLoginService } from "../../services/rbac-audit-login.service"; -import { BehaviorSubject } from "rxjs"; -import { IFilter } from "../../shared/configuration/tools/filter/filter.component"; -import { DateHelper } from "../../helpers/date-helper"; -import { WrapperColumnComponent } from "../../components/columns/wrapper-column/wrapper-column.component"; - -@Component({ - selector: 'app-audit-login', - templateUrl: './audit-login.component.html', - styleUrls: ['./audit-login.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: RbacAuditLoginService } - ], -}) -export class AuditLoginComponent extends RbacEntityListDirective { - @ViewChild(AddButtonComponent) addButton: AddButtonComponent; - - listColumns = [ - { - label: 'Login', - type: 'component', - headerClassName: 'width30pr', - className: 'width30pr', - component: WrapperColumnComponent, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance.type = ['text-substr']; - componentRef.instance.customColumnName = 'login_details/username' - }, - }, - { - label: 'Result', - type: 'component', - headerClassName: 'width30pr', - className: 'width30pr', - component: WrapperColumnComponent, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance.type = ['color']; - componentRef.instance.customColumnName = 'login_result'; - } - }, - { - label: 'Login time', - sort: 'login_time', - className: 'width30pr action_date', - headerClassName: 'width30pr action_date', - value: (row) => DateHelper.short(row.login_time), - } - ] as IColumns; - - type: TypeName = 'audit_login'; - filterParams$: BehaviorSubject = new BehaviorSubject({}); - - auditLoginFilters: IFilter[] = [ - { - id: 1, name: 'login', display_name: 'Login', filter_field: 'username', filter_type: 'input', - }, - { - id: 2, name: 'login_result', display_name: 'Result', filter_field: 'login_result', filter_type: 'list', - options: [ - {id: 1, name: 'account disabled', display_name: 'Account disabled', value: 'account disabled'}, - {id: 2, name: 'success', display_name: 'Success', value: 'success'}, - {id: 3, name: 'user not found', display_name: 'User not found', value: 'user not found'}, - {id: 4, name: 'wrong password', display_name: 'Wrong password', value: 'wrong password'}, - ] - }, - { - id: 3, name: 'login_time', display_name: 'Login time', filter_field: 'login_time', filter_type: 'datepicker', - }, - ]; - - constructor( - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - protected entityService: RbacAuditLoginService, - ) { - super(service, store, route, router, dialog, entityService); - } - - ngOnInit() { - super.ngOnInit(); - - this.filterParams$.subscribe((params) => { - const filter_params = this.baseListDirective.listParams; - - if (filter_params) { - filter_params['params'] = { ...params }; - this.router.navigate(['./', filter_params['params']], { - relativeTo: this.route, - replaceUrl: true, - }); - } - }) - } - - getTitle(row: RbacAuditLoginModel): string { - return row.login_details.username; - } - -} diff --git a/web/src/app/admin/audit-operations/audit-operations.component.html b/web/src/app/admin/audit-operations/audit-operations.component.html deleted file mode 100644 index 0fcf3ad2bb..0000000000 --- a/web/src/app/admin/audit-operations/audit-operations.component.html +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/web/src/app/admin/audit-operations/audit-operations.component.scss b/web/src/app/admin/audit-operations/audit-operations.component.scss deleted file mode 100644 index a8ab930fdd..0000000000 --- a/web/src/app/admin/audit-operations/audit-operations.component.scss +++ /dev/null @@ -1,62 +0,0 @@ -:host { - flex: 1; - width: 100%; - - ::ng-deep { - .object_name, - .operation_name, - .action_date, - .username, - .username_header, - .table-end { - flex-grow: 0; - } - - .object_type { - min-width: 80px; - } - - .object_name { - flex-basis: 200px; - width: 200px; - min-width: 50px; - } - - .operation_name { - flex-basis: 320px; - width: 320px; - min-width: 110px; - } - - .operation_type, - .operation_result { - flex-basis: 100px; - width: 100px; - min-width: 70px; - } - - .action_date { - flex-basis: 205px; - width: 205px; - min-width: 205px; - margin-left: 10px; - } - - .username { - width: 75px; - flex-basis: 75px; - min-width: 75px; - } - - .table-end { - width: 50px; - flex-basis: 50px; - } - } -} - -.controls { - position: absolute; - right: 40px; - top: 16px; -} diff --git a/web/src/app/admin/audit-operations/audit-operations.component.ts b/web/src/app/admin/audit-operations/audit-operations.component.ts deleted file mode 100644 index a0c099db2e..0000000000 --- a/web/src/app/admin/audit-operations/audit-operations.component.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { Component, ComponentRef, Type, ViewChild } from '@angular/core'; -import { ADD_SERVICE_PROVIDER } from "../../shared/add-component/add-service-model"; -import { IColumns } from "@app/adwp"; -import { TypeName } from "../../core/types"; -import { ListService } from "../../shared/components/list/list.service"; -import { Store } from "@ngrx/store"; -import { SocketState } from "../../core/store"; -import { ActivatedRoute, Router } from "@angular/router"; -import { MatDialog } from "@angular/material/dialog"; -import { RbacEntityListDirective } from "../../abstract-directives/rbac-entity-list.directive"; -import { RbacAuditOperationsModel } from "../../models/rbac/rbac-audit-operations.model"; -import { AddButtonComponent } from "../../shared/add-component"; -import { RbacAuditOperationsService } from "../../services/rbac-audit-operations.service"; -import { - RbacAuditOperationsHistoryFormComponent -} from "../../components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component"; -import { BehaviorSubject } from "rxjs"; -import { IFilter } from "../../shared/configuration/tools/filter/filter.component"; -import { HistoryColumnComponent } from "../../components/columns/history-column/history-column.component"; -import { DateHelper } from "../../helpers/date-helper"; -import { WrapperColumnComponent } from "../../components/columns/wrapper-column/wrapper-column.component"; - -@Component({ - selector: 'app-audit-operations', - templateUrl: './audit-operations.component.html', - styleUrls: ['./audit-operations.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: RbacAuditOperationsService } - ], -}) -export class AuditOperationsComponent extends RbacEntityListDirective { - @ViewChild(AddButtonComponent) addButton: AddButtonComponent; - - listColumns = [ - { - label: 'Object type', - headerClassName: 'object_type', - className: 'object_type', - value: (row) => row.object_type, - }, - { - label: 'Object name', - type: 'component', - headerClassName: 'object_name', - className: 'object_name object_name_content', - value: (row) => row.object_name, - component: WrapperColumnComponent, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance.type = ['text-substr']; - } - }, - { - label: 'Operation name', - headerClassName: 'operation_name', - className: 'operation_name', - value: (row) => row.operation_name, - }, - { - label: 'Operation type', - type: 'component', - headerClassName: ' operation_type', - className: 'operation_type', - component: WrapperColumnComponent, - value: (row) => row.operation_type, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance.type = ['color']; - } - }, - { - label: 'Operation result', - type: 'component', - headerClassName: 'operation_result', - className: 'operation_result', - component: WrapperColumnComponent, - value: (row) => row.operation_result, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance.type = ['color']; - } - }, - { - label: 'Operation time', - sort: 'operation_time', - className: 'action_date', - headerClassName: 'action_date', - value: (row) => DateHelper.short(row.operation_time), - }, - { - label: 'Username', - type: 'component', - headerClassName: 'username', - className: 'username', - value: (row) => row.username, - component: WrapperColumnComponent, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance.type = ['text-substr']; - } - }, - { - label: '', - type: 'component', - headerClassName: 'table-end', - className: 'table-end', - component: HistoryColumnComponent, - } - - ] as IColumns; - - type: TypeName = 'audit_operations'; - filterParams$: BehaviorSubject = new BehaviorSubject({}); - - auditOperationsFilters: IFilter[] = [ - { - id: 1, name: 'username', display_name: 'Username', filter_field: 'username', filter_type: 'input', - }, - { - id: 2, name: 'object_name', display_name: 'Object name', filter_field: 'object_name', filter_type: 'input', - }, - { - id: 3, name: 'object_type', display_name: 'Object type', filter_field: 'object_type', filter_type: 'list', - options: [ - {id: 1, name: 'adcm', display_name: 'ADCM', value: 'adcm'}, - {id: 2, name: 'bundle', display_name: 'Bundle', value: 'bundle'}, - {id: 3, name: 'cluster', display_name: 'Cluster', value: 'cluster'}, - {id: 4, name: 'component', display_name: 'Component', value: 'component'}, - {id: 5, name: 'group', display_name: 'Group', value: 'group'}, - {id: 6, name: 'host', display_name: 'Host', value: 'host'}, - {id: 7, name: 'policy', display_name: 'Policy', value: 'policy'}, - {id: 8, name: 'provider', display_name: 'Provider', value: 'provider'}, - {id: 9, name: 'role', display_name: 'Role', value: 'role'}, - {id: 10, name: 'service', display_name: 'Service', value: 'service'}, - {id: 11, name: 'user', display_name: 'User', value: 'user'}, - ] - }, - { - id: 4, name: 'operation_type', display_name: 'Operation type', filter_field: 'operation_type', filter_type: 'list', - options: [ - {id: 1, name: 'create', display_name: 'Create', value: 'create'}, - {id: 2, name: 'update', display_name: 'Update', value: 'update'}, - {id: 3, name: 'delete', display_name: 'Delete', value: 'delete'}, - ] - }, - { - id: 5, name: 'operation_result', display_name: 'Operation result', filter_field: 'operation_result', filter_type: 'list', - options: [ - {id: 1, name: 'success', display_name: 'Success', value: 'success'}, - {id: 2, name: 'fail', display_name: 'Fail', value: 'fail'}, - {id: 3, name: 'denied', display_name: 'Denied', value: 'denied'}, - ] - }, - { - id: 6, name: 'operation_time', display_name: 'Operation time', filter_field: 'operation_time', filter_type: 'datepicker', - }, - ]; - - component: Type = RbacAuditOperationsHistoryFormComponent; - - constructor( - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - protected entityService: RbacAuditOperationsService, - ) { - super(service, store, route, router, dialog, entityService); - } - - ngOnInit() { - super.ngOnInit(); - - this.filterParams$.subscribe((params) => { - const filter_params = this.baseListDirective.listParams; - - if (filter_params) { - filter_params['params'] = { ...params }; - this.router.navigate(['./', filter_params['params']], { - relativeTo: this.route, - replaceUrl: true, - }); - } - }) - } - - getTitle(row: RbacAuditOperationsModel): string { - return row.object_name; - } - -} diff --git a/web/src/app/admin/groups/groups.component.html b/web/src/app/admin/groups/groups.component.html deleted file mode 100644 index 21399141c9..0000000000 --- a/web/src/app/admin/groups/groups.component.html +++ /dev/null @@ -1,22 +0,0 @@ -
- - Add new {{ type }} - - -
- - diff --git a/web/src/app/admin/groups/groups.component.scss b/web/src/app/admin/groups/groups.component.scss deleted file mode 100644 index 3490a52051..0000000000 --- a/web/src/app/admin/groups/groups.component.scss +++ /dev/null @@ -1,10 +0,0 @@ -:host { - flex: 1; - width: 100%; -} - -.controls { - position: absolute; - right: 40px; - top: 16px; -} diff --git a/web/src/app/admin/groups/groups.component.ts b/web/src/app/admin/groups/groups.component.ts deleted file mode 100644 index e64a05b1cf..0000000000 --- a/web/src/app/admin/groups/groups.component.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Component, Type, ViewChild } from '@angular/core'; -import { IColumns } from '@app/adwp'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material/dialog'; -import { Store } from '@ngrx/store'; -import { RbacGroupModel } from '@app/models/rbac/rbac-group.model'; -import { TypeName } from '../../core/types'; -import { ADD_SERVICE_PROVIDER } from '../../shared/add-component/add-service-model'; -import { AddButtonComponent, BaseFormDirective } from '../../shared/add-component'; -import { ListService } from '@app/shared/components/list/list.service'; -import { SocketState } from '@app/core/store'; -import { RbacEntityListDirective } from '@app/abstract-directives/rbac-entity-list.directive'; -import { RbacGroupService } from '../../services/rbac-group.service'; -import { RbacGroupFormComponent } from '../../components/rbac/group-form/rbac-group-form.component'; - -const userNameMapper = (group: RbacGroupModel) => { - return group.user.map((u) => u.username).join(', '); -}; - -@Component({ - selector: 'app-groups', - templateUrl: './groups.component.html', - styleUrls: ['./groups.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: RbacGroupService } - ], -}) -export class GroupsComponent extends RbacEntityListDirective { - @ViewChild(AddButtonComponent) addButton: AddButtonComponent; - - listColumns = [ - { - type: 'choice', - modelKey: 'checked', - className: 'choice-column', - headerClassName: 'choice-column', - disabled: (row) => row.built_in, - }, - { - label: 'Group name', - sort: 'name', - value: (row) => row.name, - }, - { - label: 'Description', - sort: 'description', - value: (row) => row.description, - }, - { - label: 'Users', - className: 'one-line-string', - value: userNameMapper, - }, - { - label: 'Type', - sort: 'type', - value: (row) => row.type, - } - ] as IColumns; - - type: TypeName = 'group'; - - component: Type = RbacGroupFormComponent; - - constructor( - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - protected entityService: RbacGroupService, - ) { - super(service, store, route, router, dialog, entityService); - } - - getTitle(row: RbacGroupModel): string { - return row.name; - } - -} diff --git a/web/src/app/admin/intro.component.ts b/web/src/app/admin/intro.component.ts deleted file mode 100644 index 5c1dda3c14..0000000000 --- a/web/src/app/admin/intro.component.ts +++ /dev/null @@ -1,80 +0,0 @@ -// Licensed 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 { Component } from '@angular/core'; - -@Component({ - selector: 'app-intro', - template: ` -

- This is Arenadata Cluster Manager (ADCM) - the home of all your data. It connects together different data applications, providing a fast, reliable and enterprise-ready way to - manage your data landscape. Please read this short notice to start using ADCM in its most efficient way. -

-
-
    -
  • - We have to know ADCM's Url [ {{ adcm_url }} ] to send information from host. We try to guess that information from url you enter in - browser.
    But if your network has more complicated structure and we guess wrong, please fix that here.
    -
  • -
-
-

Bundle

-

- Bundle is a set of functionality that you can add to your ADCM. Every data application (Database, Hadoop cluster, etc.) is created using a bundle. For example, to start a - Hadoop cluster version 3.0.0, you will need a Hadoop 3.0.0 bundle. Other bundles may contain virtual machine access method (Amazon, Google, etc.), widgets, etc. Think of it - like a plugin, or a mobile phone application. -

-

Cluster

-

- This is the main functionality. Cluster is a set of hosts, running one distributed application. Cluster is deployed from bundle. Of course, you can have multiple clusters set - up from the same bundle. -

-

Service

-

- Service is a part of a cluster. It contain part of the cluster functionality. Service can run across all hosts in the cluster, or only across some of them. -

-

Component

-

- Component is a part of a service that is running on one host. -

-

Hostprovider

-

- Hostprovider is a set of access credentials for ADCM to create new hosts or access existing, For example, when you want to create a VM in a public cloud, you will need to add - username, access key and other access credentials to ADCM. Do it by creating a new Hostprovider and editing its config. -

-

Host

-

- This is a machine that your data app is running on. A host may be a virtual machine, a physical server, or something else.
- A host can be added to only one cluster - you cannot share a host between multiple clusters. -

-

 

- Shortly: -
    -
  • Bundle is a packet with functionality (ex. Hadoop)
  • -
  • Cluster is a logical set of functionality. Cluster is created from bundle (ex Hadoop cluster)
  • -
  • Service is a logical part of cluster (ex. HDFS)
  • -
  • Component is a part of service, that is located on some host (ex. DataNode)
  • -
- If you need a more deep dive into ADCM's functionality, - start from docs. -
- Now you are ready to start exploring ADCM by yourself - enjoy it! -

 

- `, - styles: [':host {padding: 0 10px;}', '.admin-warn {border:solid 1px #ff9800;margin-right: 20px;}', '.admin-warn ul li {padding: 8px 0;}'], -}) -export class IntroComponent { - adcm_url = `${location.protocol}//${location.host}`; - - adcm_docs = 'https://docs.arenadata.io/en/ADCM/current/introduction/intro.html'; -} diff --git a/web/src/app/admin/pattern.component.ts b/web/src/app/admin/pattern.component.ts deleted file mode 100644 index f1be46a040..0000000000 --- a/web/src/app/admin/pattern.component.ts +++ /dev/null @@ -1,119 +0,0 @@ -// Licensed 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 { Component, OnDestroy, OnInit } from '@angular/core'; -import { NavigationEnd, Router } from '@angular/router'; -import { select, Store } from '@ngrx/store'; -import { exhaustMap, filter, map, switchMap } from 'rxjs/operators'; -import { BaseDirective } from '@app/adwp'; -import { ApiService } from '@app/core/api'; -import { getProfileSelector, settingsSave, State } from '@app/core/store'; -import { IConfig,ISettingsListResponse } from '@app/shared/configuration/types'; -import { Observable } from "rxjs"; - -@Component({ - selector: 'app-pattern', - template: ` - - -
-
- - - - {{ item.title }} - - - - - - {{ title }} - - - - - - - - `, - styleUrls: ['../styles/details.scss'], -}) -export class PatternComponent extends BaseDirective implements OnInit, OnDestroy { - actionsUrl$: Observable; - title = ''; - crumbs = []; - leftMenu = [ - { url: 'intro', title: 'Intro' }, - { url: 'settings', title: 'Settings' }, - { url: 'users', title: 'Users' }, - { url: 'groups', title: 'Groups' }, - { url: 'roles', title: 'Roles' }, - { url: 'policies', title: 'Policies' }, - { url: 'audit/operations', title: 'Audit operations' }, - { url: 'audit/logins', title: 'Audit logins' } - ]; - data = { - '/admin': { title: 'Hi there!', crumbs: [{ path: '/admin/', name: 'intro' }] }, - '/admin/intro': { title: 'Hi there!', crumbs: [{ path: '/admin/', name: 'intro' }] }, - '/admin/settings': { title: 'Global configuration', crumbs: [{ path: '/admin/settings', name: 'settings' }] }, - '/admin/users': { title: 'User list', crumbs: [{ path: '/admin/users', name: 'users' }] }, - '/admin/groups': { title: 'Group list', crumbs: [{ path: '/admin/groups', name: 'groups' }] }, - '/admin/roles': { title: 'Role list', crumbs: [{ path: '/admin/roles', name: 'roles' }] }, - '/admin/policies': { title: 'Policy list', crumbs: [{ path: '/admin/policies', name: 'policies' }] }, - '/admin/audit/operations': { title: 'Audit operations', crumbs: [{ path: '/admin/audit/operations', name: 'audit operations' }] }, - '/admin/audit/logins': { title: 'Audit logins', crumbs: [{ path: '/admin/audit/logins', name: 'audit logins' }] } - }; - - constructor(private store: Store, private api: ApiService, private router: Router) { - super(); - } - - ngOnInit() { - this.actionsUrl$ = this.api.root.pipe( - switchMap((root) => this.api.get(root.adcm)), - map((adcm) => `/api/v1/adcm/${adcm.results[0]?.id}/action/`)); - - this.getContext(this.router.routerState.snapshot.url); - - this.router.events - .pipe( - filter((e) => e instanceof NavigationEnd), - this.takeUntil() - ) - .subscribe((e: NavigationEnd) => this.getContext(e.urlAfterRedirects)); - - // auto-save and flag in to profile - this.store - .pipe( - select(getProfileSelector), - filter((p) => p.username === 'admin' && !p.profile.settingsSaved), - exhaustMap(() => - this.api.get('/api/v1/adcm/1/config/current/?noview').pipe( - exhaustMap((c) => { - const config = c.config; - const global = config['global'] || {}; - global.adcm_url = global.adcm_url || `${location.protocol}//${location.host}`; - return this.api.post('/api/v1/adcm/1/config/history/', c); - }) - ) - ), - this.takeUntil() - ) - .subscribe(() => this.store.dispatch(settingsSave({ isSet: true }))); - } - - getContext(url: string) { - const uri = url.split(';')[0]; - const a = this.data[uri]; - this.title = a.title; - this.crumbs = a.crumbs; - } -} diff --git a/web/src/app/admin/policies/policies.component.html b/web/src/app/admin/policies/policies.component.html deleted file mode 100644 index 21399141c9..0000000000 --- a/web/src/app/admin/policies/policies.component.html +++ /dev/null @@ -1,22 +0,0 @@ -
- - Add new {{ type }} - - -
- - diff --git a/web/src/app/admin/policies/policies.component.scss b/web/src/app/admin/policies/policies.component.scss deleted file mode 100644 index 3490a52051..0000000000 --- a/web/src/app/admin/policies/policies.component.scss +++ /dev/null @@ -1,10 +0,0 @@ -:host { - flex: 1; - width: 100%; -} - -.controls { - position: absolute; - right: 40px; - top: 16px; -} diff --git a/web/src/app/admin/policies/policies.component.ts b/web/src/app/admin/policies/policies.component.ts deleted file mode 100644 index 503dc600c0..0000000000 --- a/web/src/app/admin/policies/policies.component.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Component, Type, ViewChild } from '@angular/core'; -import { IColumns } from '@app/adwp'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material/dialog'; -import { Store } from '@ngrx/store'; - -import { TypeName } from '@app/core/types'; -import { RbacPolicyModel } from '@app/models/rbac/rbac-policy.model'; -import { RbacEntityListDirective } from '@app/abstract-directives/rbac-entity-list.directive'; -import { ListService } from '@app/shared/components/list/list.service'; -import { SocketState } from '@app/core/store'; -import { RbacPolicyService } from '@app/services/rbac-policy.service'; -import { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model'; -import { AddButtonComponent } from '@app/shared/add-component'; -import { RbacPolicyFormComponent } from '@app/components/rbac/policy-form/rbac-policy-form.component'; -import { RbacRoleModel } from '@app/models/rbac/rbac-role.model'; -import { RbacGroupModel } from '@app/models/rbac/rbac-group.model'; - -@Component({ - selector: 'app-policies', - templateUrl: './policies.component.html', - styleUrls: ['./policies.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: RbacPolicyService } - ], -}) -export class PoliciesComponent extends RbacEntityListDirective { - @ViewChild(AddButtonComponent) addButton: AddButtonComponent; - - listColumns = [ - { - type: 'choice', - modelKey: 'checked', - className: 'choice-column', - headerClassName: 'choice-column', - disabled: (row) => row.built_in, - }, - { - label: 'Policy name', - sort: 'name', - value: (row) => row.name, - }, - { - label: 'Description', - value: (row) => row.description, - }, - { - label: 'Role', - value: (row) => (row.role && (row.role as any as RbacRoleModel).display_name) ?? '', - }, - { - label: 'Groups', - value: (row) => row.group.map((group: RbacGroupModel) => group.name).join(', '), - className: 'one-line-string', - }, - { - label: 'Objects', - value: (row) => row.object.map((object: any) => object.name).join(', '), - className: 'one-line-string', - }, - ] as IColumns; - - type: TypeName = 'policy'; - - component: Type = RbacPolicyFormComponent; - - constructor( - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - protected entityService: RbacPolicyService, - ) { - super(service, store, route, router, dialog, entityService); - } - - getTitle(row: RbacPolicyModel): string { - return row.name; - } - -} diff --git a/web/src/app/admin/roles/roles.component.html b/web/src/app/admin/roles/roles.component.html deleted file mode 100644 index 21399141c9..0000000000 --- a/web/src/app/admin/roles/roles.component.html +++ /dev/null @@ -1,22 +0,0 @@ -
- - Add new {{ type }} - - -
- - diff --git a/web/src/app/admin/roles/roles.component.scss b/web/src/app/admin/roles/roles.component.scss deleted file mode 100644 index 3490a52051..0000000000 --- a/web/src/app/admin/roles/roles.component.scss +++ /dev/null @@ -1,10 +0,0 @@ -:host { - flex: 1; - width: 100%; -} - -.controls { - position: absolute; - right: 40px; - top: 16px; -} diff --git a/web/src/app/admin/roles/roles.component.ts b/web/src/app/admin/roles/roles.component.ts deleted file mode 100644 index 79eb3bf585..0000000000 --- a/web/src/app/admin/roles/roles.component.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Component, Type, ViewChild } from '@angular/core'; -import { IColumns } from '@app/adwp'; -import { Store } from '@ngrx/store'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material/dialog'; - -import { TypeName } from '@app/core/types'; -import { RbacRoleModel } from '@app/models/rbac/rbac-role.model'; -import { RbacEntityListDirective } from '@app/abstract-directives/rbac-entity-list.directive'; -import { ListService } from '@app/shared/components/list/list.service'; -import { SocketState } from '@app/core/store'; -import { RbacRoleService } from '@app/services/rbac-role.service'; -import { ADD_SERVICE_PROVIDER } from '../../shared/add-component/add-service-model'; -import { AddButtonComponent } from '../../shared/add-component'; -import { RbacRoleFormComponent } from '../../components/rbac/role-form/rbac-role-form.component'; - -const permissionNameMapper = (role: RbacRoleModel) => { - return role.child.map((u) => u.name).join(', '); -}; - - -@Component({ - selector: 'app-roles', - templateUrl: './roles.component.html', - styleUrls: ['./roles.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: RbacRoleService } - ], -}) -export class RolesComponent extends RbacEntityListDirective { - @ViewChild(AddButtonComponent) addButton: AddButtonComponent; - - listColumns = [ - { - type: 'choice', - modelKey: 'checked', - className: 'choice-column', - headerClassName: 'choice-column', - disabled: (row) => row.built_in, - }, - { - label: 'Role name', - sort: 'display_name', - value: (row) => row.display_name, - }, - { - label: 'Description', - sort: 'description', - value: (row) => row.description, - }, - { - label: 'Permissions', - className: 'one-line-string', - value: permissionNameMapper, - } - ] as IColumns; - - type: TypeName = 'role'; - - component: Type = RbacRoleFormComponent; - - constructor( - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - protected entityService: RbacRoleService, - ) { - super(service, store, route, router, dialog, entityService); - } - - getTitle(row: RbacRoleModel): string { - return row.name; - } - -} diff --git a/web/src/app/admin/settings.component.ts b/web/src/app/admin/settings.component.ts deleted file mode 100644 index 066a6e77b6..0000000000 --- a/web/src/app/admin/settings.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed 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 { Component, OnInit } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; -import { map, switchMap } from 'rxjs/operators'; - -import { ApiService } from '@app/core/api'; -import { settingsSave, State } from '@app/core/store'; -import { DynamicEvent } from '@app/shared/directives'; -import { ISettingsListResponse } from '@app/shared/configuration/types'; - -@Component({ - selector: 'app-settings', - template: '', - styles: [':host {flex:1; display: flex;}'], -}) -export class SettingsComponent implements OnInit { - set$: Observable; - - constructor(private api: ApiService, private store: Store) {} - - ngOnInit() { - this.set$ = this.api.root.pipe( - switchMap((root) => this.api.get(root.adcm)), - map((adcm) => adcm.results[0]), - ); - } - - onEvent(e: DynamicEvent) { - if (e.name === 'send') this.store.dispatch(settingsSave({ isSet: true })); - } -} diff --git a/web/src/app/admin/users/users.component.html b/web/src/app/admin/users/users.component.html deleted file mode 100644 index c9791a0b02..0000000000 --- a/web/src/app/admin/users/users.component.html +++ /dev/null @@ -1,25 +0,0 @@ -
- - Add new {{ type }} - - -
- - - - diff --git a/web/src/app/admin/users/users.component.scss b/web/src/app/admin/users/users.component.scss deleted file mode 100644 index 3490a52051..0000000000 --- a/web/src/app/admin/users/users.component.scss +++ /dev/null @@ -1,10 +0,0 @@ -:host { - flex: 1; - width: 100%; -} - -.controls { - position: absolute; - right: 40px; - top: 16px; -} diff --git a/web/src/app/admin/users/users.component.ts b/web/src/app/admin/users/users.component.ts deleted file mode 100644 index 408354c8b4..0000000000 --- a/web/src/app/admin/users/users.component.ts +++ /dev/null @@ -1,138 +0,0 @@ -// Licensed 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 { Component, OnInit, Type, ViewChild } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material/dialog'; -import { IColumns } from '@app/adwp'; -import { Store } from '@ngrx/store'; -import { RbacUserModel } from '@app/models/rbac/rbac-user.model'; -import { ListService } from '@app/shared/components/list/list.service'; -import { SocketState } from '@app/core/store'; -import { TypeName } from '@app/core/types'; -import { RbacEntityListDirective } from '@app/abstract-directives/rbac-entity-list.directive'; -import { ADD_SERVICE_PROVIDER } from '../../shared/add-component/add-service-model'; -import { AddButtonComponent, BaseFormDirective } from '../../shared/add-component'; -import { RbacUserService } from '../../services/rbac-user.service'; -import { RbacUserFormComponent } from '../../components/rbac/user-form/rbac-user-form.component'; -import { IFilter } from "../../shared/configuration/tools/filter/filter.component"; -import { BehaviorSubject } from "rxjs"; -import { ResetLoginAttemptsButtonComponent } from '@app/shared/reset-login-attempts-button/reset-login-attempts-button.component'; - -const groupNameMapper = (user: RbacUserModel) => { - return user.group.map((group) => group.name).join(', '); -}; - -@Component({ - selector: 'app-users', - templateUrl: './users.component.html', - styleUrls: ['users.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: RbacUserService } - ], -}) -export class UsersComponent extends RbacEntityListDirective implements OnInit { - @ViewChild(AddButtonComponent) addButton: AddButtonComponent; - - listColumns = [ - { - type: 'choice', - modelKey: 'checked', - className: 'choice-column', - headerClassName: 'choice-column', - disabled: (row) => row.built_in, - }, - { - label: 'Username', - sort: 'username', - value: (row) => row.username, - }, - { - label: 'Email', - sort: 'email', - value: (row) => row.email, - }, - { - label: 'Groups', - className: 'one-line-string', - value: groupNameMapper, - }, - { - label: 'Type', - sort: 'type', - value: (row) => row.type, - }, - { - label: '', - type: 'component', - className: 'reset-column', - headerClassName: 'reset-column', - component: ResetLoginAttemptsButtonComponent, - } - ] as IColumns; - - type: TypeName = 'user' - filterParams$: BehaviorSubject = new BehaviorSubject({}); - - userFilters: IFilter[] = [ - { - id: 1, name: 'status', display_name: 'Status', filter_field: 'is_active', filter_type: 'list', - options: [ - {id: 1, name: 'active', display_name: 'Active', value: true}, - {id: 2, name: 'inactive', display_name: 'Inactive', value: false}, - ] - }, - { - id: 2, name: 'type', display_name: 'Type', filter_field: 'type', filter_type: 'list', - options: [ - {id: 1, name: 'local', display_name: 'Local', value: 'local'}, - {id: 2, name: 'ldap', display_name: 'Ldap', value: 'ldap'}, - ] - } - ] - - component: Type = RbacUserFormComponent; - - constructor( - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - protected entityService: RbacUserService - ) { - super(service, store, route, router, dialog, entityService); - } - - ngOnInit() { - super.ngOnInit(); - - this.filterParams$.subscribe((params) => { - const filter_params = this.baseListDirective.listParams; - - if (filter_params) { - filter_params['params'] = { ...params }; - this.router.navigate(['./', filter_params['params']], { - relativeTo: this.route, - replaceUrl: true, - }); - } - }) - } - - getTitle(row: RbacUserModel): string { - return row.username; - } - - isRowInactive = (value) => { - return value?.is_active === false; - } -} diff --git a/web/src/app/adwp/index.ts b/web/src/app/adwp/index.ts deleted file mode 100644 index d7a816ada5..0000000000 --- a/web/src/app/adwp/index.ts +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Public API CDK - */ -export { - AdwpFilterPipeModule, - AdwpFilterPipe, - AdwpPortalHostModule, - AdwpPortalHostComponent, - AdwpPortalHost, - AdwpMatcher, - AdwpIdentityMatcher, - AdwpStringMatcher, - ADWP_DEFAULT_MATCHER, - ADWP_DEFAULT_STRINGIFY, - ADWP_IDENTITY_MATCHER, - EMPTY_FUNCTION, - POLLING_TIME, - AdwpMapper, - AdwpHandler, - AdwpBooleanHandler, - AdwpStringHandler, - adwpAssert, - adwpPure, - adwpZonefree, - adwpDefaultProp, - difference, - concatBy, - px, - inRange, - fallbackValue, - typedFromEvent, - getClosestElement, - getClosestFocusable, - isNativeKeyboardFocusable, - isNativeMouseFocusable, - setNativeFocused, - isPresent, - getScreenWidth, - svgNodeFilter, - AdwpEventWith, - AdwpTypedEventTarget, - AdwpOverscrollModeT, - AdwpMapperPipeModule, - AdwpMapperPipe, -} from './lib/cdk'; - - -/* - * Public API Surface of widgets - */ - -export { AdwpUiWidgetsModule } from './lib/ui-widgets.module'; - -export { Entity } from './lib/models/entity'; - -export { LoginFormComponent } from './lib/login-form/login-form.component'; -export { AdwpLoginFormModule } from './lib/login-form/login-form.module'; - -export { LoadingComponent } from './lib/loading/loading.component'; -export { AdwpLoadingModule } from './lib/loading/loading.module'; - -export { TopMenuComponent } from './lib/header/top-menu/top-menu.component'; -export { AdwpHeaderModule } from './lib/header/header.module'; - -export { FooterComponent } from './lib/footer/footer/footer.component'; -export { AdwpFooterModule } from './lib/footer/footer.module'; - -export { BaseDirective } from './lib/models/base.directive'; -export { LoginCredentials } from './lib/models/login-credentials'; -export { IMenuItem } from './lib/models/menu-item'; -export { IVersionInfo } from './lib/models/version-info'; - -export { AdwpListModule } from './lib/list/list.module'; -export { ListComponent } from './lib/list/list/list.component'; -export { LinkCellComponent } from './lib/list/cell/link-cell.component'; -export { Paging } from './lib/list/list/list.component'; -export { TableComponent } from './lib/list/table/table.component'; -export { TimePipe } from './lib/list/pipes/time.pipe'; -export { PaginatorComponent } from './lib/list/paginator/paginator.component'; - -export { AdwpNotificationModule } from './lib/notification/notification.module'; - -export { AdwpToolbarModule } from './lib/toolbar/toolbar.module'; -export { ToolbarComponent } from './lib/toolbar/toolbar.component'; -export { CrumbsComponent } from './lib/toolbar/crumbs/crumbs.component'; - -export { - AdwpMiscellaneousModule, - FatalErrorComponent, - GatewayTimeoutComponent, - PageNotFoundComponent, -} from './lib/miscellaneous/miscellaneous.module'; - -export { AdwpSocketModule } from './lib/socket/socket.module'; - -export { AdwpAuthModule } from './lib/auth/auth.module'; - -export { AdwpApiModule } from './lib/api/api.module'; -export { ApiOptions } from './lib/models/api-options'; -export { ApiParams } from './lib/models/api-params'; - -export { AdwpListStorageModule } from './lib/list-storage/list-storage.module'; - -export { DjangoInterceptor } from './lib/http-interceptors/django-interceptor'; - -export { Cookie } from './lib/helpers/cookie'; -export { EventHelper } from './lib/helpers/event-helper'; - -export { ApiService } from './lib/services/api.service'; -export { AuthService } from './lib/services/auth.service'; -export { ConfigService } from './lib/services/config.service'; -export { NotificationService } from './lib/services/notification.service'; -export { SocketService } from './lib/services/socket.service'; -export { AppService } from './lib/services/app.service'; -export { ListStorageService } from './lib/services/list-storage.service'; - -export { - authCheck, - authLogout, - authLogin, - authFailed, - authSuccess, -} from './lib/store/auth/auth.actions'; -export { AuthState, authReducer } from './lib/store/auth/auth.reducers'; -export { isAuthenticated, getAuthState, isAuthChecking } from './lib/store/auth/auth.selectors'; -export { AuthEffects } from './lib/store/auth/auth.effects'; - -export { - socketResponse, - socketClose, - socketLost, - socketOpen, - socketInit, - EventMessage, - StatusType, - IEMObject, - TypeName, -} from './lib/store/socket/socket.actions'; -export { SocketState, socketReducer } from './lib/store/socket/socket.reducers'; -export { - getConnectStatus, - getMessage, - getSocketState, - selectMessage, -} from './lib/store/socket/socket.selectors'; - -export { AdwpStoreFactory } from './lib/store/factory'; -export { AdwpState } from './lib/store/state'; - -export { AdwpDialogModule } from './lib/dialog/dialog.module'; -export { AdwpDialogComponent, AdwpDynamicComponent } from './lib/dialog/dialog.component'; -export { ComponentData } from './lib/dialog/ComponentData'; - -export { AdwpFormElementModule } from './lib/form-element/form-element.module'; -export { FieldDirective } from './lib/form-element/field.directive'; -export { AdwpInputComponent } from './lib/form-element/input/input.component'; -export { AdwpInputSelectComponent } from './lib/form-element/input-select/input-select.component'; -export { AdwpControlsComponent } from './lib/form-element/controls/controls.component'; - -export { AdwpPortalService } from './lib/cdk/components/portal-host/portal.service'; - -export { AdwpSelectionListModule } from './lib/core/components/selection-list/selection-list.module'; -export { AdwpSelectionListComponent } from './lib/core/components/selection-list/selection-list.component'; - -export { AdwpSelectModule } from './lib/core/components/select/select.module'; -export { AdwpSelectComponent } from './lib/core/components/select/select.component'; - -export { AdwpDropdownModule } from './lib/core/directives/dropdown/dropdown.module'; -export { AdwpDropdownDirective } from './lib/core/directives/dropdown/dropdown.directive'; - -export { AdwpClickOutsideModule } from './lib/core/directives/click-outside/click-outside.module'; -export { AdwpClickOutsideDirective } from './lib/core/directives/click-outside/click-outside.directive'; - - -export { - RowEventData, - IListResult, - IColumnDescription, - IDynamicColumn, - ILinkColumn, - IButtonsColumn, - IDateColumn, - ICell, - IButton, - IComponentColumn, - CellValueType, - IColumn, - IColumns, - AdwpCellComponent, - AdwpComponentHolder, - IValueColumn, - IChoiceColumn, - InstanceTakenFunc, -} from './lib/models/list'; - diff --git a/web/src/app/adwp/lib/api/api-config.service.ts b/web/src/app/adwp/lib/api/api-config.service.ts deleted file mode 100644 index 43ca6600c3..0000000000 --- a/web/src/app/adwp/lib/api/api-config.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { InjectionToken } from '@angular/core'; -import { ApiConfig } from './api-config'; - -export const ApiConfigService = new InjectionToken('ApiConfig'); diff --git a/web/src/app/adwp/lib/api/api-config.ts b/web/src/app/adwp/lib/api/api-config.ts deleted file mode 100644 index 30b33ac07c..0000000000 --- a/web/src/app/adwp/lib/api/api-config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ApiConfig { - defaultRoot: string; -} diff --git a/web/src/app/adwp/lib/api/api.module.ts b/web/src/app/adwp/lib/api/api.module.ts deleted file mode 100644 index 410bc792a8..0000000000 --- a/web/src/app/adwp/lib/api/api.module.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; -import { ApiService } from '../services/api.service'; -import { ApiConfigService } from './api-config.service'; -import { ApiConfig } from './api-config'; - -@NgModule({ - providers: [ - ApiService, - ], -}) -export class AdwpApiModule { - - constructor(@Optional() @SkipSelf() parentModule?: AdwpApiModule) { - if (parentModule) { - throw new Error('AdwpApiModule is already loaded. Import it in the AppModule only'); - } - } - - public static forRoot(config: ApiConfig): ModuleWithProviders { - return { - ngModule: AdwpApiModule, - providers: [ - { - provide: ApiConfigService, - useValue: config, - } - ] - }; - } - -} diff --git a/web/src/app/adwp/lib/auth/auth-config.service.ts b/web/src/app/adwp/lib/auth/auth-config.service.ts deleted file mode 100644 index 544b1e4c30..0000000000 --- a/web/src/app/adwp/lib/auth/auth-config.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { InjectionToken } from '@angular/core'; -import { AuthConfig } from './auth-config'; - -export const AuthConfigService = new InjectionToken('AuthConfig'); diff --git a/web/src/app/adwp/lib/auth/auth-config.ts b/web/src/app/adwp/lib/auth/auth-config.ts deleted file mode 100644 index 589758fb7b..0000000000 --- a/web/src/app/adwp/lib/auth/auth-config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface AuthConfig { - uiApiRoot: string; -} diff --git a/web/src/app/adwp/lib/auth/auth.module.ts b/web/src/app/adwp/lib/auth/auth.module.ts deleted file mode 100644 index 8022c3523c..0000000000 --- a/web/src/app/adwp/lib/auth/auth.module.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; - -import { AuthService } from '../services/auth.service'; -import { AuthConfig } from './auth-config'; -import { AuthConfigService } from './auth-config.service'; - -@NgModule({ - providers: [ - AuthService, - ], -}) -export class AdwpAuthModule { - - constructor(@Optional() @SkipSelf() parentModule?: AdwpAuthModule) { - if (parentModule) { - throw new Error('AdwpAuthModule is already loaded. Import it in the AppModule only'); - } - } - - public static forRoot(config: AuthConfig): ModuleWithProviders { - return { - ngModule: AdwpAuthModule, - providers: [ - { - provide: AuthConfigService, - useValue: config, - } - ] - }; - } - -} diff --git a/web/src/app/adwp/lib/cdk/classes/assert.ts b/web/src/app/adwp/lib/cdk/classes/assert.ts deleted file mode 100644 index 5088350a63..0000000000 --- a/web/src/app/adwp/lib/cdk/classes/assert.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { EMPTY_FUNCTION } from '../constants'; - -export const adwpAssert = { - enabled: false, - get assert(): (assertion: boolean, ...args: any[]) => void { - return this.enabled - ? Function.prototype.bind.call(console.assert, console) - : EMPTY_FUNCTION; - }, -}; diff --git a/web/src/app/adwp/lib/cdk/classes/index.ts b/web/src/app/adwp/lib/cdk/classes/index.ts deleted file mode 100644 index 336b0ab1fd..0000000000 --- a/web/src/app/adwp/lib/cdk/classes/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './assert'; diff --git a/web/src/app/adwp/lib/cdk/components/index.ts b/web/src/app/adwp/lib/cdk/components/index.ts deleted file mode 100644 index 89b5c4c3ba..0000000000 --- a/web/src/app/adwp/lib/cdk/components/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './portal-host'; diff --git a/web/src/app/adwp/lib/cdk/components/portal-host/index.ts b/web/src/app/adwp/lib/cdk/components/portal-host/index.ts deleted file mode 100644 index cc2f082d8a..0000000000 --- a/web/src/app/adwp/lib/cdk/components/portal-host/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './portal-host.component'; -export * from './portal-host.module'; diff --git a/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.component.ts b/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.component.ts deleted file mode 100644 index 56884b1f2a..0000000000 --- a/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.component.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { - ChangeDetectionStrategy, - Component, - ComponentFactory, - ComponentRef, - ElementRef, - EmbeddedViewRef, - Inject, - Injector, - TemplateRef, - ViewChild, - ViewContainerRef, -} from '@angular/core'; -import { AdwpPortalService } from './portal.service'; -import { AdwpPortalHost } from '../../interfaces/portal-host'; - -const BLANK_CLIENT_RECT: ClientRect = { - bottom: 0, - height: 0, - left: 0, - right: 0, - top: 0, - width: 0, -}; - - -@Component({ - selector: 'adwp-portal-host', - templateUrl: './portal-host.template.html', - styleUrls: ['./portal-host.style.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AdwpPortalHostComponent implements AdwpPortalHost { - @ViewChild('positionFixedOffset') - private readonly positionFixedOffsetRef?: ElementRef; - - constructor( - @Inject(ViewContainerRef) - private readonly viewContainerRef: ViewContainerRef, - @Inject(ElementRef) - private readonly elementRef: ElementRef, - @Inject(AdwpPortalService) portalService: AdwpPortalService, - ) { - portalService.attach(this); - } - - get clientRect(): ClientRect { - return this.elementRef.nativeElement.getBoundingClientRect(); - } - - addComponentChild( - componentFactory: ComponentFactory, - injector: Injector, - ): ComponentRef { - return this.viewContainerRef.createComponent( - componentFactory, - undefined, - Injector.create({ - parent: injector, - providers: [ - { - provide: AdwpPortalHostComponent, - useValue: this, - }, - ], - }), - ); - } - - addTemplateChild(templateRef: TemplateRef, context?: C): EmbeddedViewRef { - return this.viewContainerRef.createEmbeddedView(templateRef, context); - } - - fixedPositionOffset(): ClientRect { - return this.positionFixedOffsetRef - ? this.positionFixedOffsetRef.nativeElement.getBoundingClientRect() - : BLANK_CLIENT_RECT; - } -} diff --git a/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.module.ts b/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.module.ts deleted file mode 100644 index 0cfc8f050a..0000000000 --- a/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NgModule } from '@angular/core'; -import { AdwpPortalHostComponent } from './portal-host.component'; - -@NgModule({ - declarations: [AdwpPortalHostComponent], - exports: [AdwpPortalHostComponent], -}) -export class AdwpPortalHostModule { -} diff --git a/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.style.scss b/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.style.scss deleted file mode 100644 index 3adb2a8b19..0000000000 --- a/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.style.scss +++ /dev/null @@ -1,22 +0,0 @@ -:host { - position: relative; - display: block; - height: 100%; - z-index: 0; - - &:before { - content: ''; - display: block; - overflow: hidden; - } -} - -.position-fixed-offset { - position: fixed; - left: 0; - top: 0; - pointer-events: none; - visibility: hidden; - width: 100%; - height: 100%; -} diff --git a/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.template.html b/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.template.html deleted file mode 100644 index d3369dadc7..0000000000 --- a/web/src/app/adwp/lib/cdk/components/portal-host/portal-host.template.html +++ /dev/null @@ -1,2 +0,0 @@ -
- diff --git a/web/src/app/adwp/lib/cdk/components/portal-host/portal.service.ts b/web/src/app/adwp/lib/cdk/components/portal-host/portal.service.ts deleted file mode 100644 index 42001d7379..0000000000 --- a/web/src/app/adwp/lib/cdk/components/portal-host/portal.service.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ComponentFactory, ComponentRef, EmbeddedViewRef, Injectable, Injector, TemplateRef, } from '@angular/core'; -import { AdwpPortalHost } from '../../interfaces/portal-host'; - -const NO_HOST = 'Portals cannot be used without AdwpPortalHostComponent'; - -@Injectable({ - providedIn: 'root', -}) -export class AdwpPortalService { - private host?: AdwpPortalHost; - - private get safeHost(): AdwpPortalHost { - if (!this.host) { - throw new Error(NO_HOST); - } - - return this.host; - } - - attach(host: AdwpPortalHost): void { - this.host = host; - } - - add(componentFactory: ComponentFactory, injector: Injector): ComponentRef { - return this.safeHost.addComponentChild(componentFactory, injector); - } - - remove({ hostView }: ComponentRef) { - hostView.destroy(); - } - - addTemplate(templateRef: TemplateRef, context?: C): EmbeddedViewRef { - return this.safeHost.addTemplateChild(templateRef, context); - } - - removeTemplate(viewRef: EmbeddedViewRef) { - viewRef.destroy(); - } -} diff --git a/web/src/app/adwp/lib/cdk/constants/empty.ts b/web/src/app/adwp/lib/cdk/constants/empty.ts deleted file mode 100644 index 44980fad8a..0000000000 --- a/web/src/app/adwp/lib/cdk/constants/empty.ts +++ /dev/null @@ -1 +0,0 @@ -export const EMPTY_FUNCTION: Function = () => {}; diff --git a/web/src/app/adwp/lib/cdk/constants/identify.ts b/web/src/app/adwp/lib/cdk/constants/identify.ts deleted file mode 100644 index 978a6adba5..0000000000 --- a/web/src/app/adwp/lib/cdk/constants/identify.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AdwpIdentityMatcher } from '../types'; - -/** - * Default method to identify two objects by ids - */ -export const ADWP_IDENTITY_MATCHER: AdwpIdentityMatcher = (item1: any, item2: any) => item1.id === item2.id; diff --git a/web/src/app/adwp/lib/cdk/constants/index.ts b/web/src/app/adwp/lib/cdk/constants/index.ts deleted file mode 100644 index 60a034c668..0000000000 --- a/web/src/app/adwp/lib/cdk/constants/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './empty'; -export * from './identify'; -export * from './matcher'; -export * from './polling-time'; -export * from './stringify'; -export * from './svg-node-filter'; diff --git a/web/src/app/adwp/lib/cdk/constants/matcher.ts b/web/src/app/adwp/lib/cdk/constants/matcher.ts deleted file mode 100644 index 3d9b038ccb..0000000000 --- a/web/src/app/adwp/lib/cdk/constants/matcher.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Default handler for matching stringified version of an item and a search query - * @param item arbitrary element to match with a string - * @param search search query - * @param stringify handler to turn item into a string - */ -import { AdwpHandler } from '../types'; -import { ADWP_DEFAULT_STRINGIFY } from './stringify'; - -export const ADWP_DEFAULT_MATCHER = ( - item: T, - search: string, - stringify: AdwpHandler = ADWP_DEFAULT_STRINGIFY, -) => stringify(item).toLowerCase().includes(search.toLowerCase()); diff --git a/web/src/app/adwp/lib/cdk/constants/polling-time.ts b/web/src/app/adwp/lib/cdk/constants/polling-time.ts deleted file mode 100644 index 9516c561e6..0000000000 --- a/web/src/app/adwp/lib/cdk/constants/polling-time.ts +++ /dev/null @@ -1 +0,0 @@ -export const POLLING_TIME = 1000 / 15; diff --git a/web/src/app/adwp/lib/cdk/constants/stringify.ts b/web/src/app/adwp/lib/cdk/constants/stringify.ts deleted file mode 100644 index b310aa7891..0000000000 --- a/web/src/app/adwp/lib/cdk/constants/stringify.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AdwpStringHandler } from '../types'; - -/** - * Default method to turn arbitrary object into string - */ -export const ADWP_DEFAULT_STRINGIFY: AdwpStringHandler = item => String(item); diff --git a/web/src/app/adwp/lib/cdk/constants/svg-node-filter.ts b/web/src/app/adwp/lib/cdk/constants/svg-node-filter.ts deleted file mode 100644 index 79a80adc35..0000000000 --- a/web/src/app/adwp/lib/cdk/constants/svg-node-filter.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Filtering SVGElements for TreeWalker -// Filter must be a function in IE, other modern browsers are compliant to this format -export const svgNodeFilter: NodeFilter = ((node: Node) => - 'ownerSVGElement' in node - ? NodeFilter.FILTER_REJECT - : NodeFilter.FILTER_ACCEPT) as any; diff --git a/web/src/app/adwp/lib/cdk/decorators/default-prop.ts b/web/src/app/adwp/lib/cdk/decorators/default-prop.ts deleted file mode 100644 index 76b162265a..0000000000 --- a/web/src/app/adwp/lib/cdk/decorators/default-prop.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { AdwpBooleanHandler } from '../types'; -import { adwpAssert } from '../classes'; - -export function adwpDefaultProp( - assertion?: AdwpBooleanHandler, - ...args: any[] -): PropertyDecorator { - return (target, key) => { - const { name } = target.constructor; - const errorGetDefaultMessage = errorGetDefault(key, name); - const errorSetDefaultMessage = errorSetDefault(key, name); - - Object.defineProperty(target, key, { - get(): undefined { - adwpAssert.assert(false, errorGetDefaultMessage); - - return undefined; - }, - set(this: T, initialValue: T[K]) { - const isValid = initialValue !== undefined; - const errorMessage = errorSetDefaultInitial(key, name); - let currentValue = initialValue; - - adwpAssert.assert(isValid, errorMessage); - - if (isValid && assertion) { - adwpAssert.assert( - assertion.call(this, initialValue), - `${String(key)} in ${name} received:`, - initialValue, - ...args, - ); - } - - Object.defineProperty(this, key, { - get(): T[K] { - return currentValue; - }, - set(this: T, value: T[K]) { - const isValid = value !== undefined; - const backupValue = initialValue; - - adwpAssert.assert( - isValid, - errorSetDefaultMessage, - String(backupValue), - ); - - if (isValid && assertion) { - adwpAssert.assert( - assertion.call(this, value), - `${String(key)} in ${name} received:`, - value, - ...args, - ); - } - - currentValue = isValid ? value : backupValue; - }, - }); - }, - }); - }; -} - -function errorGetDefault(key: string | symbol, component: string): string { - return `Default value for ${String( - key, - )} was not provided in ${component}, error in Adwp UI`; -} - -function errorSetDefault(key: string | symbol, component: string): string { - return `Undefined was passed as ${String( - key, - )} to ${component}, which is invalid input, using default value:`; -} - -function errorSetDefaultInitial(key: string | symbol, component: string): string { - return `Undefined was passed as default value for ${String( - key, - )} to ${component}, error in Adwp UI`; -} diff --git a/web/src/app/adwp/lib/cdk/decorators/index.ts b/web/src/app/adwp/lib/cdk/decorators/index.ts deleted file mode 100644 index 9eab814112..0000000000 --- a/web/src/app/adwp/lib/cdk/decorators/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './pure'; -export * from './default-prop'; diff --git a/web/src/app/adwp/lib/cdk/decorators/pure.ts b/web/src/app/adwp/lib/cdk/decorators/pure.ts deleted file mode 100644 index c59b1c26c5..0000000000 --- a/web/src/app/adwp/lib/cdk/decorators/pure.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Implements lazy initialization for getter or memoization of a function call similar to pure {@link: Pipe}. - * Replaces getter with its calculated value upon first call or keeps track of last call arguments and returned - * value for function, skipping calculation when arguments are strictly the same. - * - * @throws error if used not on getter or function - * - * CAUTION: `this` is not available inside such functions/getters, they must be pure. - */ -export function adwpPure( - _target: Object, - propertyKey: string, - {get, enumerable, value}: TypedPropertyDescriptor, -): TypedPropertyDescriptor { - if (get) { - return { - enumerable, - get(): T { - const value = get.call(this); - - Object.defineProperty(this, propertyKey, {enumerable, value}); - - return value; - }, - }; - } - - if (typeof value !== 'function') { - throw new Error('adwpPure can only be used with functions or getters'); - } - - const original = value; - - return { - enumerable, - get(): T { - let previousArgs: ReadonlyArray = []; - let previousResult: any; - - const patched = (...args: Array) => { - if ( - previousArgs.length === args.length && - args.every((arg, index) => arg === previousArgs[index]) - ) { - return previousResult; - } - - previousArgs = args; - previousResult = original.apply(this, args); - - return previousResult; - }; - - Object.defineProperty(this, propertyKey, { - value: patched, - }); - - return patched as any; - }, - }; -} diff --git a/web/src/app/adwp/lib/cdk/index.ts b/web/src/app/adwp/lib/cdk/index.ts deleted file mode 100644 index b7b0d5ad66..0000000000 --- a/web/src/app/adwp/lib/cdk/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from './classes'; -export * from './components'; -export * from './constants'; -export * from './decorators'; -export * from './interfaces'; -export * from './observables'; -export * from './pipes'; -export * from './types'; -export * from './utils'; diff --git a/web/src/app/adwp/lib/cdk/interfaces/index.ts b/web/src/app/adwp/lib/cdk/interfaces/index.ts deleted file mode 100644 index 89b5c4c3ba..0000000000 --- a/web/src/app/adwp/lib/cdk/interfaces/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './portal-host'; diff --git a/web/src/app/adwp/lib/cdk/interfaces/portal-host.ts b/web/src/app/adwp/lib/cdk/interfaces/portal-host.ts deleted file mode 100644 index 7ef7533bb1..0000000000 --- a/web/src/app/adwp/lib/cdk/interfaces/portal-host.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ComponentFactory, ComponentRef, EmbeddedViewRef, Injector, TemplateRef } from '@angular/core'; - -export interface AdwpPortalHost { - clientRect: ClientRect; - - addComponentChild(componentFactory: ComponentFactory, injector: Injector): ComponentRef; - - addTemplateChild(templateRef: TemplateRef, context?: C): EmbeddedViewRef; - - fixedPositionOffset(): ClientRect; -} diff --git a/web/src/app/adwp/lib/cdk/observables/index.ts b/web/src/app/adwp/lib/cdk/observables/index.ts deleted file mode 100644 index ebebca1f62..0000000000 --- a/web/src/app/adwp/lib/cdk/observables/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './zone-free'; -export * from './typed-from-event'; diff --git a/web/src/app/adwp/lib/cdk/observables/typed-from-event.ts b/web/src/app/adwp/lib/cdk/observables/typed-from-event.ts deleted file mode 100644 index 3c692be843..0000000000 --- a/web/src/app/adwp/lib/cdk/observables/typed-from-event.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { fromEvent, Observable } from 'rxjs'; -import { AdwpEventWith, AdwpTypedEventTarget } from '../types'; - -export function typedFromEvent( - target: Window, - event: E, - options?: AddEventListenerOptions, -): Observable>; -export function typedFromEvent( - target: Document, - event: E, - options?: AddEventListenerOptions, -): Observable>; -export function typedFromEvent( - target: T, - event: E, - options?: AddEventListenerOptions, -): Observable>; -export function typedFromEvent>, - >( - target: T, - event: string, - options?: AddEventListenerOptions, -): Observable>; -export function typedFromEvent( - target: AdwpTypedEventTarget, - event: string, - options?: AddEventListenerOptions, -): Observable; -export function typedFromEvent( - target: AdwpTypedEventTarget, - event: string, - options: AddEventListenerOptions = {}, -): Observable { - return fromEvent(target, event, options); -} diff --git a/web/src/app/adwp/lib/cdk/observables/zone-free.ts b/web/src/app/adwp/lib/cdk/observables/zone-free.ts deleted file mode 100644 index fc620d5b37..0000000000 --- a/web/src/app/adwp/lib/cdk/observables/zone-free.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NgZone } from '@angular/core'; -import { MonoTypeOperatorFunction, Observable } from 'rxjs'; - -export function adwpZonefree(ngZone: NgZone): MonoTypeOperatorFunction { - return source => - new Observable(subscriber => - ngZone.runOutsideAngular(() => source.subscribe(subscriber)), - ); -} diff --git a/web/src/app/adwp/lib/cdk/pipes/filter/filter.module.ts b/web/src/app/adwp/lib/cdk/pipes/filter/filter.module.ts deleted file mode 100644 index 7db874f73d..0000000000 --- a/web/src/app/adwp/lib/cdk/pipes/filter/filter.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { NgModule } from '@angular/core'; - -import { AdwpFilterPipe } from './filter.pipe'; - -@NgModule({ - exports: [AdwpFilterPipe], - declarations: [AdwpFilterPipe], -}) -export class AdwpFilterPipeModule { -} diff --git a/web/src/app/adwp/lib/cdk/pipes/filter/filter.pipe.ts b/web/src/app/adwp/lib/cdk/pipes/filter/filter.pipe.ts deleted file mode 100644 index d372e0ab7e..0000000000 --- a/web/src/app/adwp/lib/cdk/pipes/filter/filter.pipe.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { AdwpMatcher } from '../../types'; - -@Pipe({ name: 'adwpFilter' }) -export class AdwpFilterPipe implements PipeTransform { - /** - * Filters an array through a matcher function using additional arguments - * - * @param items array - * @param matcher method for filtering - * @param args arbitrary number of additional arguments - */ - transform(items: readonly T[], matcher: AdwpMatcher, ...args: any[]): T[] { - return items.filter(item => matcher(item, ...args)); - } -} diff --git a/web/src/app/adwp/lib/cdk/pipes/filter/index.ts b/web/src/app/adwp/lib/cdk/pipes/filter/index.ts deleted file mode 100644 index 322711d21a..0000000000 --- a/web/src/app/adwp/lib/cdk/pipes/filter/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './filter.module'; -export * from './filter.pipe'; diff --git a/web/src/app/adwp/lib/cdk/pipes/index.ts b/web/src/app/adwp/lib/cdk/pipes/index.ts deleted file mode 100644 index f8622b97dd..0000000000 --- a/web/src/app/adwp/lib/cdk/pipes/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './filter'; -export * from './mapper'; - diff --git a/web/src/app/adwp/lib/cdk/pipes/mapper/index.ts b/web/src/app/adwp/lib/cdk/pipes/mapper/index.ts deleted file mode 100644 index b7bf96b311..0000000000 --- a/web/src/app/adwp/lib/cdk/pipes/mapper/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './mapper.module'; -export * from './mapper.pipe'; diff --git a/web/src/app/adwp/lib/cdk/pipes/mapper/mapper.module.ts b/web/src/app/adwp/lib/cdk/pipes/mapper/mapper.module.ts deleted file mode 100644 index 245f01fe88..0000000000 --- a/web/src/app/adwp/lib/cdk/pipes/mapper/mapper.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NgModule } from '@angular/core'; -import { AdwpMapperPipe } from './mapper.pipe'; - -@NgModule({ - exports: [AdwpMapperPipe], - declarations: [AdwpMapperPipe], -}) -export class AdwpMapperPipeModule { -} diff --git a/web/src/app/adwp/lib/cdk/pipes/mapper/mapper.pipe.ts b/web/src/app/adwp/lib/cdk/pipes/mapper/mapper.pipe.ts deleted file mode 100644 index 4c9d184d78..0000000000 --- a/web/src/app/adwp/lib/cdk/pipes/mapper/mapper.pipe.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { AdwpMapper } from '../../types'; - -@Pipe({ name: 'adwpMapper' }) -export class AdwpMapperPipe implements PipeTransform { - /** - * Maps object to an arbitrary result through a mapper function - * - * @param value an item to transform - * @param mapper a mapping function - * @param args arbitrary number of additional arguments - */ - transform(value: T, mapper: AdwpMapper, ...args: any[]): G { - return mapper(value, ...args); - } -} diff --git a/web/src/app/adwp/lib/cdk/services/destroy.service.ts b/web/src/app/adwp/lib/cdk/services/destroy.service.ts deleted file mode 100644 index 7768045b6c..0000000000 --- a/web/src/app/adwp/lib/cdk/services/destroy.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable, OnDestroy } from '@angular/core'; -import { Subject } from 'rxjs'; - -@Injectable() -export class AdwpDestroyService extends Subject implements OnDestroy { - ngOnDestroy() { - this.next(); - this.complete(); - } -} diff --git a/web/src/app/adwp/lib/cdk/services/index.ts b/web/src/app/adwp/lib/cdk/services/index.ts deleted file mode 100644 index 2b31597d24..0000000000 --- a/web/src/app/adwp/lib/cdk/services/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './parents-scroll.service'; diff --git a/web/src/app/adwp/lib/cdk/services/parents-scroll.service.ts b/web/src/app/adwp/lib/cdk/services/parents-scroll.service.ts deleted file mode 100644 index 2f43dc16f0..0000000000 --- a/web/src/app/adwp/lib/cdk/services/parents-scroll.service.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ElementRef, Inject, Injectable } from '@angular/core'; -import { WINDOW } from '@ng-web-apis/common'; -import { defer, merge, Observable } from 'rxjs'; -import { typedFromEvent } from '../observables'; - - -@Injectable() -export class AdwpParentsScrollService extends Observable { - private readonly callback$: Observable; - - constructor( - @Inject(ElementRef) { nativeElement }: ElementRef, - @Inject(WINDOW) windowRef: any, - ) { - super(subscriber => this.callback$.subscribe(subscriber)); - - this.callback$ = defer(() => { - const eventTargets: Array = [windowRef, nativeElement]; - - while (nativeElement.parentElement) { - nativeElement = nativeElement.parentElement; - eventTargets.push(nativeElement); - } - - return merge( - ...eventTargets.map>(element => - typedFromEvent(element, 'scroll'), - ), - ); - }); - } -} diff --git a/web/src/app/adwp/lib/cdk/types/event-with.ts b/web/src/app/adwp/lib/cdk/types/event-with.ts deleted file mode 100644 index b1cda4ee4c..0000000000 --- a/web/src/app/adwp/lib/cdk/types/event-with.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface AdwpTypedEventTarget { - addEventListener( - type: string, - listener: ((evt: E) => void) | null, - options?: boolean | AddEventListenerOptions, - ): void; - - removeEventListener( - type: string, - listener?: ((evt: E) => void) | null, - options?: boolean | EventListenerOptions, - ): void; -} - -export type AdwpEventWith> = G & { - readonly currentTarget: T; -}; diff --git a/web/src/app/adwp/lib/cdk/types/handler.ts b/web/src/app/adwp/lib/cdk/types/handler.ts deleted file mode 100644 index f34d993aa6..0000000000 --- a/web/src/app/adwp/lib/cdk/types/handler.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type AdwpHandler = (item: T) => G; -export type AdwpBooleanHandler = AdwpHandler; -export type AdwpStringHandler = AdwpHandler; diff --git a/web/src/app/adwp/lib/cdk/types/index.ts b/web/src/app/adwp/lib/cdk/types/index.ts deleted file mode 100644 index e1db2f13e5..0000000000 --- a/web/src/app/adwp/lib/cdk/types/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './event-with'; -export * from './handler'; -export * from './matcher'; -export * from './mapper'; -export * from './overscroll-mode'; diff --git a/web/src/app/adwp/lib/cdk/types/mapper.ts b/web/src/app/adwp/lib/cdk/types/mapper.ts deleted file mode 100644 index ec540e4b1f..0000000000 --- a/web/src/app/adwp/lib/cdk/types/mapper.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Typed mapping function. - */ -export type AdwpMapper = (item: T, ...args: any[]) => G; diff --git a/web/src/app/adwp/lib/cdk/types/matcher.ts b/web/src/app/adwp/lib/cdk/types/matcher.ts deleted file mode 100644 index 40eb517058..0000000000 --- a/web/src/app/adwp/lib/cdk/types/matcher.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AdwpStringHandler } from './handler'; -import { AdwpMapper } from './mapper'; - -/** - * A matcher function to test items against with extra arguments. - */ -export type AdwpMatcher = AdwpMapper; - -export type AdwpStringMatcher = ( - item: I, - matchValue: string, - stringify: AdwpStringHandler, -) => boolean; - -export type AdwpIdentityMatcher = (item1: I, item2: I) => boolean; diff --git a/web/src/app/adwp/lib/cdk/types/overscroll-mode.ts b/web/src/app/adwp/lib/cdk/types/overscroll-mode.ts deleted file mode 100644 index 9c10923e22..0000000000 --- a/web/src/app/adwp/lib/cdk/types/overscroll-mode.ts +++ /dev/null @@ -1 +0,0 @@ -export type AdwpOverscrollModeT = 'all' | 'scroll' | 'none'; diff --git a/web/src/app/adwp/lib/cdk/utils/array/concat-by.ts b/web/src/app/adwp/lib/cdk/utils/array/concat-by.ts deleted file mode 100644 index 466348053e..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/array/concat-by.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { AdwpIdentityMatcher } from '../../types'; -import { ADWP_IDENTITY_MATCHER } from '../../constants'; - -/** - * Concat unique elements of two arrays by comparator - * - * @param arrA - * @param arrB - * @param matcher - */ -export function concatBy(arrA: T[], arrB: T[], matcher: AdwpIdentityMatcher = ADWP_IDENTITY_MATCHER): T[] { - return arrA.concat(arrB.filter((b) => !arrA.find((a) => matcher(a, b)))); -} diff --git a/web/src/app/adwp/lib/cdk/utils/array/difference.ts b/web/src/app/adwp/lib/cdk/utils/array/difference.ts deleted file mode 100644 index dc8f1eaa81..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/array/difference.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { AdwpIdentityMatcher } from '../../types'; -import { ADWP_IDENTITY_MATCHER } from '../../constants'; - - -/** - * Difference of two arrays - * - * @param arrA - * @param arrB - * @param matcher - */ -export function difference(arrA: T[], arrB: T[], matcher: AdwpIdentityMatcher = ADWP_IDENTITY_MATCHER): T[] { - return arrA.filter(a => !arrB.find((b) => matcher(a, b))); -} diff --git a/web/src/app/adwp/lib/cdk/utils/array/index.ts b/web/src/app/adwp/lib/cdk/utils/array/index.ts deleted file mode 100644 index d34d8cf670..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/array/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './difference'; -export * from './concat-by'; diff --git a/web/src/app/adwp/lib/cdk/utils/dom/get-closest-element.ts b/web/src/app/adwp/lib/cdk/utils/dom/get-closest-element.ts deleted file mode 100644 index 333d426219..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/dom/get-closest-element.ts +++ /dev/null @@ -1,20 +0,0 @@ -export function getClosestElement(element: Element, selector: string): Element | null { - const closest = Element.prototype.closest; - - if (closest) { - return closest.call(element, selector); - } - - const matchesSelector = - Element.prototype.matches || (Element.prototype as any).msMatchesSelector; - - do { - if (matchesSelector.call(element, selector)) { - return element; - } - - (element as Element | null) = element.parentElement; - } while (element !== null); - - return null; -} diff --git a/web/src/app/adwp/lib/cdk/utils/dom/get-screen-width.ts b/web/src/app/adwp/lib/cdk/utils/dom/get-screen-width.ts deleted file mode 100644 index 4516b78a75..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/dom/get-screen-width.ts +++ /dev/null @@ -1,6 +0,0 @@ -export function getScreenWidth(documentRef: Document): number { - return Math.max( - documentRef.documentElement.clientWidth, - documentRef.defaultView ? documentRef.defaultView.innerWidth : 0, - ); -} diff --git a/web/src/app/adwp/lib/cdk/utils/dom/index.ts b/web/src/app/adwp/lib/cdk/utils/dom/index.ts deleted file mode 100644 index f041b7d3c6..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/dom/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './get-screen-width'; -export * from './get-closest-element'; diff --git a/web/src/app/adwp/lib/cdk/utils/focus/get-closest-keyboard-focusable.ts b/web/src/app/adwp/lib/cdk/utils/focus/get-closest-keyboard-focusable.ts deleted file mode 100644 index bb156cd1c9..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/focus/get-closest-keyboard-focusable.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { isNativeKeyboardFocusable } from './is-native-keyboard-focusable'; -import { isNativeMouseFocusable } from './is-native-mouse-focusable'; -import { svgNodeFilter } from '../../constants'; - -/** - * Finds closest element that can be focused with a keyboard or mouse in theory - * - * @param initial current HTML element - * @param prev should it look backwards instead (find item that will be focused with Shift + Tab) - * @param root top Node limiting the search area - * @param keyboard determine if only keyboard focus is of interest - * - */ -export function getClosestFocusable( - initial: HTMLElement, - prev: boolean = false, - root: Node, - keyboard: boolean = true, -): HTMLElement | null { - if (!root.ownerDocument) { - return null; - } - - const check = keyboard ? isNativeKeyboardFocusable : isNativeMouseFocusable; - - // Deprecated but ony this overload works in IE - // Filter must be a function in IE, other modern browsers are compliant to this format - const treeWalker = root.ownerDocument.createTreeWalker( - root, - NodeFilter.SHOW_ELEMENT, - svgNodeFilter, - false, - ); - - treeWalker.currentNode = initial; - - while (prev ? treeWalker.previousNode() : treeWalker.nextNode()) { - if (treeWalker.currentNode instanceof HTMLElement) { - initial = treeWalker.currentNode; - } - - if (check(initial)) { - return initial; - } - } - - return null; -} diff --git a/web/src/app/adwp/lib/cdk/utils/focus/index.ts b/web/src/app/adwp/lib/cdk/utils/focus/index.ts deleted file mode 100644 index 09bbba0ebd..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/focus/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './get-closest-keyboard-focusable'; -export * from './is-native-keyboard-focusable'; -export * from './is-native-mouse-focusable'; -export * from './set-native-focused'; diff --git a/web/src/app/adwp/lib/cdk/utils/focus/is-native-keyboard-focusable.ts b/web/src/app/adwp/lib/cdk/utils/focus/is-native-keyboard-focusable.ts deleted file mode 100644 index dbd036e8fd..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/focus/is-native-keyboard-focusable.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Checks for signs that element can be focused with keyboard. tabIndex above 0 is ignored to - * only target natural focus order. Not checking the possibility of an element to - * be focused, for example element can have display: none applied to it or any other - * circumstances could prevent actual focus. - */ -export function isNativeKeyboardFocusable(element: Element): boolean { - if (element.hasAttribute('disabled') || element.getAttribute('tabIndex') === '-1') { - return false; - } - - if ( - (element instanceof HTMLElement && element.isContentEditable) || - element.getAttribute('tabIndex') === '0' - ) { - return true; - } - - switch (element.tagName) { - case 'BUTTON': - case 'SELECT': - case 'TEXTAREA': - return true; - case 'VIDEO': - case 'AUDIO': - return element.hasAttribute('controls'); - case 'INPUT': - return element.getAttribute('type') !== 'hidden'; - case 'A': - case 'LINK': - return element.hasAttribute('href'); - default: - return false; - } -} diff --git a/web/src/app/adwp/lib/cdk/utils/focus/is-native-mouse-focusable.ts b/web/src/app/adwp/lib/cdk/utils/focus/is-native-mouse-focusable.ts deleted file mode 100644 index 1854afd6c7..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/focus/is-native-mouse-focusable.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { isNativeKeyboardFocusable } from './is-native-keyboard-focusable'; - -export function isNativeMouseFocusable(element: Element): boolean { - return ( - !element.hasAttribute('disabled') && - (element.getAttribute('tabIndex') === '-1' || isNativeKeyboardFocusable(element)) - ); -} diff --git a/web/src/app/adwp/lib/cdk/utils/focus/set-native-focused.ts b/web/src/app/adwp/lib/cdk/utils/focus/set-native-focused.ts deleted file mode 100644 index 736ba35599..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/focus/set-native-focused.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Focuses or blurs and element - * - * @param element native element - * @param focused boolean focused state - * @param preventScroll optional flag to prevent native scroll to the element - */ -export function setNativeFocused( - element: HTMLOrSVGElement, - focused: boolean = true, - preventScroll: boolean = false, -) { - if (focused) { - element.focus({ preventScroll }); - } else { - element.blur(); - } -} diff --git a/web/src/app/adwp/lib/cdk/utils/format/index.ts b/web/src/app/adwp/lib/cdk/utils/format/index.ts deleted file mode 100644 index f3510c0dbc..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/format/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './px'; diff --git a/web/src/app/adwp/lib/cdk/utils/format/px.ts b/web/src/app/adwp/lib/cdk/utils/format/px.ts deleted file mode 100644 index 89f761ac1c..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/format/px.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { adwpAssert } from '../../classes'; - -export function px(value: number): string { - adwpAssert.assert(Number.isFinite(value), 'Value must be finite number'); - - return `${value}px`; -} diff --git a/web/src/app/adwp/lib/cdk/utils/index.ts b/web/src/app/adwp/lib/cdk/utils/index.ts deleted file mode 100644 index ca9ff2a3a5..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './array'; -export * from './dom'; -export * from './focus'; -export * from './format'; -export * from './math'; -export * from './format'; -export * from './miscellaneous'; diff --git a/web/src/app/adwp/lib/cdk/utils/math/in-range.ts b/web/src/app/adwp/lib/cdk/utils/math/in-range.ts deleted file mode 100644 index f181c1091d..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/math/in-range.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { adwpAssert } from '../../classes'; - -/** - * Checks if the value is in range - * - * @param value - * @param fromInclude lower inclusive limit - * @param toExclude upper exclusive limit - */ -export function inRange(value: number, fromInclude: number, toExclude: number): boolean { - adwpAssert.assert(!isNaN(value)); - adwpAssert.assert(!isNaN(fromInclude)); - adwpAssert.assert(!isNaN(toExclude)); - adwpAssert.assert(fromInclude < toExclude); - - return value >= fromInclude && value < toExclude; -} diff --git a/web/src/app/adwp/lib/cdk/utils/math/index.ts b/web/src/app/adwp/lib/cdk/utils/math/index.ts deleted file mode 100644 index 757d0a8a05..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/math/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './in-range'; diff --git a/web/src/app/adwp/lib/cdk/utils/miscellaneous/fallback-value.ts b/web/src/app/adwp/lib/cdk/utils/miscellaneous/fallback-value.ts deleted file mode 100644 index 77d4eda4ba..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/miscellaneous/fallback-value.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { isPresent } from './is-present'; - -export function fallbackValue(value: T | null | undefined, fallback: T): T { - return isPresent(value) ? value : fallback; -} diff --git a/web/src/app/adwp/lib/cdk/utils/miscellaneous/index.ts b/web/src/app/adwp/lib/cdk/utils/miscellaneous/index.ts deleted file mode 100644 index 8618880442..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/miscellaneous/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './fallback-value'; -export * from './is-present'; diff --git a/web/src/app/adwp/lib/cdk/utils/miscellaneous/is-present.ts b/web/src/app/adwp/lib/cdk/utils/miscellaneous/is-present.ts deleted file mode 100644 index fafac3999b..0000000000 --- a/web/src/app/adwp/lib/cdk/utils/miscellaneous/is-present.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function isPresent(value?: T | null): value is T { - return value !== null && value !== undefined; -} diff --git a/web/src/app/adwp/lib/core/abstract/abstract-dropdown.ts b/web/src/app/adwp/lib/core/abstract/abstract-dropdown.ts deleted file mode 100644 index ae9eea482c..0000000000 --- a/web/src/app/adwp/lib/core/abstract/abstract-dropdown.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { - AfterViewChecked, - ComponentFactoryResolver, - ComponentRef, - Directive, - ElementRef, - Injector, - Input, - OnDestroy, -} from '@angular/core'; - -import { PolymorpheusContent } from '@tinkoff/ng-polymorpheus'; -import { Observable } from 'rxjs'; -import { AdwpDropdown } from '../interfaces/dropdown-directive'; -import { adwpDefaultProp, adwpPure } from '../../cdk'; -import { DEFAULT_MAX_HEIGHT, DEFAULT_MIN_HEIGHT } from '../constants'; -import { AdwpDropdownWidthT, AdwpHorizontalDirection, AdwpVerticalDirection } from '../types'; -import { AdwpDropdownBoxComponent } from '../components/dropdown-box/dropdown-box.component'; -import { checkFixedPosition } from '../utils'; -import { AdwpPortalService } from '../../cdk/components/portal-host/portal.service'; - -@Directive() -export abstract class AbstractAdwpDropdown - implements AdwpDropdown, AfterViewChecked, OnDestroy { - @Input('adwpDropdownContent') - @adwpDefaultProp() - content: PolymorpheusContent = ''; - - @Input('adwpDropdownHost') - @adwpDefaultProp() - adwpDropdownHost: HTMLElement | null = null; - - @Input('adwpDropdownMinHeight') - @adwpDefaultProp() - minHeight = DEFAULT_MIN_HEIGHT; - - @Input('adwpDropdownMaxHeight') - @adwpDefaultProp() - maxHeight = DEFAULT_MAX_HEIGHT; - - @Input('adwpDropdownAlign') - @adwpDefaultProp() - align: AdwpHorizontalDirection = 'left'; - - @Input('adwpDropdownDirection') - @adwpDefaultProp() - direction: AdwpVerticalDirection | null = null; - - @Input('adwpDropdownSided') - @adwpDefaultProp() - sided = false; - - @Input('adwpDropdownLimitWidth') - @adwpDefaultProp() - limitMinWidth: AdwpDropdownWidthT = 'min'; - - dropdownBoxRef: ComponentRef | null = null; - - abstract refresh$: Observable; - - protected constructor( - private readonly componentFactoryResolver: ComponentFactoryResolver, - private readonly injector: Injector, - private readonly portalService: AdwpPortalService, - protected readonly elementRef: ElementRef, - ) {} - - ngOnDestroy() { - this.closeDropdownBox(); - } - - ngAfterViewChecked() { - if (this.dropdownBoxRef !== null) { - this.dropdownBoxRef.changeDetectorRef.detectChanges(); - this.dropdownBoxRef.changeDetectorRef.markForCheck(); - } - } - - get clientRect(): ClientRect { - return this.elementRef.nativeElement.getBoundingClientRect(); - } - - get host(): HTMLElement { - return this.adwpDropdownHost || this.elementRef.nativeElement; - } - - @adwpPure - get fixed(): boolean { - return checkFixedPosition(this.elementRef.nativeElement); - } - - protected openDropdownBox() { - if (this.dropdownBoxRef !== null) { - return; - } - - const componentFactory = this.componentFactoryResolver.resolveComponentFactory( - AdwpDropdownBoxComponent, - ); - - this.dropdownBoxRef = this.portalService.add(componentFactory, this.injector); - this.dropdownBoxRef.changeDetectorRef.detectChanges(); - } - - protected closeDropdownBox() { - if (this.dropdownBoxRef === null) { - return; - } - - this.portalService.remove(this.dropdownBoxRef); - this.dropdownBoxRef = null; - } -} diff --git a/web/src/app/adwp/lib/core/abstract/index.ts b/web/src/app/adwp/lib/core/abstract/index.ts deleted file mode 100644 index 99890001c1..0000000000 --- a/web/src/app/adwp/lib/core/abstract/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './abstract-dropdown'; diff --git a/web/src/app/adwp/lib/core/animations/animations.ts b/web/src/app/adwp/lib/core/animations/animations.ts deleted file mode 100644 index bb55054238..0000000000 --- a/web/src/app/adwp/lib/core/animations/animations.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { animate, style, transition, trigger } from '@angular/animations'; -import { AdwpDropdownAnimation } from '../enums'; - -const TRANSITION = '{{duration}}ms ease-in-out'; -const DURATION = { params: { duration: 300 } }; - -export const adwpDropdownAnimation = trigger('adwpDropdownAnimation', [ - transition( - `* => ${AdwpDropdownAnimation.FadeInTop}`, - [ - style({ transform: 'translateY(-10px)', opacity: 0 }), - animate(TRANSITION, style({ transform: 'translateY(0)', opacity: 1 })), - ], - DURATION, - ), - transition( - `* => ${AdwpDropdownAnimation.FadeInBottom}`, - [ - style({ transform: 'translateY(10px)', opacity: 0 }), - animate(TRANSITION, style({ transform: 'translateY(0)', opacity: 1 })), - ], - DURATION, - ), - transition( - `${AdwpDropdownAnimation.FadeInBottom} => *`, - [ - style({ transform: 'translateY(0)', opacity: 1 }), - animate(TRANSITION, style({ transform: 'translateY(10px)', opacity: 0 })), - ], - DURATION, - ), - transition( - `${AdwpDropdownAnimation.FadeInTop} => *`, - [ - style({ transform: 'translateY(0)', opacity: 1 }), - animate(TRANSITION, style({ transform: 'translateY(-10px)', opacity: 0 })), - ], - DURATION, - ), -]); diff --git a/web/src/app/adwp/lib/core/animations/index.ts b/web/src/app/adwp/lib/core/animations/index.ts deleted file mode 100644 index 9616d4a908..0000000000 --- a/web/src/app/adwp/lib/core/animations/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './animations'; diff --git a/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.component.ts b/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.component.ts deleted file mode 100644 index c44e51dc10..0000000000 --- a/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.component.ts +++ /dev/null @@ -1,359 +0,0 @@ -import { AnimationOptions } from '@angular/animations'; -import { - AfterViewChecked, - ChangeDetectionStrategy, - Component, - ElementRef, - HostBinding, - Inject, - NgZone, - ViewChild, -} from '@angular/core'; -import { ANIMATION_FRAME, WINDOW } from '@ng-web-apis/common'; -import { fromEvent, merge, Observable } from 'rxjs'; -import { takeUntil, throttleTime } from 'rxjs/operators'; -import { AdwpDestroyService } from '../../../cdk/services/destroy.service'; -import { AdwpAnimationOptions } from '../../interfaces'; -import { adwpDropdownAnimation } from '../../animations/animations'; -import { AdwpDropdownAnimation } from '../../enums'; -import { AdwpDropdown } from '../../interfaces/dropdown-directive'; -import { ADWP_ANIMATION_OPTIONS, ADWP_DROPDOWN_DIRECTIVE } from '../../tokens'; -import { - AdwpPortalHostComponent, - adwpPure, - adwpZonefree, - getClosestElement, - getScreenWidth, - inRange, - POLLING_TIME, - px -} from '../../../cdk'; -import { AdwpHorizontalDirection, AdwpVerticalDirection } from '../../types'; -import { DEFAULT_MARGIN, DEFAULT_MAX_WIDTH } from '../../constants'; -import { getClosestFocusable, setNativeFocused } from '../../../cdk/utils/focus'; - - -@Component({ - selector: 'adwp-dropdown-box', - templateUrl: './dropdown-box.template.html', - styleUrls: ['./dropdown-box.style.scss'], - changeDetection: ChangeDetectionStrategy.Default, - providers: [AdwpDestroyService], - animations: [adwpDropdownAnimation], - host: { - 'class': 'mat-select-panel' - } -}) -export class AdwpDropdownBoxComponent implements AfterViewChecked { - @HostBinding('@adwpDropdownAnimation') - dropdownAnimation!: AdwpAnimationOptions; - - private readonly animationTop = { - value: AdwpDropdownAnimation.FadeInTop, - ...this.options, - }; - - private readonly animationBottom = { - value: AdwpDropdownAnimation.FadeInBottom, - ...this.options, - }; - - private prevDirectionIsTop = false; - - @ViewChild('content', { read: ElementRef }) - readonly contentElementRef?: ElementRef; - - constructor( - @Inject(AdwpDestroyService) destroy$: AdwpDestroyService, - @Inject(NgZone) ngZone: NgZone, - @Inject(ADWP_DROPDOWN_DIRECTIVE) readonly directive: AdwpDropdown, - @Inject(WINDOW) private readonly windowRef: any, - @Inject(ElementRef) private readonly elementRef: ElementRef, - @Inject(AdwpPortalHostComponent) - private readonly portalHost: AdwpPortalHostComponent, - @Inject(ADWP_ANIMATION_OPTIONS) private readonly options: AnimationOptions, - @Inject(ANIMATION_FRAME) animationFrame$: Observable, - ) { - merge( - animationFrame$.pipe(throttleTime(POLLING_TIME)), - this.directive.refresh$, - fromEvent(this.windowRef, 'resize'), - ) - .pipe(adwpZonefree(ngZone), takeUntil(destroy$)) - .subscribe(() => { - this.calculatePositionAndSize(); - }); - } - - @adwpPure - getContext(context?: T): T { - return context; - } - - ngAfterViewChecked() { - this.calculatePositionAndSize(); - } - - onTopFocus() { - this.moveFocusOutside(true); - } - - onBottomFocus() { - this.moveFocusOutside(false); - } - - @adwpPure - private get inModal(): boolean { - return !!getClosestElement(this.directive.host, 'adwp-dialog-host'); - } - - private calculatePositionAndSize() { - const { clientRect } = this.directive; - const { style } = this.elementRef.nativeElement; - const hostRect = this.directive.fixed - ? this.portalHost.fixedPositionOffset() - : this.portalHost.clientRect; - - style.position = this.directive.fixed ? 'fixed' : 'absolute'; - - this.calculateVerticalPosition(style, clientRect, hostRect); - this.calculateHorizontalPosition(style, clientRect, hostRect); - this.calculateWidth(style, clientRect); - } - - private getFinalAlign( - style: CSSStyleDeclaration, - directiveRect: ClientRect, - ): AdwpHorizontalDirection { - const dropdownRect = this.elementRef.nativeElement.getBoundingClientRect(); - const dropdownWidth = this.elementRef.nativeElement.offsetWidth; - const screenWidth = getScreenWidth(this.windowRef.document); - const isDropdownSizeHypotheticallyFitsViewport = - directiveRect.left + dropdownWidth < screenWidth || - directiveRect.right - dropdownWidth > 0; - const isDropdownSizeActuallyFitsViewport = - dropdownRect.right <= screenWidth && dropdownRect.left >= 0; - let finalAlign: AdwpHorizontalDirection = this.directive.align; - - switch (this.directive.align) { - case 'left': - if ( - isDropdownSizeHypotheticallyFitsViewport && - dropdownRect.right > screenWidth - ) { - finalAlign = 'right'; - } - - break; - case 'right': - if (isDropdownSizeHypotheticallyFitsViewport && dropdownRect.left < 0) { - finalAlign = 'left'; - } - - break; - } - - if (style.right === 'auto' && isDropdownSizeActuallyFitsViewport) { - finalAlign = 'left'; - } - - if (style.left === 'auto' && isDropdownSizeActuallyFitsViewport) { - finalAlign = 'right'; - } - - return finalAlign; - } - - /** - * Calculates horizontal position - * - * @param style dropdownBox elementRef styles object - * @param directiveRect ClientRect of hosting directive - * @param hostRect ClientRect of portal host - */ - private calculateHorizontalPosition( - style: CSSStyleDeclaration, - directiveRect: ClientRect, - hostRect: ClientRect, - ) { - const offset = this.directive.sided - ? this.elementRef.nativeElement.getBoundingClientRect().width + DEFAULT_MARGIN - : 0; - const left = Math.ceil(directiveRect.left - hostRect.left - offset); - const right = Math.floor(hostRect.right - directiveRect.right - offset); - - switch (this.getFinalAlign(style, directiveRect)) { - case 'left': - if ( - right + DEFAULT_MARGIN > this.windowRef.innerWidth || - inRange(left + DEFAULT_MARGIN, 0, this.windowRef.innerWidth) - ) { - style.left = px(left); - style.right = 'auto'; - } else { - style.left = 'auto'; - style.right = px(right); - } - - break; - case 'right': - if ( - inRange(right + DEFAULT_MARGIN, 0, this.windowRef.innerWidth) || - left + DEFAULT_MARGIN > this.windowRef.innerWidth - ) { - style.left = 'auto'; - style.right = px(right); - } else { - style.left = px(left); - style.right = 'auto'; - } - - break; - } - } - - /** - * Calculates vertical position and height - * - * @param style dropdownBox elementRef styles object - * @param directiveRect ClientRect of hosting directive - * @param hostRect ClientRect of portal host - */ - private calculateVerticalPosition( - style: CSSStyleDeclaration, - directiveRect: ClientRect, - hostRect: ClientRect, - ) { - const windowHeight = this.windowRef.innerHeight; - // Maximum height of the box - const boxHeightLimit = Math.min( - this.directive.maxHeight, - windowHeight - DEFAULT_MARGIN * 2, - ); - const offset = this.directive.sided - ? DEFAULT_MARGIN - directiveRect.height - : DEFAULT_MARGIN * 2; - const topAvailableHeight = directiveRect.top - offset; - const bottomAvailableHeight = windowHeight - directiveRect.bottom - offset; - const finalDirection = this.getFinalDirection(directiveRect); - - this.prevDirectionIsTop = finalDirection === 'top'; - - if (finalDirection === 'top') { - this.dropdownAnimation = this.animationBottom; - - style.maxHeight = px(Math.min(boxHeightLimit, topAvailableHeight)); - style.top = 'auto'; - style.bottom = px( - hostRect.bottom - directiveRect.top - DEFAULT_MARGIN + offset, - ); - } else { - this.dropdownAnimation = this.animationTop; - - style.maxHeight = px(Math.min(boxHeightLimit, bottomAvailableHeight)); - style.top = px(directiveRect.bottom - hostRect.top - DEFAULT_MARGIN + offset); - style.bottom = 'auto'; - } - } - - private getFinalDirection(directiveRect: ClientRect): AdwpVerticalDirection | null { - const windowHeight = this.windowRef.innerHeight; - const offset = this.directive.sided - ? DEFAULT_MARGIN - directiveRect.height - : DEFAULT_MARGIN * 2; - - // Maximum space available on top and on the bottom in the viewport - const topAvailableHeight = directiveRect.top - offset; - const bottomAvailableHeight = windowHeight - directiveRect.bottom - offset; - - let finalDirection: AdwpVerticalDirection | null = null; - - // Given direction is applied if we can fit the box in the limits that way - switch (this.directive.direction) { - case 'top': - if (topAvailableHeight >= this.directive.minHeight) { - finalDirection = 'top'; - } - - break; - case 'bottom': - if (bottomAvailableHeight >= this.directive.minHeight) { - finalDirection = 'bottom'; - } - - break; - } - - // Maximum height of the box - const boxHeightLimit = Math.min( - this.directive.maxHeight, - windowHeight - DEFAULT_MARGIN * 2, - ); - - // Choose direction if given direction did not fit - if (finalDirection === null && this.contentElementRef) { - // Box height if it fits without scroll - const visualHeight = Math.min( - this.contentElementRef.nativeElement.getBoundingClientRect().height + - (this.elementRef.nativeElement.offsetHeight - - this.elementRef.nativeElement.clientHeight), - boxHeightLimit, - ); - - // If there is enough space to fit below without scroll, - // choose 'bottom', unless it was previously on the top - if (this.prevDirectionIsTop && topAvailableHeight >= visualHeight) { - finalDirection = 'top'; - } else if (bottomAvailableHeight >= visualHeight) { - finalDirection = 'bottom'; - } else { - // Corner case — select direction with more space - finalDirection = - bottomAvailableHeight >= topAvailableHeight ? 'bottom' : 'top'; - } - } - - return finalDirection; - } - - /** - * Calculates width - * - * @param style dropdownBox elementRef styles object - * @param directiveRect ClientRect of hosting directive - */ - private calculateWidth(style: CSSStyleDeclaration, directiveRect: ClientRect) { - style.width = - this.directive.limitMinWidth === 'fixed' && !this.directive.sided - ? px(directiveRect.width) - : ''; - - if (this.directive.limitMinWidth === 'min' && !this.directive.sided) { - style.minWidth = px(directiveRect.width); - style.maxWidth = px(DEFAULT_MAX_WIDTH); - - return; - } - - style.minWidth = ''; - style.maxWidth = ''; - } - - private moveFocusOutside(previous: boolean) { - const { host } = this.directive; - const { ownerDocument } = host; - const root = ownerDocument ? ownerDocument.body : host; - - let focusable = getClosestFocusable(host, previous, root); - - while (focusable !== null && host.contains(focusable)) { - focusable = getClosestFocusable(focusable, previous, root); - } - - if (focusable === null) { - return; - } - - setNativeFocused(focusable); - } -} diff --git a/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.module.ts b/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.module.ts deleted file mode 100644 index cea10008c0..0000000000 --- a/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { NgModule } from '@angular/core'; -import { PolymorpheusModule } from '@tinkoff/ng-polymorpheus'; -import { AdwpDropdownBoxComponent } from './dropdown-box.component'; - -@NgModule({ - imports: [ - PolymorpheusModule - ], - declarations: [AdwpDropdownBoxComponent], - exports: [AdwpDropdownBoxComponent], -}) -export class AdwpDropdownBoxModule { -} diff --git a/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.style.scss b/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.style.scss deleted file mode 100644 index eb131f3c46..0000000000 --- a/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.style.scss +++ /dev/null @@ -1,32 +0,0 @@ -:host { - z-index: 0; - box-shadow: 0 0.5rem 1rem rgba(51, 51, 51, 0.2); - position: absolute; - top: 0; - left: 0; - display: flex; - border-radius: 4px; - overflow: hidden; - box-sizing: border-box; - - &.ng-animating { - pointer-events: none; - } -} - -.content { - display: flex; - flex-direction: column; - max-height: 100%; -} - -.wrapper { - flex-grow: 1; - max-width: 100%; - max-height: inherit; - overflow: visible; -} - -.scroll { - height: 100%; -} diff --git a/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.template.html b/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.template.html deleted file mode 100644 index 31130dbf70..0000000000 --- a/web/src/app/adwp/lib/core/components/dropdown-box/dropdown-box.template.html +++ /dev/null @@ -1,10 +0,0 @@ -
-
-
-
-
diff --git a/web/src/app/adwp/lib/core/components/dropdown-box/index.ts b/web/src/app/adwp/lib/core/components/dropdown-box/index.ts deleted file mode 100644 index a86392f112..0000000000 --- a/web/src/app/adwp/lib/core/components/dropdown-box/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './dropdown-box.component'; -export * from './dropdown-box.module'; diff --git a/web/src/app/adwp/lib/core/components/index.ts b/web/src/app/adwp/lib/core/components/index.ts deleted file mode 100644 index d8600563ad..0000000000 --- a/web/src/app/adwp/lib/core/components/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './dropdown-box' -export * from './select' diff --git a/web/src/app/adwp/lib/core/components/select/index.ts b/web/src/app/adwp/lib/core/components/select/index.ts deleted file mode 100644 index 23e6da43ae..0000000000 --- a/web/src/app/adwp/lib/core/components/select/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './select.module'; -export * from './select.component'; diff --git a/web/src/app/adwp/lib/core/components/select/select.component.html b/web/src/app/adwp/lib/core/components/select/select.component.html deleted file mode 100644 index ad1c729d13..0000000000 --- a/web/src/app/adwp/lib/core/components/select/select.component.html +++ /dev/null @@ -1,28 +0,0 @@ -
-
- {{placeholder}} - - {{ value | adwpMapper:triggerHandler }} - -
- -
-
-
-
- - - - diff --git a/web/src/app/adwp/lib/core/components/select/select.component.scss b/web/src/app/adwp/lib/core/components/select/select.component.scss deleted file mode 100644 index 41aa1d9a12..0000000000 --- a/web/src/app/adwp/lib/core/components/select/select.component.scss +++ /dev/null @@ -1,54 +0,0 @@ -.adwp-select { - - display: inline-block; - width: 100%; - outline: none; - - - &.floating span { - opacity: 1; - } - - .mat-select-trigger { - display: inline-table; - width: 100%; - cursor: pointer; - position: relative; - box-sizing: border-box; - - .mat-select-value { - display: table-cell; - width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - - .mat-select-value-text { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - - .mat-select-arrow-wrapper { - display: table-cell; - vertical-align: middle; - - .mat-select-arrow { - width: 0; - height: 0; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-top: 5px solid; - margin: 0 4px; - } - } - } - - span { - opacity: 0; - transition: opacity 200ms; - } - -} diff --git a/web/src/app/adwp/lib/core/components/select/select.component.ts b/web/src/app/adwp/lib/core/components/select/select.component.ts deleted file mode 100644 index 504e7ae1c1..0000000000 --- a/web/src/app/adwp/lib/core/components/select/select.component.ts +++ /dev/null @@ -1,231 +0,0 @@ -import { - Component, - ElementRef, - EventEmitter, - HostBinding, - Inject, - Input, - OnDestroy, - Optional, - Output, - Self, - ViewEncapsulation -} from '@angular/core'; -import { ControlValueAccessor, NgControl } from '@angular/forms'; -import { - ADWP_DEFAULT_STRINGIFY, - ADWP_IDENTITY_MATCHER, - adwpAssert, - adwpDefaultProp, - AdwpIdentityMatcher, - AdwpStringHandler -} from '../../../cdk'; -import { MAT_FORM_FIELD, MatFormField, MatFormFieldControl } from '@angular/material/form-field'; -import { Subject } from 'rxjs'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; - -@Component({ - selector: 'adwp-select', - templateUrl: './select.component.html', - styleUrls: ['./select.component.scss'], - providers: [{ provide: MatFormFieldControl, useExisting: AdwpSelectComponent }], - host: { - 'class': 'adwp-select mat-select', - '[class.mat-select-disabled]': 'disabled', - }, - encapsulation: ViewEncapsulation.None -}) -export class AdwpSelectComponent implements ControlValueAccessor, MatFormFieldControl, OnDestroy { - - @Output() - filter: EventEmitter = new EventEmitter(); - - get open(): boolean { - return this._open; - } - - set open(value: boolean) { - if (!this._canOpen()) { - return; - } - - this._open = coerceBooleanProperty(value); - } - - private _open = false; - - controlType = 'adwp-select'; - - static nextId = 0; - - @Input() - options: T[]; - - @Input() - @adwpDefaultProp() - handler: AdwpStringHandler = ADWP_DEFAULT_STRINGIFY; - - @Input() - @adwpDefaultProp() - comparator: AdwpIdentityMatcher = ADWP_IDENTITY_MATCHER; - - @Input() - @adwpDefaultProp() - multiple: boolean = true; - - @Input() selectRowDisableCheck: (args: any) => boolean; - - @Input() - get placeholder() { - return this._placeholder; - } - - set placeholder(plh) { - this._placeholder = plh; - this.stateChanges.next(); - } - - private _placeholder: string; - - get value(): T[] | null { - this.stateChanges.next(); - return this._value; - } - - set value(value: T[] | null) { - if (this.ngControl) { - this.onTouched(); - this.ngControl.control.setValue(value); - this.ngControl.control.markAsDirty(); - } - this._value = value; - } - - private _value: T[] | null; - - get empty() { - return !this._value?.length; - } - - @Input() - get required() { - return this._required; - } - - set required(req) { - this._required = coerceBooleanProperty(req); - this.stateChanges.next(); - } - - private _required = false; - - @Input() - get disabled(): boolean { return this._disabled; } - - set disabled(value: boolean) { - this._disabled = coerceBooleanProperty(value); - this.stateChanges.next(); - } - - private _disabled = false; - - get errorState(): boolean { - return this.ngControl?.invalid; - } - - constructor( - @Optional() - @Self() - @Inject(NgControl) - public readonly ngControl: NgControl | null, - private _elementRef: ElementRef, - @Optional() @Inject(MAT_FORM_FIELD) protected _parentFormField: MatFormField, - ) { - if (ngControl === null) { - adwpAssert.assert( - false, - `NgControl not injected in ${this.constructor.name}!\n`, - 'Use [(ngModel)] or [formControl] or formControlName for correct work.', - ); - } else { - ngControl.valueAccessor = this; - } - } - - - ngOnDestroy() { - this.stateChanges.complete(); - } - - triggerHandler: AdwpStringHandler = (value): string => { - if (this.empty) { - return ''; - } - - return value.map((item) => this.handler(item))?.join(', '); - }; - - readonly autofilled: boolean; - - focused = false; - - onFocusIn(event: FocusEvent): void { - if (!this.focused && !this.disabled) { - this.focused = true; - this.stateChanges.next(); - } - } - - onFocusOut(event: FocusEvent) { - if (!this._elementRef.nativeElement.contains(event.relatedTarget as Element)) { - this.focused = false; - this.onTouched(); - this.stateChanges.next(); - } - } - - @HostBinding() - id = `adwp-select-${AdwpSelectComponent.nextId++}`; - - onContainerClick(event: MouseEvent): void { - event.stopPropagation(); - this.onFocusIn(event); - this.open = !this.open; - } - - setDescribedByIds(ids: string[]): void { - } - - @HostBinding('class.floating') - get shouldLabelFloat() { - return !this.empty; - } - - stateChanges: any = new Subject(); - - // ControlValueAccessor - - protected onChange: (value: any) => void = () => {}; - protected onTouched: () => void = () => {}; - - writeValue(value: any[]): void { - this._value = value; - } - - registerOnChange(fn: (_: any) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - setDisabledState?(isDisabled: boolean): void { - this.disabled = isDisabled; - } - - private _canOpen(): boolean { - return !this.disabled && this.options?.length > 0; - } - -} diff --git a/web/src/app/adwp/lib/core/components/select/select.module.ts b/web/src/app/adwp/lib/core/components/select/select.module.ts deleted file mode 100644 index 14473c2041..0000000000 --- a/web/src/app/adwp/lib/core/components/select/select.module.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { AdwpSelectComponent } from './select.component'; -import { OverlayModule } from '@angular/cdk/overlay'; -import { AdwpDropdownModule } from '../../directives/dropdown/dropdown.module'; -import { AdwpSelectionListModule } from '../selection-list/selection-list.module'; -import { AdwpClickOutsideModule } from '../../directives'; -import { FormsModule } from '@angular/forms'; -import { AdwpMapperPipeModule } from '../../../cdk'; - - -@NgModule({ - declarations: [ - AdwpSelectComponent - ], - exports: [ - AdwpSelectComponent, - ], - imports: [ - CommonModule, - OverlayModule, - AdwpDropdownModule, - AdwpSelectionListModule, - AdwpClickOutsideModule, - FormsModule, - AdwpMapperPipeModule - ] -}) -export class AdwpSelectModule { -} diff --git a/web/src/app/adwp/lib/core/components/selection-list/selection-list-actions.component.html b/web/src/app/adwp/lib/core/components/selection-list/selection-list-actions.component.html deleted file mode 100644 index c73abd9fcc..0000000000 --- a/web/src/app/adwp/lib/core/components/selection-list/selection-list-actions.component.html +++ /dev/null @@ -1,24 +0,0 @@ - -
-
-
- - -
- - - - -
-
-
-
-
- diff --git a/web/src/app/adwp/lib/core/components/selection-list/selection-list-actions.component.ts b/web/src/app/adwp/lib/core/components/selection-list/selection-list-actions.component.ts deleted file mode 100644 index 08059077df..0000000000 --- a/web/src/app/adwp/lib/core/components/selection-list/selection-list-actions.component.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { MatSelectionList } from '@angular/material/list'; -import { MatPseudoCheckboxState } from '@angular/material/core/selection/pseudo-checkbox/pseudo-checkbox'; - -@Component({ - selector: 'adwp-selection-list-actions', - templateUrl: 'selection-list-actions.component.html', -}) -export class SelectionListActionsComponent { - @Input() - list: MatSelectionList; - - @Output() - filterChange: EventEmitter = new EventEmitter(); - - filter: string = ''; - - get disabled(): boolean { - return !this.list?.options?.length; - } - - get selectAllState(): MatPseudoCheckboxState { - return (this.list?.options?.length && this.list?.selectedOptions.selected.length === this.list?.options?.length) - ? 'checked' : 'unchecked'; - } - - toggleOptions(selectionList: MatSelectionList): void { - if (!this.disabled) { - const selected = selectionList.selectedOptions.selected; - const options = selectionList.options; - - if (options?.length > selected?.length) { - selectionList.selectAll(); - } else { - selectionList.deselectAll(); - } - - selectionList._emitChangeEvent(options.toArray()); - } - } - - clear(e: MouseEvent): void { - e.stopPropagation(); - e.preventDefault(); - - this.filter = ''; - this.filterChange.emit(''); - } -} diff --git a/web/src/app/adwp/lib/core/components/selection-list/selection-list.component.css b/web/src/app/adwp/lib/core/components/selection-list/selection-list.component.css deleted file mode 100644 index 39c9579866..0000000000 --- a/web/src/app/adwp/lib/core/components/selection-list/selection-list.component.css +++ /dev/null @@ -1,12 +0,0 @@ -.adwp-selection-list-empty { - display: flex; - flex: 1; - align-items: center; - justify-content: center; - padding: 16px; -} - -.mat-list-item-disabled { - background: none !important; - color: #808080 !important; -} diff --git a/web/src/app/adwp/lib/core/components/selection-list/selection-list.component.html b/web/src/app/adwp/lib/core/components/selection-list/selection-list.component.html deleted file mode 100644 index 7641453bc9..0000000000 --- a/web/src/app/adwp/lib/core/components/selection-list/selection-list.component.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - {{ item | adwpMapper:handler }} - - - - - - -
No options available
-
diff --git a/web/src/app/adwp/lib/core/components/selection-list/selection-list.component.ts b/web/src/app/adwp/lib/core/components/selection-list/selection-list.component.ts deleted file mode 100644 index 10e54a023f..0000000000 --- a/web/src/app/adwp/lib/core/components/selection-list/selection-list.component.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { - AfterViewInit, - Component, - EventEmitter, - Inject, - Input, - Optional, - Output, - QueryList, - Self, - ViewChild -} from '@angular/core'; -import { - ADWP_DEFAULT_MATCHER, - ADWP_DEFAULT_STRINGIFY, - ADWP_IDENTITY_MATCHER, - adwpAssert, - adwpDefaultProp, - AdwpIdentityMatcher, - AdwpMatcher, - AdwpStringHandler, - concatBy, - difference -} from '../../../cdk'; -import { ControlValueAccessor, NgControl } from '@angular/forms'; -import { MatListOption, MatSelectionList, MatSelectionListChange } from '@angular/material/list'; - -@Component({ - selector: 'adwp-selection-list', - templateUrl: './selection-list.component.html', - styleUrls: ['./selection-list.component.css'], -}) -export class AdwpSelectionListComponent implements ControlValueAccessor, AfterViewInit { - - public readonly matcher: AdwpMatcher = ADWP_DEFAULT_MATCHER; - - @ViewChild('selectionList', { static: false }) list: MatSelectionList; - - @Input() - @adwpDefaultProp() - options: T[] = []; - - @Input() - @adwpDefaultProp() - handler: AdwpStringHandler = ADWP_DEFAULT_STRINGIFY; - - @Input() - @adwpDefaultProp() - multiple: boolean = true; - - @Input() selectRowDisableCheck: (args: any) => boolean; - - @Output() - filter: EventEmitter = new EventEmitter(); - - @Input() - @adwpDefaultProp() - comparator: AdwpIdentityMatcher = ADWP_IDENTITY_MATCHER; - - get value(): any[] | null { - return this._value; - } - - set value(value: any[] | null) { - if (this.ngControl) { - this.ngControl.control.setValue(value); - } - this._value = value; - } - - private _value: any[] | null; - - constructor( - @Optional() - @Self() - @Inject(NgControl) - public readonly ngControl: NgControl | null - ) { - if (ngControl === null) { - adwpAssert.assert( - false, - `NgControl not injected in ${this.constructor.name}!\n`, - 'Use [(ngModel)] or [formControl] or formControlName for correct work.', - ); - } else { - ngControl.valueAccessor = this; - } - } - - ngAfterViewInit(): void { - /** - * When changing the list with options (for example, after filtering), - * we need to restore the "selected" state. - * To do this, we look at "this.value" and set the checkbox. - */ - this.list.options.changes.subscribe((list: QueryList) => { - const matOptions = list.toArray(); - matOptions.forEach((option) => { - if (this.value.some((i) => i.id === option.value.id)) { - option._setSelected(true); - } - }); - }); - } - - updateValue(event: MatSelectionListChange): void { - const option = event.options[0]; - const values = event.options.map(o => o.value); - - const isAppend = option.selected; - if (isAppend) { - this.value = concatBy(this.value, values, this.comparator); - } else { - this.value = difference(this.value, values, this.comparator); - } - } - - // ControlValueAccessor - - protected onChange: (value: any) => void = () => {}; - - protected onTouched: () => void = () => {}; - - writeValue(value: T[]): void { - this._value = value; - } - - registerOnChange(fn: (_: T) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - setDisabledState?(isDisabled: boolean): void { - - } -} diff --git a/web/src/app/adwp/lib/core/components/selection-list/selection-list.module.ts b/web/src/app/adwp/lib/core/components/selection-list/selection-list.module.ts deleted file mode 100644 index a84c309b5a..0000000000 --- a/web/src/app/adwp/lib/core/components/selection-list/selection-list.module.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { AdwpSelectionListComponent } from './selection-list.component'; -import { MatPseudoCheckboxModule } from '@angular/material/core'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatListModule } from '@angular/material/list'; -import { MatInputModule } from '@angular/material/input'; -import { FormsModule } from '@angular/forms'; -import { AdwpMapperPipeModule, AdwpFilterPipeModule } from '../../../cdk'; -import { SelectionListActionsComponent } from './selection-list-actions.component'; -import { MatIconModule } from '@angular/material/icon'; -import { MatButtonModule } from '@angular/material/button'; - - -@NgModule({ - declarations: [ - AdwpSelectionListComponent, - SelectionListActionsComponent - ], - imports: [ - CommonModule, - MatPseudoCheckboxModule, - MatFormFieldModule, - MatListModule, - MatInputModule, - FormsModule, - AdwpFilterPipeModule, - AdwpMapperPipeModule, - MatIconModule, - MatButtonModule, - ], - exports: [ - AdwpSelectionListComponent - ] -}) -export class AdwpSelectionListModule { -} diff --git a/web/src/app/adwp/lib/core/constants/absolute-box-sizes.ts b/web/src/app/adwp/lib/core/constants/absolute-box-sizes.ts deleted file mode 100644 index 9150caac30..0000000000 --- a/web/src/app/adwp/lib/core/constants/absolute-box-sizes.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const DEFAULT_MARGIN = 4; -export const DEFAULT_MIN_HEIGHT = 80; -export const DEFAULT_MAX_HEIGHT = 400; -export const DEFAULT_MAX_WIDTH = 600; diff --git a/web/src/app/adwp/lib/core/constants/index.ts b/web/src/app/adwp/lib/core/constants/index.ts deleted file mode 100644 index 3cf4f6d7d0..0000000000 --- a/web/src/app/adwp/lib/core/constants/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './absolute-box-sizes'; diff --git a/web/src/app/adwp/lib/core/directives/click-outside/click-outside.directive.ts b/web/src/app/adwp/lib/core/directives/click-outside/click-outside.directive.ts deleted file mode 100644 index 514c0467db..0000000000 --- a/web/src/app/adwp/lib/core/directives/click-outside/click-outside.directive.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Directive, ElementRef, EventEmitter, HostListener, Output } from '@angular/core'; - -@Directive({ - selector: '[adwpClickOutside]' -}) -export class AdwpClickOutsideDirective { - constructor(private _elementRef: ElementRef) { - } - - @Output() - public adwpClickOutside = new EventEmitter(); - - @HostListener('document:click', ['$event', '$event.target']) - public onClick(event: MouseEvent, targetElement: HTMLElement): void { - if (!targetElement) { - return; - } - - const clickedInside = this._elementRef.nativeElement.contains(targetElement); - if (!clickedInside) { - this.adwpClickOutside.emit(event); - } - } -} diff --git a/web/src/app/adwp/lib/core/directives/click-outside/click-outside.module.ts b/web/src/app/adwp/lib/core/directives/click-outside/click-outside.module.ts deleted file mode 100644 index 845d682bd4..0000000000 --- a/web/src/app/adwp/lib/core/directives/click-outside/click-outside.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NgModule } from '@angular/core'; -import { AdwpClickOutsideDirective } from './click-outside.directive'; - -@NgModule({ - declarations: [AdwpClickOutsideDirective], - exports: [AdwpClickOutsideDirective], -}) -export class AdwpClickOutsideModule { -} diff --git a/web/src/app/adwp/lib/core/directives/click-outside/index.ts b/web/src/app/adwp/lib/core/directives/click-outside/index.ts deleted file mode 100644 index 01342bb803..0000000000 --- a/web/src/app/adwp/lib/core/directives/click-outside/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './click-outside.module'; -export * from './click-outside.directive'; diff --git a/web/src/app/adwp/lib/core/directives/dropdown/dropdown.directive.ts b/web/src/app/adwp/lib/core/directives/dropdown/dropdown.directive.ts deleted file mode 100644 index 58b3e5596a..0000000000 --- a/web/src/app/adwp/lib/core/directives/dropdown/dropdown.directive.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { - AfterViewChecked, - ComponentFactoryResolver, - Directive, - ElementRef, - forwardRef, - Inject, - Injector, - Input, - OnDestroy, -} from '@angular/core'; - -import { ADWP_DROPDOWN_DIRECTIVE } from '../../tokens'; -import { AbstractAdwpDropdown } from '../../abstract/abstract-dropdown'; -import { AdwpDropdown } from '../../interfaces/dropdown-directive'; -import { AdwpParentsScrollService } from '../../../cdk/services'; -import { AdwpPortalService } from '../../../cdk/components/portal-host/portal.service'; - -@Directive({ - selector: '[adwpDropdown]:not(ng-container)', - providers: [ - { - provide: ADWP_DROPDOWN_DIRECTIVE, - useExisting: forwardRef(() => AdwpDropdownDirective), - }, - AdwpParentsScrollService, - ], -}) -export class AdwpDropdownDirective - extends AbstractAdwpDropdown - implements AdwpDropdown, AfterViewChecked, OnDestroy { - @Input('adwpDropdown') - set open(value: boolean) { - if (value) { - this.openDropdownBox(); - } else { - this.closeDropdownBox(); - } - } - - constructor( - @Inject(ComponentFactoryResolver) - componentFactoryResolver: ComponentFactoryResolver, - @Inject(Injector) injector: Injector, - @Inject(AdwpPortalService) - portalService: AdwpPortalService, - @Inject(ElementRef) elementRef: ElementRef, - @Inject(AdwpParentsScrollService) readonly refresh$: AdwpParentsScrollService, - ) { - super(componentFactoryResolver, injector, portalService, elementRef); - } -} diff --git a/web/src/app/adwp/lib/core/directives/dropdown/dropdown.module.ts b/web/src/app/adwp/lib/core/directives/dropdown/dropdown.module.ts deleted file mode 100644 index 6ce6cf1055..0000000000 --- a/web/src/app/adwp/lib/core/directives/dropdown/dropdown.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { NgModule } from '@angular/core'; - -import { AdwpDropdownDirective } from './dropdown.directive'; -import { AdwpDropdownBoxModule } from '../../components/dropdown-box/dropdown-box.module'; - -@NgModule({ - imports: [AdwpDropdownBoxModule], - declarations: [AdwpDropdownDirective], - exports: [AdwpDropdownDirective], -}) -export class AdwpDropdownModule { -} diff --git a/web/src/app/adwp/lib/core/directives/dropdown/index.ts b/web/src/app/adwp/lib/core/directives/dropdown/index.ts deleted file mode 100644 index afdead73b7..0000000000 --- a/web/src/app/adwp/lib/core/directives/dropdown/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './dropdown.directive'; -export * from './dropdown.module'; diff --git a/web/src/app/adwp/lib/core/directives/index.ts b/web/src/app/adwp/lib/core/directives/index.ts deleted file mode 100644 index 3b88fb6a4b..0000000000 --- a/web/src/app/adwp/lib/core/directives/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './click-outside'; -export * from './dropdown'; diff --git a/web/src/app/adwp/lib/core/enums/dropdown-animation.ts b/web/src/app/adwp/lib/core/enums/dropdown-animation.ts deleted file mode 100644 index cf671b7532..0000000000 --- a/web/src/app/adwp/lib/core/enums/dropdown-animation.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const enum AdwpDropdownAnimation { - FadeInBottom = 'fadeInBottom', - FadeInTop = 'fadeInTop', -} diff --git a/web/src/app/adwp/lib/core/enums/index.ts b/web/src/app/adwp/lib/core/enums/index.ts deleted file mode 100644 index d1efb7891d..0000000000 --- a/web/src/app/adwp/lib/core/enums/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './dropdown-animation'; diff --git a/web/src/app/adwp/lib/core/index.ts b/web/src/app/adwp/lib/core/index.ts deleted file mode 100644 index cd1a52438e..0000000000 --- a/web/src/app/adwp/lib/core/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export * from './abstract'; -export * from './animations'; -export * from './components'; -export * from './directives'; -export * from './constants'; -export * from './enums'; -export * from './interfaces'; -export * from './tokens'; -export * from './types'; -export * from './utils'; diff --git a/web/src/app/adwp/lib/core/interfaces/animation-options.ts b/web/src/app/adwp/lib/core/interfaces/animation-options.ts deleted file mode 100644 index c02b5de319..0000000000 --- a/web/src/app/adwp/lib/core/interfaces/animation-options.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { AnimationOptions } from '@angular/animations'; - -export interface AdwpAnimationOptions extends AnimationOptions { - readonly value: string; -} diff --git a/web/src/app/adwp/lib/core/interfaces/dropdown-directive.ts b/web/src/app/adwp/lib/core/interfaces/dropdown-directive.ts deleted file mode 100644 index 29b35efda9..0000000000 --- a/web/src/app/adwp/lib/core/interfaces/dropdown-directive.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { PolymorpheusContent } from '@tinkoff/ng-polymorpheus'; -import { Observable } from 'rxjs'; -import { AdwpDropdownWidthT } from '../types'; -import { AdwpHorizontalDirection, AdwpVerticalDirection } from '../types'; - -export interface AdwpDropdown { - refresh$: Observable; - clientRect: ClientRect; - content: PolymorpheusContent; - host: HTMLElement; - align: AdwpHorizontalDirection; - minHeight: number; - maxHeight: number; - direction?: AdwpVerticalDirection | null; - limitMinWidth?: AdwpDropdownWidthT; - sided?: boolean; - fixed?: boolean; - context?: C; -} diff --git a/web/src/app/adwp/lib/core/interfaces/index.ts b/web/src/app/adwp/lib/core/interfaces/index.ts deleted file mode 100644 index abb6d49975..0000000000 --- a/web/src/app/adwp/lib/core/interfaces/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './animation-options'; diff --git a/web/src/app/adwp/lib/core/tokens/animation-options.ts b/web/src/app/adwp/lib/core/tokens/animation-options.ts deleted file mode 100644 index 45852d2a78..0000000000 --- a/web/src/app/adwp/lib/core/tokens/animation-options.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { AnimationOptions } from '@angular/animations'; -import { inject, InjectionToken } from '@angular/core'; -import { ADWP_ANIMATIONS_DURATION } from './animations-duration'; - -export const ADWP_ANIMATION_OPTIONS = new InjectionToken( - 'Options for Adwp UI animations', - { - factory: () => ({ - params: { - duration: inject(ADWP_ANIMATIONS_DURATION), - }, - }), - }, -); diff --git a/web/src/app/adwp/lib/core/tokens/animations-duration.ts b/web/src/app/adwp/lib/core/tokens/animations-duration.ts deleted file mode 100644 index 597e8ee84c..0000000000 --- a/web/src/app/adwp/lib/core/tokens/animations-duration.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {InjectionToken} from '@angular/core'; - -export const ADWP_ANIMATIONS_DURATION = new InjectionToken( - 'Duration of all Adwp UI animations in ms', - { - factory: () => 300, - }, -); diff --git a/web/src/app/adwp/lib/core/tokens/dropdown-directive.ts b/web/src/app/adwp/lib/core/tokens/dropdown-directive.ts deleted file mode 100644 index 50d50ae8df..0000000000 --- a/web/src/app/adwp/lib/core/tokens/dropdown-directive.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { InjectionToken } from '@angular/core'; -import { AdwpDropdown } from '../interfaces/dropdown-directive'; - -export const ADWP_DROPDOWN_DIRECTIVE = new InjectionToken( - 'Directive controlling AdwpDropdownBoxComponent', -); diff --git a/web/src/app/adwp/lib/core/tokens/index.ts b/web/src/app/adwp/lib/core/tokens/index.ts deleted file mode 100644 index 33ca8b47aa..0000000000 --- a/web/src/app/adwp/lib/core/tokens/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './animation-options'; -export * from './animations-duration'; -export * from './dropdown-directive'; diff --git a/web/src/app/adwp/lib/core/types/direction.ts b/web/src/app/adwp/lib/core/types/direction.ts deleted file mode 100644 index 46d69433a5..0000000000 --- a/web/src/app/adwp/lib/core/types/direction.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type AdwpHorizontalDirection = 'left' | 'right'; - -export type AdwpVerticalDirection = 'top' | 'bottom'; - -export type AdwpSideDirection = 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'; - -export type AdwpDirection = AdwpHorizontalDirection | AdwpSideDirection; diff --git a/web/src/app/adwp/lib/core/types/dropdown-width.ts b/web/src/app/adwp/lib/core/types/dropdown-width.ts deleted file mode 100644 index b8e0c2c8ea..0000000000 --- a/web/src/app/adwp/lib/core/types/dropdown-width.ts +++ /dev/null @@ -1 +0,0 @@ -export type AdwpDropdownWidthT = 'fixed' | 'min' | 'auto'; diff --git a/web/src/app/adwp/lib/core/types/index.ts b/web/src/app/adwp/lib/core/types/index.ts deleted file mode 100644 index 7d2af8083c..0000000000 --- a/web/src/app/adwp/lib/core/types/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './direction'; -export * from './dropdown-width'; diff --git a/web/src/app/adwp/lib/core/utils/dom/check-fixed-position.ts b/web/src/app/adwp/lib/core/utils/dom/check-fixed-position.ts deleted file mode 100644 index 5b56e1cef2..0000000000 --- a/web/src/app/adwp/lib/core/utils/dom/check-fixed-position.ts +++ /dev/null @@ -1,12 +0,0 @@ -export function checkFixedPosition(element: HTMLElement | null): boolean { - if (!element || typeof getComputedStyle === 'undefined') { - return false; - } - - const style = getComputedStyle(element); - - return ( - style.getPropertyValue('position') === 'fixed' || - checkFixedPosition(element.parentElement) - ); -} diff --git a/web/src/app/adwp/lib/core/utils/dom/index.ts b/web/src/app/adwp/lib/core/utils/dom/index.ts deleted file mode 100644 index 133f74dd12..0000000000 --- a/web/src/app/adwp/lib/core/utils/dom/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './check-fixed-position'; diff --git a/web/src/app/adwp/lib/core/utils/index.ts b/web/src/app/adwp/lib/core/utils/index.ts deleted file mode 100644 index 43f46bdef9..0000000000 --- a/web/src/app/adwp/lib/core/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './dom'; diff --git a/web/src/app/adwp/lib/dialog/ComponentData.ts b/web/src/app/adwp/lib/dialog/ComponentData.ts deleted file mode 100644 index 39442764b7..0000000000 --- a/web/src/app/adwp/lib/dialog/ComponentData.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { EventEmitter, Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class ComponentData { - path: string; - model: any; - emitter: EventEmitter; -} diff --git a/web/src/app/adwp/lib/dialog/dialog.component.html b/web/src/app/adwp/lib/dialog/dialog.component.html deleted file mode 100644 index 328f25688f..0000000000 --- a/web/src/app/adwp/lib/dialog/dialog.component.html +++ /dev/null @@ -1,20 +0,0 @@ -

{{ data.title || 'Notification' }}

- -
{{ data.text }}
- -
- - - - - - - - - - - - - diff --git a/web/src/app/adwp/lib/dialog/dialog.component.scss b/web/src/app/adwp/lib/dialog/dialog.component.scss deleted file mode 100644 index 4395736ec9..0000000000 --- a/web/src/app/adwp/lib/dialog/dialog.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -.warn { - margin-right: 30px; -} - -pre { - white-space: pre-wrap; -} diff --git a/web/src/app/adwp/lib/dialog/dialog.component.spec.ts b/web/src/app/adwp/lib/dialog/dialog.component.spec.ts deleted file mode 100644 index dc7e18a7a9..0000000000 --- a/web/src/app/adwp/lib/dialog/dialog.component.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AdwpDialogComponent } from './dialog.component'; -import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; - -describe('DialogComponent', () => { - let component: AdwpDialogComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ AdwpDialogComponent ], - providers: [ - { - provide: MatDialogRef, - useValue: {} - }, - { - provide: MAT_DIALOG_DATA, - useValue: {} - } - ], - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(AdwpDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/adwp/lib/dialog/dialog.component.ts b/web/src/app/adwp/lib/dialog/dialog.component.ts deleted file mode 100644 index 83d5b010b9..0000000000 --- a/web/src/app/adwp/lib/dialog/dialog.component.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Component, EventEmitter, Inject, Injector, OnInit, Type } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; - -import { ComponentData } from './ComponentData'; - -/** - * The 'abstract' component displayed in the dialog - * @template T the model passed to the component - */ -export interface AdwpDynamicComponent { - emitter?: EventEmitter; - model: T; - onEnterKey?: () => void; -} - -export interface DialogData { - title: string; - component: Type; - model?: any; - emitter?: EventEmitter; - text?: string; - controls?: any[] | any; - disabled?: boolean; -} - -@Component({ - selector: 'adwp-dialog', - templateUrl: './dialog.component.html', - styleUrls: ['./dialog.component.scss'], -}) -export class AdwpDialogComponent implements OnInit { - CurrentComponent: Type; - componentInjector: Injector; - - constructor( - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: DialogData, - private parentInjector: Injector - ) {} - - ngOnInit(): void { - this.buildComponent(); - } - - buildComponent(): void { - if (!this.data.component) { - return; - } - - this.CurrentComponent = this.data.component; - const { model, emitter } = this.data; - this.componentInjector = Injector.create({ - providers: [ - { - provide: ComponentData, - useValue: { - model, - emitter, - }, - deps: [], - }, - ], - parent: this.parentInjector, - }); - } - - noClick(): void { - this.dialogRef.close(); - } - - controlsIsArray(): boolean { - return Array.isArray(this.data.controls); - } -} diff --git a/web/src/app/adwp/lib/dialog/dialog.module.ts b/web/src/app/adwp/lib/dialog/dialog.module.ts deleted file mode 100644 index feda4cc164..0000000000 --- a/web/src/app/adwp/lib/dialog/dialog.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatDialogModule } from '@angular/material/dialog'; -import { MatIconModule } from '@angular/material/icon'; - -import { AdwpDialogComponent } from './dialog.component'; - - - -@NgModule({ - declarations: [AdwpDialogComponent], - imports: [ - CommonModule, - MatDialogModule, - MatButtonModule, - MatIconModule - ], - exports: [AdwpDialogComponent] -}) -export class AdwpDialogModule { } diff --git a/web/src/app/adwp/lib/footer/footer.module.ts b/web/src/app/adwp/lib/footer/footer.module.ts deleted file mode 100644 index e35558ebd8..0000000000 --- a/web/src/app/adwp/lib/footer/footer.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; - -import { FooterComponent } from './footer/footer.component'; -import { ConfigService } from '../services/config.service'; - -@NgModule({ - declarations: [ - FooterComponent, - ], - imports: [ - CommonModule, - ], - exports: [ - FooterComponent, - ], - providers: [ - ConfigService, - ] -}) -export class AdwpFooterModule { } diff --git a/web/src/app/adwp/lib/footer/footer/footer.component.html b/web/src/app/adwp/lib/footer/footer/footer.component.html deleted file mode 100644 index 01d285324e..0000000000 --- a/web/src/app/adwp/lib/footer/footer/footer.component.html +++ /dev/null @@ -1,14 +0,0 @@ - diff --git a/web/src/app/adwp/lib/footer/footer/footer.component.scss b/web/src/app/adwp/lib/footer/footer/footer.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/adwp/lib/footer/footer/footer.component.ts b/web/src/app/adwp/lib/footer/footer/footer.component.ts deleted file mode 100644 index db4a14e7e0..0000000000 --- a/web/src/app/adwp/lib/footer/footer/footer.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { ConfigService } from '../../services/config.service'; -import { IVersionInfo } from '../../models/version-info'; - -@Component({ - selector: 'adwp-footer', - templateUrl: './footer.component.html', - styleUrls: ['./footer.component.scss'] -}) -export class FooterComponent implements OnInit { - - currentYear = new Date().getFullYear(); - versionData: IVersionInfo; - - constructor( - private config: ConfigService, - ) { } - - ngOnInit(): void { - this.versionData = this.config.getVersion(this.versionData); - } - -} diff --git a/web/src/app/adwp/lib/form-element/controls/controls.component.html b/web/src/app/adwp/lib/form-element/controls/controls.component.html deleted file mode 100644 index 281de43e7f..0000000000 --- a/web/src/app/adwp/lib/form-element/controls/controls.component.html +++ /dev/null @@ -1,6 +0,0 @@ -

- - - -

diff --git a/web/src/app/adwp/lib/form-element/controls/controls.component.scss b/web/src/app/adwp/lib/form-element/controls/controls.component.scss deleted file mode 100644 index 3dc9a281bc..0000000000 --- a/web/src/app/adwp/lib/form-element/controls/controls.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -[hidden] { - display: none !important; -} diff --git a/web/src/app/adwp/lib/form-element/controls/controls.component.spec.ts b/web/src/app/adwp/lib/form-element/controls/controls.component.spec.ts deleted file mode 100644 index aa2ddf10db..0000000000 --- a/web/src/app/adwp/lib/form-element/controls/controls.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AdwpControlsComponent } from './controls.component'; - -describe('ControlsComponent', () => { - let component: AdwpControlsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ AdwpControlsComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(AdwpControlsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/adwp/lib/form-element/controls/controls.component.ts b/web/src/app/adwp/lib/form-element/controls/controls.component.ts deleted file mode 100644 index 4a6f24a5fa..0000000000 --- a/web/src/app/adwp/lib/form-element/controls/controls.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; - -@Component({ - selector: 'adwp-controls', - templateUrl: './controls.component.html', - styleUrls: ['./controls.component.scss'], -}) -export class AdwpControlsComponent { - @Input() title = 'Create'; - @Input() disabled: boolean; - @Input() hiddenSaveButton: boolean; - @Output() cancel = new EventEmitter(); - @Output() save = new EventEmitter(); - - @ViewChild('btn', { static: true, read: ElementRef }) saveBtn: ElementRef; - - oncancel(): void { - this.cancel.emit(); - } - - onsave(): void { - this.save.emit(); - } -} diff --git a/web/src/app/adwp/lib/form-element/field.directive.spec.ts b/web/src/app/adwp/lib/form-element/field.directive.spec.ts deleted file mode 100644 index 7f0e40e24b..0000000000 --- a/web/src/app/adwp/lib/form-element/field.directive.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { FieldDirective } from './field.directive'; - -describe('FieldDirective', () => { - it('should create an instance', () => { - const directive = new FieldDirective(); - expect(directive).toBeTruthy(); - }); -}); diff --git a/web/src/app/adwp/lib/form-element/field.directive.ts b/web/src/app/adwp/lib/form-element/field.directive.ts deleted file mode 100644 index 2d017b9b80..0000000000 --- a/web/src/app/adwp/lib/form-element/field.directive.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { IFieldOptions } from './../models/field-options'; -import { Directive, Input, OnInit } from '@angular/core'; -import { AbstractControl, FormGroup } from '@angular/forms'; - -@Directive({ - selector: '[adwpField]' -}) -export class FieldDirective implements OnInit { - - @Input() form: FormGroup; - @Input() field: IFieldOptions; - - ngOnInit(): void { - this.control.markAllAsTouched(); - } - - get control(): AbstractControl { - return this.form.controls[this.field.name]; - } - - get isValid(): boolean { - if (this.field.read_only) { return true; } - const control = this.control; - return control.valid && (control.dirty || control.touched); - } - - hasError(name: string): boolean { - return this.control.hasError(name); - } - -} diff --git a/web/src/app/adwp/lib/form-element/form-element.module.ts b/web/src/app/adwp/lib/form-element/form-element.module.ts deleted file mode 100644 index c6cfcbe5c6..0000000000 --- a/web/src/app/adwp/lib/form-element/form-element.module.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MatButtonModule } from '@angular/material/button'; -import { MatInputModule } from '@angular/material/input'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { AdwpInputComponent } from './input/input.component'; -import { FieldDirective } from './field.directive'; -import { AdwpControlsComponent } from './controls/controls.component'; -import { AdwpInputSelectComponent } from './input-select/input-select.component'; -import { AdwpSelectModule } from '../core'; - -@NgModule({ - declarations: [AdwpInputSelectComponent, AdwpInputComponent, FieldDirective, AdwpControlsComponent], - imports: [CommonModule, FormsModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatButtonModule, AdwpSelectModule], - exports: [AdwpInputSelectComponent, AdwpInputComponent, FieldDirective, AdwpControlsComponent], -}) -export class AdwpFormElementModule { -} diff --git a/web/src/app/adwp/lib/form-element/input-select/input-select.component.html b/web/src/app/adwp/lib/form-element/input-select/input-select.component.html deleted file mode 100644 index 035e4c4888..0000000000 --- a/web/src/app/adwp/lib/form-element/input-select/input-select.component.html +++ /dev/null @@ -1,20 +0,0 @@ -
- - - - - {{ label }} is required. - {{ label }} is not correct. - - - -
diff --git a/web/src/app/adwp/lib/form-element/input-select/input-select.component.scss b/web/src/app/adwp/lib/form-element/input-select/input-select.component.scss deleted file mode 100644 index 1185759cdd..0000000000 --- a/web/src/app/adwp/lib/form-element/input-select/input-select.component.scss +++ /dev/null @@ -1,14 +0,0 @@ -.row {display:flex;} - -::ng-deep .mat-form-field { - - &.mat-form-field-invalid { - - adwp-select { - - .mat-select-arrow { - color: #ff9800 !important; - } - } - } -} diff --git a/web/src/app/adwp/lib/form-element/input-select/input-select.component.ts b/web/src/app/adwp/lib/form-element/input-select/input-select.component.ts deleted file mode 100644 index 3391f3ca3e..0000000000 --- a/web/src/app/adwp/lib/form-element/input-select/input-select.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { AdwpIdentityMatcher, AdwpStringHandler } from '../../cdk'; - -@Component({ - selector: 'adwp-input-select', - templateUrl: './input-select.component.html', - styleUrls: ['./input-select.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class AdwpInputSelectComponent { - - @Input() form: FormGroup; - - @Input() controlName: string; - - @Input() options: T[]; - - @Input() multiple: boolean; - - @Input() label: string; - - @Input() handler: AdwpStringHandler; - - @Input() comparator: AdwpIdentityMatcher; - - @Input() isRequired = false; - - @Input() selectRowDisableCheck: (args: any) => boolean; - - @Output() filter: EventEmitter = new EventEmitter(); - - isError(name: string): boolean { - const f = this.form.get(name); - return f.invalid && (f.dirty || f.touched); - } - - hasError(name: string, error: string): boolean { - return this.form.controls[name].hasError(error); - } -} diff --git a/web/src/app/adwp/lib/form-element/input/input.component.html b/web/src/app/adwp/lib/form-element/input/input.component.html deleted file mode 100644 index a057c0391b..0000000000 --- a/web/src/app/adwp/lib/form-element/input/input.component.html +++ /dev/null @@ -1,14 +0,0 @@ -
- - - - {{ label }} is required. - {{ label }} is not correct. - {{ label }} is not match. - {{ label }} is not email. - {{ label }} max length exceeded. - {{ label }} too short. - - -
diff --git a/web/src/app/adwp/lib/form-element/input/input.component.scss b/web/src/app/adwp/lib/form-element/input/input.component.scss deleted file mode 100644 index 8e5f72e4ff..0000000000 --- a/web/src/app/adwp/lib/form-element/input/input.component.scss +++ /dev/null @@ -1 +0,0 @@ -.row {display:flex;} diff --git a/web/src/app/adwp/lib/form-element/input/input.component.spec.ts b/web/src/app/adwp/lib/form-element/input/input.component.spec.ts deleted file mode 100644 index 8f42d14a90..0000000000 --- a/web/src/app/adwp/lib/form-element/input/input.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AdwpInputComponent } from './input.component'; -import {FormControl, FormGroup} from "@angular/forms"; - -describe('InputComponent', () => { - let component: AdwpInputComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ AdwpInputComponent ] - }) - .compileComponents(); - }); - - beforeEach( async () => { - fixture = await TestBed.createComponent(AdwpInputComponent); - component = fixture.componentInstance; - component.form = new FormGroup({ name: new FormControl() }); - component.label = 'Group name'; - component.controlName = 'name'; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/adwp/lib/form-element/input/input.component.ts b/web/src/app/adwp/lib/form-element/input/input.component.ts deleted file mode 100644 index 3130282ab3..0000000000 --- a/web/src/app/adwp/lib/form-element/input/input.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { FormGroup } from '@angular/forms'; - -@Component({ - selector: 'adwp-input', - templateUrl: './input.component.html', - styleUrls: ['./input.component.scss'], -}) -export class AdwpInputComponent { - @Input() form: FormGroup; - @Input() controlName: string; - @Input() label: string; - @Input() isRequired = false; - @Input() type: 'button' | 'checkbox' | 'file' | 'hidden' | 'image' | 'password' | 'radio' | 'reset' | 'submit' | 'text' = 'text'; - - isError(name: string): boolean { - const f = this.form.get(name); - return f.invalid && (f.dirty || f.touched); - } - - hasError(name: string, error: string): boolean { - return this.form.controls[name].hasError(error); - } -} diff --git a/web/src/app/adwp/lib/header/header.module.ts b/web/src/app/adwp/lib/header/header.module.ts deleted file mode 100644 index 178c226b7e..0000000000 --- a/web/src/app/adwp/lib/header/header.module.ts +++ /dev/null @@ -1,24 +0,0 @@ - -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { MatListModule } from '@angular/material/list'; -import { MatToolbarModule } from '@angular/material/toolbar'; -import { RouterModule } from '@angular/router'; - -import { TopMenuComponent } from './top-menu/top-menu.component'; - -@NgModule({ - declarations: [ - TopMenuComponent, - ], - imports: [ - CommonModule, - RouterModule, - MatToolbarModule, - MatListModule, - ], - exports: [ - TopMenuComponent, - ] -}) -export class AdwpHeaderModule { } diff --git a/web/src/app/adwp/lib/header/top-menu/top-menu.component.html b/web/src/app/adwp/lib/header/top-menu/top-menu.component.html deleted file mode 100644 index 704898cf59..0000000000 --- a/web/src/app/adwp/lib/header/top-menu/top-menu.component.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - {{ item.label }} - - - - - - - - diff --git a/web/src/app/adwp/lib/header/top-menu/top-menu.component.scss b/web/src/app/adwp/lib/header/top-menu/top-menu.component.scss deleted file mode 100644 index 2af89ac353..0000000000 --- a/web/src/app/adwp/lib/header/top-menu/top-menu.component.scss +++ /dev/null @@ -1,38 +0,0 @@ -@import '~@angular/material/theming'; - -mat-toolbar { - @include mat-elevation(6); - height: auto; - padding: 6px 16px; - background-color: #333c47; - margin-bottom: 0; -} - -mat-nav-list { - display: flex; - justify-content: center; - height: 40px; - justify-items: baseline; - padding: 0; - - & a { - font-size: 14px; - color: mat-color($mat-green, A400); - width: auto; - height: 40px; - } -} - -a { - display: flex; - align-items: center; - - img { - height: 40px; - vertical-align: bottom; - } - - &:hover { - text-decoration: none; - } -} diff --git a/web/src/app/adwp/lib/header/top-menu/top-menu.component.ts b/web/src/app/adwp/lib/header/top-menu/top-menu.component.ts deleted file mode 100644 index e3aed2398a..0000000000 --- a/web/src/app/adwp/lib/header/top-menu/top-menu.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import { IMenuItem } from '../../models/menu-item'; - - -@Component({ - selector: 'adwp-top-menu', - templateUrl: './top-menu.component.html', - styleUrls: ['./top-menu.component.scss'], -}) -export class TopMenuComponent{ - @Input() appName = ''; - @Input() logoPath = ''; - @Input() items: IMenuItem[] = []; -} diff --git a/web/src/app/adwp/lib/helpers/cookie.ts b/web/src/app/adwp/lib/helpers/cookie.ts deleted file mode 100644 index 1dccca1efe..0000000000 --- a/web/src/app/adwp/lib/helpers/cookie.ts +++ /dev/null @@ -1,13 +0,0 @@ -export class Cookie { - - // returns the cookie with the given name, - // or undefined if not found - // https://javascript.info/cookie#getcookie-name - static get(name: string): string | undefined { - const matches = document.cookie.match(new RegExp( - '(?:^|; )' + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=([^;]*)' - )); - return matches ? decodeURIComponent(matches[1]) : undefined; - } - -} diff --git a/web/src/app/adwp/lib/helpers/event-helper.ts b/web/src/app/adwp/lib/helpers/event-helper.ts deleted file mode 100644 index 51eb45b797..0000000000 --- a/web/src/app/adwp/lib/helpers/event-helper.ts +++ /dev/null @@ -1,9 +0,0 @@ -export class EventHelper { - - static stopPropagation(event: MouseEvent): void { - if (event && event.stopPropagation) { - event.stopPropagation(); - } - } - -} diff --git a/web/src/app/adwp/lib/helpers/guid.ts b/web/src/app/adwp/lib/helpers/guid.ts deleted file mode 100644 index 0f887ffe9b..0000000000 --- a/web/src/app/adwp/lib/helpers/guid.ts +++ /dev/null @@ -1,15 +0,0 @@ -export class GUID { - - static generate(): string { - - function s4(): string { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - } - - return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); - } - -} - diff --git a/web/src/app/adwp/lib/http-interceptors/django-interceptor.ts b/web/src/app/adwp/lib/http-interceptors/django-interceptor.ts deleted file mode 100644 index 4ab63eb501..0000000000 --- a/web/src/app/adwp/lib/http-interceptors/django-interceptor.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpInterceptor } from '@angular/common/http'; -import { HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { Cookie } from '../helpers/cookie'; -import { AuthService } from '../services/auth.service'; - -@Injectable() -export class DjangoInterceptor implements HttpInterceptor { - - readonly HEADER_NAME = 'X-CSRFToken'; - - constructor( - private authService: AuthService, - ) {} - - intercept(req: HttpRequest, next: HttpHandler): Observable> { - const tokenCookieName = this.authService.getTokenCookieName(); - if (tokenCookieName) { - const token = Cookie.get(tokenCookieName); - if (token !== undefined && !req.headers.has(this.HEADER_NAME) && ['POST', 'PUT', 'DELETE', 'PATCH'].includes(req.method)) { - req = req.clone({ headers: req.headers.set(this.HEADER_NAME, token) }); - } - } - return next.handle(req); - } - -} diff --git a/web/src/app/adwp/lib/list-storage/list-storage.module.ts b/web/src/app/adwp/lib/list-storage/list-storage.module.ts deleted file mode 100644 index 5b65835205..0000000000 --- a/web/src/app/adwp/lib/list-storage/list-storage.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { NgModule } from '@angular/core'; - -import { ListStorageService } from '../services/list-storage.service'; - -@NgModule({ - providers: [ListStorageService], -}) -export class AdwpListStorageModule { } diff --git a/web/src/app/adwp/lib/list/cell/component-cell.component.ts b/web/src/app/adwp/lib/list/cell/component-cell.component.ts deleted file mode 100644 index 3ece2a2144..0000000000 --- a/web/src/app/adwp/lib/list/cell/component-cell.component.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Component, ComponentRef, Input, OnInit } from '@angular/core'; - -import { AdwpCellComponent, IComponentColumn } from '../../models/list'; -import { ComponentHolderDirective } from '../component-holder.directive'; - -@Component({ - selector: 'adwp-component-cell', - template: ``, -}) -export class ComponentCellComponent extends ComponentHolderDirective implements OnInit { - - @Input() component: AdwpCellComponent; - - private ownColumn: IComponentColumn; - @Input() set column(column: IComponentColumn) { - this.ownColumn = column; - this.setData(); - } - get column(): IComponentColumn { - return this.ownColumn; - } - - componentRef: ComponentRef>; - - setData(): void { - if (this.componentRef) { - this.componentRef.instance.row = this.row; - this.componentRef.instance.column = this.column; - - if (this.column && this.column.instanceTaken) { - this.column.instanceTaken(this.componentRef); - } - } - } - -} diff --git a/web/src/app/adwp/lib/list/cell/link-cell.component.ts b/web/src/app/adwp/lib/list/cell/link-cell.component.ts deleted file mode 100644 index 7202c678f6..0000000000 --- a/web/src/app/adwp/lib/list/cell/link-cell.component.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import { ILinkColumn } from '../../models/list'; - -@Component({ - selector: 'adwp-link-cell', - template: ` - - {{ row | listValue : column.value }} - - `, - styles: [` - :host { - width: 100%; - height: 100%; - display: block; - box-sizing: border-box; - } - - .link { - border-radius: 8px; - padding: 4px; - text-decoration: none; - width: 100%; - height: 100%; - display: block; - box-sizing: border-box; - } - - .link:hover { - background: #424242; - } - `] -}) -export class LinkCellComponent { - - @Input() row: any; - @Input() column: ILinkColumn; - - clickOnLink(event: MouseEvent): void { - if (event && event.stopPropagation) { - event.stopPropagation(); - } - } - -} diff --git a/web/src/app/adwp/lib/list/component-holder.directive.ts b/web/src/app/adwp/lib/list/component-holder.directive.ts deleted file mode 100644 index ec0b75cdc0..0000000000 --- a/web/src/app/adwp/lib/list/component-holder.directive.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ComponentFactoryResolver, ComponentRef, Directive, Input, OnInit, ViewContainerRef } from '@angular/core'; - -import { BaseDirective } from '../models/base.directive'; -import { AdwpComponentHolder } from '../models/list'; - -@Directive() -export abstract class ComponentHolderDirective extends BaseDirective implements OnInit { - - @Input() component: AdwpComponentHolder; - - private ownRow: T; - @Input() set row(row: T) { - this.ownRow = row; - this.setData(); - } - get row(): T { - return this.ownRow; - } - - componentRef: ComponentRef>; - - constructor( - protected componentFactoryResolver: ComponentFactoryResolver, - protected viewContainerRef: ViewContainerRef, - ) { - super(); - } - - abstract setData(): void; - - ngOnInit(): void { - const componentFactory = - this.componentFactoryResolver.resolveComponentFactory(this.component as any); - this.viewContainerRef.clear(); - this.componentRef = this.viewContainerRef.createComponent(componentFactory) as any; - this.setData(); - } - -} diff --git a/web/src/app/adwp/lib/list/hover.directive.ts b/web/src/app/adwp/lib/list/hover.directive.ts deleted file mode 100644 index fc6749560f..0000000000 --- a/web/src/app/adwp/lib/list/hover.directive.ts +++ /dev/null @@ -1,22 +0,0 @@ - -import { Directive, ElementRef, HostListener } from '@angular/core'; - - -@Directive({ - selector: '[adwpHover]', -}) -export class HoverDirective { - constructor(private el: ElementRef) {} - - @HostListener('mouseenter') - onmouseenter(): void { - this.el.nativeElement.style.backgroundColor = 'rgba(255, 255, 255, 0.12)'; - this.el.nativeElement.style.cursor = 'pointer'; - } - - @HostListener('mouseleave') - onmouseleave(): void { - this.el.nativeElement.style.backgroundColor = 'transparent'; - this.el.nativeElement.style.cursor = 'defautl'; - } -} diff --git a/web/src/app/adwp/lib/list/list-config.service.ts b/web/src/app/adwp/lib/list/list-config.service.ts deleted file mode 100644 index 6089d7792f..0000000000 --- a/web/src/app/adwp/lib/list/list-config.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { InjectionToken } from '@angular/core'; -import { ListConfig } from './list-config'; - -export const ListConfigService = new InjectionToken('ListConfig'); diff --git a/web/src/app/adwp/lib/list/list-config.ts b/web/src/app/adwp/lib/list/list-config.ts deleted file mode 100644 index 701db3570e..0000000000 --- a/web/src/app/adwp/lib/list/list-config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ListConfig { - itemsPerPage: number[]; -} diff --git a/web/src/app/adwp/lib/list/list.module.ts b/web/src/app/adwp/lib/list/list.module.ts deleted file mode 100644 index 4ce28c00c8..0000000000 --- a/web/src/app/adwp/lib/list/list.module.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { ModuleWithProviders, NgModule } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatPaginatorModule } from '@angular/material/paginator'; -import { MatSortModule } from '@angular/material/sort'; -import { MatTableModule } from '@angular/material/table'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { RouterModule } from '@angular/router'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatSelectModule } from '@angular/material/select'; -import { FormsModule } from '@angular/forms'; - -import { HoverDirective } from './hover.directive'; -import { ListComponent } from './list/list.component'; -import { TimePipe } from './pipes/time.pipe'; -import { AsStringPipe } from './pipes/as-string.pipe'; -import { ComponentCellComponent } from './cell/component-cell.component'; -import { ListConfig } from './list-config'; -import { ListConfigService } from './list-config.service'; -import { ListValuePipe } from './pipes/list-value.pipe'; -import { CalcDynamicCellPipe } from './pipes/calc-dynamic-cell.pipe'; -import { TableComponent } from './table/table.component'; -import { PaginatorComponent } from './paginator/paginator.component'; -import { PagesPipe } from './pipes/pages.pipe'; -import { LinkCellComponent } from './cell/link-cell.component'; -import { ComponentRowComponent } from './row/component-row.component'; -import { CalcLinkCellPipe } from './pipes/calc-link-cell.pipe'; -import { IsAllCheckedPipe } from './pipes/is-all-checked.pipe'; -import { ListCheckboxDisabledPipe } from './pipes/list-checkbox-disabled.pipe'; -import { IsIndeterminateCheckedPipe } from './pipes/is-indeterminate-checked.pipe'; -import { IsMainCheckboxDisabledPipe } from './pipes/is-main-checkbox-disabled.pipe'; - -const Material = [ - MatTableModule, - MatPaginatorModule, - MatSortModule, - MatIconModule, - MatButtonModule, - MatTooltipModule, - MatFormFieldModule, - MatSelectModule, - MatCheckboxModule, -]; - -@NgModule({ - declarations: [ - ListComponent, - HoverDirective, - TimePipe, - ListValuePipe, - ListCheckboxDisabledPipe, - IsIndeterminateCheckedPipe, - IsMainCheckboxDisabledPipe, - AsStringPipe, - ComponentCellComponent, - ComponentRowComponent, - CalcDynamicCellPipe, - TableComponent, - PaginatorComponent, - PagesPipe, - LinkCellComponent, - CalcLinkCellPipe, - IsAllCheckedPipe, - ], - imports: [CommonModule, RouterModule, FormsModule, ...Material], - exports: [ListComponent, TableComponent, TimePipe, LinkCellComponent], -}) -export class AdwpListModule { - - public static forRoot(config: ListConfig): ModuleWithProviders { - return { - ngModule: AdwpListModule, - providers: [ - { - provide: ListConfigService, - useValue: config, - } - ] - }; - } - -} diff --git a/web/src/app/adwp/lib/list/list/list.component.html b/web/src/app/adwp/lib/list/list/list.component.html deleted file mode 100644 index 132a584a47..0000000000 --- a/web/src/app/adwp/lib/list/list/list.component.html +++ /dev/null @@ -1,24 +0,0 @@ - - - diff --git a/web/src/app/adwp/lib/list/list/list.component.scss b/web/src/app/adwp/lib/list/list/list.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/adwp/lib/list/list/list.component.spec.ts b/web/src/app/adwp/lib/list/list/list.component.spec.ts deleted file mode 100644 index 280059c06f..0000000000 --- a/web/src/app/adwp/lib/list/list/list.component.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ - - -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ListComponent } from './list.component'; -import { ListConfigService } from "@app/adwp/lib/list/list-config.service"; -import { config } from "rxjs"; - -describe('ListComponent', () => { - let component: ListComponent; - let fixture: ComponentFixture>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ ListComponent ], - providers: [ - { - provide: ListConfigService, - useValue: config, - } - ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/adwp/lib/list/list/list.component.ts b/web/src/app/adwp/lib/list/list/list.component.ts deleted file mode 100644 index d2b04e962b..0000000000 --- a/web/src/app/adwp/lib/list/list/list.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { - Component, - EventEmitter, - Inject, - Input, - Output, - ViewChild, -} from '@angular/core'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; -import { Sort } from '@angular/material/sort'; -import { MatCheckboxChange } from '@angular/material/checkbox'; - -import { BaseDirective } from '../../models/base.directive'; -import { ListConfig } from '../list-config'; -import { ListConfigService } from '../list-config.service'; -import { AdwpRowComponentType, ChoiceEventData, IColumns, InstanceTakenFunc } from '../../models/list'; -import { TableComponent } from '../table/table.component'; - -export interface Paging { - pageIndex: number; - pageSize: number; -} - -@Component({ - selector: 'adwp-list', - templateUrl: './list.component.html', - styleUrls: ['./list.component.scss'], -}) -export class ListComponent extends BaseDirective { - - @ViewChild(TableComponent, { static: false }) table: TableComponent; - - @Input() columns: IColumns; - @Input() dataSource: { results: T[]; count: number; }; - @Input() paging: Paging; - @Input() sort: Sort; - @Input() defaultSort: Sort; - @Input() currentId: number; - @Input() isRowInactiveHandler: (args: any) => boolean; - - @Input() expandedRow: AdwpRowComponentType; - @Input() expandedRowClassName: string; - @Input() expandedRowInstanceTaken: InstanceTakenFunc; - - @Output() clickRow = new EventEmitter<{row: any, event: MouseEvent}>(); - @Output() auxclickRow = new EventEmitter<{row: any, event: MouseEvent}>(); - @Output() changePaging = new EventEmitter(); - @Output() changeSort = new EventEmitter(); - - @Output() choose = new EventEmitter>(); - @Output() chooseAll = new EventEmitter(); - - @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; - - constructor( - @Inject(ListConfigService) public config: ListConfig, - ) { - super(); - } - - sortChange(a: Sort): void { - this.changeSort.emit(a); - } - - pageHandler(pe: PageEvent): void { - this.changePaging.emit({ pageIndex: pe.pageIndex + 1, pageSize: pe.pageSize }); - } - -} diff --git a/web/src/app/adwp/lib/list/paginator/paginator.component.html b/web/src/app/adwp/lib/list/paginator/paginator.component.html deleted file mode 100644 index 9c5792de08..0000000000 --- a/web/src/app/adwp/lib/list/paginator/paginator.component.html +++ /dev/null @@ -1,104 +0,0 @@ -
-
- -
- - - - - ... - - - {{ page }} - - - ... - - - - -
- -
-
- {{_intl.itemsPerPageLabel}} -
- - - - - {{pageSizeOption}} - - - - -
{{pageSize}}
-
- -
-
diff --git a/web/src/app/adwp/lib/list/paginator/paginator.component.scss b/web/src/app/adwp/lib/list/paginator/paginator.component.scss deleted file mode 100644 index da74379dce..0000000000 --- a/web/src/app/adwp/lib/list/paginator/paginator.component.scss +++ /dev/null @@ -1,77 +0,0 @@ -$mat-paginator-padding: 0 8px; -$mat-paginator-page-size-margin-right: 8px; - -$mat-paginator-items-per-page-label-margin: 0 4px; -$mat-paginator-selector-margin: 6px 4px 0 4px; -$mat-paginator-selector-trigger-width: 56px; -$mat-paginator-selector-trigger-outline-width: 64px; -$mat-paginator-selector-trigger-fill-width: 64px; - -$mat-paginator-range-label-margin: 0 32px 0 24px; -$mat-paginator-button-icon-size: 28px; - -.mat-paginator { - display: block; -} - -// Note: this wrapper element is only used to get the flexbox vertical centering to work -// with the `min-height` on IE11. It can be removed if we drop support for IE. -.mat-paginator-outer-container { - display: flex; -} - -.mat-paginator-container { - display: flex; - align-items: center; - justify-content: flex-end; - padding: $mat-paginator-padding; - flex-wrap: wrap-reverse; - width: 100%; -} - -.mat-paginator-page-size { - display: flex; - align-items: baseline; - margin-right: $mat-paginator-page-size-margin-right; - - [dir='rtl'] & { - margin-right: 0; - margin-left: $mat-paginator-page-size-margin-right; - } -} - -.mat-paginator-page-size-label { - margin: $mat-paginator-items-per-page-label-margin; -} - -.mat-paginator-page-size-select { - margin: $mat-paginator-selector-margin; - width: $mat-paginator-selector-trigger-width; - - &.mat-form-field-appearance-outline { - width: $mat-paginator-selector-trigger-outline-width; - } - - &.mat-form-field-appearance-fill { - width: $mat-paginator-selector-trigger-fill-width; - } -} - -.mat-paginator-range-label { - margin: $mat-paginator-range-label-margin; -} - -.mat-paginator-range-actions { - display: flex; - align-items: center; -} - -.mat-paginator-icon { - width: $mat-paginator-button-icon-size; - fill: currentColor; - - [dir='rtl'] & { - transform: rotate(180deg); - } -} - diff --git a/web/src/app/adwp/lib/list/paginator/paginator.component.ts b/web/src/app/adwp/lib/list/paginator/paginator.component.ts deleted file mode 100644 index 2eb574b94a..0000000000 --- a/web/src/app/adwp/lib/list/paginator/paginator.component.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { - Component, - ChangeDetectionStrategy, - ViewEncapsulation, - ChangeDetectorRef, - Inject, - Optional, - Input, - HostBinding, -} from '@angular/core'; -import { - MatPaginatorDefaultOptions, - MatPaginator, - MatPaginatorIntl, - MAT_PAGINATOR_DEFAULT_OPTIONS, -} from '@angular/material/paginator'; - -@Component({ - selector: 'adwp-paginator', - exportAs: 'adwpPaginator', - templateUrl: './paginator.component.html', - styleUrls: ['./paginator.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None, -}) -export class PaginatorComponent extends MatPaginator { - - @Input() disabled: boolean; - @HostBinding('class') klass = 'mat-paginator'; - - constructor(intl: MatPaginatorIntl, - changeDetectorRef: ChangeDetectorRef, - @Optional() @Inject(MAT_PAGINATOR_DEFAULT_OPTIONS) defaults?: MatPaginatorDefaultOptions) { - super(intl, changeDetectorRef, defaults); - } - - goto(page: number): void { - const previousPageIndex = this.pageIndex; - this.pageIndex = page - 1; - this.page.emit({ - previousPageIndex, - pageIndex: this.pageIndex, - pageSize: this.pageSize, - length: this.length, - }); - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/as-string.pipe.ts b/web/src/app/adwp/lib/list/pipes/as-string.pipe.ts deleted file mode 100644 index 752fc6eace..0000000000 --- a/web/src/app/adwp/lib/list/pipes/as-string.pipe.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'asString' -}) -export class AsStringPipe implements PipeTransform { - - transform(value: any): string { - return value as string; - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/calc-dynamic-cell.pipe.ts b/web/src/app/adwp/lib/list/pipes/calc-dynamic-cell.pipe.ts deleted file mode 100644 index a617c55144..0000000000 --- a/web/src/app/adwp/lib/list/pipes/calc-dynamic-cell.pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import { DynamicColumnFunc, ICell } from '../../models/list'; - -@Pipe({ - name: 'calcDynamicCell' -}) -export class CalcDynamicCellPipe implements PipeTransform { - - transform(row: any, func: DynamicColumnFunc): ICell { - return func(row); - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/calc-link-cell.pipe.ts b/web/src/app/adwp/lib/list/pipes/calc-link-cell.pipe.ts deleted file mode 100644 index d5b63a04dc..0000000000 --- a/web/src/app/adwp/lib/list/pipes/calc-link-cell.pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import { UrlColumnFunc } from '../../models/list'; - -@Pipe({ - name: 'calcLinkCell' -}) -export class CalcLinkCellPipe implements PipeTransform { - - transform(row: any, func: UrlColumnFunc): string { - return func(row); - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/is-all-checked.pipe.ts b/web/src/app/adwp/lib/list/pipes/is-all-checked.pipe.ts deleted file mode 100644 index 1df453c765..0000000000 --- a/web/src/app/adwp/lib/list/pipes/is-all-checked.pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { MatTableDataSource } from '@angular/material/table'; - -@Pipe({ - name: 'isAllChecked', - pure: false, -}) -export class IsAllCheckedPipe implements PipeTransform { - - transform(data: MatTableDataSource, modelKey: string): boolean { - return !!data.data?.length && data.data.every(item => !!item[modelKey]); - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/is-indeterminate-checked.pipe.ts b/web/src/app/adwp/lib/list/pipes/is-indeterminate-checked.pipe.ts deleted file mode 100644 index 1bc7630b96..0000000000 --- a/web/src/app/adwp/lib/list/pipes/is-indeterminate-checked.pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { MatTableDataSource } from '@angular/material/table'; - -@Pipe({ - name: 'isIndeterminateChecked', - pure: false, -}) -export class IsIndeterminateCheckedPipe implements PipeTransform { - - transform(data: MatTableDataSource, modelKey: string): boolean { - return !!data.data?.length && data.data.some(item => !!item[modelKey]) && data.data.some(item => !item[modelKey]); - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/is-main-checkbox-disabled.pipe.ts b/web/src/app/adwp/lib/list/pipes/is-main-checkbox-disabled.pipe.ts deleted file mode 100644 index b6c23b1867..0000000000 --- a/web/src/app/adwp/lib/list/pipes/is-main-checkbox-disabled.pipe.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { MatTableDataSource } from '@angular/material/table'; -import {DisabledCheckboxFunc} from "../../models/list"; - -@Pipe({ - name: 'isMainCheckboxDisabled', - pure: false, -}) -export class IsMainCheckboxDisabledPipe implements PipeTransform { - - transform(data: MatTableDataSource, isDisabled: DisabledCheckboxFunc): boolean { - return !data.data?.length || data.data.every(item => isDisabled && isDisabled(item)); - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/list-checkbox-disabled.pipe.ts b/web/src/app/adwp/lib/list/pipes/list-checkbox-disabled.pipe.ts deleted file mode 100644 index 956df88291..0000000000 --- a/web/src/app/adwp/lib/list/pipes/list-checkbox-disabled.pipe.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import {CellValueType, DisabledCheckboxFunc, ValueFunc} from '../../models/list'; - -@Pipe({ - name: 'listCheckboxDisabled' -}) -export class ListCheckboxDisabledPipe implements PipeTransform { - - transform(row: any, func: DisabledCheckboxFunc): boolean { - return func && func(row); - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/list-value.pipe.ts b/web/src/app/adwp/lib/list/pipes/list-value.pipe.ts deleted file mode 100644 index cdd442c7e8..0000000000 --- a/web/src/app/adwp/lib/list/pipes/list-value.pipe.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { CellValueType, ValueFunc } from '../../models/list'; - -@Pipe({ - name: 'listValue' -}) -export class ListValuePipe implements PipeTransform { - - transform(row: any, func: ValueFunc): CellValueType { - return func(row); - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/pages.pipe.ts b/web/src/app/adwp/lib/list/pipes/pages.pipe.ts deleted file mode 100644 index 2da7b3ada1..0000000000 --- a/web/src/app/adwp/lib/list/pipes/pages.pipe.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'pages' -}) -export class PagesPipe implements PipeTransform { - - transform(numberOfPages: number): Array { - const ownPages = []; - for (let index = 1; index <= numberOfPages; index++) { - ownPages.push(index); - } - return ownPages; - } - -} diff --git a/web/src/app/adwp/lib/list/pipes/time.pipe.spec.ts b/web/src/app/adwp/lib/list/pipes/time.pipe.spec.ts deleted file mode 100644 index c6d585714b..0000000000 --- a/web/src/app/adwp/lib/list/pipes/time.pipe.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { TimePipe } from './time.pipe'; - -describe('TimePipe', () => { - it('create an instance', () => { - const pipe = new TimePipe(); - expect(pipe).toBeTruthy(); - }); -}); diff --git a/web/src/app/adwp/lib/list/pipes/time.pipe.ts b/web/src/app/adwp/lib/list/pipes/time.pipe.ts deleted file mode 100644 index 0a066c2ef7..0000000000 --- a/web/src/app/adwp/lib/list/pipes/time.pipe.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { DateTime } from 'luxon'; - -export type ApiTime = string; - -@Pipe({ - name: 'time' -}) -export class TimePipe implements PipeTransform { - - transform(time: ApiTime): string { - return time ? DateTime.fromISO(time).toFormat('yyyy.LL.dd HH:mm:ss') : ''; - } - -} diff --git a/web/src/app/adwp/lib/list/row/component-row.component.ts b/web/src/app/adwp/lib/list/row/component-row.component.ts deleted file mode 100644 index 771b87ef65..0000000000 --- a/web/src/app/adwp/lib/list/row/component-row.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; - -import { ComponentHolderDirective } from '../component-holder.directive'; -import { InstanceTakenFunc } from '../../models/list'; - -@Component({ - selector: 'adwp-component-row', - template: ``, -}) -export class ComponentRowComponent extends ComponentHolderDirective implements OnInit { - - @Input() instanceTaken?: InstanceTakenFunc; - - setData(): void { - if (this.componentRef) { - this.componentRef.instance.row = this.row; - - if (this.instanceTaken) { - this.instanceTaken(this.componentRef); - } - } - } - -} diff --git a/web/src/app/adwp/lib/list/table/table.component.html b/web/src/app/adwp/lib/list/table/table.component.html deleted file mode 100644 index cb00b51f95..0000000000 --- a/web/src/app/adwp/lib/list/table/table.component.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - {{ column.label }} - - - - - - - - {{ item | listValue : column.value }} - - {{ item | listValue : column.value | asString | time }} - - - - - - - - - - - - - - {{ (item | calcDynamicCell : column.handle).value }} - - - - - - - - - - - - - - - - diff --git a/web/src/app/adwp/lib/list/table/table.component.scss b/web/src/app/adwp/lib/list/table/table.component.scss deleted file mode 100644 index 5066eb0d93..0000000000 --- a/web/src/app/adwp/lib/list/table/table.component.scss +++ /dev/null @@ -1,6 +0,0 @@ -mat-row.inactive { - - mat-cell:not([class^="choice-column"]) { - color: rgba(255, 255, 255, 0.5); - } -} diff --git a/web/src/app/adwp/lib/list/table/table.component.spec.ts b/web/src/app/adwp/lib/list/table/table.component.spec.ts deleted file mode 100644 index ab565d6efd..0000000000 --- a/web/src/app/adwp/lib/list/table/table.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { TableComponent } from './table.component'; - -describe('TableComponent', () => { - let component: TableComponent; - let fixture: ComponentFixture>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ TableComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TableComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/adwp/lib/list/table/table.component.ts b/web/src/app/adwp/lib/list/table/table.component.ts deleted file mode 100644 index 47c711ee81..0000000000 --- a/web/src/app/adwp/lib/list/table/table.component.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core'; -import { MatTableDataSource } from '@angular/material/table'; -import { MatSort, Sort } from '@angular/material/sort'; -import { MatCheckboxChange } from '@angular/material/checkbox'; - -import { AdwpRowComponentType, ButtonCallback, ChoiceEventData, IColumn, IColumns, InstanceTakenFunc } from '../../models/list'; -import { GUID } from '../../helpers/guid'; -import { Entity } from '../../models/entity'; -import { EventHelper } from '../../helpers/event-helper'; -import { BaseDirective } from '../../models/base.directive'; -import { RowEventData } from '../../models/list'; - -@Component({ - selector: 'adwp-table', - templateUrl: './table.component.html', - styleUrls: ['./table.component.scss'] -}) -export class TableComponent extends BaseDirective { - - @ViewChild(MatSort, { static: false }) sort: MatSort; - - headerRow: string[]; - - ownColumns: IColumns; - @Input() set columns(columns: IColumns) { - this.headerRow = []; - columns.forEach((column) => { - const guid = GUID.generate(); - this.headerRow.push(guid); - column.guid = guid; - }); - this.ownColumns = columns; - } - - ownExpandedRow: AdwpRowComponentType; - @Input() set expandedRow(expandedRow: AdwpRowComponentType) { - this.ownExpandedRow = expandedRow; - } - - get expandedRow(): AdwpRowComponentType { - return this.ownExpandedRow; - } - - @Input() expandedRowClassName: string; - - @Input() expandedRowInstanceTaken: InstanceTakenFunc; - - data: MatTableDataSource = new MatTableDataSource([]); - - @Input() set dataSource(data: { results: any; count: number }) { - if (data) { - const list = data.results; - this.data = new MatTableDataSource(list); - } - } - - @Input() rowStatusChecker: (args: any) => boolean; - - @Input() order: Sort; - @Input() defaultOrder: Sort; - - @Input() currentId: number; - - @Input() headerRowClassName: string; - - @Output() clickRow = new EventEmitter(); - @Output() auxclickRow = new EventEmitter(); - @Output() sortChange = new EventEmitter(); - - @Output() choose = new EventEmitter>(); - @Output() chooseAll = new EventEmitter(); - - changeSort(sort: Sort): void { - if (sort.direction) { - this.sortChange.emit(sort); - } else { - this.sortChange.emit(this.defaultOrder); - } - } - - invokeCallback(callback: ButtonCallback, row: any, event: MouseEvent): void { - EventHelper.stopPropagation(event); - callback(row, event); - } - - onClickRow(row: T, event: MouseEvent): void { - EventHelper.stopPropagation(event); - this.clickRow.emit({ row, event}); - } - - onAuxclickRow(row: T, event: MouseEvent): void { - EventHelper.stopPropagation(event); - this.auxclickRow.emit({ row, event }); - } - - trackBy(index: number, item: Entity): number { - return item.id; - } - - onChoose(event: ChoiceEventData): void { - this.choose.emit(event); - } - - onChooseAll(event: MatCheckboxChange): void { - const mainCheckbox = event.source; - - // steps: indeterminate -> unchecked -> checked - // if click when indeterminate need send false state to parent handlers - // for switch off all checkboxes - if (mainCheckbox.indeterminate) { - event.checked = false; - } - // in real mainCheckbox.checked must calc from IsAllCheckedPipe - // but some times mat-checkbox set inner checked value after click - // and not correct recalc after change items checkboxes - // - // bug case without manual `mainCheckbox.checked = false`: - // 1. check main checkbox, - // 2. uncheck all items checkboxes - // 3. after uncheck last item - main checkbox will be view as checked(!) - mainCheckbox.checked = false; - - this.chooseAll.emit(event); - } - - clickCheckbox(event: any): void { - event.stopPropagation(); - } - - clickOnCell(data: { event: any, column: IColumn }): void { - if (data.column.type === 'choice') { - data.event.stopPropagation(); - } - } - -} diff --git a/web/src/app/adwp/lib/loading/loading.component.ts b/web/src/app/adwp/lib/loading/loading.component.ts deleted file mode 100644 index 27a06855f6..0000000000 --- a/web/src/app/adwp/lib/loading/loading.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'adwp-loading', - template: ` - -

Loading...

- `, - styles: [` - :host { - display: flex; - justify-content: center; - align-items: center; - font-weight: bold; - font-size: larger; - } - - mat-spinner { - margin-right: 7px; - } - - p { - margin: 0 0 0 7px; - } - `], -}) -export class LoadingComponent {} diff --git a/web/src/app/adwp/lib/loading/loading.module.ts b/web/src/app/adwp/lib/loading/loading.module.ts deleted file mode 100644 index 7f5e483f91..0000000000 --- a/web/src/app/adwp/lib/loading/loading.module.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; - -import { LoadingComponent } from './loading.component'; - -@NgModule({ - declarations: [ - LoadingComponent, - ], - imports: [ - CommonModule, - MatProgressSpinnerModule, - ], - exports: [ - LoadingComponent, - ] -}) -export class AdwpLoadingModule { } diff --git a/web/src/app/adwp/lib/login-form/login-form.component.html b/web/src/app/adwp/lib/login-form/login-form.component.html deleted file mode 100644 index 47af407fca..0000000000 --- a/web/src/app/adwp/lib/login-form/login-form.component.html +++ /dev/null @@ -1,48 +0,0 @@ -
-
-
- -
OR
-
- -
-
- -
- - - - - - -

- -

-
-
-

- - {{ message }} - -

-
diff --git a/web/src/app/adwp/lib/login-form/login-form.component.scss b/web/src/app/adwp/lib/login-form/login-form.component.scss deleted file mode 100644 index e1ed29963c..0000000000 --- a/web/src/app/adwp/lib/login-form/login-form.component.scss +++ /dev/null @@ -1,63 +0,0 @@ -:host { - flex: 1; -} - -.container { - max-width: 900px; - background: #424242; - box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12); - border-radius: 4px; - padding-top: 32px; -} - -.double-auth { - display: flex; - justify-content: center; - align-items: center; - - & div { - flex-basis: 50%; - text-align: center; - } - - & .or { - flex: 0; - border: solid 1px #666; - border-radius: 42px; - padding: 8px; - line-height: 24px; - } -} - -.google-auth { - line-height: 46px; - padding: 0; - - & svg { - width: 46px; - height: 46px; - } - - & span { - padding: 0 16px; - } -} - -.form-auth { - width: 300px; - margin: 0 auto; - - & p { - text-align: right; - } - - & mat-form-field { - width: 100%; - } -} - -.warn { - width: 300px; - margin: 0 auto; - padding: 16px; -} diff --git a/web/src/app/adwp/lib/login-form/login-form.component.ts b/web/src/app/adwp/lib/login-form/login-form.component.ts deleted file mode 100644 index 877ef39e0e..0000000000 --- a/web/src/app/adwp/lib/login-form/login-form.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; - -import { LoginCredentials } from '../models/login-credentials'; - -@Component({ - selector: 'adwp-login-form', - templateUrl: './login-form.component.html', - styleUrls: ['./login-form.component.scss'] -}) -export class LoginFormComponent { - - isNeedValidation = false; - - authForm = new FormGroup({ - username: new FormControl('', Validators.required), - password: new FormControl('', Validators.required), - }); - - @Input() loginOverGoogle: boolean; - @Input() message = ''; - - @Output() auth = new EventEmitter(); - - login(): void { - this.isNeedValidation = true; - if (this.authForm.valid) { - const credentials = this.authForm.value; - this.auth.emit(credentials); - } - } - - google(): void { - window.location.href = '/social/login/google-oauth2/'; - } - -} diff --git a/web/src/app/adwp/lib/login-form/login-form.module.ts b/web/src/app/adwp/lib/login-form/login-form.module.ts deleted file mode 100644 index d0a61b490c..0000000000 --- a/web/src/app/adwp/lib/login-form/login-form.module.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed 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 { NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { CommonModule } from '@angular/common'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { MatButtonModule } from '@angular/material/button'; - -import { LoginFormComponent } from './login-form.component'; - -@NgModule({ - declarations: [ - LoginFormComponent, - ], - imports: [ - CommonModule, - FormsModule, - ReactiveFormsModule, - MatFormFieldModule, - MatInputModule, - MatButtonModule, - ], - exports: [ - LoginFormComponent, - ] -}) -export class AdwpLoginFormModule { } diff --git a/web/src/app/adwp/lib/miscellaneous/miscellaneous.module.ts b/web/src/app/adwp/lib/miscellaneous/miscellaneous.module.ts deleted file mode 100644 index 866bbd9ec3..0000000000 --- a/web/src/app/adwp/lib/miscellaneous/miscellaneous.module.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { Inject, InjectionToken, ModuleWithProviders, NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { Component } from '@angular/core'; -import { RouterModule } from '@angular/router'; - -export interface MiscConfig { - supportUrl: any[] | string; - homeUrl: any[] | string; -} - -export const MiscConfigService = new InjectionToken('MiscConfig'); - -const styleCSS = ` - :host { display: flex; width: 100%; align-items: center; justify-content: center; } - div { font-weight: bold; text-align: center; font-size: larger; } -`; - -// http 500 -@Component({ - styles: [styleCSS], - template: '
Critical error on the server.

Contact to support.

', -}) -export class FatalErrorComponent { - - constructor( - @Inject(MiscConfigService) public config: MiscConfig, - ) {} - -} - -// http 504 -@Component({ - styles: [styleCSS], - template: '
Gateway Timeout.
', -}) -export class GatewayTimeoutComponent {} - -// http 404 -@Component({ - styles: [styleCSS], - template: '
404

Page not found.

Go to home page

', -}) -export class PageNotFoundComponent { - - constructor( - @Inject(MiscConfigService) public config: MiscConfig, - ) {} - -} - -@NgModule({ - declarations: [ - FatalErrorComponent, - GatewayTimeoutComponent, - PageNotFoundComponent, - ], - imports: [ - CommonModule, - RouterModule, - ], - exports: [ - FatalErrorComponent, - GatewayTimeoutComponent, - PageNotFoundComponent, - ], -}) -export class AdwpMiscellaneousModule { - - public static forRoot(config: MiscConfig): ModuleWithProviders { - return { - ngModule: AdwpMiscellaneousModule, - providers: [ - { - provide: MiscConfigService, - useValue: config, - } - ] - }; - } - -} diff --git a/web/src/app/adwp/lib/models/api-options.ts b/web/src/app/adwp/lib/models/api-options.ts deleted file mode 100644 index 674952bdd6..0000000000 --- a/web/src/app/adwp/lib/models/api-options.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HttpHeaders, HttpParams } from '@angular/common/http'; -import { ApiParams } from './api-params'; - -export interface ApiOptions { - ignoreErrors?: number[]; - root?: string; - params?: HttpParams | ApiParams; - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - reportProgress?: boolean; - withCredentials?: boolean; -} diff --git a/web/src/app/adwp/lib/models/api-params.ts b/web/src/app/adwp/lib/models/api-params.ts deleted file mode 100644 index 9550bd8a05..0000000000 --- a/web/src/app/adwp/lib/models/api-params.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ApiParams { - [param: string]: string | string[]; -} diff --git a/web/src/app/adwp/lib/models/auth-credentials.ts b/web/src/app/adwp/lib/models/auth-credentials.ts deleted file mode 100644 index a9ac9e80ba..0000000000 --- a/web/src/app/adwp/lib/models/auth-credentials.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface AuthCredentials { - id: number; - username: string; - csrftoken: string; -} diff --git a/web/src/app/adwp/lib/models/base.directive.ts b/web/src/app/adwp/lib/models/base.directive.ts deleted file mode 100644 index 5918cb61b9..0000000000 --- a/web/src/app/adwp/lib/models/base.directive.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {Directive, OnDestroy} from '@angular/core'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { MonoTypeOperatorFunction } from 'rxjs'; - -@Directive() -export class BaseDirective implements OnDestroy { - destroy$ = new Subject(); - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - takeUntil(): MonoTypeOperatorFunction { - return takeUntil(this.destroy$); - } - -} diff --git a/web/src/app/adwp/lib/models/config-options.ts b/web/src/app/adwp/lib/models/config-options.ts deleted file mode 100644 index 915f96cf72..0000000000 --- a/web/src/app/adwp/lib/models/config-options.ts +++ /dev/null @@ -1,37 +0,0 @@ -export type TConfigValueTypes = - | 'structure' - | 'group' - | 'dict' - | 'string' - | 'integer' - | 'int' - | 'float' - | 'boolean' - | 'option' - | 'json' - | 'map' - | 'list' - | 'file' - | 'text' - | 'password' - | 'variant'; - -export interface IUIoptions { - invisible?: boolean; - no_confirm?: boolean; - advanced?: boolean; -} - -export interface IConfigOptions { - key?: string; - type: TConfigValueTypes; - display_name: string; - name: string; - subname: string; - hidden: boolean; - read_only: boolean; - ui_options?: IUIoptions; - description?: string; - activatable?: boolean; - required: boolean; -} diff --git a/web/src/app/adwp/lib/models/django-http-error-response.ts b/web/src/app/adwp/lib/models/django-http-error-response.ts deleted file mode 100644 index c9153a85bf..0000000000 --- a/web/src/app/adwp/lib/models/django-http-error-response.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { HttpErrorResponse } from '@angular/common/http'; -import { DjangoHttpError } from './django-http-error'; - -export class DjangoHttpErrorResponse extends HttpErrorResponse { - - error: DjangoHttpError; - -} diff --git a/web/src/app/adwp/lib/models/django-http-error.ts b/web/src/app/adwp/lib/models/django-http-error.ts deleted file mode 100644 index aac8a68d60..0000000000 --- a/web/src/app/adwp/lib/models/django-http-error.ts +++ /dev/null @@ -1,13 +0,0 @@ -export enum DjangoErrorCode { - AuthError = 'AUTH_ERROR', -} - -export enum DjangoErrorLevel { - Error = 'error', -} - -export interface DjangoHttpError { - code: DjangoErrorCode; - desc: string; - level: DjangoErrorLevel; -} diff --git a/web/src/app/adwp/lib/models/entity.ts b/web/src/app/adwp/lib/models/entity.ts deleted file mode 100644 index 3d92614d3b..0000000000 --- a/web/src/app/adwp/lib/models/entity.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Entity { - id?: number; -} diff --git a/web/src/app/adwp/lib/models/field-options.ts b/web/src/app/adwp/lib/models/field-options.ts deleted file mode 100644 index 843879ea96..0000000000 --- a/web/src/app/adwp/lib/models/field-options.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { IConfigOptions } from './config-options'; -export type TValue = string | number | boolean | object | any[]; -export type TControlType = - | 'boolean' - | 'textbox' - | 'textarea' - | 'json' - | 'password' - | 'list' - | 'map' - | 'dropdown' - | 'file' - | 'text' - | 'structure'; - -export interface IValidatorInfo { - pattern?: string | RegExp; - required?: boolean; - max?: number; - min?: number; -} - -export interface IVariantSet { - name?: string; - strict: boolean; - type: 'config' | 'inline'; - value: string[]; -} - -export type TStateType = 'created' | 'locked'; - -export interface ILimits { - min?: number; - max?: number; - option?: any; - read_only?: TStateType[]; - yspec?: any; // IYspec; - rules?: any; - active?: boolean; - source?: IVariantSet; -} - -export interface ICompare { - id: number; - date: string; - value: string; - color: string; -} - -export interface IFieldOptions extends IConfigOptions { - default: TValue; - value: TValue; - controlType: TControlType; - validator: IValidatorInfo; - limits?: ILimits; - compare: ICompare[]; -} diff --git a/web/src/app/adwp/lib/models/list.ts b/web/src/app/adwp/lib/models/list.ts deleted file mode 100644 index c594669e4a..0000000000 --- a/web/src/app/adwp/lib/models/list.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { ComponentRef, Type } from '@angular/core'; -import { MatCheckboxChange } from '@angular/material/checkbox'; - -export interface RowEventData { - row: any; - event: MouseEvent; -} - -export interface ChoiceEventData { - row: T; - event: MatCheckboxChange; -} - -export interface IListResult { - count: number; - next: string; - previous: string; - results: T[]; -} - -/** - * Describing complex columns - */ -export interface IColumnDescription { - label?: string; - type?: 'buttons' | 'date' | 'link' | 'dynamic-column' | 'component' | 'choice'; - className?: string; - headerClassName?: string; - guid?: string; -} - -export interface ISortableColumn extends IColumnDescription { - sort?: string; -} - -export type CellValueType = string | number; - -export type ValueFunc = (row: T) => CellValueType; -export interface IValueColumn extends ISortableColumn { - value: ValueFunc; -} - -export type DisabledCheckboxFunc = (row: T) => boolean; - -export interface IDateColumn extends IValueColumn { - type: 'date'; -} - -export type ButtonCallback = (row: T, event: MouseEvent) => void; -export interface IButton { - icon?: string; - callback: ButtonCallback; - tooltip?: string; -} - -export interface IButtonsColumn extends IColumnDescription { - type: 'buttons'; - buttons: IButton[]; -} - -export interface IChoiceColumn extends IColumnDescription { - type: 'choice'; - modelKey: string; - disabled?: DisabledCheckboxFunc; -} - -export type UrlColumnFunc = (row: T) => string; -export interface ILinkColumn extends IValueColumn { - type: 'link'; - url: UrlColumnFunc; -} - -export interface AdwpComponentHolder { - row: T; -} - -export interface AdwpCellComponent extends AdwpComponentHolder { - column?: IColumn; -} - -export type AdwpCellComponentType = Type>; -export type AdwpRowComponentType = Type>; - -export type InstanceTakenFunc = (componentRef: ComponentRef>) => void; - -export interface IComponentColumn extends ISortableColumn { - type: 'component'; - component: AdwpCellComponentType; - instanceTaken?: InstanceTakenFunc; -} - -export interface ICell { - cssClass: string; - value: CellValueType; -} - -export type DynamicColumnFunc = (row: T) => ICell; - -export interface IDynamicColumn extends ISortableColumn { - type: 'dynamic-column'; - handle: DynamicColumnFunc; -} - -export type IColumn = - IValueColumn - | IDateColumn - | IButtonsColumn - | ILinkColumn - | IDynamicColumn - | IComponentColumn - | IChoiceColumn; - -export type IColumns = Array>; diff --git a/web/src/app/adwp/lib/models/login-credentials.ts b/web/src/app/adwp/lib/models/login-credentials.ts deleted file mode 100644 index 31abbfd8fc..0000000000 --- a/web/src/app/adwp/lib/models/login-credentials.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { AuthCredentials } from './auth-credentials'; - -export interface LoginCredentials extends AuthCredentials { - password: string; -} diff --git a/web/src/app/adwp/lib/models/menu-item.ts b/web/src/app/adwp/lib/models/menu-item.ts deleted file mode 100644 index 08d4124ecc..0000000000 --- a/web/src/app/adwp/lib/models/menu-item.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface IMenuItem { - link: string | any[]; - label: string; - issue?: string; -} diff --git a/web/src/app/adwp/lib/models/root.ts b/web/src/app/adwp/lib/models/root.ts deleted file mode 100644 index 099c712c5a..0000000000 --- a/web/src/app/adwp/lib/models/root.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IRoot { - [key: string]: string; -} diff --git a/web/src/app/adwp/lib/models/version-info.ts b/web/src/app/adwp/lib/models/version-info.ts deleted file mode 100644 index 33bd737391..0000000000 --- a/web/src/app/adwp/lib/models/version-info.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface IVersionInfo { - version: string; - commit_id: string; -} diff --git a/web/src/app/adwp/lib/notification/notification.module.ts b/web/src/app/adwp/lib/notification/notification.module.ts deleted file mode 100644 index 48a10f5c6e..0000000000 --- a/web/src/app/adwp/lib/notification/notification.module.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { NgModule, Optional, SkipSelf } from '@angular/core'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; - -import { NotificationService } from '../services/notification.service'; - -@NgModule({ - imports: [ - MatSnackBarModule, - ], - providers: [ - NotificationService, - ] -}) -export class AdwpNotificationModule { - - constructor(@Optional() @SkipSelf() parentModule?: AdwpNotificationModule) { - if (parentModule) { - throw new Error('AdwpNotificationModule is already loaded. Import it in the AppModule only'); - } - } - -} diff --git a/web/src/app/adwp/lib/services/api.service.ts b/web/src/app/adwp/lib/services/api.service.ts deleted file mode 100644 index 444a68a04d..0000000000 --- a/web/src/app/adwp/lib/services/api.service.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Inject, Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { Observable, OperatorFunction, throwError } from 'rxjs'; -import { catchError } from 'rxjs/operators'; - -import { authFailed } from '../store/auth/auth.actions'; -import { DjangoHttpErrorResponse } from '../models/django-http-error-response'; -import { NotificationService } from './notification.service'; -import { ApiOptions } from '../models/api-options'; -import { ApiConfigService } from '../api/api-config.service'; -import { ApiConfig } from '../api/api-config'; - -@Injectable() -export class ApiService { - - constructor( - private http: HttpClient, - private store: Store, - private notificationService: NotificationService, - @Inject(ApiConfigService) public config: ApiConfig, - ) {} - - protected authBehaviour(): OperatorFunction { - return catchError((err: DjangoHttpErrorResponse) => { - if (err.status === 401) { - this.store.dispatch(authFailed({ message: err.error.desc })); - } - return throwError(err); - }); - } - - protected errorBehaviour(options?: ApiOptions): OperatorFunction { - return catchError((err: DjangoHttpErrorResponse) => { - if (!options || !options.ignoreErrors || options.ignoreErrors.every(ignoredError => ignoredError !== err.status)) { - this.notificationService.error(`${err.status} - ${err.statusText}`); - } - return throwError(err); - }); - } - - protected prepareUrl(url: string, options: ApiOptions): string { - if (options && options.root) { - return `/${options.root}/${url}/`; - } - return `/${this.config.defaultRoot}/${url}/`; - } - - get(url: string, options?: ApiOptions): Observable { - return this.http.get(this.prepareUrl(url, options), options).pipe( - this.authBehaviour(), - this.errorBehaviour(options), - ); - } - - post(url: string, data: any = {}, options?: ApiOptions): Observable { - return this.http.post(this.prepareUrl(url, options), data, options).pipe( - this.authBehaviour(), - this.errorBehaviour(options), - ); - } - - put(url: string, data: any = {}, options?: ApiOptions): Observable { - return this.http.put(this.prepareUrl(url, options), data, options).pipe( - this.authBehaviour(), - this.errorBehaviour(options), - ); - } - - patch(url: string, data: any = {}, options?: ApiOptions): Observable { - return this.http.patch(this.prepareUrl(url, options), data, options).pipe( - this.authBehaviour(), - this.errorBehaviour(options), - ); - } - - delete(url: string, options?: ApiOptions): Observable { - return this.http.delete(this.prepareUrl(url, options)).pipe( - this.authBehaviour(), - this.errorBehaviour(options), - ); - } - -} diff --git a/web/src/app/adwp/lib/services/app.service.ts b/web/src/app/adwp/lib/services/app.service.ts deleted file mode 100644 index f32200e6ad..0000000000 --- a/web/src/app/adwp/lib/services/app.service.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { select } from '@ngrx/store'; -import { filter, take, takeUntil, tap } from 'rxjs/operators'; - -import { StatusType } from '../store/socket/socket.actions'; -import { getConnectStatus } from '../store/socket/socket.selectors'; -import { interval, merge, Observable } from 'rxjs'; -import { NotificationService } from './notification.service'; -import { isAuthenticated } from '../store/auth/auth.selectors'; -import { SocketService } from './socket.service'; -import { ConfigService } from './config.service'; - -@Injectable() -export class AppService { - - projectName: string; - - constructor( - private store: Store, - private notificationService: NotificationService, - private socketService: SocketService, - private configService: ConfigService, - ) {} - - checkNewVersion(): Observable { - return this.configService.checkVersion().pipe( - tap(newVersion => { - if (newVersion) { - this.notificationService.notify(`${this.projectName} will be upgraded in 2 seconds.`); - this.notificationService.setInitNotification(`${this.projectName} has been upgraded`); - setTimeout(() => location.reload(), 2000); - } - return newVersion; - }) - ); - } - - checkWSConnectStatus(): Observable { - return this.store.pipe( - select(getConnectStatus), - filter((a) => !!a), - tap((status) => { - if (status === StatusType.Open) { - this.checkNewVersion().subscribe((newVersion) => { - if (!newVersion) { - this.notificationService.notify('Connection established.'); - } - }); - } - if (status === StatusType.Lost) { - this.notificationService.error('Connection lost. Recovery attempt.'); - interval(4000) - .pipe(takeUntil(merge( - this.store.pipe(select(isAuthenticated), filter(state => !state), take(1)), - this.store.pipe(select(getConnectStatus), filter(state => state === StatusType.Open), take(1)), - ))) - .subscribe(() => { - this.notificationService.error('No connection to back-end. Check your internet connection.'); - this.socketService.init(); - }); - } - }) - ); - } - - checkAuthStatus(): Observable { - return this.store.pipe( - select(isAuthenticated), - tap(isAuth => { - if (isAuth) { - this.socketService.init(); - } else { - this.socketService.close(); - } - }), - ); - } - - init(): void { - this.checkWSConnectStatus().subscribe(); - this.checkAuthStatus().subscribe(); - } - -} diff --git a/web/src/app/adwp/lib/services/auth.service.ts b/web/src/app/adwp/lib/services/auth.service.ts deleted file mode 100644 index 3ba89ef91f..0000000000 --- a/web/src/app/adwp/lib/services/auth.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Inject, Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -import { ApiService } from './api.service'; -import { AuthConfig } from '../auth/auth-config'; -import { AuthConfigService } from '../auth/auth-config.service'; -import { AuthCredentials } from '../models/auth-credentials'; - - -@Injectable({ providedIn: 'root' }) -export class AuthService { - - readonly TOKEN_COOKIE_STORAGE_NAME = 'token-cookie-name'; - - constructor( - @Inject(AuthConfigService) public config: AuthConfig, - protected api: ApiService, - ) {} - - login(username: string, password: string): Observable { - return this.api.post(`login`, { username, password }, { root: this.config.uiApiRoot }); - } - - checkAuth(): Observable { - return this.api.get(`auth_status`, { root: this.config.uiApiRoot, ignoreErrors: [401] }); - } - - logout(): Observable { - return this.api.post(`logout`, {}, { root: this.config.uiApiRoot }); - } - - setTokenCookieName(cookieName: string): void { - sessionStorage.setItem(this.TOKEN_COOKIE_STORAGE_NAME, cookieName); - } - - getTokenCookieName(): string { - return sessionStorage.getItem(this.TOKEN_COOKIE_STORAGE_NAME); - } - -} diff --git a/web/src/app/adwp/lib/services/config.service.ts b/web/src/app/adwp/lib/services/config.service.ts deleted file mode 100644 index c7cee3128d..0000000000 --- a/web/src/app/adwp/lib/services/config.service.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable} from 'rxjs'; -import { map, tap } from 'rxjs/operators'; - -import { IVersionInfo } from '../models/version-info'; - -const CONFIG_URL = '/assets/config.json'; - -@Injectable() -export class ConfigService { - - readonly VERSION_STORAGE = 'version'; - - constructor(private http: HttpClient) {} - - get version(): string { - return localStorage.getItem(this.VERSION_STORAGE) || ''; - } - - set version(version: string) { - localStorage.setItem(this.VERSION_STORAGE, version); - } - - getVersion(versionData: IVersionInfo): IVersionInfo { - const arrVersion = this.version.split('-'); - return arrVersion.length > 1 ? { - version: arrVersion[0], - commit_id: arrVersion[1], - } : null; - } - - hasNewVersion(): Observable { - return this.http.get(`${CONFIG_URL}?nocache=${Date.now()}`).pipe( - map((configVersion: IVersionInfo) => { - const newVersion = `${configVersion.version}-${configVersion.commit_id}`; - return !this.version || this.version !== newVersion ? newVersion : null; - }), - ); - } - - checkVersion(): Observable { - return this.hasNewVersion().pipe(tap(version => { - if (version) { - this.version = version; - } - })); - } - -} diff --git a/web/src/app/adwp/lib/services/index.ts b/web/src/app/adwp/lib/services/index.ts deleted file mode 100644 index cfc7c829c6..0000000000 --- a/web/src/app/adwp/lib/services/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// export { AuthService } from './auth.service'; -// export { ApiService } from './api.service'; -// export { ConfigService } from './config.service'; diff --git a/web/src/app/adwp/lib/services/list-storage.service.ts b/web/src/app/adwp/lib/services/list-storage.service.ts deleted file mode 100644 index 6398d85378..0000000000 --- a/web/src/app/adwp/lib/services/list-storage.service.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Paging } from '../list/list/list.component'; -import { Sort } from '@angular/material/sort'; - -@Injectable({ - providedIn: 'root' -}) -export class ListStorageService { - - storage: Storage = localStorage; - - protected getItem(key: string): string { - return this.storage.getItem(key); - } - - protected setItem(key, value: string): void { - this.storage.setItem(key, value); - } - - setPaging(key: string, paging: Paging): void { - const item = JSON.parse(this.getItem(key) || '{}'); - item.paging = paging; - this.setItem(key, JSON.stringify(item)); - } - - setSort(key: string, sort: Sort): void { - const item = JSON.parse(this.getItem(key) || '{}'); - item.sort = sort; - this.setItem(key, JSON.stringify(item)); - } - - getPaging(key: string): Paging { - const item = JSON.parse(this.getItem(key)); - if (item && item.paging) { - return item.paging; - } - - return null; - } - - getSort(key: string): Sort { - const item = JSON.parse(this.getItem(key)); - if (item && item.sort) { - return item.sort; - } - - return null; - } - -} diff --git a/web/src/app/adwp/lib/services/notification.service.ts b/web/src/app/adwp/lib/services/notification.service.ts deleted file mode 100644 index 8c41f4cc8b..0000000000 --- a/web/src/app/adwp/lib/services/notification.service.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable, Subject } from 'rxjs'; -import { MatSnackBar } from '@angular/material/snack-bar'; - -@Injectable() -export class NotificationService { - - readonly SEPARATOR = '::'; - readonly INIT_STORAGE = 'init:notification'; - - protected notification = new Subject(); - - constructor( - public snackBar: MatSnackBar, - ) { } - - setInitNotification(notification: string): void { - localStorage.setItem(this.INIT_STORAGE, notification); - } - - notify(notification: string): void { - this.notification.next(notification); - } - - error(notification: string): void { - this.notify(`${notification}${this.SEPARATOR}error`); - } - - on(): Observable { - return this.notification.asObservable(); - } - - private showInitialNotification(): void { - if (localStorage.getItem(this.INIT_STORAGE)) { - this.notify(localStorage.getItem(this.INIT_STORAGE)); - localStorage.removeItem(this.INIT_STORAGE); - } - } - - init(): void { - this.notification.subscribe((m) => { - const astr = m.split(this.SEPARATOR); - const data = astr[1] - ? { panelClass: 'snack-bar-error' } - : { - duration: 5000, - panelClass: 'snack-bar-notify', - }; - this.snackBar.open(astr[0], 'Hide', data); - }); - this.showInitialNotification(); - } - -} diff --git a/web/src/app/adwp/lib/services/socket-config.service.ts b/web/src/app/adwp/lib/services/socket-config.service.ts deleted file mode 100644 index 346520da54..0000000000 --- a/web/src/app/adwp/lib/services/socket-config.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { InjectionToken } from '@angular/core'; -import { SocketConfig } from '../socket/socket-config'; - -export const SocketConfigService = new InjectionToken('SocketConfig'); diff --git a/web/src/app/adwp/lib/services/socket.service.ts b/web/src/app/adwp/lib/services/socket.service.ts deleted file mode 100644 index eae79ac827..0000000000 --- a/web/src/app/adwp/lib/services/socket.service.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Inject, Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; - -import { socketClose, socketLost, socketOpen, socketResponse, StatusType } from '../store/socket/socket.actions'; -import { SocketConfigService } from './socket-config.service'; -import { SocketConfig } from '../socket/socket-config'; - -@Injectable() -export class SocketService { - private socket: WebSocket; - - constructor( - @Inject(SocketConfigService) public config: SocketConfig, - private store: Store, - ) {} - - init(openStatus: StatusType = StatusType.Open): WebSocket { - this.socket = new WebSocket(this.config.serverEventUrl); - - this.socket.onopen = () => this.store.dispatch(socketOpen({ status: openStatus })); - this.socket.onclose = () => this.store.dispatch(socketLost({ status: StatusType.Lost })); - this.socket.onmessage = (response: MessageEvent) => - this.store.dispatch(socketResponse({ message: JSON.parse(response.data) })); - - return this.socket; - } - - close(): void { - if (this.socket) { - this.socket.onclose = () => this.store.dispatch(socketClose({ status: StatusType.Close })); - this.socket.close(); - } - } - -} diff --git a/web/src/app/adwp/lib/socket/socket-config.ts b/web/src/app/adwp/lib/socket/socket-config.ts deleted file mode 100644 index e7fde8e2f0..0000000000 --- a/web/src/app/adwp/lib/socket/socket-config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface SocketConfig { - serverEventUrl: string; -} diff --git a/web/src/app/adwp/lib/socket/socket.module.ts b/web/src/app/adwp/lib/socket/socket.module.ts deleted file mode 100644 index d91445bf9f..0000000000 --- a/web/src/app/adwp/lib/socket/socket.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ModuleWithProviders, NgModule } from '@angular/core'; - -import { SocketConfigService } from '../services/socket-config.service'; -import { SocketService } from '../services/socket.service'; -import { SocketConfig } from './socket-config'; - -@NgModule({ - providers: [ - SocketService, - ] -}) -export class AdwpSocketModule { - - public static forRoot(config: SocketConfig): ModuleWithProviders { - return { - ngModule: AdwpSocketModule, - providers: [ - { - provide: SocketConfigService, - useValue: config, - } - ] - }; - } - -} diff --git a/web/src/app/adwp/lib/store/api/api.effects.ts b/web/src/app/adwp/lib/store/api/api.effects.ts deleted file mode 100644 index 5d155cbcd2..0000000000 --- a/web/src/app/adwp/lib/store/api/api.effects.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { Store } from '@ngrx/store'; -import { of } from 'rxjs'; -import { catchError, delay, exhaustMap, filter, map, switchMap, withLatestFrom } from 'rxjs/operators'; - -import { AdwpState } from '../state'; -import { IRoot } from '../../models/root'; -import { ApiService } from '../../services/api.service'; -import { loadRoot, loadStack, rootError, rootSuccess, stackSuccess } from './api.reducer'; - -export const API_ROOT = '/api/v1/'; - -@Injectable() -export class ApiEffects { - root$ = createEffect(() => - this.actions$.pipe( - ofType(loadRoot), - exhaustMap(() => - this.api.get(API_ROOT).pipe( - map((root) => rootSuccess({ root })), - catchError(() => of(rootError())) - ) - ) - ) - ); - - retry$ = createEffect(() => - this.actions$.pipe( - ofType(rootError), - delay(3000), - switchMap(() => - this.api.get(API_ROOT).pipe( - map((root) => rootSuccess({ root })), - catchError(() => of(rootError())) - ) - ) - ) - ); - - stack$ = createEffect(() => - this.actions$.pipe( - ofType(loadStack), - withLatestFrom(this.store, (actions, store) => store.api), - filter((api) => api.root && !api.stack), - exhaustMap((api) => - this.api - .get(api.root.stack) - .pipe(map((stack) => stackSuccess({ stack }))) - ) - ) - ); - - constructor( - private actions$: Actions, - private api: ApiService, - private store: Store - ) {} -} diff --git a/web/src/app/adwp/lib/store/api/api.reducer.ts b/web/src/app/adwp/lib/store/api/api.reducer.ts deleted file mode 100644 index 5abb0a8dd2..0000000000 --- a/web/src/app/adwp/lib/store/api/api.reducer.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props } from '@ngrx/store'; - -import { IRoot } from '../../models/root'; - -export const loadRoot = createAction('[API] LoadRoot'); -export const loadStack = createAction('[API] LoadStack'); -export const rootSuccess = createAction( - '[API] LoadRootSuccess', - props<{ root: IRoot }>() -); - -export const rootError = createAction('[API] LoadRootError'); - -export const stackSuccess = createAction( - '[API] LoadStackSuccess', - props<{ stack: IRoot }>() -); - -export interface ApiState { - root: IRoot; - stack: IRoot; -} - -const InitState: ApiState = { - root: null, - stack: null, -}; - -const reducer = createReducer( - InitState, - on(rootSuccess, (state, { root }) => ({ ...state, root })), - on(rootError, (state) => ({ root: null, stack: null })), - on(stackSuccess, (state, { stack }) => ({ ...state, stack })) -); - -export function apiReducer(state: ApiState, action: Action): ApiState { - return reducer(state, action); -} - -export const getApiState = createFeatureSelector('api'); -export const getRoot = createSelector( - getApiState, - (state: ApiState) => state.root -); -export const getStack = createSelector( - getApiState, - (state: ApiState) => state.stack -); diff --git a/web/src/app/adwp/lib/store/auth/auth.actions.ts b/web/src/app/adwp/lib/store/auth/auth.actions.ts deleted file mode 100644 index fb4acf1d02..0000000000 --- a/web/src/app/adwp/lib/store/auth/auth.actions.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createAction, props } from '@ngrx/store'; - -export const authCheck = createAction('[Auth] Check'); -export const authLogin = createAction('[Auth] Login', props<{ username: string; password: string }>()); -export const authSuccess = createAction('[Auth] LoginSuccess', props<{ username: string }>()); -export const authFailed = createAction('[Auth] LoginFailed', props<{ message: string }>()); -export const authLogout = createAction('[Auth] Logout'); diff --git a/web/src/app/adwp/lib/store/auth/auth.effects.ts b/web/src/app/adwp/lib/store/auth/auth.effects.ts deleted file mode 100644 index 68369fbca8..0000000000 --- a/web/src/app/adwp/lib/store/auth/auth.effects.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { map, switchMap, catchError, tap } from 'rxjs/operators'; -import { of } from 'rxjs'; - -import { authSuccess, authFailed, authLogin, authLogout, authCheck } from './auth.actions'; -import { AuthService } from '../../services/auth.service'; -import { DjangoHttpErrorResponse } from '../../models/django-http-error-response'; - -@Injectable() -export class AuthEffects { - - check$ = createEffect(() => - this.actions$.pipe( - ofType(authCheck), - switchMap(() => this.authService.checkAuth().pipe( - tap((status) => this.authService.setTokenCookieName(status.csrftoken)), - map((auth) => authSuccess({ username: auth.username })), - catchError(() => of(authFailed({ message: '' }))), - )), - ), - { useEffectsErrorHandler: true } - ); - - auth$ = createEffect(() => - this.actions$.pipe( - ofType(authLogin), - switchMap(a => - this.authService.login(a.username, a.password).pipe( - map(() => authCheck()), - catchError((err: DjangoHttpErrorResponse) => of(authFailed({ message: err.error.desc }))), - )), - ), - { useEffectsErrorHandler: true } - ); - - logout$ = createEffect( - () => - this.actions$.pipe( - ofType(authLogout), - switchMap(() => this.authService.logout()), - ), - { dispatch: false } - ); - - constructor( - private actions$: Actions, - private authService: AuthService - ) {} - -} diff --git a/web/src/app/adwp/lib/store/auth/auth.reducers.ts b/web/src/app/adwp/lib/store/auth/auth.reducers.ts deleted file mode 100644 index 8d4389afa8..0000000000 --- a/web/src/app/adwp/lib/store/auth/auth.reducers.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Action, createReducer, on } from '@ngrx/store'; -import { authSuccess, authFailed, authLogout, authCheck } from './auth.actions'; - -export interface AuthState { - isValid: boolean; - message: string; - checking: boolean; -} - -const initialState: AuthState = { - isValid: false, - message: '', - checking: false, -}; - -const reducer = createReducer( - initialState, - on(authCheck, state => ({ isValid: false, message: '', checking: true })), - on(authSuccess, state => ({ isValid: true, message: 'Auth is success.', checking: false })), - on(authFailed, (state, { message }) => ({ isValid: false, message, checking: false })), - on(authLogout, state => ({ isValid: false, message: '', checking: false })), -); - -export function authReducer(state: AuthState, action: Action): AuthState { - return reducer(state, action); -} diff --git a/web/src/app/adwp/lib/store/auth/auth.selectors.ts b/web/src/app/adwp/lib/store/auth/auth.selectors.ts deleted file mode 100644 index 0e3aaf10ba..0000000000 --- a/web/src/app/adwp/lib/store/auth/auth.selectors.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; - -import { AuthState } from './auth.reducers'; - -export const getAuthState = createFeatureSelector('auth'); - -export const isAuthenticated = createSelector( - getAuthState, - state => state.isValid -); - -export const isAuthChecking = createSelector( - getAuthState, - state => state.checking -); diff --git a/web/src/app/adwp/lib/store/factory.ts b/web/src/app/adwp/lib/store/factory.ts deleted file mode 100644 index dd2ce78168..0000000000 --- a/web/src/app/adwp/lib/store/factory.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ActionReducerMap } from '@ngrx/store'; - -import { AuthEffects } from './auth/auth.effects'; -import { authReducer } from './auth/auth.reducers'; -import { socketReducer } from './socket/socket.reducers'; -import { AdwpState } from './state'; - -export class AdwpStoreFactory { - - static createReducers(): ActionReducerMap { - return { - auth: authReducer, - socket: socketReducer, - }; - } - - static createEffects(): Array { - return [ - AuthEffects, - ]; - } - -} diff --git a/web/src/app/adwp/lib/store/socket/socket.actions.ts b/web/src/app/adwp/lib/store/socket/socket.actions.ts deleted file mode 100644 index 5247e874ba..0000000000 --- a/web/src/app/adwp/lib/store/socket/socket.actions.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { createAction, props } from '@ngrx/store'; - -export type TypeName = - | 'bundle' - | 'cluster' - | 'host' - | 'provider' - | 'service' - | 'job' - | 'task' - | 'user' - | 'profile' - | 'adcm' - | 'stats' - | 'hostcomponent' - | 'component'; - -export interface IEMObject { - type: TypeName; - id: number; - details: { - id?: string; - type: string; - value: any; - }; -} - -export interface EventMessage { - event: - | 'add' - | 'add_job_log' - | 'create' - | 'delete' - | 'remove' - | 'change_config' - | 'change_state' - | 'change_status' - | 'change_job_status' - | 'change_hostcomponentmap' - | 'raise_issue' - | 'clear_issue' - | 'upgrade'; - object?: IEMObject; -} - -export enum StatusType { - Open = 'open', - Close = 'close', - Lost = 'lost', -} - -export const socketInit = createAction('[Socket] Init'); -export const socketOpen = createAction('[Socket] Open', props<{ status: StatusType }>()); -export const socketClose = createAction('[Socket] Close', props<{ status: StatusType }>()); -export const socketLost = createAction('[Socket] Lost', props<{ status: StatusType }>()); -export const socketResponse = createAction('[Socket] Response', props<{ message: EventMessage }>()); diff --git a/web/src/app/adwp/lib/store/socket/socket.reducers.ts b/web/src/app/adwp/lib/store/socket/socket.reducers.ts deleted file mode 100644 index e9494d37d8..0000000000 --- a/web/src/app/adwp/lib/store/socket/socket.reducers.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Action, createReducer, on } from '@ngrx/store'; - -import { StatusType, EventMessage, socketInit, socketOpen, socketClose, socketResponse, socketLost } from './socket.actions'; - -export interface SocketState { - status: StatusType; - message: EventMessage; -} - -const initialState: SocketState = { - status: null, - message: null, -}; - -const reducer = createReducer( - initialState, - on(socketInit, (state) => ({ ...state })), - on(socketOpen, (state, { status }) => ({ - ...state, - status, - })), - on(socketLost, (state, { status }) => ({ - ...state, - status, - })), - on(socketClose, (state, { status }) => ({ - ...state, - status, - })), - on(socketResponse, (state, { message }) => ({ - ...state, - message, - })), -); - -export function socketReducer(state: SocketState, action: Action): SocketState { - return reducer(state, action); -} diff --git a/web/src/app/adwp/lib/store/socket/socket.selectors.ts b/web/src/app/adwp/lib/store/socket/socket.selectors.ts deleted file mode 100644 index 5eaa7a0303..0000000000 --- a/web/src/app/adwp/lib/store/socket/socket.selectors.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { createFeatureSelector, createSelector, select } from '@ngrx/store'; -import { pipe } from 'rxjs'; -import { skip } from 'rxjs/operators'; - -import { SocketState } from './socket.reducers'; - -export const getSocketState = createFeatureSelector('socket'); -export const getConnectStatus = createSelector(getSocketState, (state: SocketState) => state.status); -export const getMessage = createSelector(getSocketState, (state) => state.message); -export const selectMessage = pipe( - select(getMessage), - skip(1), -); diff --git a/web/src/app/adwp/lib/store/state.ts b/web/src/app/adwp/lib/store/state.ts deleted file mode 100644 index 065e32d38b..0000000000 --- a/web/src/app/adwp/lib/store/state.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { AuthState } from './auth/auth.reducers'; -import { SocketState } from './socket/socket.reducers'; - -export interface AdwpState { - auth: AuthState; - socket: SocketState; - api?: any; -} diff --git a/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.html b/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.html deleted file mode 100644 index f480aef223..0000000000 --- a/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.html +++ /dev/null @@ -1,11 +0,0 @@ - - - apps - -  /  - - {{ item.label | uppercase }} - priority_hight -  /  - - diff --git a/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.scss b/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.scss deleted file mode 100644 index baafe33a4e..0000000000 --- a/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.scss +++ /dev/null @@ -1,17 +0,0 @@ -:host { - font-size: 0.8em; - margin-left: 8px; -} - -mat-nav-list { - display: flex; - align-items: center; -} - -a { - line-height: normal; -} - -mat-icon { - margin-bottom: 5px; -} diff --git a/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.spec.ts b/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.spec.ts deleted file mode 100644 index b29ac537a5..0000000000 --- a/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ - - - -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CrumbsComponent } from './crumbs.component'; - -describe('CrumbsComponent', () => { - let component: CrumbsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ CrumbsComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(CrumbsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.ts b/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.ts deleted file mode 100644 index f28c5ffd28..0000000000 --- a/web/src/app/adwp/lib/toolbar/crumbs/crumbs.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { IMenuItem } from './../../models/menu-item'; -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'adwp-crumbs', - templateUrl: './crumbs.component.html', - styleUrls: ['./crumbs.component.scss'], -}) -export class CrumbsComponent { - @Input() navigation: IMenuItem[]; -} diff --git a/web/src/app/adwp/lib/toolbar/toolbar.component.html b/web/src/app/adwp/lib/toolbar/toolbar.component.html deleted file mode 100644 index 986f7a5210..0000000000 --- a/web/src/app/adwp/lib/toolbar/toolbar.component.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/web/src/app/adwp/lib/toolbar/toolbar.component.scss b/web/src/app/adwp/lib/toolbar/toolbar.component.scss deleted file mode 100644 index 4ed1494776..0000000000 --- a/web/src/app/adwp/lib/toolbar/toolbar.component.scss +++ /dev/null @@ -1,6 +0,0 @@ -mat-toolbar { - height: auto; - min-height: 50px; - justify-content: space-between; - background-color: #21212163; -} diff --git a/web/src/app/adwp/lib/toolbar/toolbar.component.ts b/web/src/app/adwp/lib/toolbar/toolbar.component.ts deleted file mode 100644 index a7b86c2ab6..0000000000 --- a/web/src/app/adwp/lib/toolbar/toolbar.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { IMenuItem } from '../models/menu-item'; -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'adwp-toolbar', - templateUrl: './toolbar.component.html', - styleUrls: ['./toolbar.component.scss'], -}) -export class ToolbarComponent { - @Input() crumbs: IMenuItem[]; -} diff --git a/web/src/app/adwp/lib/toolbar/toolbar.module.ts b/web/src/app/adwp/lib/toolbar/toolbar.module.ts deleted file mode 100644 index a7e3818b87..0000000000 --- a/web/src/app/adwp/lib/toolbar/toolbar.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatListModule } from '@angular/material/list'; -import { MatToolbarModule } from '@angular/material/toolbar'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { RouterModule } from '@angular/router'; - -import { CrumbsComponent } from './crumbs/crumbs.component'; -import { ToolbarComponent } from './toolbar.component'; - -@NgModule({ - declarations: [ToolbarComponent, CrumbsComponent], - imports: [ - CommonModule, - RouterModule, - MatToolbarModule, - MatListModule, - MatIconModule, - MatTooltipModule, - MatButtonModule, - ], - exports: [ToolbarComponent, CrumbsComponent], -}) -export class AdwpToolbarModule {} diff --git a/web/src/app/adwp/lib/ui-widgets.module.ts b/web/src/app/adwp/lib/ui-widgets.module.ts deleted file mode 100644 index 9b61da30c8..0000000000 --- a/web/src/app/adwp/lib/ui-widgets.module.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { NgModule } from '@angular/core'; - -import { AdwpDialogModule } from './dialog/dialog.module'; -import { AdwpFormElementModule } from './form-element/form-element.module'; -import { AdwpHeaderModule } from './header/header.module'; -import { AdwpListModule } from './list/list.module'; -import { AdwpLoginFormModule } from './login-form/login-form.module'; -import { AdwpNotificationModule } from './notification/notification.module'; -import { AdwpToolbarModule } from './toolbar/toolbar.module'; - -@NgModule({ - declarations: [], - imports: [ - AdwpLoginFormModule, - AdwpHeaderModule, - AdwpListModule, - AdwpToolbarModule, - AdwpNotificationModule, - AdwpDialogModule, - AdwpFormElementModule, - ], - exports: [AdwpLoginFormModule, AdwpHeaderModule, AdwpListModule, AdwpDialogModule, AdwpFormElementModule], -}) -export class AdwpUiWidgetsModule { -} diff --git a/web/src/app/adwp/test.ts b/web/src/app/adwp/test.ts deleted file mode 100644 index 303b32a220..0000000000 --- a/web/src/app/adwp/test.ts +++ /dev/null @@ -1,26 +0,0 @@ -// This file is required by karma.conf.js and loads recursively all the .spec and framework files - -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; - -declare const require: { - context(path: string, deep?: boolean, filter?: RegExp): { - keys(): string[]; - (id: string): T; - }; -}; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); diff --git a/web/src/app/app-routing.module.ts b/web/src/app/app-routing.module.ts deleted file mode 100644 index 8b065dfc7b..0000000000 --- a/web/src/app/app-routing.module.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; - -import { LogComponent } from '@app/ws-logs/log.component'; -import { AuthGuard } from '@app/core/auth/auth.guard'; -import { LoginComponent } from '@app/main/login/login.component'; -import { ProfileComponent } from '@app/main/profile/profile.component'; -import { SupportComponent } from '@app/main/support/support.component'; -import { FatalErrorComponent, GatewayTimeoutComponent, PageNotFoundComponent } from '@app/main/server-status.component'; -import { HostListComponent } from '@app/components/host/host-list/host-list.component'; -import { MainInfoComponent } from '@app/shared/components'; -import { ConfigComponent } from '@app/shared/configuration/main/config.component'; -import { HostproviderComponent } from '@app/components/hostprovider/hostprovider.component'; -import { ConfigGroupHostListComponent, ConfigGroupListComponent } from '@app/config-groups'; -import { HostDetailsComponent } from '@app/components/host/host-details/host-details.component'; -import { ProviderDetailsComponent } from '@app/components/hostprovider/provider-details/provider-details.component'; -import { GroupConfigDetailsComponent } from '@app/components/hostprovider/group-config-details/group-config-details.component'; -import { HostStatusComponent } from '@app/components/host/host-status/host-status.component'; - -const routes: Routes = [ - { - path: 'cluster', - loadChildren: () => import('app/entry/cluster/cluster.module').then(m => m.ClusterModule), - }, - { - path: 'job', - loadChildren: () => import('app/entry/job/job.module').then(m => m.JobModule), - }, - { - path: 'task', - loadChildren: () => import('app/entry/task/task.module').then(m => m.TaskModule), - }, - { - path: 'bundle', - loadChildren: () => import('app/entry/bundle/bundle.module').then(m => m.BundleModule), - }, - { - path: 'host', - children: [ - { - path: '', - pathMatch: 'full', - component: HostListComponent, - }, { - path: ':host', - component: HostDetailsComponent, - children: [ - { path: '', redirectTo: 'main', pathMatch: 'full' }, - { path: 'main', component: MainInfoComponent }, - { path: 'config', component: ConfigComponent }, - { path: 'status', component: HostStatusComponent }, - ], - } - ], - canActivate: [AuthGuard], - }, - { - path: 'provider', - children: [ - { - path: '', - pathMatch: 'full', - component: HostproviderComponent, - }, { - path: ':provider', - component: ProviderDetailsComponent, - children: [ - { path: '', redirectTo: 'main', pathMatch: 'full' }, - { path: 'main', component: MainInfoComponent }, - { path: 'config', component: ConfigComponent }, - { path: 'group_config', component: ConfigGroupListComponent }, - ] - } - ], - canActivate: [AuthGuard], - }, - { - path: 'provider/:provider/group_config/:group_config', - canActivate: [AuthGuard], - canActivateChild: [AuthGuard], - component: GroupConfigDetailsComponent, - children: [ - { path: '', redirectTo: 'host', pathMatch: 'full' }, - { path: 'host', component: ConfigGroupHostListComponent }, - { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } }, - ], - }, - - { - path: 'cluster/:cluster/host/:host/provider/:provider', - redirectTo: 'provider/:provider', - }, - { - path: 'host/:host/provider/:provider', - redirectTo: 'provider/:provider', - }, - { path: '', redirectTo: 'admin', pathMatch: 'full' }, - { path: 'log', component: LogComponent, canActivate: [AuthGuard] }, - { path: 'login', component: LoginComponent }, - { path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] }, - { path: 'support', component: SupportComponent }, - { path: '404', component: PageNotFoundComponent }, - { path: '500', component: FatalErrorComponent }, - { path: '504', component: GatewayTimeoutComponent }, - { - path: 'admin', - loadChildren: () => import('app/admin/admin.module').then(m => m.AdminModule), - }, - { path: '**', component: PageNotFoundComponent }, -]; - -@NgModule({ - imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })], - exports: [RouterModule] -}) -export class AppRoutingModule { -} diff --git a/web/src/app/app.component.ts b/web/src/app/app.component.ts deleted file mode 100644 index ca2818e443..0000000000 --- a/web/src/app/app.component.ts +++ /dev/null @@ -1,110 +0,0 @@ -// Licensed 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 { Component, ElementRef, OnInit } from '@angular/core'; -import { AppService, ChannelService, DomService, keyChannelStrim } from '@app/core/services'; -import { filter } from 'rxjs/operators'; - -import { TooltipComponent } from '@app/shared/components/tooltip'; - -/** Magic strings for marking loading stages and other, for ci tests */ -const enum flagForConsole { - 'profile' = 'profile', - 'socket' = 'socket', - 'load_complete' = 'load_complete', -} - -@Component({ - selector: 'app-root', - template: ` - -
- -
- - -
- - -
-
- `, - providers: [AppService], -}) -export class AppComponent implements OnInit { - currentYear = new Date().getFullYear(); - versionData = { version: '', commit_id: '' }; - - constructor( - private elRef: ElementRef, - private service: AppService, - private radio: ChannelService, - private dom: DomService - ) {} - - ngOnInit() { - this.dom.appendComponentToBody(TooltipComponent); - - this.service.getRootAndCheckAuth().subscribe((c) => { - if (!c) this.elRef.nativeElement.innerHTML = ''; - else this.versionData = { ...c }; - }); - - this.service.initListeners(); - - this.service - .checkWSconnectStatus() - .pipe(filter((a) => a === 'open')) - .subscribe((_) => this.console('Socket status :: open', flagForConsole.socket)); - - this.service.checkUserProfile().subscribe((_) => this.console('User profile :: saved', flagForConsole.profile)); - - this.versionData = this.service.getVersion(this.versionData); - - this.radio - .on(keyChannelStrim.load_complete) - .subscribe((a) => this.console(a, flagForConsole.load_complete)); - } - - /** - * TODO: move this to component and append through DomService (as TooltipComponent - line: 61) - * important - to approve with QA! - */ - console(text: string, css?: string) { - const console = this.elRef.nativeElement.querySelector('div.console'); - if (!text) console.innerHTML = ''; - else { - const create = () => document.createElement('p'); - const isExist = () => console.querySelector(`.${css}`); - const inner = (p: HTMLElement) => (p.innerText = text); - const addClass = (p: HTMLElement) => p.classList.add(css); - const append = (p: HTMLElement) => console.appendChild(p); - const a = create(); - inner(a); - if (css && !isExist()) { - addClass(a); - append(a); - } - } - } -} diff --git a/web/src/app/app.module.ts b/web/src/app/app.module.ts deleted file mode 100644 index b146e16bc1..0000000000 --- a/web/src/app/app.module.ts +++ /dev/null @@ -1,99 +0,0 @@ -// Licensed 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 { APP_INITIALIZER, Injector, NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { EffectsModule } from '@ngrx/effects'; -import { StoreModule } from '@ngrx/store'; -import { StoreDevtoolsModule } from '@ngrx/store-devtools'; -import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; -import { HttpClient } from '@angular/common/http'; -import { AdwpPortalHostModule, AdwpUiWidgetsModule } from '@app/adwp'; - -import { CoreModule } from '@app/core/core.module'; -import { ConfigService } from '@app/core/services'; -import { reducers, StoreEffects } from '@app/core/store'; -import { environment } from '@env/environment'; -import { AppComponent } from './app.component'; -import { EntryModule } from './entry/entry.module'; -import { MainModule } from './main/main.module'; -import { SharedModule } from './shared/shared.module'; -import { LogComponent } from './ws-logs/log.component'; -import { appInitializer, translateLoader } from '@app/shared/translate/intializer'; -import { AppRoutingModule } from '@app/app-routing.module'; -import { ListService } from '@app/shared/components/list/list.service'; -import { LIST_SERVICE_PROVIDER } from '@app/shared/components/list/list-service-token'; -import { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model'; -import { AddService } from '@app/shared/add-component/add.service'; -import { SnackBarComponent } from './components/snack-bar/snack-bar.component'; -import { RouterHistoryService } from '@app/core/services/router-history.service'; - -@NgModule({ - declarations: [ - AppComponent, - LogComponent, - SnackBarComponent, - ], - imports: [ - BrowserModule, - BrowserAnimationsModule, - CoreModule, - SharedModule, - EntryModule, - MainModule, - AppRoutingModule, - StoreModule.forRoot(reducers), - EffectsModule.forRoot(StoreEffects), - !environment.production ? StoreDevtoolsModule.instrument() : [], - TranslateModule.forRoot({ - defaultLanguage: 'en', - loader: { - provide: TranslateLoader, - useFactory: translateLoader, - deps: [HttpClient] - } - }), - AdwpUiWidgetsModule, - AdwpPortalHostModule, - ], - bootstrap: [AppComponent], - providers: [ - { - provide: APP_INITIALIZER, - useFactory: (appConfig: ConfigService) => () => appConfig.load(), - deps: [ConfigService], - multi: true, - }, - { - provide: APP_INITIALIZER, - useFactory: appInitializer, - deps: [TranslateService, Injector], - multi: true - }, - { - provide: APP_INITIALIZER, - useFactory: (routerHistory: RouterHistoryService) => () => routerHistory.reset(), - deps: [RouterHistoryService], - multi: true - }, - { - provide: LIST_SERVICE_PROVIDER, - useClass: ListService - }, - { - provide: ADD_SERVICE_PROVIDER, - useClass: AddService - } - ], -}) -export class AppModule { -} diff --git a/web/src/app/components/actions-button/actions-button.component.html b/web/src/app/components/actions-button/actions-button.component.html deleted file mode 100644 index daea46f29a..0000000000 --- a/web/src/app/components/actions-button/actions-button.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - diff --git a/web/src/app/components/actions-button/actions-button.component.scss b/web/src/app/components/actions-button/actions-button.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/components/actions-button/actions-button.component.spec.ts b/web/src/app/components/actions-button/actions-button.component.spec.ts deleted file mode 100644 index 918518aa3f..0000000000 --- a/web/src/app/components/actions-button/actions-button.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ActionsButtonComponent } from './actions-button.component'; - -describe('ActionsButtonComponent', () => { - let component: ActionsButtonComponent; - let fixture: ComponentFixture>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ ActionsButtonComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ActionsButtonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/components/actions-button/actions-button.component.ts b/web/src/app/components/actions-button/actions-button.component.ts deleted file mode 100644 index c9087dc633..0000000000 --- a/web/src/app/components/actions-button/actions-button.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { BaseDirective, EventHelper } from '@app/adwp'; - -import { BaseEntity } from '@app/core/types'; - -@Component({ - selector: 'app-actions-button', - templateUrl: './actions-button.component.html', - styleUrls: ['./actions-button.component.scss'] -}) -export class ActionsButtonComponent extends BaseDirective { - - EventHelper = EventHelper; - - @Input() row: T; - - @Output() onMouseenter = new EventEmitter(); - - getClusterData(row: any) { - const { id, hostcomponent } = row.cluster || row; - const { action } = row; - return { id, hostcomponent, action }; - } - -} diff --git a/web/src/app/components/bell/bell.component.scss b/web/src/app/components/bell/bell.component.scss deleted file mode 100644 index c12380c497..0000000000 --- a/web/src/app/components/bell/bell.component.scss +++ /dev/null @@ -1,66 +0,0 @@ -.bell-wrapper { - width: 50px; - height: 50px; - background: none; -} - -.circle { - width: 50px; - height: 50px; - border-radius: 50%; - background-repeat: no-repeat; - - cursor: pointer; - position: relative; -} - -@keyframes spinner { - 0% { - transform: rotate(0deg); - opacity: 1; - } - 50% { - transform: rotate(180deg); - opacity: 0.8; - } - 75% { - transform: rotate(270deg); - opacity: 0.6; - } - 100% { - transform: rotate(360deg); - opacity: 0; - } -} - -.animation { - width: 100%; - height: 100%; - border-radius: 50%; - background-repeat: no-repeat; - background-image: conic-gradient(#fff, #262d37); - animation-duration: 0.7s; - animation-timing-function: linear; -} - -.animated { - animation-name: spinner; -} - -.hide { - opacity: 0; -} - -.insider { - width: 36px; - height: 36px; - border-radius: 50%; - background: #262d37; - top: 7px; - left: 7px; - position: absolute; - - display: flex; - align-items: center; - justify-content: center; -} diff --git a/web/src/app/components/bell/bell.component.ts b/web/src/app/components/bell/bell.component.ts deleted file mode 100644 index fda1621038..0000000000 --- a/web/src/app/components/bell/bell.component.ts +++ /dev/null @@ -1,285 +0,0 @@ -import { AfterViewInit, Component, ElementRef, Renderer2, ViewChild } from '@angular/core'; -import { BaseDirective } from '@app/adwp'; -import { BehaviorSubject, combineLatest, interval, Observable, zip } from 'rxjs'; -import { filter, map, mergeMap, take, takeWhile } from 'rxjs/operators'; - -import { TaskService } from '@app/services/task.service'; -import { ACKNOWLEDGE_EVENT, NotificationsComponent } from '@app/components/notifications/notifications.component'; -import { JobStatus, Task, TaskRaw } from '@app/core/types'; -import { EventMessage, ProfileService } from '@app/core/store'; -import { Stats, StatsService } from '@app/services/stats.service'; - -const RUNNING_COLOR = '#FFEA00'; -const SUCCESS_COLOR = '#1EE564'; -const FAILED_COLOR = '#FF8A80'; - -export interface NotificationsData { - runningCount: number; - successCount: number; - failedCount: number; -} - -@Component({ - selector: 'app-bell', - template: ` -
-
-
-
- notifications -
-
-
- `, - styleUrls: ['./bell.component.scss'] -}) -export class BellComponent extends BaseDirective implements AfterViewInit { - - NotificationsComponent = NotificationsComponent; - - @ViewChild('animation', { static: false }) animationRef: ElementRef; - - runningCount = new BehaviorSubject(0); - successCount = new BehaviorSubject(0); - failedCount = new BehaviorSubject(0); - - bellGradient = ''; - currentTaskId: number; - - isAnimationRunning = new BehaviorSubject(false); - animationElem = new BehaviorSubject(null); - - counts = new BehaviorSubject(null); - tasks = new BehaviorSubject([]); - - readonly bindedPopoverEvent = this.popoverEvent.bind(this); - - constructor( - private taskService: TaskService, - private renderer: Renderer2, - private profileService: ProfileService, - private statsService: StatsService, - ) { - super(); - } - - popoverEvent(event: any) { - if (event === ACKNOWLEDGE_EVENT) { - const lastTaskId = this.tasks.value[0]?.id; - if (lastTaskId) { - this.profileService.setLastViewedTask(lastTaskId).subscribe(); - } - this.tasks.next([]); - this.successCount.next(0); - this.runningCount.next(0); - this.failedCount.next(0); - this.afterCountChanged(false); - } - } - - onAnimationStart() { - this.isAnimationRunning.next(true); - } - - onAnimationEnd() { - this.isAnimationRunning.next(false); - } - - startAnimation() { - if (this.animationElem.value && !this.isAnimationRunning.value) { - this.renderer.removeClass(this.animationElem.value, 'hide'); - this.renderer.addClass(this.animationElem.value, 'animated'); - } - } - - endAnimation() { - if (this.animationElem.value) { - this.renderer.addClass(this.animationElem.value, 'hide'); - this.renderer.removeClass(this.animationElem.value, 'animated'); - } - } - - afterCountChanged(animationNeeds = true) { - const total = this.runningCount.value + this.successCount.value + this.failedCount.value; - if (total > 0) { - const degOne = 360 / total; - const degRunning = this.runningCount.value * degOne; - const degSuccess = this.successCount.value * degOne; - this.bellGradient = - `conic-gradient(` - + `${RUNNING_COLOR} 0deg ${degRunning}deg,` - + `${SUCCESS_COLOR} ${degRunning}deg ${degRunning + degSuccess}deg,` - + `${FAILED_COLOR} ${degRunning + degSuccess}deg 360deg)`; - } else { - this.bellGradient = 'transparent'; - } - if (animationNeeds) { - this.startAnimation(); - } - } - - getChangeTaskObservable(): Observable { - return this.taskService.events({ events: ['change_job_status'] }, 'task').pipe(this.takeUntil()); - } - - getChangeJobObservable(): Observable { - return this.taskService.events({ events: ['change_job_status'] }, 'job').pipe(this.takeUntil()); - } - - decRunningCount() { - const runningCount = this.runningCount.value - 1; - this.runningCount.next(runningCount < 0 ? 0 : runningCount); - } - - updateTask(updatedTaskId: number, task: TaskRaw, status: JobStatus) { - const tasks: TaskRaw[] = this.tasks.value.slice(); - const index = tasks.findIndex(item => item.id === updatedTaskId); - task.status = status; - tasks.splice(index, 1, task); - this.tasks.next(tasks); - } - - updateJob(updatedJobId: number, status: JobStatus) { - const tasks: TaskRaw[] = this.tasks.value.slice(); - const taskIndex = tasks.findIndex((task) => task.id === this.currentTaskId); - - if (taskIndex < 0) return; - - const updatedJobIndex = tasks[taskIndex].jobs.findIndex((job) => job.id === updatedJobId); - - if (updatedJobIndex < 0) return; - - tasks[taskIndex].jobs[updatedJobIndex].status = status; - this.tasks.next(tasks); - } - - listenToTasks() { - this.getChangeTaskObservable().subscribe((event) => { - const status = event.object.details.value; - this.currentTaskId = event.object.id; - if (status === 'running') { - this.runningCount.next(this.runningCount.value + 1); - this.afterCountChanged(); - } else if (status === 'success') { - this.successCount.next(this.successCount.value + 1); - this.decRunningCount(); - this.afterCountChanged(); - } else if (status === 'failed' || status === 'aborted') { // fix if aborted counter will be added - this.failedCount.next(this.failedCount.value + 1); - this.decRunningCount(); - this.afterCountChanged(); - } - }); - - this.getChangeJobObservable().subscribe((event) => { - const jobStatus = event.object.details.value; - const jobId = event.object.id; - this.updateJob(jobId, jobStatus); - }); - - this.getChangeTaskObservable().pipe( - filter(event => event.object.details.type === 'status'), - filter(event => event.object.details.value !== 'created'), - ).subscribe((event) => { - const tasks: TaskRaw[] = this.tasks.value.slice(); - const updatedTaskId = event.object.id; - const index = tasks.findIndex(item => item.id === updatedTaskId); - if (index >= 0) { - this.taskService.get(updatedTaskId).subscribe((updatedTask) => { - this.updateTask(updatedTaskId, updatedTask, event.object.details.value); - - const task: TaskRaw = Object.assign({}, this.tasks.value[index]); - tasks.splice(index, 1, task); - this.tasks.next(tasks); - }); - } else { - this.taskService.get(event.object.id).subscribe((task) => { - task.status = event.object.details.value; - tasks.unshift(task); - this.tasks.next(tasks.slice(0, 5)); - }); - } - }); - } - - getCurrentCounts(): Observable { - return this.profileService.getProfile().pipe( - take(1), - mergeMap((user) => this.statsService.tasks(user.profile?.lastViewedTask?.id)), - ); - } - - getLastTasks(): Observable { - return zip( - this.taskService.list({ ordering: '-finish_date', status: 'aborted', limit: '5' }), - this.taskService.list({ ordering: '-finish_date', status: 'failed', limit: '5' }), - this.taskService.list({ ordering: '-finish_date', status: 'success', limit: '5' }), - this.taskService.list({ ordering: '-start_date', status: 'running', limit: '5' }), - this.profileService.getProfile(), - ).pipe(map(([aborted, failed, succeed, running, user]) => { - let tasks = [...aborted.results, ...failed.results, ...succeed.results, ...running.results].sort((a, b) => { - const getDateField = (task: Task) => task.status === 'failed' || task.status === 'aborted' || task.status === 'success' ? task.finish_date : task.start_date; - const aDate = new Date(getDateField(a)); - const bDate = new Date(getDateField(b)); - return aDate.getTime() - bDate.getTime(); - }).reverse().slice(0, 5); - - if (user.profile?.lastViewedTask?.id) { - tasks = tasks.filter(task => task.id > user.profile.lastViewedTask.id); - } - - return tasks; - })); - } - - ngAfterViewInit(): void { - interval(200).pipe( - this.takeUntil(), - takeWhile(() => !this.animationElem.value), - ).subscribe(() => { - this.animationElem.next(this.animationRef ? this.animationRef.nativeElement : null); - }); - - this.animationElem.pipe( - this.takeUntil(), - filter((elem) => !!elem), - take(1), - ).subscribe(() => { - zip(this.getCurrentCounts(), this.getLastTasks()) - .subscribe(([stats, tasks]) => { - this.runningCount.next(stats.running); - this.successCount.next(stats.success); - this.failedCount.next(stats.failed + stats.aborted); - this.afterCountChanged(!!(stats.running || stats.success || stats.failed || stats.aborted)); - this.tasks.next(tasks); - this.listenToTasks(); - }); - }); - - this.isAnimationRunning.pipe( - this.takeUntil(), - filter(isRunning => !isRunning), - ).subscribe(() => this.endAnimation()); - - combineLatest(this.runningCount, this.successCount, this.failedCount) - .pipe(this.takeUntil()) - .subscribe( - ([runningCount, successCount, failedCount]) => this.counts.next({ - runningCount, - successCount, - failedCount, - }) - ); - } - -} diff --git a/web/src/app/components/bundle/bundle-details/bundle-details.component.ts b/web/src/app/components/bundle/bundle-details/bundle-details.component.ts deleted file mode 100644 index 4e4119c455..0000000000 --- a/web/src/app/components/bundle/bundle-details/bundle-details.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Component, Injector } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; - -import { DetailsFactory } from '@app/factories/details.factory'; -import { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive'; -import { Bundle } from '@app/core/types'; -import { SocketState } from '@app/core/store'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ChannelService } from '@app/core/services'; -import { BundleService } from '@app/services/bundle.service'; - -@Component({ - selector: 'app-bundle-details', - templateUrl: '../../../templates/details.html', - styleUrls: ['../../../styles/details.scss'] -}) -export class BundleDetailsComponent extends DetailAbstractDirective { - - entityParam = 'bundle'; - - leftMenu = [ - DetailsFactory.labelMenuItem('Main', 'main'), - DetailsFactory.labelMenuItem('License', 'license'), - ]; - - constructor( - socket: Store, - protected route: ActivatedRoute, - protected service: ClusterService, - protected channel: ChannelService, - protected store: Store, - injector: Injector, - protected subjectService: BundleService, - ) { - super(socket, route, service, channel, store, injector); - } - -} diff --git a/web/src/app/components/cluster/cluster-details/cluster-details.component.ts b/web/src/app/components/cluster/cluster-details/cluster-details.component.ts deleted file mode 100644 index 93908e26d0..0000000000 --- a/web/src/app/components/cluster/cluster-details/cluster-details.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Component, Injector } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; - -import { DetailsFactory } from '@app/factories/details.factory'; -import { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive'; -import { ICluster } from '@app/models/cluster'; -import { SocketState } from '@app/core/store'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ChannelService } from '@app/core/services'; -import { ClusterEntityService } from '@app/services/cluster-entity.service'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -@Component({ - selector: 'app-cluster-details', - templateUrl: '../../../templates/details.html', - styleUrls: ['../../../styles/details.scss'] -}) -export class ClusterDetailsComponent extends DetailAbstractDirective { - - entityParam = 'cluster'; - - leftMenu = [ - DetailsFactory.labelMenuItem('Main', 'main'), - DetailsFactory.concernMenuItem('Services', 'service', 'service', ConcernEventType.Cluster, 'cluster'), - DetailsFactory.labelMenuItem('Hosts', 'host'), - DetailsFactory.concernMenuItem('Hosts - Components', 'host_component', 'host-component', ConcernEventType.Cluster, 'cluster'), - DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.Cluster, 'cluster'), - DetailsFactory.labelMenuItem('Configuration groups', 'group_config'), - DetailsFactory.statusMenuItem('Status', 'status', 'cluster'), - DetailsFactory.concernMenuItem('Import', 'import', 'import', ConcernEventType.Cluster, 'cluster'), - ]; - - constructor( - socket: Store, - protected route: ActivatedRoute, - protected service: ClusterService, - protected channel: ChannelService, - protected store: Store, - injector: Injector, - protected subjectService: ClusterEntityService, - ) { - super(socket, route, service, channel, store, injector); - } - -} diff --git a/web/src/app/components/cluster/cluster-status/cluster-status.component.ts b/web/src/app/components/cluster/cluster-status/cluster-status.component.ts deleted file mode 100644 index 975ca6f060..0000000000 --- a/web/src/app/components/cluster/cluster-status/cluster-status.component.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { fromJS, updateIn } from 'immutable'; - -import { ClusterEntityService } from '@app/services/cluster-entity.service'; -import { ClusterStatusTree } from '@app/models/status-tree'; -import { EventMessage, SocketState } from '@app/core/store'; -import { StatusAbstractDirective } from '@app/abstract-directives/status.abstract.directive'; -import { ICluster } from '../../../models/cluster'; - -@Component({ - selector: 'app-cluster-status', - templateUrl: '../../../templates/status-tree.html', - styleUrls: ['../../../styles/status-tree.scss'] -}) -export class ClusterStatusComponent extends StatusAbstractDirective { - - constructor( - protected route: ActivatedRoute, - protected store: Store, - public entityService: ClusterEntityService, - ) { - super(route, store, entityService); - } - - eventReceived(event: EventMessage) { - let output; - switch (event.object.type) { - case 'hostcomponent': - output = updateIn(fromJS(this.statusTree.value), ['chilren', 'services'], (services: any[]) => - services.map(service => updateIn(service, ['hc'], (components: any) => - components.map( (component: any) => updateIn(component, ['hosts'], (hosts: any) => - hosts.map((host: any) => { - if (host.get('id') === event.object.id && component.get('id') === +event.object.details.id) { - return host.set('status', +event.object.details.value); - } - return host; - }) - )) - )) - ); - this.statusTree.next(output.toJS() as any as ClusterStatusTree); - break; - case 'component': - output = updateIn(fromJS(this.statusTree.value), ['chilren', 'services'], (services: any[]) => ( - services.map(service => updateIn(service, ['hc'], (components: any) => components.map( (component: any) => { - if (component.get('id') === event.object.id) { - return component.set('status', +event.object.details.value); - } - return component; - }))) - )); - this.statusTree.next(output.toJS() as any as ClusterStatusTree); - break; - case 'service': - output = updateIn(fromJS(this.statusTree.value), ['chilren', 'services'], (services: any[]) => ( - services.map(service => { - if (service.get('id') === event.object.id) { - return service.set('status', +event.object.details.value); - } - return service; - }))); - this.statusTree.next(output.toJS() as any as ClusterStatusTree); - break; - case 'host': - output = updateIn(fromJS(this.statusTree.value), ['chilren', 'hosts'], (hosts: any[]) => ( - hosts.map(host => { - if (host.get('id') === event.object.id) { - return host.set('status', +event.object.details.value); - } - return host; - }) - )); - this.statusTree.next(output.toJS() as any as ClusterStatusTree); - break; - case 'cluster': - output = fromJS(this.statusTree.value); - if (output.get('id') === event.object.id) { - output = output.set('status', +event.object.details.value); - } - this.statusTree.next(output.toJS() as any as ClusterStatusTree); - break; - } - } - - getEntityIdFromParams(): number { - return +this.route.parent.snapshot.params.cluster; - } - - prepareStatusTree(input: ClusterStatusTree): ClusterStatusTree { - input.id = this.entityId; - return input; - } - -} diff --git a/web/src/app/components/cluster/hcmap/hcmap.component.ts b/web/src/app/components/cluster/hcmap/hcmap.component.ts deleted file mode 100644 index 8720c8a385..0000000000 --- a/web/src/app/components/cluster/hcmap/hcmap.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { ClusterService } from '@app/core/services/cluster.service'; - -@Component({ - template: ` `, - styles: [':host { flex: 1; }'], -}) -export class HcmapComponent implements OnInit { - cluster: { id: number; hostcomponent: string }; - constructor(private service: ClusterService) {} - - ngOnInit() { - const { id, hostcomponent } = { ...this.service.Cluster }; - this.cluster = { id, hostcomponent }; - } -} diff --git a/web/src/app/components/cluster/host/cluster-host.component.ts b/web/src/app/components/cluster/host/cluster-host.component.ts deleted file mode 100644 index b44ed623d5..0000000000 --- a/web/src/app/components/cluster/host/cluster-host.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Component } from '@angular/core'; -import { IColumns } from '@app/adwp'; - -import { TypeName } from '@app/core/types'; -import { IHost } from '@app/models/host'; -import { ListFactory } from '../../../factories/list.factory'; -import { ConcernListDirective } from '@app/abstract-directives/concern-list.directive'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -@Component({ - selector: 'app-cluster-host', - template: ` - Add hosts - - - `, - styles: [':host { flex: 1; }', '.add-button {position:fixed; right: 20px;top:120px;}'], -}) -export class ClusterHostComponent extends ConcernListDirective { - - type: TypeName = 'host2cluster'; - eventTypes = [ConcernEventType.Host]; - - listColumns = [ - ListFactory.fqdnColumn(), - ListFactory.providerColumn(), - ListFactory.stateColumn(), - ListFactory.statusColumn(this), - ListFactory.actionsButton(this), - ListFactory.configColumn(this), - ListFactory.maintenanceModeColumn(this, 'host'), - { - type: 'buttons', - className: 'list-control', - headerClassName: 'list-control', - buttons: [{ - icon: 'link_off', - tooltip: 'Remove from cluster', - callback: (row, event) => this.delete(event, row), - }], - } - ] as IColumns; - -} diff --git a/web/src/app/components/cluster/services/services.component.ts b/web/src/app/components/cluster/services/services.component.ts deleted file mode 100644 index 8f630a7ed7..0000000000 --- a/web/src/app/components/cluster/services/services.component.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Component } from '@angular/core'; -import { IColumns } from '@app/adwp'; - -import { TypeName } from '@app/core/types'; -import { ListFactory } from '../../../factories/list.factory'; -import { IClusterService } from '@app/models/cluster-service'; -import { ConcernListDirective } from '@app/abstract-directives/concern-list.directive'; -import { ConcernEventType } from '../../../models/concern/concern-reason'; - -@Component({ - selector: 'app-services', - template: ` - Add services - - - `, - styles: [':host { flex: 1; }', '.add-button {position:fixed; right: 20px;top:120px;}'], -}) -export class ServicesComponent extends ConcernListDirective { - - type: TypeName = 'service2cluster'; - eventTypes = [ConcernEventType.Service]; - - listColumns = [ - ListFactory.nameColumn('display_name'), - { - label: 'Version', - value: (row) => row.version, - }, - ListFactory.stateColumn(), - ListFactory.statusColumn(this), - ListFactory.actionsButton(this), - ListFactory.importColumn(this), - ListFactory.configColumn(this), - ListFactory.maintenanceModeColumn(this, 'service'), - ListFactory.deleteColumn(this), - ] as IColumns; - -} diff --git a/web/src/app/components/columns/cluster-column/cluster-column.component.ts b/web/src/app/components/columns/cluster-column/cluster-column.component.ts deleted file mode 100644 index 486b5041af..0000000000 --- a/web/src/app/components/columns/cluster-column/cluster-column.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, Input, Output, EventEmitter } from '@angular/core'; -import { AdwpCellComponent, ILinkColumn, EventHelper } from '@app/adwp'; - -import { IHost } from '@app/models/host'; -import { UniversalAdcmEventData } from '@app/models/universal-adcm-event-data'; -import { ICluster } from '@app/models/cluster'; - -export interface AddClusterEventData extends UniversalAdcmEventData { - cluster: ICluster; -} - -@Component({ - selector: 'app-cluster-column', - template: ` - - - - - - ... - - {{ item.title }} - - - - - - `, - styles: [` - :host { - width: 100%; - } - `], -}) -export class ClusterColumnComponent implements AdwpCellComponent { - - EventHelper = EventHelper; - - @Input() row: IHost; - - @Output() onGetNextPageCluster = new EventEmitter>(); - @Output() onGetClusters = new EventEmitter>(); - @Output() onAddCluster = new EventEmitter(); - - linkColumn: ILinkColumn = { - label: '', - type: 'link', - value: (row) => row.cluster_name, - url: (row) => `/cluster/${row.cluster_id}`, - }; - - getNextPageCluster(event: MouseEvent) { - this.onGetNextPageCluster.emit({ event, action: 'getNextPageCluster', row: this.row }); - } - - getClusters(event: MouseEvent) { - this.onGetClusters.emit({ event, action: 'getClusters', row: this.row }); - } - - addCluster(event: MouseEvent, cluster: ICluster) { - this.onAddCluster.emit({ event, action: 'addCluster', row: this.row, cluster }); - } - -} diff --git a/web/src/app/components/columns/download-button-column/download-button-column.component.html b/web/src/app/components/columns/download-button-column/download-button-column.component.html deleted file mode 100644 index 67b426d28f..0000000000 --- a/web/src/app/components/columns/download-button-column/download-button-column.component.html +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/web/src/app/components/columns/download-button-column/download-button-column.component.scss b/web/src/app/components/columns/download-button-column/download-button-column.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/components/columns/download-button-column/download-button-column.component.ts b/web/src/app/components/columns/download-button-column/download-button-column.component.ts deleted file mode 100644 index d28a9faf87..0000000000 --- a/web/src/app/components/columns/download-button-column/download-button-column.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { AuthService } from "@app/core/auth/auth.service"; - -@Component({ - selector: 'app-download-button-column', - templateUrl: './download-button-column.component.html', - styleUrls: ['./download-button-column.component.scss'] -}) -export class DownloadButtonColumnComponent implements OnInit { - - url: string; - tooltip: string; - - constructor(private auth: AuthService) {} - - ngOnInit(): void {} - - download() { - location.href = this.url; - } -} diff --git a/web/src/app/components/columns/edition-column/edition-column.component.scss b/web/src/app/components/columns/edition-column/edition-column.component.scss deleted file mode 100644 index bea911de6f..0000000000 --- a/web/src/app/components/columns/edition-column/edition-column.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.mat-icon-button ::ng-deep .mat-button-focus-overlay { - display: none; -} diff --git a/web/src/app/components/columns/edition-column/edition-column.component.ts b/web/src/app/components/columns/edition-column/edition-column.component.ts deleted file mode 100644 index 9e68b71121..0000000000 --- a/web/src/app/components/columns/edition-column/edition-column.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component, Input, Output } from '@angular/core'; -import { AdwpCellComponent } from '@app/adwp'; - -import { IBundle } from '@app/models/bundle'; - -@Component({ - selector: 'app-edition-column', - template: ` - {{ row.edition }} - - - - `, - styleUrls: ['./edition-column.component.scss'] -}) -export class EditionColumnComponent implements AdwpCellComponent { - - @Input() row: IBundle; - - @Output() onClick: (data: { event: MouseEvent, action: string, row: any }) => void; - -} diff --git a/web/src/app/components/columns/history-column/history-column.component.html b/web/src/app/components/columns/history-column/history-column.component.html deleted file mode 100644 index e5e37f7581..0000000000 --- a/web/src/app/components/columns/history-column/history-column.component.html +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/web/src/app/components/columns/history-column/history-column.component.scss b/web/src/app/components/columns/history-column/history-column.component.scss deleted file mode 100644 index 9cf5a8dea6..0000000000 --- a/web/src/app/components/columns/history-column/history-column.component.scss +++ /dev/null @@ -1,17 +0,0 @@ -:host { - display: flex; - flex: 1; - width: 100px; - justify-content: center; -} - -.history-button { - display: flex; - width: 24px !important; - min-width: unset !important; - color: rgba(255, 255, 255, 0.3); -} - -.has-history { - color: #78909c !important; -} diff --git a/web/src/app/components/columns/history-column/history-column.component.ts b/web/src/app/components/columns/history-column/history-column.component.ts deleted file mode 100644 index 97f7a68e9c..0000000000 --- a/web/src/app/components/columns/history-column/history-column.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { MatDialog, MatDialogConfig } from "@angular/material/dialog"; -import { DialogComponent } from "@app/shared/components"; -import { - RbacAuditOperationsHistoryFormComponent -} from "@app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component"; - -@Component({ - selector: 'app-history-column', - templateUrl: './history-column.component.html', - styleUrls: ['./history-column.component.scss'] -}) -export class HistoryColumnComponent implements OnInit { - - row: any; - - constructor(private dialog: MatDialog) { } - - ngOnInit(): void {} - - hasChangesHistory() { - return Object.keys(this?.row?.object_changes)?.length !== 0; - } - - show(event) { - if (this.hasChangesHistory()) { - this.prepare(); - } - event.preventDefault(); - event.stopPropagation(); - } - - prepare(): void { - let dialogModel: MatDialogConfig - const maxWidth = '1000px'; - const width = '1000px'; - const title = 'Operation detail'; - - - dialogModel = { - width, - maxWidth, - data: { - title, - model: { - row: this.row, - }, - component: RbacAuditOperationsHistoryFormComponent, - controls: ['Cancel'], - }, - }; - - this.dialog.open(DialogComponent, dialogModel) - } -} diff --git a/web/src/app/components/columns/job-name/job-name.component.scss b/web/src/app/components/columns/job-name/job-name.component.scss deleted file mode 100644 index f85ccae89b..0000000000 --- a/web/src/app/components/columns/job-name/job-name.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -.job-name-container { - padding-left: 30px; -} - -.regular-name { - padding-left: 4px; -} diff --git a/web/src/app/components/columns/job-name/job-name.component.ts b/web/src/app/components/columns/job-name/job-name.component.ts deleted file mode 100644 index 10bb92f2d7..0000000000 --- a/web/src/app/components/columns/job-name/job-name.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Component } from '@angular/core'; -import { AdwpCellComponent, ILinkColumn } from '@app/adwp'; - -import { Job } from '@app/core/types'; - -@Component({ - selector: 'app-job-name', - template: ` -
- - {{ row.display_name || row.id }} - - - - -
- `, - styleUrls: ['./job-name.component.scss'] -}) -export class JobNameComponent implements AdwpCellComponent { - - row: Job; - - linkColumn: ILinkColumn = { - label: '', - type: 'link', - value: (row) => row.display_name || row.id, - url: (row) => `/job/${row.id}`, - }; - -} diff --git a/web/src/app/components/columns/job-status-column/job-status-column.component.html b/web/src/app/components/columns/job-status-column/job-status-column.component.html deleted file mode 100644 index dff879c1dc..0000000000 --- a/web/src/app/components/columns/job-status-column/job-status-column.component.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - autorenew - - - - - {{ iconDisplay[row.status] }} - - diff --git a/web/src/app/components/columns/job-status-column/job-status-column.component.scss b/web/src/app/components/columns/job-status-column/job-status-column.component.scss deleted file mode 100644 index cbdd0d4329..0000000000 --- a/web/src/app/components/columns/job-status-column/job-status-column.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -:host { - .stop-btn { - min-width: 32px; - } -} - -.mat-icon { - vertical-align: middle; - font-size: 1.2em; - width: auto; - height: auto; -} diff --git a/web/src/app/components/columns/job-status-column/job-status-column.component.ts b/web/src/app/components/columns/job-status-column/job-status-column.component.ts deleted file mode 100644 index 59875ded47..0000000000 --- a/web/src/app/components/columns/job-status-column/job-status-column.component.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Component } from '@angular/core'; -import { AdwpCellComponent } from '@app/adwp'; -import { filter, switchMap } from 'rxjs/operators'; -import { MatDialog } from '@angular/material/dialog'; - -import { Job } from '@app/core/types'; -import { DialogComponent } from '@app/shared/components'; - - -import { ApiService } from '@app/core/api'; - -@Component({ - selector: 'app-job-status-column', - templateUrl: './job-status-column.component.html', - styleUrls: ['./job-status-column.component.scss'] -}) -export class JobStatusColumnComponent implements AdwpCellComponent { - - constructor( - public dialog: MatDialog, - private api: ApiService, - ) {} - - row: Job; - - iconDisplay = { - created: 'watch_later', - running: 'autorenew', - success: 'done', - failed: 'error', - aborted: 'block' - }; - - - cancelJob() { - this.dialog - .open(DialogComponent, { - data: { - text: 'Are you sure?', - controls: ['Yes', 'No'], - }, - }) - .beforeClosed() - .pipe( - filter((yes) => yes), - switchMap(() => this.api.put(`/api/v1/job/${this.row.id}/cancel/`, {})) - ) - .subscribe(); - } -} diff --git a/web/src/app/components/columns/name-edit-column/name-edit-column-field.component.ts b/web/src/app/components/columns/name-edit-column/name-edit-column-field.component.ts deleted file mode 100644 index 7251f209e6..0000000000 --- a/web/src/app/components/columns/name-edit-column/name-edit-column-field.component.ts +++ /dev/null @@ -1,65 +0,0 @@ -// Licensed 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 { Component, Input, OnInit } from '@angular/core'; -import { BaseDirective } from '@app/adwp'; -import { FormControl } from "@angular/forms"; -import { debounceTime } from "rxjs/operators"; -import { editColumnValues } from "@app/components/columns/name-edit-column/name-edit-column.component"; - -@Component({ - selector: 'name-edit-column-field', - template: ` - -
- - {{ column_rules?.modal_placeholder }} - - Please enter a valid {{ column_rules?.entity_type }} name - -
-
- `, - styles: [` - .form { - min-width: 150px; - max-width: 500px; - width: 100%; - } - - .full-width { - width: 100%; - } - `] -}) -export class NameEditColumnFieldComponent extends BaseDirective implements OnInit { - @Input() model: any; - - row: any; - form: FormControl; - column_rules: editColumnValues; - - ngOnInit() { - this.row = this.model.row; - this.form = this.model.form; - - this.form.valueChanges - .pipe(debounceTime(500)) - .subscribe(newValue => { - this.form.markAsTouched(); - this.form.setValue(newValue, {emitEvent: false}); - }); - } - - checkValidity() { - return this.form.invalid; - } -} diff --git a/web/src/app/components/columns/name-edit-column/name-edit-column.component.html b/web/src/app/components/columns/name-edit-column/name-edit-column.component.html deleted file mode 100644 index 51b2a8e9fc..0000000000 --- a/web/src/app/components/columns/name-edit-column/name-edit-column.component.html +++ /dev/null @@ -1,6 +0,0 @@ -
{{ row[column.sort] }}
-
- -
diff --git a/web/src/app/components/columns/name-edit-column/name-edit-column.component.scss b/web/src/app/components/columns/name-edit-column/name-edit-column.component.scss deleted file mode 100644 index a11495d09c..0000000000 --- a/web/src/app/components/columns/name-edit-column/name-edit-column.component.scss +++ /dev/null @@ -1,27 +0,0 @@ -:host { - display: flex; - flex-grow: 1; - align-items: center; - justify-content: space-between; - width: 50% -} - -.name { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.rename-button { - display: none; - margin-left: 10px; - width: 24px !important; - min-width: unset !important; -} - -.editIcon { - font-size: 20px !important; - height: 20px !important; - width: 20px !important; - vertical-align: text-bottom; -} diff --git a/web/src/app/components/columns/name-edit-column/name-edit-column.component.ts b/web/src/app/components/columns/name-edit-column/name-edit-column.component.ts deleted file mode 100644 index 21843131d6..0000000000 --- a/web/src/app/components/columns/name-edit-column/name-edit-column.component.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { AdwpCellComponent } from "@app/adwp"; -import { MatDialog, MatDialogConfig } from "@angular/material/dialog"; -import { DialogComponent } from "@app/shared/components"; -import { NameEditColumnFieldComponent } from "@app/components/columns/name-edit-column/name-edit-column-field.component"; -import { filter } from "rxjs/operators"; -import { FormControl, Validators } from "@angular/forms"; -import { ListService } from "@app/shared/components/list/list.service"; - -export interface editColumnValues { - modal_placeholder: string; - entity_type: string; - regex: any; -} - -@Component({ - selector: 'app-name-edit-column', - templateUrl: './name-edit-column.component.html', - styleUrls: ['./name-edit-column.component.scss'] -}) -export class NameEditColumnComponent implements AdwpCellComponent, OnInit { - - row: any; - column: any; - form: FormControl; - entity: string; - - constructor(private dialog: MatDialog, protected service: ListService) {} - - ngOnInit() { - this.form = new FormControl(this.row[this.column.sort], - [ - Validators.required, - Validators.maxLength(253), - Validators.pattern(new RegExp(this.column?.column_rules?.regex)) - ]); - this.entity = this.column?.column_rules?.entity_type; - } - - isEditable() { - switch (this.entity) { - case 'cluster': - return this.row.state === 'created'; - case 'host': - return this.row.cluster_id === null && this.row.state === 'created'; - } - } - - rename(event) { - this.prepare(); - event.preventDefault(); - event.stopPropagation(); - } - - prepare(): void { - let dialogModel: MatDialogConfig - const maxWidth = '1400px'; - const width = '500px'; - const title = `Edit ${ this.entity }`; - - this.form.setValue(this.row[this.column.sort]); - - dialogModel = { - width, - maxWidth, - data: { - title, - model: { - row: this.row, - column: this.column.sort, - form: this.form, - column_rules: this.column?.column_rules - }, - component: NameEditColumnFieldComponent, - controls: ['Save', 'Cancel'], - disabled: this.getFormStatus, - }, - }; - - this.dialog - .open(DialogComponent, dialogModel) - .beforeClosed() - .pipe(filter((save) => save)) - .subscribe(() => { - this.service[`rename${this.titleCase(this.entity)}`](this.column.sort, this.form.value, this.row.id) - .subscribe((value) => { - if (value) { - const colName = this.column.sort; - this.row[colName] = value[colName]; - } - }); - }); - } - - getFormStatus = (value) => { - return value.form.invalid; - } - - titleCase(string){ - return string[0].toUpperCase() + string.slice(1).toLowerCase(); - } -} diff --git a/web/src/app/components/columns/signature-column/signature-column.component.html b/web/src/app/components/columns/signature-column/signature-column.component.html deleted file mode 100644 index df5db5e15a..0000000000 --- a/web/src/app/components/columns/signature-column/signature-column.component.html +++ /dev/null @@ -1,5 +0,0 @@ -
{{ firstCharToUpperCase(row['signature_status']) }}
diff --git a/web/src/app/components/columns/signature-column/signature-column.component.scss b/web/src/app/components/columns/signature-column/signature-column.component.scss deleted file mode 100644 index 8741dd990e..0000000000 --- a/web/src/app/components/columns/signature-column/signature-column.component.scss +++ /dev/null @@ -1,36 +0,0 @@ -:host { - div { - display: inline-flex; - align-items: center; - - &:after { - content: '\A'; - width: 6px; - height: 6px; - border-radius: 50%; - display: inline-block; - margin: 0 10px; - } - - &.valid { - - &:after { - background: #00D2A0; - } - } - - &.invalid { - - &:after { - background: #C64A6F; - } - } - - &.absent { - - &:after { - background: #FCFCFD; - } - } - } -} diff --git a/web/src/app/components/columns/signature-column/signature-column.component.ts b/web/src/app/components/columns/signature-column/signature-column.component.ts deleted file mode 100644 index c426d3a1a4..0000000000 --- a/web/src/app/components/columns/signature-column/signature-column.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Input } from "@angular/core"; -import { AdwpCellComponent } from "@app/adwp"; - -export enum SignatureStatus { - Valid = 'valid', - Invalid = 'invalid', - Absent = 'absent', -} - -@Component({ - selector: 'app-signature-column', - templateUrl: './signature-column.component.html', - styleUrls: ['./signature-column.component.scss'] -}) -export class SignatureColumnComponent implements AdwpCellComponent { - @Input() row: T; - signatureStatus = SignatureStatus; - - firstCharToUpperCase(string){ - return string[0].toUpperCase() + string.slice(1).toLowerCase(); - } -} diff --git a/web/src/app/components/columns/state-column/state-column.component.html b/web/src/app/components/columns/state-column/state-column.component.html deleted file mode 100644 index df986f1e8e..0000000000 --- a/web/src/app/components/columns/state-column/state-column.component.html +++ /dev/null @@ -1,2 +0,0 @@ -autorenew -{{ row?.state }} diff --git a/web/src/app/components/columns/state-column/state-column.component.scss b/web/src/app/components/columns/state-column/state-column.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/components/columns/state-column/state-column.component.spec.ts b/web/src/app/components/columns/state-column/state-column.component.spec.ts deleted file mode 100644 index d032e18fcf..0000000000 --- a/web/src/app/components/columns/state-column/state-column.component.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatIconModule } from '@angular/material/icon'; - -import { StateColumnComponent } from './state-column.component'; - -describe('StateColumnComponent', () => { - let component: StateColumnComponent; - let fixture: ComponentFixture>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - StateColumnComponent, - ], - imports: [ - MatIconModule, - ], - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(StateColumnComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/components/columns/state-column/state-column.component.ts b/web/src/app/components/columns/state-column/state-column.component.ts deleted file mode 100644 index e3199713c3..0000000000 --- a/web/src/app/components/columns/state-column/state-column.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'app-state-column', - templateUrl: './state-column.component.html', - styleUrls: ['./state-column.component.scss'] -}) -export class StateColumnComponent { - - @Input() row: T; - -} diff --git a/web/src/app/components/columns/status-column/status-column.component.html b/web/src/app/components/columns/status-column/status-column.component.html deleted file mode 100644 index 8c961057c4..0000000000 --- a/web/src/app/components/columns/status-column/status-column.component.html +++ /dev/null @@ -1,21 +0,0 @@ -{{ row?.status }} - - - - diff --git a/web/src/app/components/columns/status-column/status-column.component.scss b/web/src/app/components/columns/status-column/status-column.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/components/columns/status-column/status-column.component.spec.ts b/web/src/app/components/columns/status-column/status-column.component.spec.ts deleted file mode 100644 index 762eda2e28..0000000000 --- a/web/src/app/components/columns/status-column/status-column.component.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { StatusColumnComponent } from './status-column.component'; -import { MatIconModule } from '@angular/material/icon'; - -describe('StatusColumnComponent', () => { - let component: StatusColumnComponent; - let fixture: ComponentFixture>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - StatusColumnComponent, - ], - imports: [ - MatIconModule, - ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(StatusColumnComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/components/columns/status-column/status-column.component.ts b/web/src/app/components/columns/status-column/status-column.component.ts deleted file mode 100644 index 6d41f3c33d..0000000000 --- a/web/src/app/components/columns/status-column/status-column.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component, Input, Output, EventEmitter } from '@angular/core'; -import { AdwpCellComponent } from '@app/adwp'; - -export interface StatusData { - event: MouseEvent; - action: string; - row: T; -} - -@Component({ - selector: 'app-status-column', - templateUrl: './status-column.component.html', - styleUrls: ['./status-column.component.scss'] -}) -export class StatusColumnComponent implements AdwpCellComponent { - - @Input() row: T; - - @Output() onClick = new EventEmitter>(); - - clickCell(event: MouseEvent, action: string, row: T): void { - this.onClick.emit({ event, action, row }); - } - -} diff --git a/web/src/app/components/columns/task-name/task-name.component.scss b/web/src/app/components/columns/task-name/task-name.component.scss deleted file mode 100644 index c8343eedbe..0000000000 --- a/web/src/app/components/columns/task-name/task-name.component.scss +++ /dev/null @@ -1,14 +0,0 @@ -:host { - width: 100%; -} - -.multi-title { - cursor: pointer; -} - -.mat-icon { - vertical-align: middle; - font-size: 1.2em; - width: auto; - height: auto; -} diff --git a/web/src/app/components/columns/task-name/task-name.component.ts b/web/src/app/components/columns/task-name/task-name.component.ts deleted file mode 100644 index e1f5145a25..0000000000 --- a/web/src/app/components/columns/task-name/task-name.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { AdwpCellComponent, ILinkColumn } from '@app/adwp'; -import { BehaviorSubject } from 'rxjs'; - -import { Task } from '@app/core/types'; - -@Component({ - selector: 'app-task-name', - template: ` - - -
- {{ row.action?.display_name || 'unknown' }} -   - - {{ (expandedTask | async) && (expandedTask | async).id === row.id ? 'expand_less' : 'expand_more' }} - -
-
- `, - styleUrls: ['./task-name.component.scss'] -}) -export class TaskNameComponent implements AdwpCellComponent { - - row: Task; - - linkColumn: ILinkColumn = { - label: '', - type: 'link', - value: (row) => row.action?.display_name || 'unknown', - url: (row) => `/job/${row.jobs[0].id}`, - }; - - @Input() expandedTask: BehaviorSubject; - @Input() toggleExpand: (row: Task) => void; - -} diff --git a/web/src/app/components/columns/task-objects/task-objects.component.html b/web/src/app/components/columns/task-objects/task-objects.component.html deleted file mode 100644 index b3381bf022..0000000000 --- a/web/src/app/components/columns/task-objects/task-objects.component.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - / - - diff --git a/web/src/app/components/columns/task-objects/task-objects.component.scss b/web/src/app/components/columns/task-objects/task-objects.component.scss deleted file mode 100644 index 8f6ea85613..0000000000 --- a/web/src/app/components/columns/task-objects/task-objects.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -adwp-link-cell { - display: inline; -} - -:host ::ng-deep adwp-link-cell a { - display: inline !important; - line-height: 22px; -} diff --git a/web/src/app/components/columns/task-objects/task-objects.component.ts b/web/src/app/components/columns/task-objects/task-objects.component.ts deleted file mode 100644 index 5575a86a5c..0000000000 --- a/web/src/app/components/columns/task-objects/task-objects.component.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { AdwpCellComponent } from '@app/adwp'; - -import { Task } from '@app/core/types'; - -@Component({ - selector: 'app-task-objects', - templateUrl: './task-objects.component.html', - styleUrls: ['./task-objects.component.scss'] -}) -export class TaskObjectsComponent implements AdwpCellComponent { - row: Task; - - @Input() set object(currentObject: any) { - if (currentObject) { - this.row = currentObject; - } - } - -} diff --git a/web/src/app/components/columns/task-status-column/task-status-column.component.html b/web/src/app/components/columns/task-status-column/task-status-column.component.html deleted file mode 100644 index 44d4e75a09..0000000000 --- a/web/src/app/components/columns/task-status-column/task-status-column.component.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - autorenew - - - - - block - - done_all - - - diff --git a/web/src/app/components/columns/task-status-column/task-status-column.component.scss b/web/src/app/components/columns/task-status-column/task-status-column.component.scss deleted file mode 100644 index 4f9cb7d898..0000000000 --- a/web/src/app/components/columns/task-status-column/task-status-column.component.scss +++ /dev/null @@ -1,6 +0,0 @@ -.mat-icon { - vertical-align: middle; - font-size: 1.2em; - width: auto; - height: auto; -} diff --git a/web/src/app/components/columns/task-status-column/task-status-column.component.ts b/web/src/app/components/columns/task-status-column/task-status-column.component.ts deleted file mode 100644 index 1df878dd82..0000000000 --- a/web/src/app/components/columns/task-status-column/task-status-column.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component } from '@angular/core'; -import { filter, switchMap, tap } from 'rxjs/operators'; -import { AdwpCellComponent } from '@app/adwp'; -import { MatDialog } from '@angular/material/dialog'; - -import { Task } from '@app/core/types'; -import { DialogComponent } from '@app/shared/components'; -import { ApiService } from '@app/core/api'; - -@Component({ - selector: 'app-task-status-column', - templateUrl: './task-status-column.component.html', - styleUrls: ['./task-status-column.component.scss'] -}) -export class TaskStatusColumnComponent implements AdwpCellComponent { - - constructor( - public dialog: MatDialog, - private api: ApiService, - ) {} - - row: Task; - - cancelTask(url: string) { - this.dialog - .open(DialogComponent, { - data: { - text: 'Are you sure?', - controls: ['Yes', 'No'], - }, - }) - .beforeClosed() - .pipe( - filter((yes) => yes), - switchMap(() => this.api.put(url, {}) - .pipe( - tap(()=> this.row.status = 'aborted') - ) - ) - ) - .subscribe(); - } - -} diff --git a/web/src/app/components/columns/wrapper-column/wrapper-column.component.html b/web/src/app/components/columns/wrapper-column/wrapper-column.component.html deleted file mode 100644 index 221e12a371..0000000000 --- a/web/src/app/components/columns/wrapper-column/wrapper-column.component.html +++ /dev/null @@ -1 +0,0 @@ -
{{ columnNameNested ? row[nestedColumnName[0]][nestedColumnName[1]] : row[columnName] }}
diff --git a/web/src/app/components/columns/wrapper-column/wrapper-column.component.scss b/web/src/app/components/columns/wrapper-column/wrapper-column.component.scss deleted file mode 100644 index f2e45c35ec..0000000000 --- a/web/src/app/components/columns/wrapper-column/wrapper-column.component.scss +++ /dev/null @@ -1,25 +0,0 @@ -:host { - display: flex; - flex-grow: 1; - align-items: center; - justify-content: space-between; - width: 50% -} - -.text-ellipsed { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.green { - color: #00e676; -} - -.orange { - color: #ff8c00; -} - -.red { - color: #ff8a80; -} diff --git a/web/src/app/components/columns/wrapper-column/wrapper-column.component.ts b/web/src/app/components/columns/wrapper-column/wrapper-column.component.ts deleted file mode 100644 index e9713082d7..0000000000 --- a/web/src/app/components/columns/wrapper-column/wrapper-column.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; - -/* -* Component wrapper for columns -* If you need to change color of column value - use type 'color' -* If you need to make sure that long names will be trimmed to the column size - use type 'text-substr' -*/ - -@Component({ - selector: 'app-wrapper-column', - templateUrl: './wrapper-column.component.html', - styleUrls: ['./wrapper-column.component.scss'] -}) -export class WrapperColumnComponent implements OnInit { - - @Input() type: string[]; - - row: any; - column: any; - customColumnName: string; - red: string[] = ['delete', 'fail', 'user not found']; - orange: string[] = ['update', 'denied', 'wrong password', 'account disabled']; - green: string[] = ['create', 'success']; - - constructor() { } - - get columnName(): string { - return this.customColumnName || this.column?.label?.toLowerCase()?.replace(' ', '_'); - } - - get nestedColumnName(): string[] { - return this.customColumnName?.split('/'); - } - - get columnNameNested(): boolean { - return this.customColumnName?.includes('/'); - } - - ngOnInit(): void {} - - getWrapperClass() { - return this.type.map(value => { - switch(value) { - case 'color': - return this.getColorClass(); - case 'text-substr': - return 'text-ellipsed'; - } - }).join(' '); - } - - getColorClass() { - const value = this.row[this.columnName]; - - if (this.red.includes(value)) { - return 'red'; - } else if (this.orange.includes(value)) { - return 'orange'; - } else if (this.green.includes(value)) { - return 'green'; - } - } -} diff --git a/web/src/app/components/concern/concern-item/concern-item.component.html b/web/src/app/components/concern/concern-item/concern-item.component.html deleted file mode 100644 index f550f69f2d..0000000000 --- a/web/src/app/components/concern/concern-item/concern-item.component.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - {{placeholder.name}} - {{placeholder.name}} - {{placeholder.name}} - {{placeholder.name}} - {{placeholder.name}} - {{placeholder.name}} - {{placeholder.name}} - diff --git a/web/src/app/components/concern/concern-item/concern-item.component.scss b/web/src/app/components/concern/concern-item/concern-item.component.scss deleted file mode 100644 index 86ce97291b..0000000000 --- a/web/src/app/components/concern/concern-item/concern-item.component.scss +++ /dev/null @@ -1,25 +0,0 @@ -@import "~@angular/material/_theming"; - -.action-link { - color: #1ee564; - cursor: pointer; -} - -.action-button { - padding: 0; - min-width: auto; - line-height: normal; -} - -a { - cursor: pointer; - color: mat-color($mat-blue, 200) !important; - - &:hover { - text-decoration: underline; - } - - .red { - color: #f00; - } -} diff --git a/web/src/app/components/concern/concern-item/concern-item.component.ts b/web/src/app/components/concern/concern-item/concern-item.component.ts deleted file mode 100644 index ed02146755..0000000000 --- a/web/src/app/components/concern/concern-item/concern-item.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { CauseType, IMPlaceholderItem, IMPlaceholderItemType } from '@app/models/concern/concern-reason'; - -@Component({ - selector: 'app-concern-item', - templateUrl: './concern-item.component.html', - styleUrls: ['./concern-item.component.scss'] -}) -export class ConcernItemComponent { - - IMPlaceholderItemType = IMPlaceholderItemType; - - @Input() item: string; - @Input() cause: string; - @Input() placeholder: IMPlaceholderItem; - - runAction() {} - - sectionByCause() { - switch (this.cause) { - case CauseType.HostComponent: - return 'host_component'; - case CauseType.Config: - return 'config'; - case CauseType.Import: - return 'import'; - case CauseType.Service: - return 'service'; - default: - return 'main'; - } - } - -} diff --git a/web/src/app/components/concern/concern-list-ref/concern-list-ref.component.scss b/web/src/app/components/concern/concern-list-ref/concern-list-ref.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/components/concern/concern-list-ref/concern-list-ref.component.ts b/web/src/app/components/concern/concern-list-ref/concern-list-ref.component.ts deleted file mode 100644 index 80816c54af..0000000000 --- a/web/src/app/components/concern/concern-list-ref/concern-list-ref.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import { ConcernListComponent } from '@app/components/concern/concern-list/concern-list.component'; -import { Concern } from '@app/models/concern/concern'; - -@Component({ - selector: 'app-concern-list-ref', - template: ` - - `, - styleUrls: ['./concern-list-ref.component.scss'] -}) -export class ConcernListRefComponent { - - ConcernListComponent = ConcernListComponent; - - private ownConcerns: Concern[]; - @Input() set concerns(concerns: Concern[]) { - this.ownConcerns = concerns; - this.data = { - concerns, - }; - } - data: { concerns: Concern[] }; - -} diff --git a/web/src/app/components/concern/concern-list/concern-list.component.scss b/web/src/app/components/concern/concern-list/concern-list.component.scss deleted file mode 100644 index a22aec4cf1..0000000000 --- a/web/src/app/components/concern/concern-list/concern-list.component.scss +++ /dev/null @@ -1,6 +0,0 @@ -ul { - padding-inline-start: 0px; - padding-left: 15px; - margin-block-start: 0px; - margin-block-end: 0px; -} diff --git a/web/src/app/components/concern/concern-list/concern-list.component.ts b/web/src/app/components/concern/concern-list/concern-list.component.ts deleted file mode 100644 index b7bbe99473..0000000000 --- a/web/src/app/components/concern/concern-list/concern-list.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import { Concern } from '@app/models/concern/concern'; - -@Component({ - selector: 'app-concern-list', - template: ` -
    -
  • - -
  • -
- `, - styleUrls: ['./concern-list.component.scss'] -}) -export class ConcernListComponent { - - private ownConcerns: Concern[] = []; - @Input() set concerns(concerns: Concern[]) { - this.ownConcerns = concerns; - } - get concerns(): Concern[] { - return this.ownConcerns; - } - - @Input() set data(data: { concerns: Concern[] }) { - if (data?.concerns) { - this.ownConcerns = data.concerns; - } - } - -} diff --git a/web/src/app/components/concern/concern.component.html b/web/src/app/components/concern/concern.component.html deleted file mode 100644 index 1867f7d1a9..0000000000 --- a/web/src/app/components/concern/concern.component.html +++ /dev/null @@ -1,9 +0,0 @@ - - - {{item}} - diff --git a/web/src/app/components/concern/concern.component.scss b/web/src/app/components/concern/concern.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/components/concern/concern.component.ts b/web/src/app/components/concern/concern.component.ts deleted file mode 100644 index 08d8036a27..0000000000 --- a/web/src/app/components/concern/concern.component.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { ConcernService } from '@app/services/concern.service'; -import { Concern } from '@app/models/concern/concern'; - -@Component({ - selector: 'app-concern', - templateUrl: './concern.component.html', - styleUrls: ['./concern.component.scss'] -}) -export class ConcernComponent { - - private ownConcern: Concern; - @Input() set concern(concern: Concern) { - this.ownConcern = concern; - if (this.concern) { - this.preparedMessage = this.concernService.parse(this.concern.reason.message); - } - } - get concern(): Concern { - return this.ownConcern; - } - - @Input() set data(data: { concern: Concern }) { - if (data?.concern) { - this.ownConcern = data.concern; - this.preparedMessage = this.concernService.parse(this.concern.reason.message); - } - } - - preparedMessage: string[]; - - constructor( - private concernService: ConcernService, - ) { } - -} diff --git a/web/src/app/components/host/host-details/host-details.component.ts b/web/src/app/components/host/host-details/host-details.component.ts deleted file mode 100644 index e1e1d74b09..0000000000 --- a/web/src/app/components/host/host-details/host-details.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Component, Injector } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; - -import { DetailsFactory } from '@app/factories/details.factory'; -import { IHost } from '@app/models/host'; -import { SocketState } from '@app/core/store'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ChannelService } from '@app/core/services'; -import { HostService } from '@app/services/host.service'; -import { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -@Component({ - selector: 'app-host-details', - templateUrl: '../../../templates/details.html', - styleUrls: ['../../../styles/details.scss'] -}) -export class HostDetailsComponent extends DetailAbstractDirective { - - entityParam = 'host'; - - leftMenu = [ - DetailsFactory.labelMenuItem('Main', 'main'), - DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.Host, 'host'), - DetailsFactory.statusMenuItem('Status', 'status', 'host'), - ]; - - constructor( - socket: Store, - protected route: ActivatedRoute, - protected service: ClusterService, - protected channel: ChannelService, - protected store: Store, - injector: Injector, - protected subjectService: HostService, - ) { - super(socket, route, service, channel, store, injector); - } - -} diff --git a/web/src/app/components/host/host-list/host-list.component.scss b/web/src/app/components/host/host-list/host-list.component.scss deleted file mode 100644 index 9f71ea3b81..0000000000 --- a/web/src/app/components/host/host-list/host-list.component.scss +++ /dev/null @@ -1,19 +0,0 @@ -:host { - flex: 1; -} - -::ng-deep mat-row { - - &:hover { - - mat-cell { - - button { - - &.rename-button.editable { - display: flex !important; - } - } - } - } -} diff --git a/web/src/app/components/host/host-list/host-list.component.ts b/web/src/app/components/host/host-list/host-list.component.ts deleted file mode 100644 index c11e634b1c..0000000000 --- a/web/src/app/components/host/host-list/host-list.component.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { Component, ComponentRef } from '@angular/core'; -import { IColumns, IListResult } from '@app/adwp'; -import { Store } from '@ngrx/store'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material/dialog'; - -import { TypeName } from '@app/core/types'; -import { IHost } from '@app/models/host'; -import { ListFactory } from '@app/factories/list.factory'; -import { AddClusterEventData, ClusterColumnComponent } from '@app/components/columns/cluster-column/cluster-column.component'; -import { UniversalAdcmEventData } from '@app/models/universal-adcm-event-data'; -import { ConcernListDirective } from '@app/abstract-directives/concern-list.directive'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; -import { ICluster } from '@app/models/cluster'; -import { ListService } from '@app/shared/components/list/list.service'; -import { SocketState } from '@app/core/store'; -import { ConcernService } from '@app/services/concern.service'; -import { HostService } from '@app/services/host.service'; -import { ApiService } from '@app/core/api'; - -@Component({ - selector: 'app-host-list', - template: ` - - - Create {{ type }} - - - - `, - styleUrls: ['./host-list.component.scss'], -}) -export class HostListComponent extends ConcernListDirective { - - type: TypeName = 'host'; - eventTypes = [ConcernEventType.Host]; - - listColumns = [ - ListFactory.fqdnColumn(), - ListFactory.providerColumn(), - { - type: 'component', - label: 'Cluster', - sort: 'cluster_name', - component: ClusterColumnComponent, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance - .onGetNextPageCluster - .pipe(this.takeUntil()) - .subscribe((data: UniversalAdcmEventData) => { - this.clickCell(data.event, data.action, data.row); - }); - - componentRef.instance - .onGetClusters - .pipe(this.takeUntil()) - .subscribe((data: UniversalAdcmEventData) => { - this.clickCell(data.event, data.action, data.row); - }); - - componentRef.instance - .onAddCluster - .pipe(this.takeUntil()) - .subscribe((data: AddClusterEventData) => { - if (data?.cluster) { - this.hostService.addToCluster(data.row.id, data.cluster as any as number) - .subscribe((host) => { - if (this.data$?.value?.results) { - this.api.getOne('cluster', host.cluster_id).subscribe((cluster: ICluster) => { - const tableData = Object.assign({}, this.data$.value); - const index = tableData.results.findIndex(item => item.id === host.id); - const row = Object.assign({}, tableData.results[index]); - - row.cluster_id = cluster.id; - row.cluster_name = cluster.name; - - tableData.results.splice(index, 1, row); - this.reload(tableData as IListResult); - }); - } - }); - } - }); - } - }, - ListFactory.stateColumn(), - ListFactory.statusColumn(this), - ListFactory.actionsButton(this), - ListFactory.configColumn(this), - ListFactory.maintenanceModeColumn(this, 'host'), - ListFactory.deleteColumn(this), - ] as IColumns; - - constructor( - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - protected concernService: ConcernService, - protected hostService: HostService, - protected api: ApiService, - ) { - super(service, store, route, router, dialog, concernService); - } -} diff --git a/web/src/app/components/host/host-status/host-status.component.ts b/web/src/app/components/host/host-status/host-status.component.ts deleted file mode 100644 index 5a4291bcf9..0000000000 --- a/web/src/app/components/host/host-status/host-status.component.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { fromJS, updateIn } from 'immutable'; - -import { EventMessage, SocketState } from '@app/core/store'; -import { HostStatusTree } from '@app/models/status-tree'; -import { HostService } from '@app/services/host.service'; -import { StatusAbstractDirective } from '@app/abstract-directives/status.abstract.directive'; -import { IHost } from '@app/models/host'; - -@Component({ - selector: 'app-host-status', - templateUrl: '../../../templates/status-tree.html', - styleUrls: ['../../../styles/status-tree.scss'] -}) -export class HostStatusComponent extends StatusAbstractDirective { - - constructor( - protected route: ActivatedRoute, - protected store: Store, - public entityService: HostService, - ) { - super(route, store, entityService); - } - - pipeData(): any { - return this.entity.cluster_id; - } - - eventReceived(event: EventMessage) { - let output; - switch (event.object.type) { - case 'host': - output = fromJS(this.statusTree.value); - if (output.get('id') === event.object.id) { - output = output.set('status', +event.object.details.value); - } - this.statusTree.next(output.toJS() as any as HostStatusTree); - break; - case 'hostcomponent': - output = fromJS(this.statusTree.value); - const hostId = output.get('id'); - output = updateIn(output, ['hc'], (components: any[]) => components.map((component: any) => { - if (component.get('id') === +event.object.details.id && hostId === event.object.id) { - return component.set('status', +event.object.details.value); - } - return component; - })); - this.statusTree.next(output.toJS() as any as HostStatusTree); - break; - } - } - - getEntityIdFromParams(): number { - return +this.route.parent.snapshot.params.host; - } - -} diff --git a/web/src/app/components/hostprovider/group-config-details/group-config-details.component.ts b/web/src/app/components/hostprovider/group-config-details/group-config-details.component.ts deleted file mode 100644 index d2939d0cb5..0000000000 --- a/web/src/app/components/hostprovider/group-config-details/group-config-details.component.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Component, Injector } from '@angular/core'; -import { ActivatedRoute, ParamMap } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; - -import { DetailsFactory } from '@app/factories/details.factory'; -import { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive'; -import { SocketState } from '@app/core/store'; -import { ClusterService, WorkerInstance } from '@app/core/services/cluster.service'; -import { ChannelService } from '@app/core/services'; -import { ConfigGroup, ConfigGroupListService } from '@app/config-groups'; - -@Component({ - selector: 'app-group-config-provider-details', - templateUrl: '../../../templates/details.html', - styleUrls: ['../../../styles/details.scss'] -}) -export class GroupConfigDetailsComponent extends DetailAbstractDirective { - - entityParam = 'group_config'; - - leftMenu = [ - DetailsFactory.labelMenuItem('Hosts', 'host'), - DetailsFactory.labelMenuItem('Configuration', 'config'), - ]; - - constructor( - socket: Store, - protected route: ActivatedRoute, - protected service: ClusterService, - protected channel: ChannelService, - protected store: Store, - injector: Injector, - protected subjectService: ConfigGroupListService, - ) { - super(socket, route, service, channel, store, injector); - } - - initContext(param: ParamMap): Observable { - return this.service.getContext(param, this.subjectService); - } - -} diff --git a/web/src/app/components/hostprovider/hostprovider.component.ts b/web/src/app/components/hostprovider/hostprovider.component.ts deleted file mode 100644 index 2cc347fe41..0000000000 --- a/web/src/app/components/hostprovider/hostprovider.component.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed 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 { Component } from '@angular/core'; -import { IColumns } from '@app/adwp'; - -import { TypeName } from '@app/core/types'; -import { ListFactory } from '@app/factories/list.factory'; -import { ConcernListDirective } from '@app/abstract-directives/concern-list.directive'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -@Component({ - selector: 'app-hostprovider', - template: ` - - - Create {{ type }} - - - - `, - styles: [':host { flex: 1; }'], -}) -export class HostproviderComponent extends ConcernListDirective { - - type: TypeName = 'provider'; - eventTypes = [ConcernEventType.HostProvider]; - - listColumns = [ - ListFactory.nameColumn(), - ListFactory.bundleColumn(), - ListFactory.stateColumn(), - ListFactory.actionsButton(this), - ListFactory.updateColumn(this.type), - ListFactory.configColumn(this), - ListFactory.deleteColumn(this), - ] as IColumns; - -} diff --git a/web/src/app/components/hostprovider/provider-details/provider-details.component.ts b/web/src/app/components/hostprovider/provider-details/provider-details.component.ts deleted file mode 100644 index cbca1b7204..0000000000 --- a/web/src/app/components/hostprovider/provider-details/provider-details.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Component, Injector } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; - -import { DetailsFactory } from '@app/factories/details.factory'; -import { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive'; -import { Provider } from '@app/core/types'; -import { SocketState } from '@app/core/store'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ChannelService } from '@app/core/services'; -import { ProviderService } from '@app/services/provider.service'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -@Component({ - selector: 'app-provider-details', - templateUrl: '../../../templates/details.html', - styleUrls: ['../../../styles/details.scss'] -}) -export class ProviderDetailsComponent extends DetailAbstractDirective { - - entityParam = 'provider'; - - leftMenu = [ - DetailsFactory.labelMenuItem('Main', 'main'), - DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.HostProvider, 'provider'), - DetailsFactory.labelMenuItem('Configuration groups', 'group_config'), - ]; - - constructor( - socket: Store, - protected route: ActivatedRoute, - protected service: ClusterService, - protected channel: ChannelService, - protected store: Store, - injector: Injector, - protected subjectService: ProviderService, - ) { - super(socket, route, service, channel, store, injector); - } - -} diff --git a/web/src/app/components/job/job-details/job-details.component.ts b/web/src/app/components/job/job-details/job-details.component.ts deleted file mode 100644 index 96f66a7677..0000000000 --- a/web/src/app/components/job/job-details/job-details.component.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Component, Injector } from '@angular/core'; -import { ActivatedRoute, convertToParamMap } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { filter, switchMap } from 'rxjs/operators'; -import { Subscription } from 'rxjs'; - -import { Job } from '@app/core/types'; -import { DetailsFactory } from '@app/factories/details.factory'; -import { SocketState } from '@app/core/store'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ChannelService } from '@app/core/services'; -import { JobService } from '@app/services/job.service'; -import { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive'; - -@Component({ - selector: 'app-job-details', - templateUrl: '../../../templates/details.html', - styleUrls: ['../../../styles/details.scss'] -}) -export class JobDetailsComponent extends DetailAbstractDirective { - - entityParam = 'job'; - - leftMenu = []; - - jobEvents$: Subscription; - - constructor( - socket: Store, - protected route: ActivatedRoute, - protected service: ClusterService, - protected channel: ChannelService, - protected store: Store, - injector: Injector, - protected subjectService: JobService, - ) { - super(socket, route, service, channel, store, injector); - } - - prepareMenuItems() { - const itemsOfFiles = this.entity.log_files.map( - (file) => DetailsFactory.logMenuItem(`${file.name} [ ${file.type} ]`, file.id.toString(), file.id) - ); - - this.leftMenu = [ - DetailsFactory.labelMenuItem('Main', 'main'), - ...itemsOfFiles, - ]; - } - - entityReceived(entity: Job) { - super.entityReceived(entity); - - this.currentName = entity.display_name; - this.prepareMenuItems(); - - if (this.jobEvents$) { - this.jobEvents$.unsubscribe(); - } - - this.jobEvents$ = this.subjectService.events({ - events: ['change_job_status', 'add_job_log'], - }).pipe( - this.takeUntil(), - filter(event => event?.object?.id === this.entity.id), - switchMap(() => this.subjectService.get(this.entity.id)), - ).subscribe((resp) => { - const param = convertToParamMap({job: resp.id}); - this.entity = resp; - - this.initContext(param); - this.prepareMenuItems(); - }); - } - -} diff --git a/web/src/app/components/job/jobs/jobs.component.scss b/web/src/app/components/job/jobs/jobs.component.scss deleted file mode 100644 index fbe2617f4c..0000000000 --- a/web/src/app/components/job/jobs/jobs.component.scss +++ /dev/null @@ -1,37 +0,0 @@ -:host { - width: 100%; -} - -adwp-table { - width: 100%; -} - -:host adwp-table ::ng-deep mat-table { - width: 100%; -} - -:host ::ng-deep .action_date { - width: 200px; - flex-basis: 200px; - flex-grow: 0; -} - -:host ::ng-deep .padding20 { - padding-right: 20px; -} - -:host ::ng-deep .table-end { - width: 50px; - flex-basis: 50px; - flex-grow: 0; - padding-right: 78px; -} - -:host ::ng-deep .center { - text-align: center; -} - -:host ::ng-deep .status { - display: flex; - justify-content: center; -} diff --git a/web/src/app/components/job/jobs/jobs.component.ts b/web/src/app/components/job/jobs/jobs.component.ts deleted file mode 100644 index 293637a9a8..0000000000 --- a/web/src/app/components/job/jobs/jobs.component.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { animate, state, style, transition, trigger } from '@angular/animations'; -import { IColumns, AdwpComponentHolder } from '@app/adwp'; -import { BehaviorSubject } from 'rxjs'; - -import { Job, Task } from '@app/core/types'; -import { DateHelper } from '@app/helpers/date-helper'; -import { JobStatusColumnComponent } from '@app/components/columns/job-status-column/job-status-column.component'; -import { JobNameComponent } from '@app/components/columns/job-name/job-name.component'; - -@Component({ - selector: 'app-jobs', - animations: [ - trigger('jobsExpand', [ - state('collapsed', style({ height: '0px', minHeight: '0' })), - state('expanded', style({ height: '*' })), - transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), - ]), - ], - template: ` -
- -
- `, - styleUrls: ['./jobs.component.scss'], -}) -export class JobsComponent implements AdwpComponentHolder { - - sortDirection = 'ASC'; - - columns: IColumns = [ - { - type: 'component', - label: '', - component: JobNameComponent, - }, - { - label: '', - value: (row) => { - return row.status !== 'created' ? DateHelper.short(row.start_date) : ''; - }, - className: 'action_date', - headerClassName: 'action_date', - }, - { - label: '', - value: (row) => row.status === 'success' || row.status === 'failed' ? DateHelper.short(row.finish_date) : '', - className: 'action_date', - headerClassName: 'action_date', - }, - { - label: '', - type: 'component', - component: JobStatusColumnComponent, - className: 'table-end center status', - headerClassName: 'table-end center status', - } - ]; - - private ownData: { results: Job[], count: number }; - get data(): { results: Job[], count: number } { - return this.ownData; - } - - private ownRow: Task; - @Input() set row(row: Task) { - this.ownRow = row; - this.ownData = { results: this.sortJobs(this.ownRow?.jobs), count: 0 }; - } - get row(): Task { - return this.ownRow; - } - - @Input() expandedTask: BehaviorSubject; - - sortJobs(jobs: Job[]) { - if (this.sortDirection === 'ASC'){ - return jobs.sort((cur: Job , next: Job) => cur.id - next.id) - } - - if (this.sortDirection === 'DESC'){ - return jobs.sort((cur: Job , next: Job) => next.id - cur.id) - } - } - -} diff --git a/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.html b/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.html deleted file mode 100644 index 5bef053669..0000000000 --- a/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.html +++ /dev/null @@ -1,11 +0,0 @@ -
- -
diff --git a/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.scss b/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.scss deleted file mode 100644 index e2cf1777d7..0000000000 --- a/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.scss +++ /dev/null @@ -1,5 +0,0 @@ -.mat-button.mat-on, -.mat-icon-button.mat-on, -.mat-stroked-button.mat-on { - color: #dc3545 !important; -} diff --git a/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.spec.ts b/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.spec.ts deleted file mode 100644 index 418f170080..0000000000 --- a/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MaintenanceModeButtonComponent } from './maintenance-mode-button.component'; -import { MatIconModule } from "@angular/material/icon"; - -describe('MaintenanceModeButtonComponent', () => { - let component: MaintenanceModeButtonComponent; - let fixture: ComponentFixture>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ MaintenanceModeButtonComponent ], - imports: [ - MatIconModule, - ], - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(MaintenanceModeButtonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.ts b/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.ts deleted file mode 100644 index 909d6d2c70..0000000000 --- a/web/src/app/components/maintenance-mode-button/maintenance-mode-button.component.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { AdwpCellComponent } from "@app/adwp"; - -export enum StatusType { - On = 'ON', - Off = 'OFF', - Changing = 'CHANGING' -} - -export interface Status { - isButtonActive: boolean; - isModeActive: boolean; - color: string; - tooltip: string; -} - -@Component({ - selector: 'app-maintenance-mode-button', - templateUrl: './maintenance-mode-button.component.html', - styleUrls: ['./maintenance-mode-button.component.scss'] -}) -export class MaintenanceModeButtonComponent implements AdwpCellComponent { - mminaTooltip = 'Maintenance mode is not available'; - statuses: { [key in StatusType]: Status; } = { - [StatusType.On]: { - isButtonActive: true, - isModeActive: true, - color: 'on', - tooltip: 'Turn maintenance mode OFF' - }, - [StatusType.Off]: { - isButtonActive: false, - isModeActive: true, - color: 'primary', - tooltip:'Turn maintenance mode ON' - }, - [StatusType.Changing]: { - isButtonActive: false, - isModeActive: false, - color: 'primary', - tooltip: 'Maintenance mode is not available' - } - } - - get maintenanceModeStatus(): string { - return this?.row?.maintenance_mode; - } - - get status(): Status { - return this.statuses[this.maintenanceModeStatus]; - } - - get isMaintenanceModeAvailable(): boolean { - return this?.row?.is_maintenance_mode_available; - } - - @Input() row: any; - @Input() type: string; - @Output() onClick = new EventEmitter(); - - ngOnInit(): void {} - - clickCell(event: MouseEvent, row: T): void { - if (this.maintenanceModeStatus !== StatusType.Changing && this.maintenanceModeStatus === StatusType.On) { - this.row.maintenance_mode = StatusType.Off; - } else if (this.maintenanceModeStatus !== StatusType.Changing && this.maintenanceModeStatus === StatusType.Off) { - this.row.maintenance_mode = StatusType.On; - } - - this.onClick.emit({ event, value: { id: this.row['id'], maintenance_mode: this.row.maintenance_mode, type: this.type } }); - } - - preventIfDisabled(event) { - if (this.isMaintenanceModeAvailable && this.status?.isModeActive) return; - - event.stopPropagation(); - event.preventDefault(); - } -} diff --git a/web/src/app/components/navigation/navigation.component.spec.ts b/web/src/app/components/navigation/navigation.component.spec.ts deleted file mode 100644 index 07f73656d9..0000000000 --- a/web/src/app/components/navigation/navigation.component.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatListModule } from '@angular/material/list'; -import { MatIconModule } from '@angular/material/icon'; - -import { NavigationComponent } from './navigation.component'; -import { NavItemPipe } from '@app/pipes/nav-item.pipe'; - -describe('NavigationComponent', () => { - let component: NavigationComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - NavigationComponent, - NavItemPipe, - ], - imports: [ - MatListModule, - MatIconModule, - ], - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavigationComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/components/navigation/navigation.component.ts b/web/src/app/components/navigation/navigation.component.ts deleted file mode 100644 index 92ef8aa0b6..0000000000 --- a/web/src/app/components/navigation/navigation.component.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Observable } from 'rxjs'; -import { BaseDirective } from '@app/adwp'; - -import { AdcmTypedEntity } from '@app/models/entity'; -import { EmmitRow, IAction } from '@app/core/types'; -import { IIssues } from '@app/models/issue'; - -@Component({ - selector: 'app-navigation', - template: ` - - apps -  /  - - - - - - -  /  - - - `, - styles: [` - :host { - font-size: 14px; - margin-left: 8px; - width: 100%; - display: flex; - justify-content: space-between; - align-items: center; - } - - mat-nav-list { - padding-top: 0; - display: flex; - align-items: center; - max-width: 100%; - overflow: hidden; - flex-flow: row nowrap; - justify-content: flex-start; - } - - mat-nav-list > * { - display: block; - box-sizing: border-box; - } - - mat-nav-list a { - display: flex; - align-items: center; - line-height: normal; - } - - .mat-nav-list .entity { - border: 1px solid #54646E; - border-radius: 5px; - padding: 2px 8px; - display: flex; - align-items: center; - justify-content: space-around; - flex: 0 1 auto; - overflow: hidden; - - } - - .mat-nav-list .entity.last { - flex: 0 0 auto; - } - - .mat-nav-list .entity * { - flex: 0 0 auto; - } - - .mat-nav-list .entity .link { - flex: 0 1 auto; - overflow: hidden; - } - - .mat-nav-list .entity a { - line-height: 40px; - text-overflow: ellipsis; - overflow: hidden; - display: block; - } - - .mat-nav-list app-upgrade { - margin-left: -8px; - } - - `], -}) -export class NavigationComponent extends BaseDirective { - - actionFlag = false; - actionLink: string; - actions: IAction[] = []; - state: string; - cluster: { id: number; hostcomponent: string }; - - private ownPath: Observable; - - isIssue = (issue: IIssues): boolean => !!(issue && Object.keys(issue).length); - - @Input() set path(path: Observable) { - this.ownPath = path; - this.ownPath.pipe(this.takeUntil()).subscribe((lPath) => { - if (lPath && !!lPath.length) { - const last = lPath[lPath.length - 1]; - const exclude = ['bundle', 'job']; - this.actionFlag = !exclude.includes(last.typeName); - this.actionLink = (last).action; - this.actions = (last).actions; - this.state = (last).state; - const { id, hostcomponent } = lPath[0]; - this.cluster = { id, hostcomponent }; - } - }); - } - - get path(): Observable { - return this.ownPath; - } - - @Output() - refresh: EventEmitter = new EventEmitter(); - -} diff --git a/web/src/app/components/notifications/notifications.component.scss b/web/src/app/components/notifications/notifications.component.scss deleted file mode 100644 index 8046afe06e..0000000000 --- a/web/src/app/components/notifications/notifications.component.scss +++ /dev/null @@ -1,66 +0,0 @@ -.counters { - display: flex; - align-items: center; - justify-content: space-between; - width: 300px; - - & .item { - display: flex; - align-items: center; - cursor: pointer; - } -} - -.notifications { - margin-top: 10px; - padding-top: 10px; - width: 100%; -} - -.notification { - display: flex; - align-items: center; - width: 100%; -} - -.notification + .notification { - border-top: solid 1px #455A64; - margin-top: 5px; - padding-top: 5px; -} - -.footer, .header { - margin-top: 20px; -} - -.footer { - display: flex; - justify-content: space-between; - align-items: center; -} - -.acknowledge { - cursor: pointer; - display: flex; - align-items: center; - text-decoration: none; -} - -.empty-label { - margin: 20px 0; - text-align: center; - font-style: italic; - display: flex; - align-items: center; - justify-content: center; -} - -.empty-footer { - margin-bottom: 10px; - display: flex; - justify-content: center; -} - -mat-icon { - margin-right: 3px; -} diff --git a/web/src/app/components/notifications/notifications.component.spec.ts b/web/src/app/components/notifications/notifications.component.spec.ts deleted file mode 100644 index 4ae22edcca..0000000000 --- a/web/src/app/components/notifications/notifications.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { NotificationsComponent } from './notifications.component'; - -describe('NotificationsComponent', () => { - let component: NotificationsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NotificationsComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NotificationsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/components/notifications/notifications.component.ts b/web/src/app/components/notifications/notifications.component.ts deleted file mode 100644 index 89fbe64724..0000000000 --- a/web/src/app/components/notifications/notifications.component.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { Component, ElementRef, Input, ViewChild } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; - -import { NotificationsData } from '@app/components/bell/bell.component'; -import { TaskRaw } from '@app/core/types'; -import { PopoverEventFunc } from '@app/abstract-directives/popover-content.directive'; - -export const ACKNOWLEDGE_EVENT = 'acknowledge'; - -@Component({ - selector: 'app-notifications', - template: ` -
-
- autorenew {{ (data?.counts | async)?.runningCount }} -
-
- done_all {{ (data?.counts | async)?.successCount }} -
-
- done_all {{ (data?.counts | async)?.failedCount }} -
-
- - -
- Last {{(data.tasks | async)?.length}} notifications: -
- -
-
- - autorenew - block - done_all - - {{ task?.action?.display_name }} -
- - - -
-
- -
- Nothing to display -
- -
- `, - styleUrls: ['./notifications.component.scss'] -}) -export class NotificationsComponent { - - minHeightNotifications = 200; - - @ViewChild('notifications', { static: false }) notificationsRef: ElementRef; - - @Input() data: { counts: BehaviorSubject, tasks: BehaviorSubject }; - - event: PopoverEventFunc; - - jobId(task) { - const endStatuses = ['aborted', 'success', 'failed']; - - if (task.status === 'running') { - const runningJob = task.jobs.find(job => job.status === 'running'); - - if (runningJob) { - return runningJob.id; - } - - const createdJob = task.jobs.find(job => job.status === 'created'); - - if (createdJob) { - return createdJob.id; - } - - const descOrderedJobs = task.jobs.slice().reverse(); - const finishedJob = descOrderedJobs.find(job => endStatuses.includes(job.status)); - - if (finishedJob) { - return finishedJob.id; - } - } else if (endStatuses.includes(task.status)) { - const descOrderedJobs = task.jobs.slice().reverse(); - const finishedJob = descOrderedJobs.find(job => endStatuses.includes(job.status)); - - if (finishedJob) { - return finishedJob.id; - } - } - } - - setLabelHeightAfterAcknowledge() { - this.minHeightNotifications = this.notificationsRef.nativeElement.clientHeight; - } - - acknowledge() { - this.setLabelHeightAfterAcknowledge(); - this.event(ACKNOWLEDGE_EVENT); - } - -} diff --git a/web/src/app/components/popover/popover.component.scss b/web/src/app/components/popover/popover.component.scss deleted file mode 100644 index d0b880db3f..0000000000 --- a/web/src/app/components/popover/popover.component.scss +++ /dev/null @@ -1,27 +0,0 @@ -:host { - line-height: normal; - text-align: left; - font-family: Roboto, "Helvetica Neue", sans-serif; - color: #fff; - font-size: 14px; - position: fixed; - display: flex; - border: solid 1px #455A64; - padding: 0; - background-color: #37474F; - border-radius: 5px; - box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), - 0px 2px 2px 0px rgba(0, 0, 0, 0.14), - 0px 1px 5px 0px rgba(0, 0, 0, 0.12); - height: auto; - z-index: 1100; - overflow: auto; - box-sizing: content-box; - cursor: auto; -} - -.container { - margin: 8px 14px; - box-sizing: content-box; - width: auto !important; -} diff --git a/web/src/app/components/popover/popover.component.ts b/web/src/app/components/popover/popover.component.ts deleted file mode 100644 index 4d3c8a755e..0000000000 --- a/web/src/app/components/popover/popover.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { - Component, - ViewChild, - ViewContainerRef, - ComponentRef, - Input, - ComponentFactory, - ComponentFactoryResolver, - AfterViewInit, - Type, - HostListener, ElementRef, HostBinding, -} from '@angular/core'; -import { EventHelper } from '@app/adwp'; - -import { PopoverContentDirective, PopoverEventFunc } from '@app/abstract-directives/popover-content.directive'; -import { PopoverInput } from '@app/directives/popover.directive'; - -@Component({ - selector: 'app-popover', - template: ` -
- -
- `, - styleUrls: ['./popover.component.scss'] -}) -export class PopoverComponent implements AfterViewInit { - - @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef; - containerRef: ComponentRef; - - @Input() component: Type; - @Input() data: PopoverInput = {}; - @Input() event: PopoverEventFunc; - - @HostListener('click', ['$event']) click(event: MouseEvent) { - EventHelper.stopPropagation(event); - } - - @HostBinding('style.right') right: string; - - constructor( - private componentFactoryResolver: ComponentFactoryResolver, - private elementRef: ElementRef, - ) {} - - ngAfterViewInit() { - setTimeout(() => { - const factory: ComponentFactory = this.componentFactoryResolver.resolveComponentFactory(this.component); - this.container.clear(); - this.containerRef = this.container.createComponent(factory); - this.containerRef.instance.data = this.data; - this.containerRef.instance.event = this.event; - setTimeout(() => { - const left = document.documentElement.clientWidth - (this.elementRef.nativeElement.offsetLeft + this.elementRef.nativeElement.offsetWidth); - if (left < 0) { - this.right = `0px`; - } - }); - }); - } - -} diff --git a/web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.html b/web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.html deleted file mode 100644 index 9eda829686..0000000000 --- a/web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.scss b/web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.scss deleted file mode 100644 index d7b35a3757..0000000000 --- a/web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.scss +++ /dev/null @@ -1,31 +0,0 @@ -:host { - - ::ng-deep adwp-paginator { - display: none; - } -} - -.legend { - display: flex; - flex-direction: column; - width: 100%; -} -.square-wrapper { - display: inline-flex; - align-items: center; - margin-bottom: 10px; -} - -.square { - height: 30px; - width: 30px; - margin-right: 10px; - - &.added { - background-color: #00e676; - } - - &.deleted { - background-color: #ff8a80; - } -} diff --git a/web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.ts b/web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.ts deleted file mode 100644 index 0591f9de3b..0000000000 --- a/web/src/app/components/rbac/audit-operations-history-form/rbac-audit-operations-history-form.component.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Component, ComponentRef, forwardRef, OnInit } from '@angular/core'; -import { ADD_SERVICE_PROVIDER } from "@app/shared/add-component/add-service-model"; -import { RbacAuditOperationsService } from "@app/services/rbac-audit-operations.service"; -import { AuditOperationsChangesHistory } from "@app/models/rbac/rbac-audit-operations.model"; -import { IColumns } from "@app/adwp"; -import { ListService } from "@app/shared/components/list/list.service"; -import { BehaviorSubject } from "rxjs"; -import { WrapperColumnComponent } from "@app/components/columns/wrapper-column/wrapper-column.component"; - -@Component({ - selector: 'app-rbac-audit-operations-form', - templateUrl: './rbac-audit-operations-history-form.component.html', - styleUrls: ['./rbac-audit-operations-history-form.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: forwardRef(() => RbacAuditOperationsService) } - ] -}) -export class RbacAuditOperationsHistoryFormComponent implements OnInit { - - data$: BehaviorSubject = new BehaviorSubject(null); - model: any; - listColumns = [ - { - label: 'Attribute', - headerClassName: 'width100', - className: 'width100', - value: (row) => row.attribute, - }, - { - label: 'Old value', - type: 'component', - component: WrapperColumnComponent, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance.type = ['text-substr']; - } - }, - { - label: 'New Value', - type: 'component', - component: WrapperColumnComponent, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance.type = ['text-substr']; - } - } - ] as IColumns; - - constructor(protected service: ListService,) {} - - ngOnInit(): void { - const history = Object.keys(this.model.row.object_changes.current).map(v => { - return { - attribute: (v.charAt(0).toUpperCase() + v.slice(1)).replace('_', ' '), - new_value: this.model.row.object_changes.current[v], - old_value: this.model.row.object_changes.previous[v] - } - }); - this.data$.next({ - "count": 1, - "next": null, - "previous": null, - "results": history - }); - } - -} diff --git a/web/src/app/components/rbac/group-form/options/rbac-groups-as-options.directive.ts b/web/src/app/components/rbac/group-form/options/rbac-groups-as-options.directive.ts deleted file mode 100644 index 4a694b216c..0000000000 --- a/web/src/app/components/rbac/group-form/options/rbac-groups-as-options.directive.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Directive, Inject, Input } from '@angular/core'; -import { RbacGroupService } from '../../../../services/rbac-group.service'; -import { RbacGroupModel } from '../../../../models/rbac/rbac-group.model'; -import { AdwpStringHandler } from '@app/adwp'; -import { Params } from '@angular/router'; -import { RbacOptionsDirective } from '../../../../abstract-directives/rbac-options.directive'; - -@Directive({ - selector: '[appRbacGroupsAsOptions], [rbac-groups-as-options]', - exportAs: 'rbacGroups' -}) -export class RbacGroupsAsOptionsDirective extends RbacOptionsDirective { - initialParams: Params = { - ordering: 'name' - }; - - @Input('rbac-groups-as-options') - params: Params; - - label: AdwpStringHandler = (item: RbacGroupModel) => item.name; - - constructor(@Inject(RbacGroupService) public service: RbacGroupService) { - super(service); - } -} diff --git a/web/src/app/components/rbac/group-form/options/rbac-groups-as-options.module.ts b/web/src/app/components/rbac/group-form/options/rbac-groups-as-options.module.ts deleted file mode 100644 index 9373b4fb9c..0000000000 --- a/web/src/app/components/rbac/group-form/options/rbac-groups-as-options.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RbacGroupsAsOptionsDirective } from './rbac-groups-as-options.directive'; - - -@NgModule({ - declarations: [RbacGroupsAsOptionsDirective], - exports: [ - RbacGroupsAsOptionsDirective - ], - imports: [ - CommonModule - ] -}) -export class RbacGroupsAsOptionsModule { -} diff --git a/web/src/app/components/rbac/group-form/rbac-group-form.component.html b/web/src/app/components/rbac/group-form/rbac-group-form.component.html deleted file mode 100644 index 7337634654..0000000000 --- a/web/src/app/components/rbac/group-form/rbac-group-form.component.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/web/src/app/components/rbac/group-form/rbac-group-form.component.ts b/web/src/app/components/rbac/group-form/rbac-group-form.component.ts deleted file mode 100644 index 4c272d5aab..0000000000 --- a/web/src/app/components/rbac/group-form/rbac-group-form.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component, forwardRef } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { RbacFormDirective } from '@app/shared/add-component/rbac-form.directive'; -import { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model'; -import { RbacGroupService } from '@app/services/rbac-group.service'; -import { RbacGroupModel } from '@app/models/rbac/rbac-group.model'; -import { CustomValidators } from '../../../shared/validators/custom-validators'; - -@Component({ - selector: 'app-rbac-group-form', - templateUrl: './rbac-group-form.component.html', - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: forwardRef(() => RbacGroupService) } - ] -}) -export class RbacGroupFormComponent extends RbacFormDirective { - - form = new FormGroup({ - id: new FormControl(null), - name: new FormControl(null, [ - CustomValidators.required, - Validators.minLength(2), - Validators.maxLength(150), - Validators.pattern('[a-zA-Z0-9_]+.*$') - ]), - description: new FormControl(null), - user: new FormControl([]), - url: new FormControl(null), - }); - - ngOnInit() { - super.ngOnInit(); - this._checkType(); - this.form.markAllAsTouched(); - } - - _checkType() { - if (this?.value?.type === 'ldap') { - this.form.controls.name.disable(); - this.form.controls.description.disable(); - this.form.controls.user.disable(); - } - } -} diff --git a/web/src/app/components/rbac/group-form/rbac-group-form.module.ts b/web/src/app/components/rbac/group-form/rbac-group-form.module.ts deleted file mode 100644 index 86f9e822ba..0000000000 --- a/web/src/app/components/rbac/group-form/rbac-group-form.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RbacGroupFormComponent } from './rbac-group-form.component'; -import { ReactiveFormsModule } from '@angular/forms'; -import { RbacUsersAsOptionsModule } from '../user-form/options/rbac-users-as-options.module'; -import { AdwpFormElementModule } from '@app/adwp'; -import { FalseAsEmptyArrayModule } from '../../../shared/pipes/false-as-empty-array/false-as-empty-array.module'; - - -@NgModule({ - declarations: [ - RbacGroupFormComponent, - ], - exports: [ - RbacGroupFormComponent, - ], - imports: [ - CommonModule, - AdwpFormElementModule, - ReactiveFormsModule, - RbacUsersAsOptionsModule, - FalseAsEmptyArrayModule, - ], -}) -export class RbacGroupFormModule { -} diff --git a/web/src/app/components/rbac/permission-form/rbac-permission-form.component.html b/web/src/app/components/rbac/permission-form/rbac-permission-form.component.html deleted file mode 100644 index 730930e5e2..0000000000 --- a/web/src/app/components/rbac/permission-form/rbac-permission-form.component.html +++ /dev/null @@ -1,42 +0,0 @@ -
-
Select permissions:
- -
- -
- - - {{ category }} - - -
- - - -
- - -
- - - 100+ matches - -
-
- -
-
diff --git a/web/src/app/components/rbac/permission-form/rbac-permission-form.component.scss b/web/src/app/components/rbac/permission-form/rbac-permission-form.component.scss deleted file mode 100644 index 02c4cbe1ac..0000000000 --- a/web/src/app/components/rbac/permission-form/rbac-permission-form.component.scss +++ /dev/null @@ -1,85 +0,0 @@ -:host { - width: 100%; -} - -.adcm-rbac-permission { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - - &__wrapper { - display: flex; - width: 100%; - height: 100%; - background-color: #303030; - border: 1px solid #585858; - padding: 8px; - box-sizing: border-box; - overflow: hidden; - } - - &__label { - color: rgba(255, 255, 255, 0.7); - margin-bottom: 4px; - } - - &__filter { - display: flex; - width: 120px; - padding-right: 16px; - } - - &__filter-category.mat-chip-list-stacked { - width: 100%; - - ::ng-deep { - .mat-chip-list-wrapper { - height: 100%; - box-sizing: border-box; - padding-right: 8px; - padding-left: 8px; - overflow-y: auto; - overflow-x: hidden; - flex-wrap: nowrap; - } - } - } - - &__filter-category-item { - margin-left: 0; - margin-right: 0; - justify-content: center; - } - - &__options { - display: flex; - flex-direction: column; - flex: 1; - padding-left: 8px; - height: 100%; - overflow: hidden; - - adwp-selection-list { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - overflow: hidden; - margin-bottom: 8px; - - ::ng-deep { - .mat-selection-list { - padding-top: 0; - height: 100%; - overflow-y: auto; - } - } - } - } - - &__notification { - margin-left: 8px; - color: #ff9800; - } -} diff --git a/web/src/app/components/rbac/permission-form/rbac-permission-form.component.ts b/web/src/app/components/rbac/permission-form/rbac-permission-form.component.ts deleted file mode 100644 index 70462b2c69..0000000000 --- a/web/src/app/components/rbac/permission-form/rbac-permission-form.component.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Component, Inject, Input } from '@angular/core'; -import { RbacFormDirective } from '../../../shared/add-component/rbac-form.directive'; -import { RbacRoleModel } from '../../../models/rbac/rbac-role.model'; -import { FormGroup } from '@angular/forms'; -import { ADWP_DEFAULT_STRINGIFY, adwpDefaultProp, AdwpHandler, AdwpMatcher, AdwpStringHandler } from '@app/adwp'; -import { RbacRoleService } from '../../../services/rbac-role.service'; -import { MatDialog } from '@angular/material/dialog'; -import { Observable } from 'rxjs'; -import { IAddService } from '../../../shared/add-component/add-service-model'; -import { Params } from '@angular/router'; - -@Component({ - selector: 'app-rbac-permission-form', - templateUrl: './rbac-permission-form.component.html', - styleUrls: ['./rbac-permission-form.component.scss'] -}) -export class RbacPermissionFormComponent extends RbacFormDirective { - @Input() - form: FormGroup; - - @Input() - @adwpDefaultProp() - options: RbacRoleModel[] = []; - - @Input() - idHandler: AdwpStringHandler; - - @Input() - nameHandler: AdwpStringHandler; - - @Input() - controlName: string; - - filter: Params = { - type: 'business', - limit: 100 - }; - - categories$: Observable; - - matcher: AdwpMatcher = ( - item: RbacRoleModel, - search: RbacRoleModel[], - stringify: AdwpHandler = ADWP_DEFAULT_STRINGIFY, - ) => !search.map(stringify).includes(stringify(item)); - - constructor(@Inject(RbacRoleService) service: RbacRoleService, dialog: MatDialog) { - super(service as unknown as IAddService, dialog); - - this.categories$ = service.getCategories(); - } - - save(): void { - this.form.controls[this.controlName].setValue(this.value); - this.form.markAsDirty(); - } -} diff --git a/web/src/app/components/rbac/permission-form/rbac-permission-form.module.ts b/web/src/app/components/rbac/permission-form/rbac-permission-form.module.ts deleted file mode 100644 index b98f47fcc6..0000000000 --- a/web/src/app/components/rbac/permission-form/rbac-permission-form.module.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RbacPermissionFormComponent } from './rbac-permission-form.component'; -import { AdwpFormElementModule, AdwpSelectionListModule, AdwpFilterPipeModule } from '@app/adwp'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatChipsModule } from '@angular/material/chips'; -import { MatDividerModule } from '@angular/material/divider'; -import { MatButtonModule } from '@angular/material/button'; -import { FalseAsEmptyArrayModule } from '../../../shared/pipes/false-as-empty-array/false-as-empty-array.module'; - - -@NgModule({ - declarations: [ - RbacPermissionFormComponent - ], - imports: [ - CommonModule, - AdwpFormElementModule, - ReactiveFormsModule, - MatChipsModule, - MatDividerModule, - AdwpSelectionListModule, - FormsModule, - MatButtonModule, - AdwpFilterPipeModule, - FalseAsEmptyArrayModule - ], - exports: [ - RbacPermissionFormComponent - ] -}) -export class RbacPermissionFormModule { -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.html b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.html deleted file mode 100644 index 66268d8226..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - -
- - - - - - - - - {{ role | adwpMapper: roles.label }} - - - - - Role is required. - - -
- - - - diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.scss b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.scss deleted file mode 100644 index 81e6027a6a..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.row { - display: flex -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.ts deleted file mode 100644 index 5027dfb360..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/rbac-policy-form-step-one.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { BaseFormDirective } from '@app/shared/add-component'; -import { FormGroup } from '@angular/forms'; -import { ADWP_DEFAULT_MATCHER, AdwpIdentityMatcher, AdwpMatcher } from '@app/adwp'; -import { RbacRoleModel } from '@app/models/rbac/rbac-role.model'; - -@Component({ - selector: 'app-rbac-policy-form-step-one', - templateUrl: './rbac-policy-form-step-one.component.html', - styleUrls: ['./rbac-policy-form-step-one.component.scss'] -}) -export class RbacPolicyFormStepOneComponent extends BaseFormDirective { - roleFilter = ''; - groupFilter = ''; - - matcher: AdwpMatcher = ADWP_DEFAULT_MATCHER; - - @Input() - form: FormGroup; - - @Output() - roleChanged: EventEmitter = new EventEmitter(); - - comparator: AdwpIdentityMatcher = (item1: any, item2: any) => item1?.id === item2?.id; - - isError(name: string): boolean { - const f = this.form.get(name); - return f.invalid && (f.dirty || f.touched); - } - - hasError(error: string, path): boolean { - return this.form.hasError(error, path); - } -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/validators/user-or-group-required.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/validators/user-or-group-required.ts deleted file mode 100644 index 7faab5934d..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-one/validators/user-or-group-required.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { FormGroup, ValidationErrors, ValidatorFn } from '@angular/forms'; - -export const atLeastOne = (firstControlName: string, secondControlName: string): ValidatorFn => (group: FormGroup): ValidationErrors | null => { - if (!group) { - return null; - } - - const firstControl = group.controls[firstControlName]; - const secondControl = group.controls[secondControlName]; - - if (!firstControl || !secondControl) { - return null; - } - - const userValue = firstControl.value; - const groupValue = secondControl.value; - - if (!userValue?.length && !groupValue?.length) { - firstControl.setErrors({ required: true }, { emitEvent: false }); - secondControl.setErrors({ required: true }, { emitEvent: false }); - firstControl.markAsDirty({ onlySelf: true }); - secondControl.markAsDirty({ onlySelf: true }); - return { required: true }; - } else { - firstControl.setErrors(null); - secondControl.setErrors(null); - firstControl.updateValueAndValidity({ onlySelf: true }); - secondControl.updateValueAndValidity({ onlySelf: true }); - } - - return null; -}; diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.html b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.html deleted file mode 100644 index 2a7c8d39aa..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.html +++ /dev/null @@ -1 +0,0 @@ -

You are now done.

diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.scss b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.ts deleted file mode 100644 index 001fbaff49..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-three/rbac-policy-form-step-three.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { BaseFormDirective } from '../../../../shared/add-component'; -import { FormGroup } from '@angular/forms'; -import { RbacPolicyFormComponent } from '../rbac-policy-form.component'; -import { RbacPolicyModel } from '../../../../models/rbac/rbac-policy.model'; -import { Observable } from 'rxjs'; -import { map, startWith } from 'rxjs/operators'; - -@Component({ - selector: 'app-rbac-policy-form-step-three', - templateUrl: './rbac-policy-form-step-three.component.html', - styleUrls: ['./rbac-policy-form-step-three.component.scss'] -}) -export class RbacPolicyFormStepThreeComponent extends BaseFormDirective implements OnInit { - @Input() - form: FormGroup; - - result$: Observable; - - ngOnInit(): void { - this.result$ = this.form.valueChanges.pipe( - startWith(this.form.value), - map(RbacPolicyFormComponent.EXPORT_TO_JSON), - this.takeUntil() - ); - } - -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.html b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.html deleted file mode 100644 index 6a8848da01..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.scss b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.scss deleted file mode 100644 index 81e6027a6a..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.row { - display: flex -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.ts deleted file mode 100644 index 8249a0edca..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { adwpDefaultProp, AdwpStringHandler } from '@app/adwp'; -import { - IRbacObjectCandidateClusterModel, - IRbacObjectCandidateModel -} from '../../../../../../models/rbac/rbac-object-candidate'; -import { ParametrizedByDirective } from '../../directives/parametrized-by.directive'; - -@Component({ - selector: 'app-parametrized-by-cluster', - templateUrl: './parametrized-by-cluster.component.html', - styleUrls: ['./parametrized-by-cluster.component.scss'] -}) -export class ParametrizedByClusterComponent extends ParametrizedByDirective { - - @Input() - candidates: Pick; - - @Input() - @adwpDefaultProp() - isParent = false; - - clusterHandler: AdwpStringHandler = (cluster: IRbacObjectCandidateClusterModel) => cluster.name; - -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.html b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.html deleted file mode 100644 index 4b2ea878ee..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.scss b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.ts deleted file mode 100644 index 642f3e9818..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { ParametrizedByDirective } from '../../directives/parametrized-by.directive'; -import { - IRbacObjectCandidateHostModel, - IRbacObjectCandidateModel -} from '../../../../../../models/rbac/rbac-object-candidate'; -import { AdwpStringHandler } from '@app/adwp'; - -@Component({ - selector: 'app-parametrized-by-host', - templateUrl: './parametrized-by-host.component.html', - styleUrls: ['./parametrized-by-host.component.scss'] -}) -export class ParametrizedByHostComponent extends ParametrizedByDirective { - - @Input() - candidates: Pick; - - hostHandler: AdwpStringHandler = (host: IRbacObjectCandidateHostModel) => host.name; -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.html b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.html deleted file mode 100644 index aa1d3bcb19..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.scss b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.scss deleted file mode 100644 index 81e6027a6a..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.row { - display: flex -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.ts deleted file mode 100644 index f991945577..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { ParametrizedByDirective } from '../../directives/parametrized-by.directive'; -import { - IRbacObjectCandidateModel, - IRbacObjectCandidateProviderModel -} from '../../../../../../models/rbac/rbac-object-candidate'; -import { AdwpStringHandler } from '@app/adwp'; - -@Component({ - selector: 'app-parametrized-by-provider', - templateUrl: './parametrized-by-provider.component.html', - styleUrls: ['./parametrized-by-provider.component.scss'] -}) -export class ParametrizedByProviderComponent extends ParametrizedByDirective { - - @Input() - candidates: Pick; - - providerHandler: AdwpStringHandler = (provider: IRbacObjectCandidateProviderModel) => provider.name; - -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/get-clusters-from-services.pipe.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/get-clusters-from-services.pipe.ts deleted file mode 100644 index 86a19ed8cf..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/get-clusters-from-services.pipe.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { - IRbacObjectCandidateModel, - IRbacObjectCandidateServiceModel -} from '../../../../../../models/rbac/rbac-object-candidate'; - -@Pipe({ - name: 'getParents' -}) -export class GetParentsFromServicesPipe implements PipeTransform { - - transform(service: IRbacObjectCandidateServiceModel): Pick { - if (!service) { - return null; - } - - return { - cluster: service.clusters - }; - } - -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.html b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.html deleted file mode 100644 index 3eabd68baa..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.html +++ /dev/null @@ -1,34 +0,0 @@ - - -
- - - -- - - {{ service | adwpMapper:serviceHandler }} - - - - - Service is required. - - - -
- - - -
diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.scss b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.scss deleted file mode 100644 index 81e6027a6a..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.row { - display: flex -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.ts deleted file mode 100644 index 5559a5d4e3..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component } from '@angular/core'; -import { AdwpIdentityMatcher, AdwpStringHandler } from '@app/adwp'; -import { IRbacObjectCandidateServiceModel } from '../../../../../../models/rbac/rbac-object-candidate'; -import { ParametrizedByDirective } from '../../directives/parametrized-by.directive'; - -@Component({ - selector: 'app-parametrized-by-service', - templateUrl: './parametrized-by-service.component.html', - styleUrls: ['./parametrized-by-service.component.scss'] -}) -export class ParametrizedByServiceComponent extends ParametrizedByDirective { - roleFilter = ''; - - serviceHandler: AdwpStringHandler = (service: IRbacObjectCandidateServiceModel) => service.name; - serviceComparator: AdwpIdentityMatcher = (item1: IRbacObjectCandidateServiceModel, item2: IRbacObjectCandidateServiceModel) => (item1?.name === item2?.name); - - isError(name: string): boolean { - const f = this.object.get(name); - return f.invalid && (f.dirty || f.touched); - } - - hasError(error: string): boolean { - return this.object.hasError(error); - } - - reset(): void { - this.object.get('cluster').reset([]); - this.object.get('parent').reset([]); - } -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/directives/parametrized-by.directive.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/directives/parametrized-by.directive.ts deleted file mode 100644 index d8fc192149..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/directives/parametrized-by.directive.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Directive, Input } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { IRbacObjectCandidateModel } from '../../../../../models/rbac/rbac-object-candidate'; -import { adwpDefaultProp, BaseDirective } from '@app/adwp'; - -@Directive({ - selector: 'parametrizedBy' -}) -export class ParametrizedByDirective extends BaseDirective { - - @Input() - @adwpDefaultProp() - object: FormGroup | null = null; - - @Input() - @adwpDefaultProp() - candidates: Partial | null = null; - -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/pipes/parametrized.pipe.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/pipes/parametrized.pipe.ts deleted file mode 100644 index 43991b2710..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/pipes/parametrized.pipe.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { RbacRoleModel, RbacRoleParametrizedBy } from '../../../../../models/rbac/rbac-role.model'; - -@Pipe({ - name: 'parametrizedBy' -}) -export class ParametrizedPipe implements PipeTransform { - - transform(role: RbacRoleModel, ...cases: (RbacRoleParametrizedBy | RbacRoleParametrizedBy[])[]): boolean { - return cases.some((c) => { - if (Array.isArray(c)) { - return c.every((value) => role.parametrized_by_type.includes(value)); - } - - return role.parametrized_by_type.length === 1 && role.parametrized_by_type[0] === c; - - }); - } - -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.html b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.html deleted file mode 100644 index 77b280a176..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - -

The selected role does not require specifying an object. - The policy will apply to all ADCM objects.

-
- -
diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.scss b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.ts deleted file mode 100644 index a16b07da7f..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form-step-two/rbac-policy-form-step-two.component.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Component, forwardRef, Input, OnInit } from '@angular/core'; -import { BaseFormDirective } from '../../../../shared/add-component'; -import { AbstractControl, FormGroup } from '@angular/forms'; -import { AdwpStringHandler, Entity } from '@app/adwp'; -import { - IRbacObjectCandidateHostModel, - IRbacObjectCandidateModel, - IRbacObjectCandidateProviderModel -} from '../../../../models/rbac/rbac-object-candidate'; -import { ADD_SERVICE_PROVIDER } from '../../../../shared/add-component/add-service-model'; -import { RbacObjectCandidateService } from '../../../../services/rbac-object-candidate.service'; -import { filter, startWith, switchMap } from 'rxjs/operators'; -import { RbacRoleModel } from '../../../../models/rbac/rbac-role.model'; - - -@Component({ - selector: 'app-rbac-policy-form-step-two', - templateUrl: './rbac-policy-form-step-two.component.html', - styleUrls: ['./rbac-policy-form-step-two.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: forwardRef(() => RbacObjectCandidateService) } - ], -}) -export class RbacPolicyFormStepTwoComponent extends BaseFormDirective implements OnInit { - @Input() - form: FormGroup; - - get roleControl(): AbstractControl | null { - return this.form.parent?.get([0])?.get('role'); - } - - get role(): RbacRoleModel | null { - return this.roleControl?.value; - } - - get object(): FormGroup | null { - return this.form.controls['object'] as FormGroup; - } - - providerHandler: AdwpStringHandler = (service: IRbacObjectCandidateProviderModel) => service.name; - hostHandler: AdwpStringHandler = (service: IRbacObjectCandidateHostModel) => service.name; - - candidates: IRbacObjectCandidateModel | null = null; - - ngOnInit(): void { - this.roleControl.valueChanges.pipe( - startWith(this.role), - filter((v) => !!v), - switchMap((role) => this.service.get(role.id)), - this.takeUntil() - ).subscribe((candidates: IRbacObjectCandidateModel) => { - this.candidates = candidates; - - // Set service & parents values - const selectedService = this.object.get('service')?.value; - const serviceCandidate = candidates.service.find((s) => selectedService?.name === s?.name); - const selectedParents: (Pick)[] | null = this.object.get('parent')?.value; - const selectedClusters = selectedParents && selectedParents.map((item: Pick) => { - return serviceCandidate && serviceCandidate.clusters.find((cluster) => cluster.id === item.id); - }).filter(Boolean); - - if (selectedService && serviceCandidate && selectedClusters) { - this.object.get('service').setValue(serviceCandidate); - this.object.get('parent').setValue(selectedClusters); - } - }); - } - - reset(value: any): void { - if (!this.object) { - return; - } - - if (this.object.disabled) { - this.object.enable(); - } - - this.object.reset(value); - } -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form.component.html b/web/src/app/components/rbac/policy-form/rbac-policy-form.component.html deleted file mode 100644 index 1ab862cbdb..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form.component.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Step 1 - -
- - -
-
- - -
- - - -
-
- - Done - -
- - - -
-
-
-
-
- diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form.component.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form.component.ts deleted file mode 100644 index ca9d4413fd..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form.component.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { Component, forwardRef, OnInit } from '@angular/core'; -import { AbstractControl, FormArray, FormControl, FormGroup, Validators } from '@angular/forms'; -import { RbacFormDirective } from '@app/shared/add-component/rbac-form.directive'; -import { RbacPolicyModel } from '@app/models/rbac/rbac-policy.model'; -import { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model'; -import { RbacPolicyService } from '@app/services/rbac-policy.service'; -import { - IRbacObjectCandidateClusterModel, - IRbacObjectCandidateHostModel, - IRbacObjectCandidateProviderModel, - IRbacObjectCandidateServiceModel -} from '@app/models/rbac/rbac-object-candidate'; -import { rbacPolicyObjectValidator } from './validators/object-validator'; -import { CustomValidators } from '@app/shared/validators/custom-validators'; - -const INITIAL_OBJECT = { - cluster: [], - parent: [], - service: null, - provider: [], - host: [] -}; - -@Component({ - selector: 'app-rbac-policy-form', - templateUrl: './rbac-policy-form.component.html', - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: forwardRef(() => RbacPolicyService) } - ] -}) -export class RbacPolicyFormComponent extends RbacFormDirective implements OnInit { - static EXPORT_TO_JSON = (value): RbacPolicyModel => { - if (!value) { - return null; - } - - const object = (value.steps[1] && value.steps[1].object) || {}; - - const { cluster, parent, provider, host } = object; - - return { - ...value.steps[0], - object: [ - ...cluster || [], - ...parent || [], - ...provider || [], - ...host || [] - ] - }; - }; - - initialObject = INITIAL_OBJECT; - - /** Returns a FormArray with the name 'steps'. */ - get steps(): AbstractControl | null { return this.form.get('steps'); } - - get title(): string { - return this.value ? 'Update' : 'Add'; - } - - step(id: number): FormGroup | null { - return this.steps.get([id]) as FormGroup; - } - - ngOnInit() { - this._createForm(); - this._fillForm(this.value); - this.form.markAllAsTouched(); - } - - rbacBeforeSave(form: FormGroup): RbacPolicyModel { - return RbacPolicyFormComponent.EXPORT_TO_JSON(form.value); - } - - private _fillForm(value: RbacPolicyModel): void { - if (value) { - this.form.setValue({ - steps: [ - { - name: value.name, - description: value.description || '', - role: value.role, - group: value.group - }, - { - object: { - cluster: value.object.filter((item: IRbacObjectCandidateClusterModel) => item.type === 'cluster'), - parent: value.object.reduce((acc: any[], item: IRbacObjectCandidateClusterModel) => [...acc, { id: item.id }], []), - service: value.object.find((item: IRbacObjectCandidateServiceModel) => item.type === 'service') || '', - provider: value.object.filter((item: IRbacObjectCandidateProviderModel) => item.type === 'provider'), - host: value.object.filter((item: IRbacObjectCandidateHostModel) => item.type === 'host'), - } - } - ] - }); - } - } - - private _createForm(): void { - const roleControl = new FormControl(null, [Validators.required]); - - this.form = new FormGroup({ - steps: new FormArray([ - new FormGroup({ - name: new FormControl(null, [ - CustomValidators.required, - Validators.maxLength(255), - Validators.minLength(2), - Validators.pattern('[a-zA-Z0-9_]+.*$') - ]), - description: new FormControl(null), - role: roleControl, - group: new FormControl([], [CustomValidators.required]) - }), - new FormGroup({ - object: new FormGroup({ - cluster: new FormControl(null, [Validators.required]), - parent: new FormControl(null, [Validators.required]), - service: new FormControl(null, [Validators.required]), - provider: new FormControl(null, [Validators.required]), - host: new FormControl(null, [Validators.required]), - }, { - validators: [ - rbacPolicyObjectValidator(roleControl) - ] - }) - }) - ]) - }); - } -} diff --git a/web/src/app/components/rbac/policy-form/rbac-policy-form.module.ts b/web/src/app/components/rbac/policy-form/rbac-policy-form.module.ts deleted file mode 100644 index 53f8922054..0000000000 --- a/web/src/app/components/rbac/policy-form/rbac-policy-form.module.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RbacPolicyFormComponent } from './rbac-policy-form.component'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatStepperModule } from '@angular/material/stepper'; -import { MatButtonModule } from '@angular/material/button'; -import { AdwpFilterPipeModule, AdwpFormElementModule, AdwpMapperPipeModule } from '@app/adwp'; -import { RbacPolicyFormStepOneComponent } from './rbac-policy-form-step-one/rbac-policy-form-step-one.component'; -import { RbacPolicyFormStepTwoComponent } from './rbac-policy-form-step-two/rbac-policy-form-step-two.component'; -import { RbacPolicyFormStepThreeComponent } from './rbac-policy-form-step-three/rbac-policy-form-step-three.component'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatSelectModule } from '@angular/material/select'; -import { NgxMatSelectSearchModule } from 'ngx-mat-select-search'; -import { RbacRolesAsOptionsModule } from '../role-form/options/rbac-roles-as-options.module'; -import { FalseAsEmptyArrayModule } from '../../../shared/pipes/false-as-empty-array/false-as-empty-array.module'; -import { RbacUsersAsOptionsModule } from '../user-form/options/rbac-users-as-options.module'; -import { RbacGroupsAsOptionsModule } from '../group-form/options/rbac-groups-as-options.module'; -import { GetParentsFromServicesPipe } from './rbac-policy-form-step-two/components/parametrized-by-service/get-clusters-from-services.pipe'; -import { ParametrizedByClusterComponent } from './rbac-policy-form-step-two/components/parametrized-by-cluster/parametrized-by-cluster.component'; -import { ParametrizedByServiceComponent } from './rbac-policy-form-step-two/components/parametrized-by-service/parametrized-by-service.component'; -import { ParametrizedByProviderComponent } from './rbac-policy-form-step-two/components/parametrized-by-provider/parametrized-by-provider.component'; -import { ParametrizedByDirective } from './rbac-policy-form-step-two/directives/parametrized-by.directive'; -import { ParametrizedPipe } from './rbac-policy-form-step-two/pipes/parametrized.pipe'; -import { ParametrizedByHostComponent } from './rbac-policy-form-step-two/components/parametrized-by-host/parametrized-by-host.component'; - - -@NgModule({ - declarations: [ - RbacPolicyFormComponent, - RbacPolicyFormStepOneComponent, - RbacPolicyFormStepTwoComponent, - RbacPolicyFormStepThreeComponent, - GetParentsFromServicesPipe, - ParametrizedByClusterComponent, - ParametrizedByServiceComponent, - ParametrizedByProviderComponent, - ParametrizedByDirective, - ParametrizedPipe, - ParametrizedByHostComponent - ], - exports: [ - RbacPolicyFormComponent - ], - imports: [ - CommonModule, - FormsModule, - ReactiveFormsModule, - ReactiveFormsModule, - MatStepperModule, - MatButtonModule, - AdwpFormElementModule, - MatFormFieldModule, - MatSelectModule, - NgxMatSelectSearchModule, - RbacRolesAsOptionsModule, - AdwpMapperPipeModule, - AdwpFilterPipeModule, - FalseAsEmptyArrayModule, - RbacUsersAsOptionsModule, - RbacGroupsAsOptionsModule - ] -}) -export class RbacPolicyFormModule { -} diff --git a/web/src/app/components/rbac/policy-form/validators/object-validator.ts b/web/src/app/components/rbac/policy-form/validators/object-validator.ts deleted file mode 100644 index 642b9bb1fd..0000000000 --- a/web/src/app/components/rbac/policy-form/validators/object-validator.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { AbstractControl, FormGroup, ValidationErrors, ValidatorFn } from '@angular/forms'; -import { RbacRoleModel, RbacRoleParametrizedBy } from '../../../../models/rbac/rbac-role.model'; -import { ParametrizedPipe } from '../rbac-policy-form-step-two/pipes/parametrized.pipe'; - -enum StateVariants { - byCluster = 'byCluster', - byService = 'byService', - byProvider = 'byProvider', - byHost = 'byHost', -} - -type PolicyObjectControlsState = { - [key in StateVariants]: { - controls: AbstractControl[]; - state: boolean; - } -} - -export const rbacPolicyObjectValidator = (roleControl: AbstractControl): ValidatorFn => { - return (objectControl: FormGroup): ValidationErrors | null => { - const role: RbacRoleModel | null = roleControl.value; - if (!role) { - return null; - } - - const { parametrized_by_type } = role; - - const variants: StateVariants[] = [StateVariants.byCluster, StateVariants.byService, StateVariants.byProvider, StateVariants.byHost]; - - const clusterControl = objectControl.controls['cluster']; - const serviceControl = objectControl.controls['service']; - const parentControl = objectControl.controls['parent']; - const providerControl = objectControl.controls['provider']; - const hostControl = objectControl.controls['host']; - - const parametrizedByToState = (...cases: (RbacRoleParametrizedBy | RbacRoleParametrizedBy[])[]) => new ParametrizedPipe().transform(role, ...cases); - - const controlsState: PolicyObjectControlsState = { - byCluster: { - controls: [clusterControl], - state: parametrizedByToState(['cluster']) && !serviceControl.value - }, - byService: { - controls: [serviceControl, parentControl], - state: parametrizedByToState(['service'], ['component']) && !clusterControl.value?.length - }, - byProvider: { - controls: [providerControl], - state: parametrizedByToState(['provider']) && !hostControl.value?.length - - }, - byHost: { - controls: [hostControl], - state: parametrizedByToState('host', ['host', 'provider']) && !providerControl.value?.length - }, - }; - - variants.forEach((variant) => { - const stateVariant = controlsState[variant]; - if (stateVariant) { - stateVariant.controls.forEach((control) => { - if (stateVariant.state && !control.enabled) { - control.enable(); - } else if (!stateVariant.state && control.enabled) { - control.disable(); - } - }); - } - }); - - if (parametrized_by_type.length === 0) { - return null; - } - }; -}; diff --git a/web/src/app/components/rbac/policy-form/validators/provider-or-host.ts b/web/src/app/components/rbac/policy-form/validators/provider-or-host.ts deleted file mode 100644 index c1da558eb5..0000000000 --- a/web/src/app/components/rbac/policy-form/validators/provider-or-host.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { FormGroup, ValidationErrors, ValidatorFn } from '@angular/forms'; -import { isEmptyObject } from '../../../../core/types'; - -export const onlyOne = (firstControlName: string, secondControlName: string): ValidatorFn => (group: FormGroup): ValidationErrors | null => { - if (!group) { - return null; - } - - const firstControl = group.controls[firstControlName]; - const secondControl = group.controls[secondControlName]; - - if (!firstControl || !secondControl) { - return null; - } - - const value1 = firstControl.value; - const value2 = secondControl.value; - const emptyValue = (value: any) => !value || isEmptyObject(value) || (Array.isArray(value) && value.length === 0); - - if (!emptyValue(value1)) { - secondControl.enabled && secondControl.disable({ - onlySelf: true, - emitEvent: false - }); - } else if (!emptyValue(value2)) { - firstControl.enabled && firstControl.disable({ - onlySelf: true, - emitEvent: false - }); - } - - return null; -}; diff --git a/web/src/app/components/rbac/role-form/options/rbac-roles-as-options.directive.ts b/web/src/app/components/rbac/role-form/options/rbac-roles-as-options.directive.ts deleted file mode 100644 index a38606b273..0000000000 --- a/web/src/app/components/rbac/role-form/options/rbac-roles-as-options.directive.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Directive, Inject, Input } from '@angular/core'; -import { AdwpHandler, AdwpStringHandler } from '@app/adwp'; -import { RbacRoleModel } from '../../../../models/rbac/rbac-role.model'; -import { Params } from '@angular/router'; -import { RbacOptionsDirective } from '../../../../abstract-directives/rbac-options.directive'; -import { RbacRoleService } from '../../../../services/rbac-role.service'; - -@Directive({ - selector: '[appRbacRolesAsOptions], [rbac-roles-as-options]', - exportAs: 'rbacRoles' -}) -export class RbacRolesAsOptionsDirective extends RbacOptionsDirective { - initialParams: Params = { - ordering: 'name' - }; - - @Input('rbac-roles-as-options') - params: Params; - - id: AdwpStringHandler = (item: RbacRoleModel) => String(item.id); - - label: AdwpStringHandler = (item: RbacRoleModel) => item.display_name; - - category: AdwpHandler = (item: RbacRoleModel) => item.category; - - constructor(@Inject(RbacRoleService) public service: RbacRoleService) { - super(service); - } -} diff --git a/web/src/app/components/rbac/role-form/options/rbac-roles-as-options.module.ts b/web/src/app/components/rbac/role-form/options/rbac-roles-as-options.module.ts deleted file mode 100644 index 911d72f0e9..0000000000 --- a/web/src/app/components/rbac/role-form/options/rbac-roles-as-options.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RbacRolesAsOptionsDirective } from './rbac-roles-as-options.directive'; - - -@NgModule({ - declarations: [RbacRolesAsOptionsDirective], - imports: [ - CommonModule - ], - exports: [RbacRolesAsOptionsDirective] -}) -export class RbacRolesAsOptionsModule { -} diff --git a/web/src/app/components/rbac/role-form/rbac-role-form.component.html b/web/src/app/components/rbac/role-form/rbac-role-form.component.html deleted file mode 100644 index 7a290657e4..0000000000 --- a/web/src/app/components/rbac/role-form/rbac-role-form.component.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - diff --git a/web/src/app/components/rbac/role-form/rbac-role-form.component.scss b/web/src/app/components/rbac/role-form/rbac-role-form.component.scss deleted file mode 100644 index 428ff12818..0000000000 --- a/web/src/app/components/rbac/role-form/rbac-role-form.component.scss +++ /dev/null @@ -1,19 +0,0 @@ -.row { - display: flex -} -.role-category { - min-height: 28px; - font-size: 12px; - border-radius: 4px; - padding: 4px 8px; - - ::ng-deep button { - width: 20px; - height: 20px; - line-height: 20px; - - mat-icon { - line-height: 20px; - } - } -} diff --git a/web/src/app/components/rbac/role-form/rbac-role-form.component.ts b/web/src/app/components/rbac/role-form/rbac-role-form.component.ts deleted file mode 100644 index 518bd8b924..0000000000 --- a/web/src/app/components/rbac/role-form/rbac-role-form.component.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { Component, forwardRef, OnInit, ViewChild } from '@angular/core'; -import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model'; -import { RbacRoleService } from '@app/services/rbac-role.service'; -import { RbacFormDirective } from '@app/shared/add-component/rbac-form.directive'; -import { RbacRoleModel } from '@app/models/rbac/rbac-role.model'; -import { RbacPermissionFormComponent } from '../permission-form/rbac-permission-form.component'; -import { AdwpStringHandler } from '@app/adwp'; -import { MatChipInputEvent } from '@angular/material/chips'; -import { CustomValidators } from '../../../shared/validators/custom-validators'; - -@Component({ - selector: 'app-rbac-role-form', - templateUrl: './rbac-role-form.component.html', - styleUrls: ['rbac-role-form.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: forwardRef(() => RbacRoleService) } - ], -}) -export class RbacRoleFormComponent extends RbacFormDirective implements OnInit { - form: FormGroup = undefined; - - @ViewChild(RbacPermissionFormComponent) permissionForm: RbacPermissionFormComponent; - - nameHandler: AdwpStringHandler = (item: RbacRoleModel) => item.display_name; - - get categoryControl(): AbstractControl | null { - return this.form.get('category'); - } - - rbacBeforeSave(form: FormGroup): RbacRoleModel { - let categories = form.value?.category; - const permissions = form.value.child; - - if (!form.value?.category?.length) { - categories = permissions.reduce((acc, cur) => [...acc, ...cur.category], []); - } - - return { - ...form.value, - category: categories - }; - } - - ngOnInit(): void { - this.form = new FormGroup({ - id: new FormControl(null), - name: new FormControl({ value: '', disabled: this.value?.built_in }), - description: new FormControl({ value: '', disabled: this.value?.built_in }), - display_name: new FormControl({ value: '', disabled: this.value?.built_in }, [ - CustomValidators.required, - Validators.minLength(2), - Validators.maxLength(160), - Validators.pattern('[a-zA-Z0-9_]+.*$') - ]), - any_category: new FormControl(null), - built_in: new FormControl(null), - type: new FormControl('role'), - category: new FormControl({ value: [], disabled: this.value?.built_in }), - parametrized_by_type: new FormControl([]), - child: new FormControl([], [ - Validators.required - ]), - url: new FormControl(null), - }); - super.ngOnInit(); - - this.form.markAllAsTouched(); - } - - addKeywordFromInput(event: MatChipInputEvent): void { - const value = (event.value || '').trim(); - if (value) { - this.categoryControl.setValue([ - ...new Set([...this.categoryControl.value, value]) - ]); - } - event.input.value = ''; - this.categoryControl.markAsDirty(); - } - - removeKeyword(category: string): void { - const categories = [...this.categoryControl?.value || []]; - const index = categories.indexOf(category); - - if (index >= 0) { - categories.splice(index, 1); - } - - this.categoryControl.setValue(categories); - this.categoryControl.markAsDirty(); - } -} diff --git a/web/src/app/components/rbac/role-form/rbac-role-form.module.ts b/web/src/app/components/rbac/role-form/rbac-role-form.module.ts deleted file mode 100644 index 472befab6e..0000000000 --- a/web/src/app/components/rbac/role-form/rbac-role-form.module.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RbacRoleFormComponent } from './rbac-role-form.component'; -import { ReactiveFormsModule } from '@angular/forms'; -import { AdwpFormElementModule } from '@app/adwp'; -import { AdcmInputRbacPermissionModule } from '../../../shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.module'; -import { RbacPermissionFormModule } from '../permission-form/rbac-permission-form.module'; -import { RbacRolesAsOptionsModule } from './options/rbac-roles-as-options.module'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatChipsModule } from '@angular/material/chips'; -import { MatIconModule } from '@angular/material/icon'; -import { MatButtonModule } from '@angular/material/button'; - - -@NgModule({ - declarations: [ - RbacRoleFormComponent - ], - exports: [ - RbacRoleFormComponent - ], - imports: [ - CommonModule, - AdwpFormElementModule, - ReactiveFormsModule, - AdcmInputRbacPermissionModule, - RbacPermissionFormModule, - RbacRolesAsOptionsModule, - MatFormFieldModule, - MatChipsModule, - MatIconModule, - MatButtonModule - ], -}) -export class RbacRoleFormModule { -} diff --git a/web/src/app/components/rbac/user-form/options/rbac-users-as-options.directive.ts b/web/src/app/components/rbac/user-form/options/rbac-users-as-options.directive.ts deleted file mode 100644 index 3bfdee75f7..0000000000 --- a/web/src/app/components/rbac/user-form/options/rbac-users-as-options.directive.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Directive, Inject, Input } from '@angular/core'; -import { RbacUserModel } from '../../../../models/rbac/rbac-user.model'; -import { RbacUserService } from '../../../../services/rbac-user.service'; -import { AdwpStringHandler } from '@app/adwp'; -import { Params } from '@angular/router'; -import { RbacOptionsDirective } from '../../../../abstract-directives/rbac-options.directive'; - -@Directive({ - selector: '[appRbacUsersAsOptions], [rbac-users-as-options]', - exportAs: 'rbacUsers' -}) -export class RbacUsersAsOptionsDirective extends RbacOptionsDirective { - initialParams: Params = { - ordering: 'username' - }; - - @Input('rbac-users-as-options') - params: Params; - - label: AdwpStringHandler = (item: RbacUserModel) => item.username; - - constructor(@Inject(RbacUserService) public service: RbacUserService) { - super(service); - } -} diff --git a/web/src/app/components/rbac/user-form/options/rbac-users-as-options.module.ts b/web/src/app/components/rbac/user-form/options/rbac-users-as-options.module.ts deleted file mode 100644 index aa021da95c..0000000000 --- a/web/src/app/components/rbac/user-form/options/rbac-users-as-options.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RbacUsersAsOptionsDirective } from './rbac-users-as-options.directive'; - - -@NgModule({ - declarations: [RbacUsersAsOptionsDirective], - exports: [ - RbacUsersAsOptionsDirective - ], - imports: [ - CommonModule - ] -}) -export class RbacUsersAsOptionsModule { -} diff --git a/web/src/app/components/rbac/user-form/rbac-user-form.component.html b/web/src/app/components/rbac/user-form/rbac-user-form.component.html deleted file mode 100644 index b3bca54a67..0000000000 --- a/web/src/app/components/rbac/user-form/rbac-user-form.component.html +++ /dev/null @@ -1,30 +0,0 @@ -
- -
- - -
-
- ADCM Administrator -
- - - - - -
diff --git a/web/src/app/components/rbac/user-form/rbac-user-form.component.scss b/web/src/app/components/rbac/user-form/rbac-user-form.component.scss deleted file mode 100644 index ff9ccc496a..0000000000 --- a/web/src/app/components/rbac/user-form/rbac-user-form.component.scss +++ /dev/null @@ -1,13 +0,0 @@ -.rbac-user-form__password { - display: flex; - gap: 5px -} - -.rbac-user-form__password > adwp-input { - flex: 1 -} - -.row { - display:flex; - color: rgba(255, 255, 255, 0.7); -} diff --git a/web/src/app/components/rbac/user-form/rbac-user-form.component.ts b/web/src/app/components/rbac/user-form/rbac-user-form.component.ts deleted file mode 100644 index 7dca8f4b01..0000000000 --- a/web/src/app/components/rbac/user-form/rbac-user-form.component.ts +++ /dev/null @@ -1,244 +0,0 @@ -import { Component, forwardRef } from '@angular/core'; -import { AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; -import { RbacFormDirective } from '@app/shared/add-component/rbac-form.directive'; -import { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model'; -import { RbacUserService } from '@app/services/rbac-user.service'; -import { RbacUserModel } from '@app/models/rbac/rbac-user.model'; -import { CustomValidators } from '../../../shared/validators/custom-validators'; - -/** The password and the confirm password must be equals */ -export const passwordsConfirmValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - const password = control.get('user')?.get('password'); - const confirm = control.get('confirm')?.get('password'); - - return password && confirm && password.value !== confirm.value ? { passwordsNotMatch: true } : null; -}; - -@Component({ - selector: 'app-rbac-user-form', - templateUrl: './rbac-user-form.component.html', - styleUrls: ['rbac-user-form.component.scss'], - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: forwardRef(() => RbacUserService) } - ] -}) -export class RbacUserFormComponent extends RbacFormDirective { - private _isFirstTouch = true; - passMinLength = null; - passMaxLength = null; - dummyValue = '******'; - form: FormGroup = new FormGroup({ - user: new FormGroup({ - id: new FormControl(null), - is_superuser: new FormControl(null), - built_in: new FormControl(null), - url: new FormControl(null), - profile: new FormControl(null), - username: new FormControl(null, [ - CustomValidators.required, - Validators.minLength(2), - Validators.maxLength(150), - Validators.pattern('^[a-zA-Z0-9_.-\/]*$') - ]), - password: new FormControl(null, [ - CustomValidators.required - ]), - first_name: new FormControl(null, [ - CustomValidators.required, - Validators.minLength(2), - Validators.maxLength(150), - Validators.pattern('^[a-zA-Z\S]*$') - ]), - last_name: new FormControl(null, [ - CustomValidators.required, - Validators.minLength(2), - Validators.maxLength(150), - Validators.pattern('^[a-zA-Z\S]*$') - ]), - email: new FormControl(null, [ - CustomValidators.required, - Validators.maxLength(254), - // regexp from django - Validators.pattern('(^[-!#$%&\'*+\\/=?^_`{}|~0-9A-Za-z]+(.[-!#$%&\'*+\\/=?^_`{}|~0-9A-Za-z]+)*|^"([\\001-\\010\\013\\014\\016-\\037!#-[]-\\177]|\\[\\001-\\011\\013\\014\\016-\\177])*")@((?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?.)+)(?:[A-Za-z0-9-]{2,63}(? { - return value?.type === 'ldap'; - }; - - get passwordValidators() { - return [ - Validators.required, - Validators.minLength(this.passMinLength || 3), - Validators.maxLength(this.passMaxLength || 128), - Validators.pattern(new RegExp(/^[\s\S]*$/u)) - ] - } - - get userForm(): FormGroup { - return this.form.get('user') as FormGroup; - } - - get confirmForm(): FormGroup { - return this.form.get('confirm') as FormGroup; - } - - ngOnInit(): void { - this.getGlobalSettings().subscribe((resp) => { - this.passMinLength = resp.config['auth_policy'].min_password_length; - this.passMaxLength = resp.config['auth_policy'].max_password_length; - - this._setValue(this.value); - this._initPasswordConfirmSubscription(); - this.form.markAllAsTouched(); - }) - } - - rbacBeforeSave(form: FormGroup): Partial { - return this.getDirtyValues(form); - } - - getDirtyValues(data) { - const user = data?.controls['user']?.controls; - const result = {}; - - Object.keys(user).forEach((key) => { - if (user[key].dirty && user[key].value !== '') { - result[key] = user[key]?.value; - } - }) - - return result; - } - - /** Add password length validators only if we are going to change it - * because password length rules could be changed anytime - */ - onFocus() { - this.clearPasswordControlIfFocusIn(); - this.addPasswordValidators(); - } - - onBlur() { - if (this.title === 'Add') return; - - const controls = [this.userForm.get('password'), this.confirmForm.get('password')]; - const [pwdControl, confirmControl] = controls; - - if (pwdControl.value || confirmControl.value) return; - - if (!this._isFirstTouch) { - controls.forEach((control) => { - control.setValue(this.dummyValue); - control.clearValidators(); - control.markAsUntouched(); - }) - } - - this.form.updateValueAndValidity(); - this._isFirstTouch = true; - } - - addPasswordValidators() { - const userForm: Partial = this.form.controls.user; - const confirmForm: Partial = this.form.controls.confirm; - userForm.controls['password'].setValidators(this.passwordValidators); - confirmForm.controls['password'].setValidators(this.passwordValidators); - this.form.updateValueAndValidity(); - } - - /** - * As soon as a user focuses an input with password or an input of password confirmation, - * then in this case we delete the dummy (*****) text - */ - clearPasswordControlIfFocusIn(): void { - const forms = Object.values(this.form.controls); - - forms.forEach((form: AbstractControl) => { - if (this._isFirstTouch) { - form.get('password').setValue(''); - form.get('password').markAsTouched(); - form.updateValueAndValidity(); - } - }); - - this._isFirstTouch = false; - } - - /** - * Need to set form value and form value to confirm password - * - * @param value - * @private - */ - private _setValue(value: RbacUserModel): void { - if (value) { - const type: string = this.value?.type; - // ToDo(lihih) the "adwp-list" should not change the composition of the original model. - // Now he adds the "checked" key to the model - this._updateAndSetValueForForm(this.userForm); - this.confirmForm.setValue({ password: this.dummyValue }); // read commentary inside _updateAndSetValueForForm - this.form.get('user.username').disable(); - - if (type === 'ldap' || value?.is_active === false) { - this.userForm.controls.first_name.disable(); - this.userForm.controls.last_name.disable(); - this.userForm.controls.email.disable(); - this.userForm.controls.password.disable(); - this.confirmForm.controls.password.disable(); - } - - if (value?.is_active === false) { - this.userForm.controls.group.disable(); - this.userForm.controls.is_superuser.disable(); - } - } - } - - /** - * Our adwp-input does not know how to work with nested forms, therefore, in this case, - * it does not display an error message if the control with the password is "invalid". - * Therefore, we need to manually install and remove the desired error message. - * - * @private - */ - private _initPasswordConfirmSubscription(): void { - const controls = [this.userForm.get('password'), this.confirmForm.get('password')]; - - this.form.statusChanges.subscribe(_ => { - if (this.form.errors && this.form.errors.passwordsNotMatch) { - controls.forEach((control) => { - control.setErrors({ passwordsNotMatch: true }, { emitEvent: false }); - }); - } else { - controls.forEach((control) => { - control.setErrors({}, { emitEvent: false }); - control.updateValueAndValidity({ emitEvent: false }); - }); - } - }); - } - - _isUserNotActive(value) { - return value?.is_active === false; - } - - _updateAndSetValueForForm(form) { - const formValue = { ...this.value }; - Object.keys(formValue).forEach((prop) => { - if (!form.controls.hasOwnProperty(prop)) delete formValue[prop]; - }) - - formValue.password = this.dummyValue; // password will not be provided from backend, but we still need to use it in formControl - - form.setValue(formValue); - } -} diff --git a/web/src/app/components/rbac/user-form/rbac-user-form.module.ts b/web/src/app/components/rbac/user-form/rbac-user-form.module.ts deleted file mode 100644 index 0b02d2e952..0000000000 --- a/web/src/app/components/rbac/user-form/rbac-user-form.module.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RbacUserFormComponent } from './rbac-user-form.component'; -import { ReactiveFormsModule } from '@angular/forms'; -import { RbacGroupFormModule } from '../group-form/rbac-group-form.module'; -import { RbacGroupsAsOptionsModule } from '../group-form/options/rbac-groups-as-options.module'; -import { AdwpFormElementModule } from '@app/adwp'; -import { FalseAsEmptyArrayModule } from '../../../shared/pipes/false-as-empty-array/false-as-empty-array.module'; -import { MatCheckboxModule } from '@angular/material/checkbox'; - - -@NgModule({ - declarations: [ - RbacUserFormComponent, - ], - exports: [ - RbacUserFormComponent, - ], - imports: [ - CommonModule, - AdwpFormElementModule, - ReactiveFormsModule, - RbacGroupFormModule, - RbacGroupsAsOptionsModule, - FalseAsEmptyArrayModule, - MatCheckboxModule - ], -}) -export class RbacUserFormModule { -} diff --git a/web/src/app/components/service-component/service-component-details/service-component-details.component.ts b/web/src/app/components/service-component/service-component-details/service-component-details.component.ts deleted file mode 100644 index 76d7583648..0000000000 --- a/web/src/app/components/service-component/service-component-details/service-component-details.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Component, Injector } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { ActivatedRoute } from '@angular/router'; - -import { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive'; -import { SocketState } from '@app/core/store'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ChannelService } from '@app/core/services'; -import { ServiceComponentService } from '@app/services/service-component.service'; -import { DetailsFactory } from '@app/factories/details.factory'; -import { IServiceComponent } from '@app/models/service-component'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -@Component({ - selector: 'app-service-component-details', - templateUrl: '../../../templates/details.html', - styleUrls: ['../../../styles/details.scss'] -}) -export class ServiceComponentDetailsComponent extends DetailAbstractDirective { - - entityParam = 'servicecomponent'; - - leftMenu = [ - DetailsFactory.labelMenuItem('Main', 'main'), - DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.ServiceComponent, 'component'), - DetailsFactory.labelMenuItem('Configuration groups', 'group_config'), - DetailsFactory.statusMenuItem('Status', 'status', 'component'), - ]; - - constructor( - socket: Store, - protected route: ActivatedRoute, - protected service: ClusterService, - protected channel: ChannelService, - protected store: Store, - injector: Injector, - protected subjectService: ServiceComponentService, - ) { - super(socket, route, service, channel, store, injector); - } - -} diff --git a/web/src/app/components/service-component/service-component-status/service-component-status.component.ts b/web/src/app/components/service-component/service-component-status/service-component-status.component.ts deleted file mode 100644 index 48ffd01373..0000000000 --- a/web/src/app/components/service-component/service-component-status/service-component-status.component.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { fromJS, updateIn } from 'immutable'; - -import { StatusAbstractDirective } from '@app/abstract-directives/status.abstract.directive'; -import { HostComponentStatusTree } from '@app/models/status-tree'; -import { EventMessage, SocketState } from '@app/core/store'; -import { ServiceComponentService } from '@app/services/service-component.service'; -import { IServiceComponent } from '@app/models/service-component'; - -@Component({ - selector: 'app-service-component-status', - templateUrl: '../../../templates/status-tree.html', - styleUrls: ['../../../styles/status-tree.scss'] -}) -export class ServiceComponentStatusComponent extends StatusAbstractDirective { - - constructor( - protected route: ActivatedRoute, - protected store: Store, - public entityService: ServiceComponentService, - ) { - super(route, store, entityService); - } - - pipeData(): any { - return this.entity.cluster_id; - } - - eventReceived(event: EventMessage) { - let output; - switch (event.object.type) { - case 'hostcomponent': - const componentId = this.statusTree.value.id; - output = updateIn(fromJS(this.statusTree.value), ['hosts'], (hosts: any[]) => - hosts.map(host => { - if (host.get('id') === event.object.id && componentId === +event.object.details.id) { - return host.set('status', +event.object.details.value); - } - return host; - }) - ); - this.statusTree.next(output.toJS() as any as HostComponentStatusTree); - break; - case 'component': - output = fromJS(this.statusTree.value); - if (output.get('id') === event.object.id) { - output = output.set('status', +event.object.details.value); - } - this.statusTree.next(output.toJS() as any as HostComponentStatusTree); - break; - } - } - - getEntityIdFromParams(): number { - return +this.route.parent.snapshot.params.servicecomponent; - } - -} diff --git a/web/src/app/components/service-component/service-components.component.ts b/web/src/app/components/service-component/service-components.component.ts deleted file mode 100644 index e576fe418e..0000000000 --- a/web/src/app/components/service-component/service-components.component.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { IColumns } from '@app/adwp'; -import { Component } from '@angular/core'; - -import { TypeName } from '@app/core/types'; -import { ListFactory } from '@app/factories/list.factory'; -import { ConcernListDirective } from '@app/abstract-directives/concern-list.directive'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -@Component({ - selector: 'app-service-components', - template: ` - - `, - styles: [` - :host { flex: 1; } - `], -}) -export class ServiceComponentsComponent extends ConcernListDirective { - - type: TypeName = 'servicecomponent'; - eventTypes = [ConcernEventType.ServiceComponent]; - - listColumns = [ - ListFactory.nameColumn('display_name'), - ListFactory.stateColumn(), - ListFactory.statusColumn(this), - ListFactory.actionsButton(this), - ListFactory.configColumn(this), - ListFactory.maintenanceModeColumn(this, 'component'), - ] as IColumns; - -} diff --git a/web/src/app/components/service/service-details/service-details.component.ts b/web/src/app/components/service/service-details/service-details.component.ts deleted file mode 100644 index ce2bddc63e..0000000000 --- a/web/src/app/components/service/service-details/service-details.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component, Injector } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; - -import { DetailAbstractDirective } from '@app/abstract-directives/detail.abstract.directive'; -import { Service } from '@app/core/types'; -import { SocketState } from '@app/core/store'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ChannelService } from '@app/core/services'; -import { ServiceService } from '@app/services/service.service'; -import { DetailsFactory } from '@app/factories/details.factory'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -@Component({ - selector: 'app-service-details', - templateUrl: '../../../templates/details.html', - styleUrls: ['../../../styles/details.scss'] -}) -export class ServiceDetailsComponent extends DetailAbstractDirective { - - entityParam = 'service'; - - leftMenu = [ - DetailsFactory.labelMenuItem('Main', 'main'), - DetailsFactory.concernMenuItem('Components', 'component', 'host-component', ConcernEventType.Service, 'service'), - DetailsFactory.concernMenuItem('Configuration', 'config', 'config', ConcernEventType.Service, 'service'), - DetailsFactory.labelMenuItem('Configuration groups', 'group_config'), - DetailsFactory.statusMenuItem('Status', 'status', 'service'), - DetailsFactory.concernMenuItem('Import', 'import', 'import', ConcernEventType.Service, 'service'), - ]; - - constructor( - socket: Store, - protected route: ActivatedRoute, - protected service: ClusterService, - protected channel: ChannelService, - protected store: Store, - injector: Injector, - protected subjectService: ServiceService, - ) { - super(socket, route, service, channel, store, injector); - } - -} diff --git a/web/src/app/components/service/service-status/service-status.component.ts b/web/src/app/components/service/service-status/service-status.component.ts deleted file mode 100644 index 9f364a444d..0000000000 --- a/web/src/app/components/service/service-status/service-status.component.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { fromJS, updateIn } from 'immutable'; - -import { StatusAbstractDirective } from '@app/abstract-directives/status.abstract.directive'; -import { EventMessage, SocketState } from '@app/core/store'; -import { ServiceService } from '@app/services/service.service'; -import { ServiceStatusTree } from '@app/models/status-tree'; -import { Service } from '@app/core/types'; - -@Component({ - selector: 'app-service-status', - templateUrl: '../../../templates/status-tree.html', - styleUrls: ['../../../styles/status-tree.scss'] -}) -export class ServiceStatusComponent extends StatusAbstractDirective { - - constructor( - protected route: ActivatedRoute, - protected store: Store, - public entityService: ServiceService, - ) { - super(route, store, entityService); - } - - pipeData(): any { - return this.entity.cluster_id; - } - - eventReceived(event: EventMessage) { - let output; - switch (event.object.type) { - case 'hostcomponent': - output = updateIn(fromJS(this.statusTree.value), ['hc'], (components: any[]) => - components.map(component => updateIn(component, ['hosts'], (hosts: any[]) => - hosts.map((host: any) => { - if (host.get('id') === event.object.id && component.get('id') === +event.object.details.id) { - return host.set('status', +event.object.details.value); - } - return host; - }) - )) - ); - this.statusTree.next(output.toJS() as any as ServiceStatusTree); - break; - case 'component': - output = updateIn(fromJS(this.statusTree.value), ['hc'], (components: any[]) => - components.map(component => { - if (component.get('id') === event.object.id) { - return component.set('status', +event.object.details.value); - } - return component; - }) - ); - this.statusTree.next(output.toJS() as any as ServiceStatusTree); - break; - case 'service': - output = fromJS(this.statusTree.value); - if (output.get('id') === event.object.id) { - output = output.set('status', +event.object.details.value); - } - this.statusTree.next(output.toJS() as any as ServiceStatusTree); - break; - } - } - - getEntityIdFromParams(): number { - return +this.route.parent.snapshot.params.service; - } - -} diff --git a/web/src/app/components/snack-bar/snack-bar.component.ts b/web/src/app/components/snack-bar/snack-bar.component.ts deleted file mode 100644 index 88e6637894..0000000000 --- a/web/src/app/components/snack-bar/snack-bar.component.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Component, Inject } from '@angular/core'; -import { MAT_SNACK_BAR_DATA, MatSnackBarRef } from '@angular/material/snack-bar'; - -@Component({ - selector: 'app-snack-bar', - template: ` -
-
-
{{ data?.message }}
-
- args - {{ data?.args }} -
-
- -
- `, - styles: [` - .snack-bar-container { - display: flex; - justify-content: space-between; - align-items: center; - font-size: 14px; - line-height: 20px; - } - .message-wrapper { - margin-right: 16px; - } - .args { - border-top: 1px solid #78909c; - margin-top: 7px; - padding-top: 7px; - } - .chip { - background: #78909c; - color: #fff; - padding: 1px 3px; - border-radius: 3px; - } - `] -}) -export class SnackBarComponent { - - constructor( - public snackBarRef: MatSnackBarRef, - @Inject(MAT_SNACK_BAR_DATA) public data: { - message: string, - args: string; - }, - ) { } - -} diff --git a/web/src/app/components/status-tree/status-tree.component.html b/web/src/app/components/status-tree/status-tree.component.html deleted file mode 100644 index 78a795dad0..0000000000 --- a/web/src/app/components/status-tree/status-tree.component.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - check_circle_outline - - error_outline - - -   - {{node.subject.name}} - - - {{node.subject.name}} - - -   - - successful {{node.counts.succeed}}/{{node.counts.total}} - - diff --git a/web/src/app/components/status-tree/status-tree.component.scss b/web/src/app/components/status-tree/status-tree.component.scss deleted file mode 100644 index accce7e872..0000000000 --- a/web/src/app/components/status-tree/status-tree.component.scss +++ /dev/null @@ -1,20 +0,0 @@ -.expandable { - font-weight: bold; -} - -.counts { - color: #ff9800; -} - -.success { - color: #00e676; -} - -button { - width: 35px; - height: 35px; -} - -mat-tree-node { - min-height: 35px; -} diff --git a/web/src/app/components/status-tree/status-tree.component.ts b/web/src/app/components/status-tree/status-tree.component.ts deleted file mode 100644 index 6d65873499..0000000000 --- a/web/src/app/components/status-tree/status-tree.component.ts +++ /dev/null @@ -1,124 +0,0 @@ -/* tslint:disable:member-ordering */ -import { Component, Input, ViewChild } from '@angular/core'; -import { FlatTreeControl } from '@angular/cdk/tree'; -import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'; - -import { StatusTree, StatusTreeSubject } from '@app/models/status-tree'; - -interface ExampleFlatNode { - expandable: boolean; - subject: StatusTreeSubject; - level: number; -} - -interface Counts { - total: number; - succeed: number; -} - -interface CountedStatusTree extends StatusTree { - counts?: Counts; -} - -export enum Folding { - Collapsed, - Expanded, -} - -@Component({ - selector: 'app-status-tree', - templateUrl: './status-tree.component.html', - styleUrls: ['./status-tree.component.scss'] -}) -export class StatusTreeComponent { - - @ViewChild('treeNode', { static: true }) treeNode: any; - - private calcCounts = (children: CountedStatusTree[]): Counts => { - return children.reduce((acc: Counts, child: CountedStatusTree) => { - acc.total++; - if ('status' in child.subject) { - if (child.subject.status === 0) { - acc.succeed++; - } - } else { - const childrenSucceed = child.children.reduce((accum, item) => item.subject.status === 0 ? accum + 1 : accum, 0); - if (childrenSucceed === child.children.length) { - acc.succeed++; - } - } - return acc; - }, - { total: 0, succeed: 0 } as Counts, - ) as Counts; - } - - private transformer = (node: StatusTree, level: number) => { - return { - expandable: !!node.children && node.children.length > 0, - subject: node.subject, - level: level, - counts: node.children ? this.calcCounts(node.children) : { total: 0, succeed: 0 }, - }; - } - - treeControl = new FlatTreeControl( - node => node.level, - node => node.expandable, - ); - - treeFlattener = new MatTreeFlattener( - this.transformer, - node => node.level, - node => node.expandable, - node => node.children, - ); - - dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); - - private ownTree: StatusTree[]; - @Input() set tree(tree: StatusTree[]) { - this.ownTree = tree; - this.dataSource.data = tree; - - if (this.folding === Folding.Expanded) { - this.treeControl.expandAll(); - } - - if (this.folding === Folding.Collapsed) { - this.treeControl.collapseAll(); - } - } - get tree(): StatusTree[] { - return this.ownTree; - } - - hasChild = (_: number, node: ExampleFlatNode) => node.expandable; - - private ownFolding: Folding; - @Input() set folding(folding: Folding) { - this.ownFolding = folding; - this.tree = this.tree; - } - get folding(): Folding { - return this.ownFolding; - } - - expandAll() { - this.treeControl.expandAll(); - } - - collapseAll() { - this.treeControl.collapseAll(); - } - - hasCollapsed(): boolean { - for (const item of this.treeControl.dataNodes) { - if (!this.treeControl.isExpanded(item)) { - return true; - } - } - return false; - } - -} diff --git a/web/src/app/config-groups/components/config-group-add/config-group-add.component.ts b/web/src/app/config-groups/components/config-group-add/config-group-add.component.ts deleted file mode 100644 index 77ad6c2cd3..0000000000 --- a/web/src/app/config-groups/components/config-group-add/config-group-add.component.ts +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed 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 { Component, forwardRef, OnInit } from '@angular/core'; - -import { BaseFormDirective } from '../../../shared/add-component'; -import { ADD_SERVICE_PROVIDER } from '../../../shared/add-component/add-service-model'; -import { ConfigGroupAddService } from '../../service'; -import { clearEmptyField } from '../../../core/types'; -import { ConfigGroup } from '../../model'; -import { take } from 'rxjs/operators'; - -@Component({ - selector: 'app-config-group-add', - template: ` - - - - - - `, - providers: [ - { provide: ADD_SERVICE_PROVIDER, useExisting: forwardRef(() => ConfigGroupAddService) } - ], -}) -export class AddConfigGroupComponent extends BaseFormDirective implements OnInit { - - ngOnInit(): void { - this.form = this.service.model().form; - } - - save(): void { - const data = clearEmptyField(this.form.value) as ConfigGroup; - this.service - .add(data) - .pipe(take(1)) - .subscribe((_) => this.onCancel()); - } -} diff --git a/web/src/app/config-groups/components/config-group-host-add/config-group-host-add.component.ts b/web/src/app/config-groups/components/config-group-host-add/config-group-host-add.component.ts deleted file mode 100644 index b5cb40f7e8..0000000000 --- a/web/src/app/config-groups/components/config-group-host-add/config-group-host-add.component.ts +++ /dev/null @@ -1,123 +0,0 @@ -// Licensed 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 { ChangeDetectionStrategy, Component, OnInit, ViewChild } from '@angular/core'; -import { MatSelectionList, MatSelectionListChange } from '@angular/material/list'; -import { Host } from '@app/core/types'; -import { Observable } from 'rxjs'; - -import { BaseFormDirective } from '@app/shared/add-component'; -import { MatDialog } from '@angular/material/dialog'; -import { ConfigGroupHostAddService } from '../../service'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ListResult } from '@app/models/list-result'; -import { PageEvent } from '@angular/material/paginator'; - -@Component({ - selector: 'app-config-group-host-add', - template: ` - - - All - - {{ host.fqdn }} - - - - - - -

- - There are no new hosts. You config group already has all of them. - -

-
- `, - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class AddHostToConfigGroupComponent extends BaseFormDirective implements OnInit { - - selected: { [key: number]: boolean } = {}; - - get disabled() { - return !Object.keys(this.selected).length; - } - - pageIndex = 0; - pageSize = 10; - - list$: Observable>; - @ViewChild('selectionList') - private list: MatSelectionList; - - constructor(service: ConfigGroupHostAddService, dialog: MatDialog, private cluster: ClusterService) { - super(service, dialog); - } - - ngOnInit(): void { - this.getAvailableHosts(this.pageIndex, this.pageSize); - } - - selectAll(e: MatSelectionListChange): void { - const value = e.option.value; - if (!value) { - if (e.option.selected) { - this.list.selectAll(); - this.list.options.filter((o) => !!o.value).forEach((o) => { - this.selected[o.value.id] = true; - }); - - } else { - this.list.deselectAll(); - - this.list.options.filter((o) => !!o.value).forEach((o) => { - if (this.selected[o.value.id]) { - delete this.selected[o.value.id]; - } - }); - } - } else { - if (this.selected[value.id]) { - delete this.selected[value.id]; - } else { - this.selected[value.id] = true; - } - } - } - - save(): void { - const groupId = this.service.Current.id; - const result = Object.entries(this.selected).map(([id]) => ({ - host: +id, - group: groupId - })); - - this.service - .add(result) - .pipe(this.takeUntil()) - .subscribe(() => this.dialog.closeAll()); - } - - getAvailableHosts(pageIndex, pageSize): void { - const { typeName } = this.cluster.Current; - this.list$ = this.service.getListResults(typeName, { limit: pageSize, page: pageIndex }); - } - - pageHandler(pageEvent: PageEvent): void { - this.pageIndex = pageEvent.pageIndex; - this.pageSize = pageEvent.pageSize; - this.getAvailableHosts(this.pageIndex, this.pageSize); - } -} diff --git a/web/src/app/config-groups/components/index.ts b/web/src/app/config-groups/components/index.ts deleted file mode 100644 index bd37677935..0000000000 --- a/web/src/app/config-groups/components/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './config-group-add/config-group-add.component'; -export * from './config-group-host-add/config-group-host-add.component'; diff --git a/web/src/app/config-groups/config-group.module.ts b/web/src/app/config-groups/config-group.module.ts deleted file mode 100644 index bdac2b81c8..0000000000 --- a/web/src/app/config-groups/config-group.module.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ConfigGroupHostListComponent, ConfigGroupListComponent } from './pages'; -import { AdwpListModule } from '@app/adwp'; -import { AddConfigGroupComponent, AddHostToConfigGroupComponent } from './components'; -import { ReactiveFormsModule } from '@angular/forms'; -import { MatListModule } from '@angular/material/list'; -import { AddingModule } from '@app/shared/add-component/adding.module'; -import { FormElementsModule } from '@app/shared/form-elements/form-elements.module'; -import { ListService } from '../shared/components/list/list.service'; -import { LIST_SERVICE_PROVIDER } from '../shared/components/list/list-service-token'; -import { MatPaginatorModule } from '@angular/material/paginator'; -import { MatCheckboxModule } from '@angular/material/checkbox'; - - -@NgModule({ - declarations: [ - ConfigGroupListComponent, - AddConfigGroupComponent, - ConfigGroupHostListComponent, - AddHostToConfigGroupComponent, - ], - imports: [ - CommonModule, - ReactiveFormsModule, - AdwpListModule, - MatListModule, - AddingModule, - FormElementsModule, - MatPaginatorModule, - MatCheckboxModule - ], - exports: [ - AddConfigGroupComponent, - ], - providers: [ - { - provide: LIST_SERVICE_PROVIDER, - useClass: ListService - } - ] -}) -export class ConfigGroupModule { -} diff --git a/web/src/app/config-groups/index.ts b/web/src/app/config-groups/index.ts deleted file mode 100644 index b11677dfeb..0000000000 --- a/web/src/app/config-groups/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './components'; -export * from './model'; -export * from './pages'; -export * from './service'; -export * from './config-group.module'; diff --git a/web/src/app/config-groups/loader.ts b/web/src/app/config-groups/loader.ts deleted file mode 100644 index 4811c06691..0000000000 --- a/web/src/app/config-groups/loader.ts +++ /dev/null @@ -1,3 +0,0 @@ -const loadConfigGroup = () => import('./config-group.module').then((m) => m.ConfigGroupModule); - -export { loadConfigGroup }; diff --git a/web/src/app/config-groups/model/config-group.model.ts b/web/src/app/config-groups/model/config-group.model.ts deleted file mode 100644 index 3f1dbecf23..0000000000 --- a/web/src/app/config-groups/model/config-group.model.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ApiFlat } from '@app/core/types'; - -export interface ConfigGroup extends ApiFlat { - name: string; - description: string; - hosts: string; - config: string; - host_candidate: string; -} diff --git a/web/src/app/config-groups/model/index.ts b/web/src/app/config-groups/model/index.ts deleted file mode 100644 index b631e072cf..0000000000 --- a/web/src/app/config-groups/model/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './config-group.model'; diff --git a/web/src/app/config-groups/pages/group-list/group-list.component.ts b/web/src/app/config-groups/pages/group-list/group-list.component.ts deleted file mode 100644 index dc09678ea2..0000000000 --- a/web/src/app/config-groups/pages/group-list/group-list.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Component, OnInit, Type } from '@angular/core'; -import { TypeName } from '@app/core/types'; -import { AdwpListDirective } from '@app/abstract-directives/adwp-list.directive'; -import { IColumns } from '@app/adwp'; -import { ListFactory } from '@app/factories/list.factory'; -import { ConfigGroupAddService, ConfigGroupListService } from '../../service'; -import { LIST_SERVICE_PROVIDER } from '@app/shared/components/list/list-service-token'; -import { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model'; -import { BaseFormDirective } from '@app/shared/add-component'; -import { AddConfigGroupComponent } from '../../components'; - -@Component({ - selector: 'app-config-group-list', - template: ` - Add config group - - - `, - styles: [':host { flex: 1; }', '.add-button {position:fixed; right: 20px;top:120px;}'], - providers: [ - { provide: LIST_SERVICE_PROVIDER, useClass: ConfigGroupListService }, - { provide: ADD_SERVICE_PROVIDER, useClass: ConfigGroupAddService } - ], -}) -export class ConfigGroupListComponent extends AdwpListDirective implements OnInit { - type: TypeName = 'group_config'; - addComponent: Type = AddConfigGroupComponent; - - listColumns: IColumns = [ - ListFactory.nameColumn(), - ListFactory.descriptionColumn(), - ListFactory.deleteColumn(this), - ]; -} diff --git a/web/src/app/config-groups/pages/host-list/host-list.component.ts b/web/src/app/config-groups/pages/host-list/host-list.component.ts deleted file mode 100644 index 0682a07d8f..0000000000 --- a/web/src/app/config-groups/pages/host-list/host-list.component.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Component, Type } from '@angular/core'; -import { IColumns, RowEventData } from '@app/adwp'; -import { AdwpListDirective } from '@app/abstract-directives/adwp-list.directive'; -import { TypeName } from '@app/core/types'; -import { ListFactory } from '@app/factories/list.factory'; -import { IHost } from '@app/models/host'; -import { LIST_SERVICE_PROVIDER } from '@app/shared/components/list/list-service-token'; -import { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model'; -import { ConfigGroupHostAddService, ConfigGroupHostListService } from '../../service'; -import { BaseFormDirective } from '@app/shared/add-component'; -import { AddHostToConfigGroupComponent } from '../../components'; - - -@Component({ - selector: 'app-config-group-host-list', - template: ` - Add hosts - - - `, - styles: [':host { flex: 1; }', '.add-button {position:fixed; right: 20px;top:120px;}'], - providers: [ - { provide: LIST_SERVICE_PROVIDER, useClass: ConfigGroupHostListService }, - { provide: ADD_SERVICE_PROVIDER, useClass: ConfigGroupHostAddService } - ], -}) -export class ConfigGroupHostListComponent extends AdwpListDirective { - type: TypeName = 'group_config_hosts'; - addComponent: Type = AddHostToConfigGroupComponent; - - listColumns = [ - ListFactory.fqdnColumn(), - ListFactory.deleteColumn(this), - ] as IColumns; - - clickRow(data: RowEventData): void { - data.event.preventDefault(); - data.event.stopPropagation(); - return; - } - -} diff --git a/web/src/app/config-groups/pages/index.ts b/web/src/app/config-groups/pages/index.ts deleted file mode 100644 index 5786f1574e..0000000000 --- a/web/src/app/config-groups/pages/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './group-list/group-list.component'; -export * from './host-list/host-list.component'; diff --git a/web/src/app/config-groups/service/config-group-add.service.ts b/web/src/app/config-groups/service/config-group-add.service.ts deleted file mode 100644 index 5c824b2aca..0000000000 --- a/web/src/app/config-groups/service/config-group-add.service.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Injectable } from '@angular/core'; -import { FormModel, IAddService } from '@app/shared/add-component/add-service-model'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { Observable } from 'rxjs'; -import { ApiService } from '@app/core/api'; -import { ConfigGroup } from '../model'; -import { environment } from '@env/environment'; - -const newConfigGroupForm = (): FormGroup => - new FormGroup({ - name: new FormControl('', [Validators.required, Validators.maxLength(30)]), - description: new FormControl(), - }); - -@Injectable({ - providedIn: 'root' -}) -export class ConfigGroupAddService implements IAddService { - - get Cluster() { - return this.service.Cluster; - } - - get Current() { - return this.service.Current; - } - - constructor(private service: ClusterService, protected api: ApiService) {} - - model(name?: string): FormModel { - return { - name: 'group_config', - title: 'Config group', - form: newConfigGroupForm() - }; - } - - add(group: Partial): Observable { - const params = { ...group }; - params.object_type = this.service.Current.typeName === 'servicecomponent' ? 'component' : this.service.Current.typeName; - params.object_id = this.service.Current.id; - return this.api.post(`${environment.apiRoot}group-config/`, params); - } - -} diff --git a/web/src/app/config-groups/service/config-group-host-add.service.ts b/web/src/app/config-groups/service/config-group-host-add.service.ts deleted file mode 100644 index ac7472356d..0000000000 --- a/web/src/app/config-groups/service/config-group-host-add.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Injectable } from '@angular/core'; -import { FormModel, IAddService } from '@app/shared/add-component/add-service-model'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { TypeName } from '@app/core/types'; -import { convertToParamMap, Params } from '@angular/router'; -import { forkJoin, Observable } from 'rxjs'; -import { ApiService } from '@app/core/api'; -import { environment } from '@env/environment'; -import { ConfigGroup } from '@app/config-groups'; -import { ListResult } from '@app/models/list-result'; - -const newConfigGroupHostForm = () => - new FormGroup({ - name: new FormControl('', Validators.required), - description: new FormControl(), - }); - -@Injectable({ - providedIn: 'root' -}) -export class ConfigGroupHostAddService implements IAddService { - - get Cluster() { - return this.service.Cluster; - } - - get Current() { - return this.service.Current; - } - - constructor(private service: ClusterService, protected api: ApiService) {} - - model(name?: string): FormModel { - return { - name: 'host2configgroup', - title: 'Config group hosts', - form: newConfigGroupHostForm() - }; - } - - add(data: { host: number, group: number }[]): Observable { - return forkJoin(data.map((o) => this.api.post(`${environment.apiRoot}group-config/${o.group}/host/`, { id: o.host }))); - } - - getListResults(type: TypeName, param: Params = {}): Observable> { - const paramMap = convertToParamMap(param); - const current = this.Current as unknown as ConfigGroup; - - return this.api.getList(current.host_candidate, paramMap); - } - -} diff --git a/web/src/app/config-groups/service/config-group-host-list.service.ts b/web/src/app/config-groups/service/config-group-host-list.service.ts deleted file mode 100644 index 6ee0e4975f..0000000000 --- a/web/src/app/config-groups/service/config-group-host-list.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { ApiService } from '@app/core/api'; -import { ParamMap } from '@angular/router'; -import { IListService, ListInstance } from '@app/shared/components/list/list-service-token'; -import { ListResult } from '@app/models/list-result'; -import { ApiFlat, Host } from '@app/core/types'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { environment } from '@env/environment'; - -@Injectable({ - providedIn: 'root' -}) -export class ConfigGroupHostListService implements IListService { - - current: ListInstance; - - constructor( - protected api: ApiService, - protected cluster: ClusterService - ) { - } - - getList(p: ParamMap): Observable> { - const current = this.cluster.Current as unknown as ApiFlat; - const listParamStr = localStorage.getItem('list:param'); - - if (p?.keys.length) { - const param = p.keys.reduce((a, c) => ({ ...a, [c]: p.get(c) }), {}); - delete param['page']; - - if (listParamStr) { - const json = JSON.parse(listParamStr); - json[`group_config_host_${current.object_type}`] = param; - localStorage.setItem('list:param', JSON.stringify(json)); - } else localStorage.setItem('list:param', JSON.stringify({ [`group_config_host_${current.object_type}`]: param })); - } - - const configGroupId = this.cluster.Current.id; - - return this.api.getList(`${environment.apiRoot}group-config/${configGroupId}/host/`, p); - } - - initInstance(): ListInstance { - this.current = { typeName: 'group_config_hosts', columns: ['name', 'remove'] }; - return this.current; - } - - delete(row: Host): Observable { - return this.api.delete(row.url); - } - -} diff --git a/web/src/app/config-groups/service/config-group-list.service.ts b/web/src/app/config-groups/service/config-group-list.service.ts deleted file mode 100644 index 57694d6e86..0000000000 --- a/web/src/app/config-groups/service/config-group-list.service.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Injectable, InjectionToken } from '@angular/core'; -import { Observable } from 'rxjs'; -import { ParamMap } from '@angular/router'; -import { EntityService } from '@app/abstract/entity-service'; -import { ApiService } from '@app/core/api'; -import { environment } from '@env/environment'; -import { ConfigGroup } from '@app/config-groups/model/config-group.model'; -import { IListService, ListInstance } from '@app/shared/components/list/list-service-token'; -import { ListResult } from '@app/models/list-result'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { Service } from '@app/core/types'; -import { ICluster } from '@app/models/cluster'; - -export const CONFIG_GROUP_LIST_SERVICE = new InjectionToken>('EntityService'); - -@Injectable({ - providedIn: 'root' -}) -export class ConfigGroupListService extends EntityService implements IListService { - - current: ListInstance; - - constructor( - protected api: ApiService, - private cluster: ClusterService - ) { - super(api); - } - - getList(p: ParamMap): Observable> { - const current = this.cluster.Current as ICluster | Service; - const listParamStr = localStorage.getItem('list:param'); - - if (p?.keys.length) { - const param = p.keys.reduce((a, c) => ({ ...a, [c]: p.get(c) }), {}); - delete param['page']; - - if (listParamStr) { - const json = JSON.parse(listParamStr); - json[`group_config_${current.typeName}`] = param; - localStorage.setItem('list:param', JSON.stringify(json)); - } else localStorage.setItem('list:param', JSON.stringify({ [`group_config_${current.typeName}`]: param })); - } - - return this.api.getList(current.group_config, p); - } - - initInstance(): ListInstance { - this.current = { typeName: 'group_config', columns: ['name', 'description', 'remove'] }; - return this.current; - } - - get( - id: number, - params: { [key: string]: string } = {}, - ): Observable { - return this.api.get(`${environment.apiRoot}group-config/${id}/`, params); - } - - delete(row: ConfigGroup): Observable { - return this.api.delete(row.url); - } - -} diff --git a/web/src/app/config-groups/service/config-group.service.ts b/web/src/app/config-groups/service/config-group.service.ts deleted file mode 100644 index 1b182e87a2..0000000000 --- a/web/src/app/config-groups/service/config-group.service.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { - IConfigListResponse, - IConfigResponse, - IConfigService -} from '@app/shared/configuration/services/config.service'; -import { ApiService } from '@app/core/api'; -import { CompareConfig, IConfig } from '@app/shared/configuration/types'; -import { map, switchMap } from 'rxjs/operators'; -import { getRandomColor } from '@app/core/types'; -import { environment } from '@env/environment'; - - -@Injectable({ - providedIn: 'root' -}) -export class ConfigGroupService implements IConfigService { - constructor(private api: ApiService) { } - - changeVersion(id: number): Observable { - return this.api.get(`${environment.apiRoot}config-log/${id}`); - } - - getConfig(url: string): Observable { - return this.api.get(url).pipe( - switchMap((config) => this.api.get(config.current)) - ); - } - - getHistoryList(url: string): Observable { - return this.api.get(url).pipe( - switchMap((config) => this.api.get(config.history)), - map((value) => value.results), - map((h) => h.map((b) => ({ - ...b, - color: getRandomColor() - })))); - } - - send(url: string, data: any): Observable { - return this.api.get(url).pipe( - switchMap((config) => this.api.post(config.history, data)), - ); - } -} diff --git a/web/src/app/config-groups/service/index.ts b/web/src/app/config-groups/service/index.ts deleted file mode 100644 index e8f6ebbc39..0000000000 --- a/web/src/app/config-groups/service/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './config-group-add.service'; -export * from './config-group-host-add.service'; -export * from './config-group-host-list.service'; -export * from './config-group-list.service'; -export * from './config-group.service'; diff --git a/web/src/app/core/animations/index.ts b/web/src/app/core/animations/index.ts deleted file mode 100644 index 45a540cdf7..0000000000 --- a/web/src/app/core/animations/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed 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 { animate, state, style, transition, trigger } from '@angular/animations'; - -export const openClose = trigger('openClose', [ - state('true', style({ height: '*', opacity: 1 })), - state('false', style({ height: '0px', opacity: 0 })), - transition('true <=> false', [animate('0.5s')]), -]); - -export const notify = trigger('notify', [ - state('show', style({ opacity: 1 })), - state('hide', style({ opacity: 0 })), - transition('hide => show', [animate('.2s')]), - transition('show => hide', [animate('2s')]), -]); diff --git a/web/src/app/core/api/api.effects.ts b/web/src/app/core/api/api.effects.ts deleted file mode 100644 index 2166f28649..0000000000 --- a/web/src/app/core/api/api.effects.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { IRoot } from '@app/core/types/api'; -import { environment } from '@env/environment'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { Store } from '@ngrx/store'; -import { of } from 'rxjs'; -import { catchError, delay, exhaustMap, filter, map, switchMap, withLatestFrom } from 'rxjs/operators'; - -import { State } from '../store'; -import { loadRoot, loadStack, rootError, rootSuccess, stackSuccess } from './api.reducer'; -import { ApiService } from './api.service'; - -@Injectable() -export class ApiEffects { - root$ = createEffect(() => - this.actions$.pipe( - ofType(loadRoot), - exhaustMap(() => - this.api.get(environment.apiRoot).pipe( - map(root => rootSuccess({ root })), - catchError(() => of(rootError())) - ) - ) - ) - ); - - retry$ = createEffect(() => - this.actions$.pipe( - ofType(rootError), - delay(3000), - switchMap(() => - this.api.get(environment.apiRoot).pipe( - map(root => rootSuccess({ root })), - catchError(() => of(rootError())) - ) - ) - ) - ); - - stack$ = createEffect(() => - this.actions$.pipe( - ofType(loadStack), - withLatestFrom(this.store, (actions, store) => store.api), - filter(api => api.root && !api.stack), - exhaustMap(api => this.api.get(api.root.stack).pipe(map(stack => stackSuccess({ stack })))) - ) - ); - - constructor(private actions$: Actions, private api: ApiService, private store: Store) {} -} diff --git a/web/src/app/core/api/api.reducer.ts b/web/src/app/core/api/api.reducer.ts deleted file mode 100644 index 928f6544b9..0000000000 --- a/web/src/app/core/api/api.reducer.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed 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 { IRoot } from '@app/core/types/api'; -import { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props } from '@ngrx/store'; - -export const loadRoot = createAction('[API] LoadRoot'); -export const loadStack = createAction('[API] LoadStack'); -export const rootSuccess = createAction('[API] LoadRootSuccess', props<{ root: IRoot }>()); -export const rootError = createAction('[API] LoadRootError'); -export const stackSuccess = createAction('[API] LoadStackSuccess', props<{ stack: IRoot }>()); - -export interface ApiState { - root: IRoot; - stack: IRoot; -} - -const InitState: ApiState = { - root: null, - stack: null, -}; - -const reducer = createReducer( - InitState, - on(rootSuccess, (state, { root }) => ({ ...state, root })), - on(rootError, state => ({ root: null, stack: null })), - on(stackSuccess, (state, { stack }) => ({ ...state, stack })) -); - -export function apiReducer(state: ApiState, action: Action) { - return reducer(state, action); -} - -export const getApiState = createFeatureSelector('api'); -export const getRoot = createSelector( - getApiState, - (state: ApiState) => state.root -); -export const getStack = createSelector( - getApiState, - (state: ApiState) => state.stack -); diff --git a/web/src/app/core/api/api.service.ts b/web/src/app/core/api/api.service.ts deleted file mode 100644 index 59b0bdd6ac..0000000000 --- a/web/src/app/core/api/api.service.ts +++ /dev/null @@ -1,79 +0,0 @@ -// Licensed 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 { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { ParamMap } from '@angular/router'; -import { IRoot, TypeName } from '@app/core/types/api'; -import { ListResult } from '@app/models/list-result'; -import { select, Store } from '@ngrx/store'; -import { EMPTY, Observable } from 'rxjs'; -import { catchError, filter, switchMap } from 'rxjs/operators'; - -import { State } from '../store'; -import { getRoot } from './api.reducer'; - -@Injectable() -export class ApiService { - constructor(private http: HttpClient, private store: Store) {} - - get root(): Observable { - return this.store.pipe(select(getRoot)).pipe(filter((root) => !!root)); - } - - getPure(typeName: TypeName, params: { [key: string]: string } = {}): Observable { - return this.root.pipe(switchMap((root) => this.get(root[typeName], params))).pipe(catchError(() => EMPTY)); - } - - getOne(typeName: TypeName, id: number, params: { [key: string]: string } = {}) { - return this.root.pipe(switchMap((root) => this.get(`${root[typeName]}${id}/`, params))).pipe(catchError(() => EMPTY)); - } - - get(url: string, params: { [key: string]: string } = {}): Observable { - return this.http.get(url, { params }); - } - - getList(url: string, paramMap: ParamMap, outsideParams?: { [item: string]: string }): Observable> { - const params = paramMap?.keys.reduce((pr, c) => ({ ...pr, [c]: paramMap.get(c) }), {}); - if (paramMap) { - const limit = paramMap.get('limit') ? +paramMap.get('limit') : +localStorage.getItem('limit') || 10, - offset = (paramMap.get('page') ? +paramMap.get('page') : 0) * limit; - params['limit'] = limit.toString(); - params['offset'] = offset.toString(); - params['status'] = paramMap.get('filter') || ''; - params['ordering'] = paramMap.get('ordering') || '-id' - } - return this.get>(url, { ...params, ...outsideParams }); - } - - list(url: string, params: { limit: string; offset: string; ordering?: string } | null) { - if (!params) { - params = { limit: localStorage.getItem('limit'), offset: '0' }; - } - return this.get>(url, params); - } - - post(url: string, item: Object | FormData): Observable { - return this.http.post(url, item); - } - - put(url: string, item: any): Observable { - return this.http.put(url, item).pipe(catchError(() => EMPTY)); - } - - patch(url: string, item: any): Observable { - return this.http.patch(url, item).pipe(catchError(() => EMPTY)); - } - - delete(url: string) { - return this.http.delete(url).pipe(catchError(() => EMPTY)); - } -} diff --git a/web/src/app/core/api/index.ts b/web/src/app/core/api/index.ts deleted file mode 100644 index db35a6ba63..0000000000 --- a/web/src/app/core/api/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed 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 * from './api.service'; diff --git a/web/src/app/core/auth/auth.guard.ts b/web/src/app/core/auth/auth.guard.ts deleted file mode 100644 index ab3ec2eb9e..0000000000 --- a/web/src/app/core/auth/auth.guard.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'; -import { select, Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; -import { filter, tap } from 'rxjs/operators'; - -import { AuthService } from './auth.service'; -import { authCheck, AuthState, isAuthenticated } from './auth.store'; - -@Injectable() -export class AuthGuard implements CanActivate, CanActivateChild { - constructor(private store: Store, private authService: AuthService, private router: Router) {} - - canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - this.store.dispatch(authCheck()); - const a$ = this.store.pipe(select(isAuthenticated)); - - a$.pipe( - filter(a => !a), - tap(() => { - this.authService.redirectUrl = state.url; - this.router.navigate(['/login']); - }) - ).subscribe(); - - return a$; - } - - canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - return this.canActivate(route, state); - } -} diff --git a/web/src/app/core/auth/auth.service.ts b/web/src/app/core/auth/auth.service.ts deleted file mode 100644 index dc61133e36..0000000000 --- a/web/src/app/core/auth/auth.service.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Observable, throwError } from 'rxjs'; -// Licensed 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 { Injectable } from '@angular/core'; -import { environment } from '@env/environment'; -import { catchError, map, tap } from 'rxjs/operators'; - -import { ApiService } from '../api'; - -@Injectable() -export class AuthService { - public get token(): string { - return this.auth.token; - } - - public get auth() { - const auth = localStorage.getItem('auth') || ''; - return auth ? JSON.parse(auth) : { login: '', token: '' }; - } - - public set auth(value: { login: string; token: string }) { - localStorage.setItem('auth', JSON.stringify(value)); - } - - public redirectUrl: string; - - constructor(private api: ApiService) {} - - checkGoogle() { - return this.api.get<{ google_oauth: boolean }>(`${environment.apiRoot}info/`).pipe(map(a => a.google_oauth)); - } - - login(login: string, password: string): Observable<{ token: string }> { - return this.api.post(`${environment.apiRoot}rbac/token/`, { username: login, password }).pipe( - tap((response: { token: string }) => { - let token = response && response.token; - if (token) { - this.auth = { login, token }; - } - }), - catchError(err => { - this.auth = { login: '', token: '' }; - return throwError(err); - }) - ); - } - - logout() { - this.auth = { login: '', token: '' }; - } -} diff --git a/web/src/app/core/auth/auth.store.ts b/web/src/app/core/auth/auth.store.ts deleted file mode 100644 index 639c48a4c8..0000000000 --- a/web/src/app/core/auth/auth.store.ts +++ /dev/null @@ -1,90 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props } from '@ngrx/store'; -import { of } from 'rxjs'; -import { catchError, map, switchMap, tap } from 'rxjs/operators'; - -import { AuthService } from './auth.service'; - -export const authCheck = createAction('[Auth] Check'); -export const authLogin = createAction('[Auth] Login', props<{ login: string; password: string }>()); -export const authSuccess = createAction('[Auth] LoginSuccess', props<{ login: string }>()); -export const authFaled = createAction('[Auth] LoginFaled', props<{ message: string }>()); -export const authLogout = createAction('[Auth] Logout'); - -export interface AuthState { - isValid: boolean; - message: string; -} - -const initialState: AuthState = { - isValid: false, - message: '', -}; - -const reducer = createReducer( - initialState, - on(authSuccess, state => ({ isValid: true, message: 'Auth is success.' })), - on(authFaled, (state, { message }) => ({ isValid: false, message })), - on(authLogout, state => ({ isValid: false, message: '' })) -); - -export function authReducer(state: AuthState, action: Action) { - return reducer(state, action); -} - -export const getAuthState = createFeatureSelector('auth'); -export const isAuthenticated = createSelector( - getAuthState, - state => state.isValid -); - -@Injectable() -export class AuthEffects { - check$ = createEffect(() => - this.actions$.pipe( - ofType(authCheck), - map(() => - this.authService.auth.token - ? authSuccess({ login: this.authService.auth.login }) - : authFaled({ message: 'User is not authorized!' }) - ) - ) - ); - - auth$ = createEffect( - () => - this.actions$.pipe( - ofType(authLogin), - switchMap(a => - this.authService.login(a.login, a.password).pipe( - map(() => authSuccess({ login: a.login })), - catchError(() => of(authFaled({ message: 'Incorrect password or user.' }))) - ) - ) - ), - { useEffectsErrorHandler: true } - ); - - logout$ = createEffect( - () => - this.actions$.pipe( - ofType(authLogout), - tap(() => this.authService.logout()) - ), - { dispatch: false } - ); - - constructor(private actions$: Actions, private authService: AuthService) {} -} diff --git a/web/src/app/core/core.module.ts b/web/src/app/core/core.module.ts deleted file mode 100644 index c367270b17..0000000000 --- a/web/src/app/core/core.module.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed 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 { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; -import { NgModule } from '@angular/core'; - -import { ApiService } from '@app/core/api'; -import { AuthGuard } from './auth/auth.guard'; -import { AuthService } from './auth/auth.service'; -import { RequestCacheService, RequestCache } from '@app/core/http-interseptors/request-cache.service'; -import { CachingInterseptor } from '@app/core/http-interseptors/caching-interseptor'; -import { AuthInterceptor } from '@app/core/http-interseptors/auth-interseptor'; - -@NgModule({ - imports: [HttpClientModule], - providers: [ - ApiService, - { provide: RequestCache, useClass: RequestCacheService }, - { provide: HTTP_INTERCEPTORS, useClass: CachingInterseptor, multi: true }, - { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, - AuthGuard, - AuthService - ], -}) -export class CoreModule {} diff --git a/web/src/app/core/http-interseptors/auth-interseptor.ts b/web/src/app/core/http-interseptors/auth-interseptor.ts deleted file mode 100644 index 4e4eaab6a3..0000000000 --- a/web/src/app/core/http-interseptors/auth-interseptor.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Licensed 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 { HttpErrorResponse, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; -import { Location } from '@angular/common'; -import { Observable, throwError } from 'rxjs'; -import { catchError, finalize } from 'rxjs/operators'; - -import { AuthService } from '@app/core/auth/auth.service'; -import { ChannelService, keyChannelStrim, PreloaderService, ResponseError, ResponseErrorCode } from '../services'; -import { RouterHistoryService } from '@app/core/services/router-history.service'; - -const EXCLUDE_URLS = ['/api/v1/rbac/token/', '/assets/config.json']; - -@Injectable() -export class AuthInterceptor implements HttpInterceptor { - constructor( - private authService: AuthService, - private preloader: PreloaderService, - private router: Router, - private channel: ChannelService, - private location: Location, - private routerHistory: RouterHistoryService - ) {} - - addAuthHeader(request: HttpRequest): HttpRequest { - const token = this.authService.token; - if (token && !EXCLUDE_URLS.includes(request.url)) { - const setParams = request.url.split('?').find((a, i) => i === 1 && a.includes('noview')) ? {} : { view: 'interface' }; - request = request.clone({ setHeaders: { Authorization: `Token ${token}` }, setParams }); - } - - return request; - } - - intercept(request: HttpRequest, next: HttpHandler): Observable { - this.preloader.start(); - request = this.addAuthHeader(request); - return next.handle(request).pipe( - catchError((res: HttpErrorResponse) => { - this.authService.redirectUrl = this.router.url; - - if (res.status === 401) { - this.router.navigate(['/login']); - } - - /** redirect to previous page if it is present and method === GET */ - /** - if (res.status === 403 && request.method === 'GET') { - const previous = this.routerHistory.previous(); - - if (previous) { - this.router.navigate([previous]); - } else { - this.router.navigate(['/']); - } - } - */ - - if (res.status === 500) this.router.navigate(['/500']); - - /** no need to show notification because error handling on landing page */ - const exclude = [ResponseErrorCode.UserNotFound, ResponseErrorCode.AuthError, ResponseErrorCode.ConfigNotFound]; - - if (!exclude.includes(res.error.code)) { - this.channel.next(keyChannelStrim.error, res); - } - - return throwError(res); - }), - finalize(() => this.preloader.end()) - ); - } -} diff --git a/web/src/app/core/http-interseptors/caching-interseptor.ts b/web/src/app/core/http-interseptors/caching-interseptor.ts deleted file mode 100644 index dd9d689a82..0000000000 --- a/web/src/app/core/http-interseptors/caching-interseptor.ts +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { HttpInterceptor, HttpRequest, HttpResponse, HttpHandler, HttpHeaders, HttpEvent } from '@angular/common/http'; -import { RequestCache } from './request-cache.service'; -import { of, Observable } from 'rxjs'; -import { startWith, tap } from 'rxjs/operators'; - -@Injectable() -export class CachingInterseptor implements HttpInterceptor { - constructor(private cache: RequestCache) {} - - intercept(req: HttpRequest, next: HttpHandler) { - if (!isCachable(req)) return next.handle(req); - - const cachedResponse = this.cache.get(req); - - // cache-then-refresh - if (req.headers.get('x-refresh')) { - const results$ = sendRequest(req, next, this.cache); - return cachedResponse ? results$.pipe(startWith(cachedResponse)) : results$; - } - - return cachedResponse ? of(cachedResponse) : sendRequest(req, next, this.cache); - } -} - -function isCachable(req: HttpRequest) { - const method = req.method, - url = req.url; - return req.params.get('c') ? true : false; -} - -function sendRequest(req: HttpRequest, next: HttpHandler, cache: RequestCache): Observable> { - const noHeaderClone = req.clone({ headers: new HttpHeaders() }); - - return next.handle(noHeaderClone).pipe( - tap(event => { - if (event instanceof HttpResponse) cache.put(req, event); - }) - ); -} diff --git a/web/src/app/core/http-interseptors/request-cache.service.ts b/web/src/app/core/http-interseptors/request-cache.service.ts deleted file mode 100644 index 964676f795..0000000000 --- a/web/src/app/core/http-interseptors/request-cache.service.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { HttpRequest, HttpResponse } from '@angular/common/http'; - -const maxAge = Number.MAX_VALUE; // maximum cache age (ms) - -interface RequestCacheEntry { - url: string; - response: HttpResponse; - lastRead: number; -} - -export abstract class RequestCache { - abstract get(req: HttpRequest): HttpResponse | undefined; - abstract put(req: HttpRequest, response: HttpResponse): void; -} - -@Injectable() -export class RequestCacheService implements RequestCache { - cache = new Map(); - - constructor() {} - - get(req: HttpRequest): HttpResponse | undefined { - const url = req.urlWithParams; - const cached = this.cache.get(url); - - if (!cached) return undefined; - - const isExpired = cached.lastRead < Date.now() - maxAge; - - const expired = isExpired ? 'Expired ' : ''; - // this.messanger.add(new Message(`${expired}cached response for "${url}".`)); - - return isExpired ? undefined : cached.response; - } - - put(req: HttpRequest, response: HttpResponse): void { - const url = req.urlWithParams; - // this.messanger.add(new Message(`Caching response from "${url}".` )); - - const entry = { url, response, lastRead: Date.now() }; - this.cache.set(url, entry); - - const expired = Date.now() - maxAge; - - this.cache.forEach(c => { - if (c.lastRead < expired) this.cache.delete(c.url); - }); - - // this.messanger.add(new Message(`Request cache size: ${this.cache.size}.`)); - } -} diff --git a/web/src/app/core/services/app/app.service.spec.ts b/web/src/app/core/services/app/app.service.spec.ts deleted file mode 100644 index 612e737531..0000000000 --- a/web/src/app/core/services/app/app.service.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed 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 { TestBed } from '@angular/core/testing'; - -import { AppService } from './app.service'; - -describe('AppService', () => { - let service: AppService; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{ provide: AppService, useValue: {} }], - }); - service = TestBed.inject(AppService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/web/src/app/core/services/app/app.service.ts b/web/src/app/core/services/app/app.service.ts deleted file mode 100644 index 72f0dd44ba..0000000000 --- a/web/src/app/core/services/app/app.service.ts +++ /dev/null @@ -1,138 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { NavigationStart, Router } from '@angular/router'; -import { - getConnectStatus, - getFirstAdminLogin, - getProfile, - getRoot, - isAuthenticated, - loadProfile, - loadRoot, - loadStack, - rootError, - socketInit, - State -} from '@app/core/store'; -import { select, Store } from '@ngrx/store'; -import { combineLatest } from 'rxjs'; -import { filter, switchMap, tap } from 'rxjs/operators'; - -import { ChannelService, keyChannelStrim, ResponseError } from '../channel.service'; -import { ConfigService, IVersionInfo } from '../config.service'; -import { SnackBarComponent } from '@app/components/snack-bar/snack-bar.component'; - -@Injectable() -export class AppService { - constructor( - private store: Store, - private config: ConfigService, - private router: Router, - private dialog: MatDialog, - private channel: ChannelService, - public snackBar: MatSnackBar, - ) {} - - getRootAndCheckAuth() { - this.store.dispatch(loadRoot()); - const b$ = this.store.pipe(select(getRoot)); - const a$ = this.store.pipe(select(isAuthenticated)); - return combineLatest([a$, b$]).pipe( - filter((a) => a[0] && !!a[1]), - switchMap((_) => this.config.load()), - tap((c) => { - if (!c) { - this.channel.next(keyChannelStrim.notifying, 'New version available. Page has been refreshed.'); - setTimeout(() => location.reload(), 2000); - } else { - this.store.dispatch(socketInit()); - this.store.dispatch(loadStack()); - this.store.dispatch(loadProfile()); - } - }) - ); - } - - checkWSconnectStatus() { - return this.store.pipe( - select(getConnectStatus), - filter((a) => !!a), - tap((status) => { - if (status === 'open') this.channel.next(keyChannelStrim.notifying, 'Connection established.'); - if (status === 'close') { - this.channel.next(keyChannelStrim.error, 'Connection lost. Recovery attempt.'); - this.store.dispatch(rootError()); - } - }) - ); - } - - checkUserProfile() { - return this.store.pipe( - select(getProfile), - filter((u) => u.settingsSaved) - ); - } - - getVersion(versionData: IVersionInfo): IVersionInfo { - return this.config.version.split('-').reduce((p, c, i) => ({ - ...p, - [Object.keys(versionData)[i]]: c - }), {} as IVersionInfo); - } - - initListeners() { - // check user profile settings - this is the first entry - this.store - .pipe( - select(getFirstAdminLogin), - filter((u) => u) - ) - .subscribe(() => this.router.navigate(['admin'])); - - // close dialog - this.router.events.pipe(filter((e) => e instanceof NavigationStart)).subscribe(() => this.dialog.closeAll()); - - // notification - this.channel.on(keyChannelStrim.notifying).subscribe((message) => { - this.snackBar.openFromComponent(SnackBarComponent, { - duration: 5000, - panelClass: 'snack-bar-notify', - data: { message } - }); - }); - - // error - this.channel.on(keyChannelStrim.error).subscribe((respError) => { - if (typeof respError === 'string') { - this.snackBar.openFromComponent(SnackBarComponent, { - panelClass: 'snack-bar-error', - data: { message: respError }, - }); - } else { - const message = - respError.statusText === 'Unknown Error' || respError.statusText === 'Gateway Timeout' - ? 'No connection to back-end. Check your internet connection.' - : `[ ${respError.statusText.toUpperCase()} ] ${respError.error.code ? ` ${respError.error.code} -- ${respError.error.desc}` : respError.error?.detail || ''}`; - - this.snackBar.openFromComponent(SnackBarComponent, { - panelClass: 'snack-bar-error', - data: { message, args: respError.error?.args }, - }); - } - }); - - } -} diff --git a/web/src/app/core/services/channel.service.spec.ts b/web/src/app/core/services/channel.service.spec.ts deleted file mode 100644 index 65c8472961..0000000000 --- a/web/src/app/core/services/channel.service.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Licensed 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 { TestBed } from '@angular/core/testing'; - -import { ChannelService } from './channel.service'; - -describe('ChannelService', () => { - beforeEach(() => TestBed.configureTestingModule({})); - - it('should be created', () => { - const service: ChannelService = TestBed.inject(ChannelService); - expect(service).toBeTruthy(); - }); -}); diff --git a/web/src/app/core/services/channel.service.ts b/web/src/app/core/services/channel.service.ts deleted file mode 100644 index fe16bf3bbe..0000000000 --- a/web/src/app/core/services/channel.service.ts +++ /dev/null @@ -1,66 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { Observable, Subject } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; -import { HttpErrorResponse } from '@angular/common/http'; - -export enum keyChannelStrim { - 'scroll', - 'notifying', - 'load_complete', - 'error', -} - -export interface IBroadcast { - key: TKey; - value: any; -} - -export enum ResponseErrorLevel { - Error = 'error', -} - -export enum ResponseErrorCode { - InvalidObjectDefinition = 'INVALID_OBJECT_DEFINITION', - UserNotFound = 'USER_NOT_FOUND', - AuthError = 'AUTH_ERROR', - ConfigNotFound = 'CONFIG_NOT_FOUND', -} - -export interface ResponseError extends HttpErrorResponse { - error: { - args?: string; - desc?: string; - detail?: string; - code?: ResponseErrorCode; - level?: ResponseErrorLevel; - }; -} - -@Injectable({ - providedIn: 'root', -}) -export class ChannelService { - private event = new Subject>(); - - next(key: TKey, value: T) { - this.event.next({ key, value }); - } - - on(key: TKey): Observable { - return this.event.asObservable().pipe( - filter((e) => e.key === key), - map, T>((a) => a.value) - ); - } -} diff --git a/web/src/app/core/services/cluster.service.ts b/web/src/app/core/services/cluster.service.ts deleted file mode 100644 index 03568955e0..0000000000 --- a/web/src/app/core/services/cluster.service.ts +++ /dev/null @@ -1,210 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { ParamMap } from '@angular/router'; -import { ApiService } from '@app/core/api'; -import { BehaviorSubject, EMPTY, forkJoin, Observable, of } from 'rxjs'; -import { filter, map, switchMap, tap } from 'rxjs/operators'; -import { Store } from '@ngrx/store'; - -import { Bundle, Entities, Host, IAction, IImport, Job, License, LogFile, Provider, Service } from '@app/core/types'; -import { environment } from '@env/environment'; -import { ServiceComponentService } from '@app/services/service-component.service'; -import { EntityNames } from '@app/models/entity-names'; -import { setPathOfRoute } from '@app/store/navigation/navigation.store'; -import { EntityService } from '@app/abstract/entity-service'; -import { ICluster } from '@app/models/cluster'; - -export interface WorkerInstance { - current: Entities; - cluster: ICluster | null; -} - -@Injectable({ - providedIn: 'root', -}) -export class ClusterService { - private worker: WorkerInstance | null; - private workerSubject = new BehaviorSubject(null); - public worker$ = this.workerSubject.asObservable(); - - get Cluster() { - return this.worker ? this.worker.cluster : null; - } - - set Cluster(cluster: ICluster) { - if (cluster) cluster.typeName = 'cluster'; - if (this.worker) this.worker.cluster = cluster; - else this.worker = { current: cluster, cluster: cluster }; - } - - get Current(): Entities { - return this.worker ? this.worker.current : null; - } - - constructor( - protected api: ApiService, - protected serviceComponentService: ServiceComponentService, - protected store: Store, - ) {} - - clearWorker() { - this.worker = null; - } - - one_cluster(id: number): Observable { - return this.Cluster ? of(this.Cluster) : this.api.getOne('cluster', id); - } - - one_service(id: number): Observable { - return this.api.get(`${this.worker.cluster.service}${id}/`); - } - - one_host(id: number): Observable { - return this.api.getOne('host', id).pipe(map((host: Host) => ({ ...host, name: host.fqdn }))); - } - - one_provider(id: number): Observable { - return this.api.getOne('provider', id); - } - - one_job(id: number): Observable { - return this.api.getOne('job', id).pipe( - map((j: Job) => ({ - ...j, - prototype_name: j.action ? j.action.prototype_name : '', - prototype_version: j.action ? j.action.prototype_version : '', - bundle_id: j.action ? j.action.bundle_id : null, - name: j.action ? `${j.action.display_name}` : 'Object has been deleted', - })) - ); - } - - one_bundle(id: number): Observable { - return this.api.get(`${environment.apiRoot}stack/bundle/${id}/`); - } - - getContext(param: ParamMap, service?: EntityService): Observable { - this.store.dispatch(setPathOfRoute({ params: param })); - - const typeName = EntityNames.find((entity) => param.keys?.some((key) => entity === key)); - const id = +param?.get(typeName); - const cluster$ = param.has('cluster') ? this.api.getOne('cluster', +param?.get('cluster')) : of(null); - return cluster$ - .pipe( - tap((cluster) => (this.Cluster = cluster)), - switchMap((cluster) => { - if (typeName === 'group_config') { - return service.get(id); - } else if (cluster && (typeName === 'servicecomponent' || typeName === 'component')) { - return this.serviceComponentService.get(id); - } else if (cluster && typeName !== 'cluster') { - return this.api.get(`${cluster[typeName]}${id}/`); - } else { - return this[`one_${typeName}`](id); - } - }), - ) - .pipe( - map((a: any) => { - this.worker.current = { ...a, name: (a?.display_name || a?.name || (a as Host)?.fqdn) ?? '', typeName }; - this.workerSubject.next(this.worker); - return this.worker; - }) - ); - } - - getLog(url: string): Observable { - return this.api.get(url); - } - - getActions(): Observable { - return typeof this.worker.current.action === 'string' ? this.api.get(this.worker.current.action) : of([]); - } - - getServices(p: ParamMap) { - return this.api.getList(this.Cluster.service, p).pipe( - map((r) => { - r.results = r.results.map((a) => ({ ...a, cluster: this.Cluster })); - return r; - }) - ); - } - - addServices(output: { prototype_id: number }) { - return this.api.post(this.Cluster.service, output); - } - - getHosts(p: ParamMap) { - return this.api.getList(this.Cluster?.host, p); - } - - addHost(host_id: number) { - return this.api.post(this.Cluster?.host, { host_id }); - } - - reset(): Observable { - if (!this.Current) return EMPTY; - const typeName = this.Current.typeName; - return this.api.get(this.Current.url).pipe( - filter((_) => !!this.worker), - map((a) => { - if (typeName === 'cluster') this.worker.cluster = { ...(a as ICluster), typeName }; - this.worker.current = { ...a, typeName, name: a.display_name || a.name || (a as Host).fqdn }; - return this.worker; - }) - ); - } - - getMainInfo(): string { - if (!this.Current) { - return ''; - } - - return this.Current.main_info || ''; - } - - getBundleLicenseText(): Observable { - const { license_url, license } = (this.Current as Bundle); - - return this.api.get(license_url).pipe( - map(({ text }) => license !== 'absent' ? text : 'No license required'), - ); - } - - /** - * Import / Export data for `Cluster` - */ - getImportData() { - return 'imports' in this.Current ? this.api.get(this.Current.imports) : EMPTY; - } - - bindImport(bind: any) { - return 'imports' in this.Current ? this.api.post(this.Current.imports, bind) : EMPTY; - } - - /** - * For `Job` and `Task` operating time data - */ - getOperationTimeData(job: Job) { - const { start_date, finish_date, status } = job; - const sdn = Date.parse(start_date), - fdn = Date.parse(finish_date), - ttm = fdn - sdn, - sec = Math.floor(ttm / 1000), - min = Math.floor(sec / 60), - time = status !== 'running' ? `${min}m. ${sec - min * 60}s.` : ''; - const a = new Date(sdn); - const b = new Date(fdn); - return { start: a.toLocaleTimeString(), end: status !== 'running' ? b.toLocaleTimeString() : '', time }; - } -} diff --git a/web/src/app/core/services/config.service.ts b/web/src/app/core/services/config.service.ts deleted file mode 100644 index 098f49cf09..0000000000 --- a/web/src/app/core/services/config.service.ts +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed 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 { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; - -const CONFIG_URL = '/assets/config.json'; -export interface IVersionInfo { - version: string; - commit_id: string; -} - -@Injectable({ - providedIn: 'root', -}) -export class ConfigService { - appConfig$: Observable; - - constructor(private http: HttpClient) {} - - get version() { - return localStorage.getItem('adcm:version') || ''; - } - - set version(version: string) { - localStorage.setItem('adcm:version', version); - } - - checkVersion(c: IVersionInfo): IVersionInfo { - const version = `${c.version}-${c.commit_id}`; - if (!this.version) this.version = version; - else if (this.version !== version) { - this.version = version; - return null; - } - return c; - } - - load() { - return this.http.get(`${CONFIG_URL}?nocache=${Date.now()}`).pipe(map((c) => this.checkVersion(c))); - } -} diff --git a/web/src/app/core/services/dom.service.spec.ts b/web/src/app/core/services/dom.service.spec.ts deleted file mode 100644 index 9feb2a38f1..0000000000 --- a/web/src/app/core/services/dom.service.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed 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 { TestBed } from '@angular/core/testing'; - -import { DomService } from './dom.service'; - -describe('DomService', () => { - let service: DomService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(DomService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/web/src/app/core/services/dom.service.ts b/web/src/app/core/services/dom.service.ts deleted file mode 100644 index 57e2cb05e1..0000000000 --- a/web/src/app/core/services/dom.service.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed 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 { ApplicationRef, ComponentFactoryResolver, EmbeddedViewRef, Injectable, Injector, Type } from '@angular/core'; - -@Injectable({ - providedIn: 'root', -}) -export class DomService { - constructor( - private componentFactoryResolver: ComponentFactoryResolver, - private appRef: ApplicationRef, - private injector: Injector - ) {} - - appendComponentToBody(component: Type) { - const componentRef = this.componentFactoryResolver.resolveComponentFactory(component).create(this.injector); - - this.appRef.attachView(componentRef.hostView); - - const domElem = (componentRef.hostView as EmbeddedViewRef).rootNodes[0] as HTMLElement; - - document.body.appendChild(domElem); - - /** TODO: remove component, need to add variable where keep links to componentRef */ - // this.appRef.detachView(componentRef.hostView); - // componentRef.destroy(); - } -} diff --git a/web/src/app/core/services/fully-rendered.service.ts b/web/src/app/core/services/fully-rendered.service.ts deleted file mode 100644 index d0be807350..0000000000 --- a/web/src/app/core/services/fully-rendered.service.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Licensed 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 { Injectable, NgZone } from '@angular/core'; -import { NavigationStart, Router } from '@angular/router'; -import { interval } from 'rxjs'; -import { distinctUntilChanged, filter, map, startWith, take, tap } from 'rxjs/operators'; - -@Injectable({ - providedIn: 'root', -}) -export class FullyRenderedService { - navStart$ = this.router.events - .pipe( - filter((event) => event instanceof NavigationStart), - startWith(null as string), // Start with something, because the app doesn't fire this on appload, only on subsequent route changes - tap((event) => { - /* Place code to track NavigationStart here */ - }) - ) - .subscribe(); - - constructor(private router: Router, private zone: NgZone) {} - - /** - * - * - * @param {() => void} callback - * @memberof FullyRenderedService - */ - stableView(callback: () => void) { - this.zone.runOutsideAngular(() => { - interval(10) - .pipe( - startWith(0), - // To prevent a memory leak on two closely times route changes, take until the next nav start - //takeUntil(this.navigationStart$), - // Turn the interval number into the current state of the zone - map(() => !this.zone.hasPendingMacrotasks), - // Don't emit until the zone state actually flips from `false` to `true` - distinctUntilChanged(), - // Filter out unstable event. Only emit once the state is stable again - filter((stateStable) => stateStable === true), - // Complete the observable after it emits the first result - take(1), - tap((stateStable) => { - callback(); - }) - ) - .subscribe(); - }); - } -} diff --git a/web/src/app/core/services/index.ts b/web/src/app/core/services/index.ts deleted file mode 100644 index 09aa4875e5..0000000000 --- a/web/src/app/core/services/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Licensed 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 * from './preloader.service'; -export * from './config.service'; -export * from './stack.service'; -export * from './channel.service'; -export * from './app/app.service'; -export * from './fully-rendered.service'; -export * from './dom.service'; diff --git a/web/src/app/core/services/preloader.service.ts b/web/src/app/core/services/preloader.service.ts deleted file mode 100644 index 4e18554c3a..0000000000 --- a/web/src/app/core/services/preloader.service.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed 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 { Subject } from 'rxjs'; -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class PreloaderService { - private _counter = 0; - private isFreese = false; - - active$: Subject = new Subject(); - - get counter(): number { - return this._counter; - } - - start(): void { - this._counter++; - if (!this.isFreese) this.active$.next(this._counter > 0); - this.isFreese = false; - } - - end(): void { - this._counter--; - this.active$.next(this._counter > 0); - } - - freeze(): void { - this.isFreese = true; - } -} diff --git a/web/src/app/core/services/router-history.service.ts b/web/src/app/core/services/router-history.service.ts deleted file mode 100644 index de4b2f8119..0000000000 --- a/web/src/app/core/services/router-history.service.ts +++ /dev/null @@ -1,73 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { NavigationEnd, Router } from '@angular/router'; -import { filter } from 'rxjs/operators'; - -export type IRouteHistory = string[]; - -@Injectable({ - providedIn: 'root' -}) -export class RouterHistoryService { - - static HISTORY_DEPTH = 10; - - private readonly _history: BehaviorSubject; - - readonly history: Observable; - - constructor(private readonly _router: Router) { - this._history = new BehaviorSubject([]); - this.history = this._history.asObservable(); - - this._router.events.pipe(filter((event) => event instanceof NavigationEnd)) - .subscribe((event: NavigationEnd) => this._push(event)); - } - - reset(): void { - this._history.next([]); - } - - current(): string | null { - const value = this._history.getValue(); - - return (Array.isArray(value) && value[0]) ?? null; - } - - previous(): string | null { - const value = this._history.getValue(); - - return (Array.isArray(value) && value[1]) ?? null; - } - - private _push(event: NavigationEnd): void { - const history = this._history.getValue(); - - const matcher = /;page=\d*;limit=\d*;filter=\d*;ordering=\d*/g; - const url = event.urlAfterRedirects.replace(matcher, ''); - - let value = history; - - if (!history[0] || history[0] !== url) { - value = [url, ...history]; - - if (value.length > RouterHistoryService.HISTORY_DEPTH) { - value.pop(); - } - } - - this._history.next(value); - } -} diff --git a/web/src/app/core/services/stack.service.ts b/web/src/app/core/services/stack.service.ts deleted file mode 100644 index cf649218a4..0000000000 --- a/web/src/app/core/services/stack.service.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { ApiService } from '@app/core/api'; -import { ApiState, getStack } from '@app/core/store'; -import { Bundle } from '@app/core/types'; -import { environment } from '@env/environment'; -import { select, Store } from '@ngrx/store'; -import { combineLatest, Observable } from 'rxjs'; -import { filter, map, mergeMap, switchMap } from 'rxjs/operators'; -import { ListResult } from '@app/models/list-result'; - -export type StackInfo = 'cluster' | 'host' | 'provider' | 'service' | 'bundle' | 'prototype'; - -const UPLOAD_URL = `${environment.apiRoot}stack/upload/`, - LOAD_URL = `${environment.apiRoot}stack/load/`; - -@Injectable({ providedIn: 'root' }) -export class StackService { - constructor(private api: ApiService, private store: Store) {} - - fromStack(name: StackInfo, param?: { [key: string]: string | number }): Observable { - const params = Object.keys(param).reduce((p, c) => ({ ...p, [c]: param[c] }), {}); - return this.store.pipe( - select(getStack), - filter((a) => a && !!Object.keys(a).length), - switchMap((s) => this.api.get>(s[name], params).pipe( - map((a) => a.results))) - ); - } - - upload(output: FormData[]) { - const item = (form: FormData) => { - return this.api.post(UPLOAD_URL, form).pipe( - mergeMap(() => this.api.post(LOAD_URL, { bundle_file: (form.get('file') as File).name })) - ); - }; - return combineLatest(output.map((o) => item(o))); - } -} diff --git a/web/src/app/core/store/index.ts b/web/src/app/core/store/index.ts deleted file mode 100644 index 4816a5e0f9..0000000000 --- a/web/src/app/core/store/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed 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 { environment } from '@env/environment'; -import { ActionReducerMap, MetaReducer } from '@ngrx/store'; - -import { ApiEffects } from '../api/api.effects'; -import { apiReducer, ApiState } from '../api/api.reducer'; -import { AuthEffects, authReducer, AuthState } from '../auth/auth.store'; -import { IssueEffect, issueReducer, IssueState } from './issue'; -import { ProfileEffects, profileReducer, ProfileState } from './profile'; -import { SocketEffect } from './sockets/socket.effect'; -import { socketReducer, SocketState } from './sockets/socket.reducer'; -import { navigationReducer, NavigationState } from '@app/store/navigation/navigation.store'; -import { NavigationEffects } from '@app/store/navigation/navigation-effects'; - -export interface State { - auth: AuthState; - socket: SocketState; - api: ApiState; - profile: ProfileState; - issue: IssueState; - navigation: NavigationState, -} - -export const reducers: ActionReducerMap = { - auth: authReducer, - socket: socketReducer, - api: apiReducer, - profile: profileReducer, - issue: issueReducer, - navigation: navigationReducer, -}; - -export const metaReducers: MetaReducer[] = !environment.production ? [] : []; - -export const StoreEffects = [AuthEffects, ApiEffects, ProfileEffects, IssueEffect, SocketEffect, NavigationEffects]; - -export * from '../api/api.reducer'; -export * from '../auth/auth.store'; -export * from './profile'; -export * from './profile/profile.service'; -export * from './issue'; -export * from './sockets/socket.service'; -export * from './sockets/socket.reducer'; -export * from '@app/store/navigation/navigation.store'; diff --git a/web/src/app/core/store/issue.ts b/web/src/app/core/store/issue.ts deleted file mode 100644 index 25d396a00d..0000000000 --- a/web/src/app/core/store/issue.ts +++ /dev/null @@ -1,60 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props, Store } from '@ngrx/store'; -import { exhaustMap, filter, map, withLatestFrom } from 'rxjs/operators'; - -import { ApiService } from '../api'; -import { State } from '../store'; -import { BaseEntity } from '../types'; -import { IIssues } from '@app/models/issue'; - -export interface IssueState { - value: IIssues; - url: string; -} - -const InitState = { - value: null, - url: '', -}; - -export const loadIssue = createAction('[Issue] LoadIssue'); -export const fillIssue = createAction('[Issue] FillIssue', props<{ value: IIssues; url: string }>()); - -const reducer = createReducer(InitState, on(loadIssue, state => ({ ...state })), on(fillIssue, (state, { value, url }) => ({ value, url }))); - -export function issueReducer(state: IssueState, action: Action) { - return reducer(state, action); -} - -@Injectable() -export class IssueEffect { - load$ = createEffect(() => - this.actions$.pipe( - ofType(loadIssue), - withLatestFrom(this.store, (action, state) => state.issue.url), - filter(url => !!url), - exhaustMap(url => this.api.get(url).pipe(map(o => fillIssue({ value: o.issue, url: o.url })))) - ) - ); - - constructor(private actions$: Actions, private api: ApiService, private store: Store) {} -} - -export const getIssueSelector = createFeatureSelector('issue'); - -export const checkIssue = createSelector( - getIssueSelector, - state => state -); diff --git a/web/src/app/core/store/profile/index.ts b/web/src/app/core/store/profile/index.ts deleted file mode 100644 index d1aa78f17c..0000000000 --- a/web/src/app/core/store/profile/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { Action, createAction, createFeatureSelector, createReducer, createSelector, on, props } from '@ngrx/store'; -import { exhaustMap, map } from 'rxjs/operators'; - -import { IUser, ProfileService } from './profile.service'; - -export type ProfileState = IUser; - -const InitState = { - username: '', - change_password: '', - profile: { - textarea: {}, - settingsSaved: false, - }, -}; - -export const loadProfile = createAction('[Profile] Load'); -export const clearProfile = createAction('[Profile] ClearProfile'); -export const loadProfileSuccess = createAction('[Profile] LoadSuccess', props<{ profile: IUser }>()); -export const setTextareaHeight = createAction('[Profile] SetTextareaHeight', props<{ key: string; value: number }>()); -export const settingsSave = createAction('[Profile] SettingsSave', props<{ isSet: boolean }>()); - -const reducer = createReducer( - InitState, - on(loadProfileSuccess, (state, { profile }) => ({ ...profile })), - on(setTextareaHeight, state => ({ ...state })), - on(settingsSave, (state, { isSet }) => ({ ...state, isSet })), - on(clearProfile, () => InitState) -); - -export function profileReducer(state: ProfileState, action: Action) { - return reducer(state, action); -} - -@Injectable() -export class ProfileEffects { - load$ = createEffect(() => - this.actions$.pipe( - ofType(loadProfile), - exhaustMap(() => this.service.getProfile().pipe(map(user => loadProfileSuccess({ profile: user })))) - ) - ); - - saveTextarea$ = createEffect(() => - this.actions$.pipe( - ofType(setTextareaHeight), - exhaustMap(a => - this.service.setTextareaProfile(a).pipe(map(user => loadProfileSuccess({ profile: user }))) - ) - ) - ); - - saveSettings$ = createEffect(() => - this.actions$.pipe( - ofType(settingsSave), - map(a => this.service.setUser('settingsSaved', a.isSet)), - exhaustMap(() => this.service.setProfile().pipe(map(user => loadProfileSuccess({ profile: user })))) - ) - ); - - constructor(private actions$: Actions, private service: ProfileService) {} -} - -export const getProfileSelector = createFeatureSelector('profile'); - -export const getProfile = createSelector( - getProfileSelector, - state => state.profile -); - -export const getFirstAdminLogin = createSelector( - getProfileSelector, - state => state.username === 'admin' && !state.profile.settingsSaved -); - diff --git a/web/src/app/core/store/profile/profile.service.ts b/web/src/app/core/store/profile/profile.service.ts deleted file mode 100644 index 66212940da..0000000000 --- a/web/src/app/core/store/profile/profile.service.ts +++ /dev/null @@ -1,91 +0,0 @@ -// Licensed 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 { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { environment } from '@env/environment'; -import { Observable, throwError } from 'rxjs'; -import { map, tap } from 'rxjs/operators'; - -import { AuthService } from '@app/core/auth/auth.service'; -import { RbacUserModel } from '@app/models/rbac/rbac-user.model'; - -const PROFILE_LINK = `${environment.apiRoot}profile/`; - -export interface LastViewedTask { - id: number; -} - -export interface IProfile { - textarea: { [key: string]: number }; - settingsSaved: boolean; - lastViewedTask?: LastViewedTask; -} - -export interface IUser { - username: string; - change_password: string; - profile: IProfile; -} - -@Injectable({ providedIn: 'root' }) -export class ProfileService { - private user: RbacUserModel; - - constructor(private http: HttpClient, private auth: AuthService) {} - - public getProfile(): Observable { - const source$ = this.me().pipe( - map(user => (!user.profile ? { ...user, profile: this.emptyProfile() } : user)), - tap(user => (this.user = user)) - ); - return this.auth.auth.login ? source$ : throwError('Not authorized!'); - } - - emptyProfile() { - return { textarea: {}, settingsSaved: false }; - } - - setUser(key: string, value: string | boolean | { [key: string]: number }) { - const profile = { ...this.user.profile }; - profile[key] = value; - this.user = { ...this.user, profile }; - } - - me(): Observable { - return this.http.get(`${environment.apiRoot}rbac/me/`); - } - - setProfile(): Observable { - const { username, password, profile } = { ...this.user }; - return this.http.patch(`${environment.apiRoot}rbac/me/`, { username, profile }); - } - - setTextareaProfile(data: { key: string; value: number }): Observable { - const textarea = { ...this.user.profile.textarea }; - textarea[data.key] = data.value; - this.setUser('textarea', textarea); - return this.setProfile(); - } - - setLastViewedTask(id: number): Observable { - this.setUser('lastViewedTask', { id }); - return this.setProfile(); - } - - addUser(user: { username: string; profile: string }): Observable { - return this.http.post(`${PROFILE_LINK}`, user); - } - - setPassword(password: string, currentPassword: string) { - return this.http.patch(`${environment.apiRoot}rbac/me/`, { password, current_password: currentPassword }); - } -} diff --git a/web/src/app/core/store/router/route-serializer.ts b/web/src/app/core/store/router/route-serializer.ts deleted file mode 100644 index 4b1eed85c5..0000000000 --- a/web/src/app/core/store/router/route-serializer.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed 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 { RouterStateSerializer } from '@ngrx/router-store'; -import { RouterStateSnapshot, Params } from '@angular/router'; - -export interface RouterStateUrl { - url: string; - params: Params; - queryParams: Params; -} - -export class RouteSerializer implements RouterStateSerializer { - serialize(routerState: RouterStateSnapshot): RouterStateUrl { - let route = routerState.root; - - while (route.firstChild) { - route = route.firstChild; - } - - const { - url, - root: { queryParams }, - } = routerState; - const { params } = route; - - // Only return an object including the URL, params and query params - // instead of the entire snapshot - return { url, params, queryParams }; - } -} diff --git a/web/src/app/core/store/router/router.actions.ts b/web/src/app/core/store/router/router.actions.ts deleted file mode 100644 index 99637a99f6..0000000000 --- a/web/src/app/core/store/router/router.actions.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed 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 { Action } from '@ngrx/store'; -import { NavigationExtras } from '@angular/router'; - -export const GO = '[Router] Go'; -export const BACK = '[Router] Back'; -export const FORWARD = '[Router] Forward'; - -export class Go implements Action { - readonly type = GO; - - constructor( - public payload: { - path: any[]; - query?: object; - extras?: NavigationExtras; - } - ) {} -} - -export class Back implements Action { - readonly type = BACK; -} - -export class Forward implements Action { - readonly type = FORWARD; -} - -export type RouterActionsUnion = Go | Back | Forward; diff --git a/web/src/app/core/store/router/router.effects.ts b/web/src/app/core/store/router/router.effects.ts deleted file mode 100644 index 2ab369fcd2..0000000000 --- a/web/src/app/core/store/router/router.effects.ts +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; -import { Location } from '@angular/common'; -import { Effect, Actions, ofType } from '@ngrx/effects'; -import { map, tap } from 'rxjs/operators'; -import * as RouterActions from './router.actions'; - -@Injectable() -export class RouterEffects { - @Effect({ dispatch: false }) - navigate$ = this.actions$.pipe( - ofType(RouterActions.GO), - map((action: RouterActions.Go) => action.payload), - tap(({ path, query: queryParams, extras }) => this.router.navigate(path, { queryParams, ...extras })) - ); - - @Effect({ dispatch: false }) - navigateBack$ = this.actions$.pipe(ofType(RouterActions.BACK), tap(() => this.location.back())); - - @Effect({ dispatch: false }) - navigateForward$ = this.actions$.pipe(ofType(RouterActions.FORWARD), tap(() => this.location.forward())); - - constructor(private actions$: Actions, private router: Router, private location: Location) {} -} diff --git a/web/src/app/core/store/sockets/socket.effect.ts b/web/src/app/core/store/sockets/socket.effect.ts deleted file mode 100644 index 3d1e71178f..0000000000 --- a/web/src/app/core/store/sockets/socket.effect.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { exhaustMap } from 'rxjs/operators'; - -import { socketInit } from './socket.reducer'; -import { SocketService } from './socket.service'; - -@Injectable() -export class SocketEffect { - init$ = createEffect( - () => - this.actions$.pipe( - ofType(socketInit), - exhaustMap(() => this.service.init()) - ), - { dispatch: false } - ); - - constructor(private service: SocketService, private actions$: Actions) {} -} diff --git a/web/src/app/core/store/sockets/socket.reducer.ts b/web/src/app/core/store/sockets/socket.reducer.ts deleted file mode 100644 index f885197c20..0000000000 --- a/web/src/app/core/store/sockets/socket.reducer.ts +++ /dev/null @@ -1,105 +0,0 @@ -// Licensed 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 { TypeName } from '@app/core/types'; -import { - Action, - createAction, - createFeatureSelector, - createReducer, - createSelector, - on, - props, - select -} from '@ngrx/store'; -import { pipe } from 'rxjs'; -import { skip } from 'rxjs/operators'; - -/** - * Event Message Object dispatched from socket - */ -export interface IEMObject { - type: TypeName; - id: number; - details: { - id?: number; - type: string; - value: any; - }; -} - -export type EntityEvent = - | 'add' - | 'add_job_log' - | 'create' - | 'delete' - | 'remove' - | 'change_config' - | 'change_state' - | 'change_status' - | 'change_job_status' - | 'change_hostcomponentmap' - | 'upgrade' - | 'update' - | 'concern'; - -export interface EventMessage { - event: EntityEvent; - object?: IEMObject; -} - -export type StatusType = 'open' | 'close' | 're-open'; - -export const socketInit = createAction('[Socket] Init'); -export const socketOpen = createAction('[Socket] Open', props<{ status: StatusType }>()); -export const socketClose = createAction('[Socket] Close', props<{ status: StatusType }>()); -export const socketResponse = createAction('[Socket] Response', props<{ message: EventMessage }>()); -export const clearMessages = createAction('[Socket] Clear messages'); - -export interface SocketState { - status: StatusType; - message: EventMessage; -} - -const initialState: SocketState = { - status: null, - message: null, -}; - -const reducer = createReducer( - initialState, - on(socketInit, (state) => ({ ...state })), - on(socketOpen, (state, { status }) => ({ - ...state, - status, - })), - on(socketClose, (state, { status }) => ({ - ...state, - status, - })), - on(socketResponse, (state, { message }) => ({ - ...state, - message, - })), - on(clearMessages, (state) => ({ ...state, message: null })) -); - -export function socketReducer(state: SocketState, action: Action) { - return reducer(state, action); -} - -export const getSocketState = createFeatureSelector('socket'); -export const getConnectStatus = createSelector(getSocketState, (state: SocketState) => state.status); -export const getMessage = createSelector(getSocketState, (state) => state.message); -export const selectMessage = pipe( - select(getMessage), - skip(1), -); diff --git a/web/src/app/core/store/sockets/socket.service.ts b/web/src/app/core/store/sockets/socket.service.ts deleted file mode 100644 index 4da486f252..0000000000 --- a/web/src/app/core/store/sockets/socket.service.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { AuthService } from '@app/core/auth/auth.service'; -import { environment } from '@env/environment'; -import { Store } from '@ngrx/store'; -import { EMPTY, of } from 'rxjs'; - -import { socketClose, socketOpen, socketResponse, SocketState, StatusType } from './socket.reducer'; - -@Injectable({ - providedIn: 'root', -}) -export class SocketService { - connectUrl = environment.SERVER_URL_EVENT; - socket: WebSocket; - - constructor(private store: Store, private auth: AuthService) {} - - init(openStatus: StatusType = 'open') { - if (!this.auth.token) { - console.warn('Socket can not connect. Token is failed.'); - return EMPTY; - } - - this.socket = new WebSocket(this.connectUrl, ['adcm', `${this.auth.token}`]); - - this.socket.onopen = () => this.store.dispatch(socketOpen({ status: openStatus })); - this.socket.onclose = () => this.store.dispatch(socketClose({ status: 'close' })); - this.socket.onmessage = (response: { data: string }) => this.store.dispatch(socketResponse({ message: JSON.parse(response.data) })); - - return of(this.socket); - } -} diff --git a/web/src/app/core/types/actions.ts b/web/src/app/core/types/actions.ts deleted file mode 100644 index 6fe1f9610a..0000000000 --- a/web/src/app/core/types/actions.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Licensed 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 { IConfig } from '@app/shared/configuration/types'; - -/** - * - *``` -{ - action: 'add' | 'remove'; - component: string; // name of servise to work with - service: string; // name of component to work with -} -``` - * - */ -export interface IActionParameter { - action: 'add' | 'remove'; - component: string; - service: string; -} - -export interface IUIOptions { - disclaimer?: string; -} - -export interface IAction { - name: string; - description: string; - display_name: string; - start_impossible_reason: string; - run: string; - config: IConfig; - hostcomponentmap: IActionParameter[]; - button: 'create_host' | null; - ui_options: IUIOptions; - children?: IAction[]; -} diff --git a/web/src/app/core/types/api.ts b/web/src/app/core/types/api.ts deleted file mode 100644 index a5be8e7c72..0000000000 --- a/web/src/app/core/types/api.ts +++ /dev/null @@ -1,121 +0,0 @@ -// Licensed 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 { IAction } from './actions'; -import { IComponent } from './host-component'; -import { Job, Task } from './task-job'; -import { AdcmEntity } from '@app/models/entity'; -import { IIssues } from '@app/models/issue'; -import { ICluster } from '@app/models/cluster'; -import { Concern } from '@app/models/concern/concern'; - -export type TypeName = - 'bundle' | - 'cluster' | - 'host' | - 'provider' | - 'service' | - 'job' | - 'task' | - 'user' | - 'profile' | - 'adcm' | - 'stats' | - 'hostcomponent' | - 'service2cluster' | - 'host2cluster' | - 'servicecomponent' | - 'component' | - 'group_config' | - 'group_config_hosts' | - 'group' | - 'role' | - 'policy' | - 'audit_operations' | - 'audit_login'; -export type Entities = ICluster | Service | Host | Provider | Job | Task | Bundle; - -/** - *``` - { - [key: string]: string; - } - ``` - */ -export interface IRoot { - [key: string]: string; -} - -export interface BaseEntity extends AdcmEntity { - typeName: TypeName; - description?: string; - url: string; - state?: string; - config: string; - action?: string; - actions?: IAction[]; - issue?: IIssues; - prototype_id?: number; - prototype_name?: string; - prototype_display_name?: string; - prototype_version?: string; - bundle_id?: number; - status?: number | string; - concerns: Concern[]; - locked: boolean; - main_info?: string; -} - -export interface ApiFlat { - id: number; - object_id: number; - object_type: TypeName; - url: string; -} - -export interface Provider extends BaseEntity { - host: string; -} - -export interface Host extends BaseEntity { - fqdn: string; - provider_id: number; - provider_name: string; - cluster: string; - cluster_id?: number; - cluster_name?: string; - maintenance_mode?: string; -} - -export interface Service extends BaseEntity { - components: IComponent[]; - status: number; - hostcomponent: string; - display_name: string; - cluster_id?: number; - group_config: string; -} - -export interface CanLicensed { - license: 'unaccepted' | 'accepted' | 'absent'; - license_url: string; -} - -export interface License { - accept: string; - license: 'unaccepted' | 'accepted' | 'absent'; - text: string; -} - -export interface Bundle extends BaseEntity, CanLicensed { - [key: string]: any; -} diff --git a/web/src/app/core/types/context-manager.ts b/web/src/app/core/types/context-manager.ts deleted file mode 100644 index 9bb6e45031..0000000000 --- a/web/src/app/core/types/context-manager.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed 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 class ContextManager { - constructor(typeName: string) {} -} diff --git a/web/src/app/core/types/func.spec.ts b/web/src/app/core/types/func.spec.ts deleted file mode 100644 index 3c10a8a071..0000000000 --- a/web/src/app/core/types/func.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -// Licensed 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 { clearEmptyField, nullEmptyField } from './func'; - -describe('Functions test', () => { - - - it('function [clearEmptyField] should return', () => { - expect( - clearEmptyField({ - int: 2, - float_zero: 2.0, - float: 2.1, - str: '0abs', - bool_false: false, - bool_true: true, - nul: null, - empty: '', - empty_object: { a: null }, - json: { - a: null, - b: 'b', - c: 123, - d: '', - e: [{ a: 1 }, {}, { b: 2 }, { c: null }, { k: ['a', 0, 1, null, false] }], - k: ['a', 0, 1, null, false], - }, - }) - ).toEqual({ - int: 2, - float_zero: 2, - float: 2.1, - str: '0abs', - bool_false: false, - bool_true: true, - json: { - b: 'b', - c: 123, - e: [{ a: 1 }, {}, { b: 2 }, { c: null }, { k: ['a', 0, 1, null, false] }], - k: ['a', 0, 1, null, false], - }, - }); - }); - - it('function [nullEmptyField] should return', () => { - expect( - nullEmptyField({ - int: 2, - int_o: 0, - float_zero: 2.0, - float: 2.1, - float_o: 0, - str: '0abs', - bool_false: false, - bool_true: true, - bool_null: null, - nul: null, - empty: '', - empty_object: { a: null }, - json: { - a: null, - b: 'b', - c: 123, - d: '', - e: [{ a: 1 }, {}, { b: 2 }, { c: null }, { k: ['a', 0, 1, null, false] }], - k: ['a', 0, 1, null, false], - }, - }) - ).toEqual({ - int: 2, - int_o: 0, - float_zero: 2.0, - float: 2.1, - float_o: 0, - str: '0abs', - bool_false: false, - bool_true: true, - bool_null: null, - nul: null, - empty: null, - empty_object: { a: null }, - json: { - a: null, - b: 'b', - c: 123, - d: null, - e: [{ a: 1 }, {}, { b: 2 }, { c: null }, { k: ['a', 0, 1, null, false] }], - k: ['a', 0, 1, null, false], - }, - }); - }); -}); diff --git a/web/src/app/core/types/func.ts b/web/src/app/core/types/func.ts deleted file mode 100644 index 50f1540ba6..0000000000 --- a/web/src/app/core/types/func.ts +++ /dev/null @@ -1,94 +0,0 @@ -// Licensed 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 const isBoolean = (x: any) => typeof x === 'boolean'; -export const isObject = (x: any) => x !== null && typeof x === 'object'; -export const isEmptyObject = (x: any) => isObject(x) && !Object.keys(x).length; -export const isNumber = (x: any) => typeof x === 'number' && !isNaN(x); - -export const randomInteger = (max: number, min: number = 0): number => - Math.floor(min + Math.random() * (max + 1 - min)); - -/** - * Remove empty, null, undefined properties - */ -export function clearEmptyField(input: Object): Object { - return Object.keys(input).reduce((output, key) => { - const value = input[key]; - - if (isObject(value) && !Array.isArray(value) && Object.keys(input[key]).length) { - const result = clearEmptyField(value); - if (Object.keys(result).length) output[key] = result; - } else if (isBoolean(value) || isNumber(value) || value) output[key] = value; - - return output; - }, {}); -} - -/** - * Support nullable value in object properties, - * if value input field is empty return null. - * @deprecated - */ -export function nullEmptyField(input: Object): Object { - return Object.keys(input).reduce((output, key) => { - const data = input[key]; - if (isObject(data) && !Array.isArray(data)) { - // tslint:disable-next-line: deprecation - output[key] = nullEmptyField(data); - if (!Object.keys(output[key]).length) delete output[key]; - } else if ((typeof data === 'number' && isNaN(data)) || (typeof data === 'string' && !data) || data === null) - output[key] = null; - else if (isBoolean(data) || (typeof data === 'number' && data === 0) || data) output[key] = data; - return output; - }, {}); -} - -/** - * Utility function for a array, - * flattening an array of arrays - * @param a - */ -export function flatten(a: T[]) { - return a.reduce((acc, val) => (Array.isArray(val) ? acc.concat(flatten(val as T[])) : acc.concat(val)), []); -} - -/** - * - * - * @template T - * @param {number} count - * @param {(_: never, i: number) => T} fn - * @returns - */ -export function newArray(count: number, fn: (_: never, i: number) => T) { - return Array(count).fill(0).map(fn); -} - -/** - * @returns 16-bit hex string - * @example '#110C2E' - */ -export function getRandomColor(): string { - const letters = '0123456789ABCDEF'; - return newArray(6, (_, i) => i).reduce((p) => (p += letters[Math.floor(Math.random() * 16)]), '#'); -} - -export function uniqid(prefix: string = '', isFloat: boolean = false): string { - const seed = (s: number, w: number, z = s.toString(16)): string => - w < z.length ? z.slice(z.length - w) : w > z.length ? new Array(1 + (w - z.length)).join('0') + z : z; - let result = - prefix + - seed(parseInt((new Date().getTime() / 1000).toString(), 10), 8) + - seed(Math.floor(Math.random() * 0x75bcd15) + 1, 5); - if (isFloat) result += (Math.random() * 10).toFixed(8).toString(); - return result; -} diff --git a/web/src/app/core/types/host-component.ts b/web/src/app/core/types/host-component.ts deleted file mode 100644 index 0d3839c06b..0000000000 --- a/web/src/app/core/types/host-component.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Licensed 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. - - - -/** - * Information about the installed service component on a specific host - */ -export interface HostComponent { - id: number; - /** host name */ - host: string; - host_id: number; - /** component name */ - component: string; - component_display_name: string; - component_id: number; - service_id: number; - service_display_name: string; - service_name: string; - service_version: string; - state: string; - url: string; - host_url: string; - status: number; - monitoring: 'passive' | 'active'; -} - -/** - * A service component that may be installed on hosts in a cluster. - */ -export interface IComponent { - id: number; - prototype_id: number; - service_id: number; - service_name: string; - service_state: string; - name: string; - display_name: string; - status: number; - constraint: any; - monitoring?: 'passive' | 'active'; // status page - requires?: IRequires[]; -} - -export interface IRequires { - // id: number; - prototype_id: number; - name: string; - display_name: string; - components?: IRequires[]; -} diff --git a/web/src/app/core/types/import-export.ts b/web/src/app/core/types/import-export.ts deleted file mode 100644 index ba46b1ae37..0000000000 --- a/web/src/app/core/types/import-export.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed 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 interface IExport { - id: { [key: string]: number }; - bind_id: number | null; - obj_name: string; - bundle_name: string; - bundle_version: string; - binded: boolean; -} - -/** Model for import the configuration of cluster or service */ -export interface IImport { - id: number; - name: string; - required: boolean; - multibind: boolean; - exports: IExport[]; -} diff --git a/web/src/app/core/types/index.ts b/web/src/app/core/types/index.ts deleted file mode 100644 index 08bbf65e8d..0000000000 --- a/web/src/app/core/types/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed 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 * from './func'; -export * from './api'; -export * from './utils'; -export * from './actions'; -export * from './stack'; -export * from './host-component'; -export * from './import-export'; -export * from './task-job'; diff --git a/web/src/app/core/types/stack.ts b/web/src/app/core/types/stack.ts deleted file mode 100644 index 2ab2e328e0..0000000000 --- a/web/src/app/core/types/stack.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed 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 interface StackBase { - id: number; - name: string; - url: string; - version: string; - edition: string; - description: string; - display_name: string; - license: 'unaccepted' | 'accepted' | 'absent'; - bundle_id: number; - bundle_edition: string; -} - -export interface PrototypeListResult { - count: number; - next: any; - previous: any; - results: PrototypeList[]; -} - -export interface PrototypeList { - display_name: string; - versions: Version[]; -} - -export interface Version { - prototype_id: number; - version: string; -} - -export type Prototype = StackBase & {bundle_id: number}; -export type ServicePrototype = StackBase & {selected: boolean}; diff --git a/web/src/app/core/types/task-job.ts b/web/src/app/core/types/task-job.ts deleted file mode 100644 index a75d8efecb..0000000000 --- a/web/src/app/core/types/task-job.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Licensed 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 { BaseEntity } from './api'; -import { Entity } from '@app/adwp'; - -export type JobStatus = 'created' | 'running' | 'failed' | 'success' | 'aborted'; - -export type JobType = 'component' | 'service' | 'cluster' | 'host' | 'provider'; - -export interface JobObject { - id: number; - name: string; - type: JobType; - url?: string[]; -} - -interface TaskBase extends Entity { - start_date: string; - finish_date: string; - objects: JobObject[]; - status: JobStatus; - action: JobAction; - terminatable: boolean; - cancel: string; -} - -export interface JobAction { - prototype_name?: string; - prototype_version?: string; - bundle_id?: number; - display_name: string; -} -interface JobRaw extends TaskBase { - log_files: LogFile[]; - start_date: string; - finish_date: string; -} - -export interface TaskRaw extends TaskBase { - jobs: Job[]; -} - -export type Job = JobRaw & BaseEntity; -export type Task = TaskRaw & BaseEntity; - -export interface LogFile { - id: number; - url: string; - name: string; - type: string; - format: 'txt' | 'json'; - download_url: string; - content: string | CheckLog[]; -} - -export interface CheckLog { - title: string; - message: string; - result: boolean; - type: 'group' | 'check'; - content?: CheckLog[]; -} diff --git a/web/src/app/core/types/utils.ts b/web/src/app/core/types/utils.ts deleted file mode 100644 index b49dfa393b..0000000000 --- a/web/src/app/core/types/utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed 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. - -/** - * For lists - * @field `cmd: string` - command name - * @field `row: any` - data model from row of list - * @field `item?: any` - any transmitted object of additionally - */ -export interface EmmitRow { - cmd: string; - row: any; - item?: any; -} - -export interface SelectOption { - id: number | string; - name: string; -} - -export interface IError { - code: string; - desc: string; - level: string; -} diff --git a/web/src/app/directives/popover.directive.ts b/web/src/app/directives/popover.directive.ts deleted file mode 100644 index 75c2ec674e..0000000000 --- a/web/src/app/directives/popover.directive.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { ComponentFactory, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Renderer2, Type, ViewContainerRef, } from '@angular/core'; -import { BaseDirective } from '@app/adwp'; - -import { PopoverComponent } from '@app/components/popover/popover.component'; -import { PopoverContentDirective, PopoverEventFunc } from '@app/abstract-directives/popover-content.directive'; - -export interface PopoverInput { [inputKey: string]: any; } - -@Directive({ - selector: '[appPopover]' -}) -export class PopoverDirective extends BaseDirective implements OnInit, OnDestroy { - - containerRef: ComponentRef; - factory: ComponentFactory; - leaveListener: () => void; - - shown = false; - timeoutId: any; - - @Input() component: Type; - @Input() data: PopoverInput = {}; - @Input() event: PopoverEventFunc; - @Input() hideTimeout = 0; - - constructor( - private elementRef: ElementRef, - public viewContainer: ViewContainerRef, - public componentFactoryResolver: ComponentFactoryResolver, - public renderer: Renderer2, - ) { - super(); - } - - ngOnInit() { - this.factory = this.componentFactoryResolver.resolveComponentFactory(PopoverComponent); - } - - hideComponent() { - if (!this.timeoutId) { - this.timeoutId = setTimeout(() => { - this.clear(); - this.shown = false; - this.timeoutId = undefined; - }, this.hideTimeout); - } - } - - checkReEnter() { - if (this.timeoutId) { - clearTimeout(this.timeoutId); - this.timeoutId = undefined; - } - } - - @HostListener('mouseenter') mouseEnter() { - this.checkReEnter(); - if (this.component && !this.shown) { - this.containerRef = this.viewContainer.createComponent(this.factory); - this.containerRef.instance.component = this.component; - this.containerRef.instance.data = this.data; - this.containerRef.instance.event = this.event; - - this.leaveListener = this.renderer.listen( - this.elementRef.nativeElement.parentElement, - 'mouseleave', - () => this.hideComponent(), - ); - - this.renderer.listen( - this.containerRef.location.nativeElement, - 'mouseenter', - () => this.checkReEnter(), - ); - - this.shown = true; - } - } - - clear() { - if (this.containerRef) { - this.containerRef.destroy(); - } - - this.viewContainer.clear(); - - if (this.leaveListener) { - this.elementRef.nativeElement.parentElement.removeEventListener('mouseleave', this.leaveListener); - } - } - - ngOnDestroy() { - super.ngOnDestroy(); - this.clear(); - } - -} diff --git a/web/src/app/entry/bundle/bundle-list.component.ts b/web/src/app/entry/bundle/bundle-list.component.ts deleted file mode 100644 index e4f61e459a..0000000000 --- a/web/src/app/entry/bundle/bundle-list.component.ts +++ /dev/null @@ -1,151 +0,0 @@ -// Licensed 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 { Component, ComponentRef, OnInit, ViewChild } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material/dialog'; -import { IColumns } from '@app/adwp'; -import { Observable } from 'rxjs'; - -import { StackService } from '../../core/services'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { AdwpListDirective } from '@app/abstract-directives/adwp-list.directive'; -import { ListService } from '@app/shared/components/list/list.service'; -import { SocketState } from '@app/core/store'; -import { TypeName } from '@app/core/types'; -import { IBundle } from '@app/models/bundle'; -import { ListFactory } from '../../factories/list.factory'; -import { EditionColumnComponent } from '@app/components/columns/edition-column/edition-column.component'; - -@Component({ - selector: 'app-bundle-list', - template: ` - - - - - - - `, - styles: [':host { flex: 1; }'], -}) -export class BundleListComponent extends AdwpListDirective { - - type: TypeName = 'bundle'; - - listColumns = [ - ListFactory.nameColumn(), - { - label: 'Version', - sort: 'version', - value: row => row.version, - }, - { - label: 'Edition', - type: 'component', - component: EditionColumnComponent, - instanceTaken: (componentRef: ComponentRef) => { - componentRef.instance.onClick = this.license.bind(this); - } - }, - ListFactory.descriptionColumn(), - ListFactory.signatureStatusColumn(), - ListFactory.deleteColumn(this), - ] as IColumns; - - @ViewChild('uploadBtn', { static: true }) uploadBtn: any; - - constructor( - private stack: StackService, - protected service: ListService, - protected store: Store, - public route: ActivatedRoute, - public router: Router, - public dialog: MatDialog, - ) { - super(service, store, route, router, dialog); - } - - upload(data: FormData[]) { - this.stack.upload(data).subscribe(); - } - - license(data: { event: MouseEvent, action: string, row: any }) { - this.clickCell(data.event, data.action, data.row); - } - -} - -@Component({ - selector: 'app-main', - template: ` - - `, - styles: [':host {width: 100%; max-width: 960px}'] -}) -export class MainComponent implements OnInit { - model: any; - - keys = ['display_name', 'version', 'license', 'license_path']; - - listColumns = [ - ListFactory.keyColumn(), - ListFactory.valueColumn(), - ] as IColumns; - - constructor(private service: ClusterService) {} - - ngOnInit() { - this.model = this.service.Current; - } - -} - -@Component({ - selector: 'app-license', - template: ` -
{{ text | async }}
- `, - styles: [`:host { - width: 100%; - max-width: 960px - } - - pre { - white-space: pre-wrap; - }`] -}) -export class LicenseComponent implements OnInit { - text: Observable; - - constructor(private service: ClusterService) {} - - ngOnInit(): void { - this.text = this.service.getBundleLicenseText(); - } - -} diff --git a/web/src/app/entry/bundle/bundle.module.ts b/web/src/app/entry/bundle/bundle.module.ts deleted file mode 100644 index f677383961..0000000000 --- a/web/src/app/entry/bundle/bundle.module.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed 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 { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { Routes, RouterModule } from '@angular/router'; - -import { AuthGuard } from '../../core/auth/auth.guard'; -import { BundleListComponent, MainComponent, LicenseComponent } from './bundle-list.component'; -import { SharedModule } from '@app/shared/shared.module'; -import { BundleDetailsComponent } from '../../components/bundle/bundle-details/bundle-details.component'; - -const routes: Routes = [ - { - path: '', - canActivate: [AuthGuard], - component: BundleListComponent, - }, - { - path: ':bundle', - canActivate: [AuthGuard], - component: BundleDetailsComponent, - children: [ - { path: '', redirectTo: 'main', pathMatch: 'full' }, - { path: 'main', component: MainComponent }, - { path: 'license', component: LicenseComponent }, - ], - }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], -}) -export class BundleRoutingModule {} - -@NgModule({ - declarations: [BundleListComponent, MainComponent, LicenseComponent], - imports: [CommonModule, SharedModule, BundleRoutingModule, RouterModule, BundleRoutingModule], -}) -export class BundleModule {} diff --git a/web/src/app/entry/cluster/cluster.component.scss b/web/src/app/entry/cluster/cluster.component.scss deleted file mode 100644 index 3d857b59bf..0000000000 --- a/web/src/app/entry/cluster/cluster.component.scss +++ /dev/null @@ -1,20 +0,0 @@ -:host { - flex: 1; - max-width: 100%; -} - -::ng-deep mat-row { - - &:hover { - - mat-cell { - - button { - - &.rename-button.editable { - display: flex !important; - } - } - } - } -} diff --git a/web/src/app/entry/cluster/cluster.component.ts b/web/src/app/entry/cluster/cluster.component.ts deleted file mode 100644 index 7884f354ed..0000000000 --- a/web/src/app/entry/cluster/cluster.component.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed 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 { Component } from '@angular/core'; -import { IColumns } from '@app/adwp'; - -import { ICluster } from '@app/models/cluster'; -import { TypeName } from '@app/core/types'; -import { ListFactory } from '../../factories/list.factory'; -import { ConcernListDirective } from '../../abstract-directives/concern-list.directive'; -import { ConcernEventType } from '../../models/concern/concern-reason'; - -@Component({ - template: ` - - - Create {{ type }} - - - - `, - styleUrls: ['cluster.component.scss'], -}) -export class ClusterListComponent extends ConcernListDirective { - - type: TypeName = 'cluster'; - eventTypes = [ConcernEventType.Cluster]; - - listColumns = [ - ListFactory.nameColumnCLuster(), - ListFactory.bundleColumn(), - ListFactory.descriptionColumn(), - ListFactory.stateColumn(), - ListFactory.statusColumn(this), - ListFactory.actionsButton(this), - ListFactory.importColumn(this), - ListFactory.updateColumn(this.type), - ListFactory.configColumn(this), - ListFactory.deleteColumn(this), - ] as IColumns; - -} diff --git a/web/src/app/entry/cluster/cluster.module.ts b/web/src/app/entry/cluster/cluster.module.ts deleted file mode 100644 index 64ee6e3781..0000000000 --- a/web/src/app/entry/cluster/cluster.module.ts +++ /dev/null @@ -1,165 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; - - -import { ConfigComponent } from '../../shared/configuration/main/config.component'; -import { ImportComponent, MainInfoComponent } from '@app/shared/components'; -import { SharedModule } from '@app/shared/shared.module'; - -import { ClusterListComponent } from './cluster.component'; -import { HcmapComponent } from '@app/components/cluster/hcmap/hcmap.component'; -import { ClusterHostComponent } from '../../components/cluster/host/cluster-host.component'; -import { ServicesComponent } from '@app/components/cluster/services/services.component'; -import { AuthGuard } from '../../core/auth/auth.guard'; -import { ServiceComponentsComponent } from '../../components/service-component/service-components.component'; -import { - ConfigGroupHostListComponent, - ConfigGroupListComponent, - ConfigGroupModule -} from '../../config-groups'; -import { ClusterDetailsComponent } from '../../components/cluster/cluster-details/cluster-details.component'; -import { GroupConfigDetailsComponent } from '../../components/hostprovider/group-config-details/group-config-details.component'; -import { ServiceDetailsComponent } from '../../components/service/service-details/service-details.component'; -import { ServiceComponentDetailsComponent } from '../../components/service-component/service-component-details/service-component-details.component'; -import { HostDetailsComponent } from '../../components/host/host-details/host-details.component'; -import { ClusterStatusComponent } from '../../components/cluster/cluster-status/cluster-status.component'; -import { ServiceStatusComponent } from '../../components/service/service-status/service-status.component'; -import { ServiceComponentStatusComponent } from '../../components/service-component/service-component-status/service-component-status.component'; -import { HostStatusComponent } from '../../components/host/host-status/host-status.component'; - -const clusterRoutes: Routes = [ - { - path: '', - component: ClusterListComponent, - canActivate: [AuthGuard], - }, - { - path: ':cluster', - component: ClusterDetailsComponent, - canActivate: [AuthGuard], - canActivateChild: [AuthGuard], - children: [ - { path: '', redirectTo: 'main', pathMatch: 'full' }, - { path: 'main', component: MainInfoComponent }, - { path: 'service', component: ServicesComponent }, - { path: 'host', component: ClusterHostComponent }, - { path: 'host_component', component: HcmapComponent }, - { path: 'config', component: ConfigComponent }, - { path: 'group_config', component: ConfigGroupListComponent }, - { path: 'status', component: ClusterStatusComponent }, - { path: 'import', component: ImportComponent }, - ], - }, - { - path: ':cluster/group_config/:group_config', - canActivate: [AuthGuard], - canActivateChild: [AuthGuard], - component: GroupConfigDetailsComponent, - children: [ - { path: '', redirectTo: 'host', pathMatch: 'full' }, - { path: 'host', component: ConfigGroupHostListComponent }, - { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } }, - ], - }, - { - path: ':cluster/service/:service', - component: ServiceDetailsComponent, - canActivate: [AuthGuard], - canActivateChild: [AuthGuard], - children: [ - { path: '', redirectTo: 'main', pathMatch: 'full' }, - { path: 'main', component: MainInfoComponent }, - { path: 'config', component: ConfigComponent }, - { path: 'group_config', component: ConfigGroupListComponent }, - { path: 'status', component: ServiceStatusComponent }, - { path: 'import', component: ImportComponent }, - { path: 'component', component: ServiceComponentsComponent }, - ], - }, - { - path: ':cluster/service/:service/group_config/:group_config', - canActivate: [AuthGuard], - canActivateChild: [AuthGuard], - component: GroupConfigDetailsComponent, - children: [ - { path: '', redirectTo: 'host', pathMatch: 'full' }, - { path: 'host', component: ConfigGroupHostListComponent }, - { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } }, - ], - }, - { - path: ':cluster/service/:service/component/:servicecomponent', - component: ServiceComponentDetailsComponent, - canActivate: [AuthGuard], - canActivateChild: [AuthGuard], - children: [ - { path: '', redirectTo: 'main', pathMatch: 'full' }, - { path: 'main', component: MainInfoComponent }, - { path: 'config', component: ConfigComponent }, - { path: 'group_config', component: ConfigGroupListComponent }, - { path: 'status', component: ServiceComponentStatusComponent }, - ], - }, - { - path: ':cluster/service/:service/component/:component/group_config/:group_config', - canActivate: [AuthGuard], - canActivateChild: [AuthGuard], - component: GroupConfigDetailsComponent, - children: [ - { path: '', redirectTo: 'host', pathMatch: 'full' }, - { path: 'host', component: ConfigGroupHostListComponent }, - { path: 'config', component: ConfigComponent, data: { isGroupConfig: true } }, - ], - }, - { - path: ':cluster/host/:host', - component: HostDetailsComponent, - canActivate: [AuthGuard], - canActivateChild: [AuthGuard], - children: [ - { path: '', redirectTo: 'main', pathMatch: 'full' }, - { path: 'main', component: MainInfoComponent }, - { path: 'config', component: ConfigComponent }, - { path: 'status', component: HostStatusComponent }, - ], - }, -]; - -@NgModule({ - imports: [ - RouterModule.forChild(clusterRoutes), - ], - exports: [RouterModule], -}) -export class ClusterRoutingModule { -} - -@NgModule({ - imports: [ - CommonModule, - SharedModule, - RouterModule, - ConfigGroupModule, - ClusterRoutingModule, - ], - declarations: [ - ClusterListComponent, - ServicesComponent, - ClusterHostComponent, - HcmapComponent, - ClusterStatusComponent, - ], -}) -export class ClusterModule {} diff --git a/web/src/app/entry/entry.module.ts b/web/src/app/entry/entry.module.ts deleted file mode 100644 index 74f197e627..0000000000 --- a/web/src/app/entry/entry.module.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { SharedModule } from '@app/shared/shared.module'; -import { HostproviderComponent } from '@app/components/hostprovider/hostprovider.component'; -import { HostListComponent } from '@app/components/host/host-list/host-list.component'; -import { NameEditColumnComponent } from "@app/components/columns/name-edit-column/name-edit-column.component"; -import { NameEditColumnFieldComponent } from "@app/components/columns/name-edit-column/name-edit-column-field.component"; - -@NgModule({ - imports: [CommonModule, SharedModule], - declarations: [HostproviderComponent, HostListComponent, NameEditColumnComponent, NameEditColumnFieldComponent], -}) -export class EntryModule {} diff --git a/web/src/app/entry/job/job-info.component.ts b/web/src/app/entry/job/job-info.component.ts deleted file mode 100644 index 5f0b894da7..0000000000 --- a/web/src/app/entry/job/job-info.component.ts +++ /dev/null @@ -1,72 +0,0 @@ -// 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 { Component, Input } from '@angular/core'; -import { JobStatus } from '@app/core/types'; - -import { ITimeInfo } from './log/log.component'; - -@Component({ - selector: 'app-job-info', - styles: [ - ` - :host { - position: fixed; - right: 40px; - top: 120px; - } - .time-info, - .time-info div { - display: flex; - align-items: center; - } - .time-info div mat-icon { - margin-right: 6px; - } - .time-info div span { - margin-right: 30px; - } - .start_flag { - transform: rotate(30deg); - font-size: 20px; - margin-top: 8px; - } - .finish_flag { - transform: rotate(150deg); - font-size: 20px; - } - `, - ], - template: ` -
-
- outlined_flag - {{ timeInfo?.start }} -
-
- autorenew - {{ Icon(status) }} - {{ timeInfo?.time }} -
-
- outlined_flag - {{ timeInfo?.end }} -
-
- `, -}) -export class JobInfoComponent { - @Input() timeInfo: ITimeInfo; - @Input() status: JobStatus; - Icon = (status: string): string => (status === 'aborted' ? 'block' : 'done_all'); - get isRun(): boolean { - return this.status === 'running'; - } -} diff --git a/web/src/app/entry/job/job-routing.module.ts b/web/src/app/entry/job/job-routing.module.ts deleted file mode 100644 index f1471d52e5..0000000000 --- a/web/src/app/entry/job/job-routing.module.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed 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 { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; - -import { AuthGuard } from '@app/core/auth/auth.guard'; -import { MainComponent } from './job.component'; -import { LogComponent } from './log/log.component'; -import { JobDetailsComponent } from '../../components/job/job-details/job-details.component'; - -const routes: Routes = [ - { - path: ':job', - canActivate: [AuthGuard], - component: JobDetailsComponent, - children: [ - { path: '', redirectTo: 'main', pathMatch: 'full' }, - { path: 'main', component: MainComponent }, - { path: ':log', component: LogComponent } - ] - } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class JobRoutingModule {} diff --git a/web/src/app/entry/job/job.component.ts b/web/src/app/entry/job/job.component.ts deleted file mode 100644 index f78dd9b9c6..0000000000 --- a/web/src/app/entry/job/job.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed 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 { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { BaseDirective } from '@app/adwp'; - -import { ClusterService } from '@app/core/services/cluster.service'; - -@Component({ - selector: 'app-main', - template: '', -}) -export class MainComponent extends BaseDirective implements OnInit { - - constructor( - private clusterService: ClusterService, - private router: Router, - private route: ActivatedRoute, - ) { - super(); - } - - ngOnInit() { - this.route.parent.params.pipe(this.takeUntil()).subscribe(params => { - this.clusterService.one_job(params?.job).subscribe(job => { - const logs = job.log_files; - const log = logs.find((a) => a.type === 'check') || logs[0]; - if (log) this.router.navigate([`../${log.id}`], { relativeTo: this.route, replaceUrl: true }); - }); - }); - } - -} diff --git a/web/src/app/entry/job/job.module.ts b/web/src/app/entry/job/job.module.ts deleted file mode 100644 index 165d95720b..0000000000 --- a/web/src/app/entry/job/job.module.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; - -import { SharedModule } from '@app/shared/shared.module'; -import { JobInfoComponent } from './job-info.component'; -import { JobRoutingModule } from './job-routing.module'; -import { MainComponent } from './job.component'; -import { LogComponent } from './log/log.component'; -import { CheckComponent } from './log/check.component'; -import { TextComponent } from './log/text.component'; - - -@NgModule({ - declarations: [ - MainComponent, - LogComponent, - JobInfoComponent, - CheckComponent, - TextComponent, - ], - imports: [ - CommonModule, - SharedModule, - RouterModule, - JobRoutingModule, - ] -}) -export class JobModule {} diff --git a/web/src/app/entry/job/log/check.component.ts b/web/src/app/entry/job/log/check.component.ts deleted file mode 100644 index b21ad4a3f0..0000000000 --- a/web/src/app/entry/job/log/check.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed 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 { Component, Input } from '@angular/core'; -import { CheckLog, LogFile } from '@app/core/types/task-job'; - -@Component({ - selector: 'app-log-check', - template: ` - - - list {{ item.title }} - - [ {{ item.result ? 'Success' : 'Fails' }} ] - - - -

{{ item.message }}

- - - -
- - - -
- `, - styles: [ - ` - .status { - white-space: nowrap; - } - - .item-info { - align-items: center; - justify-content: flex-end; - } - - textarea { - background-color: #424242; - border: 0; - color: #fff; - height: 300px; - width: 100%; - } - `, - ], -}) -export class CheckComponent { - @Input() content: CheckLog[] = []; - current: CheckLog; - trackBy(index: number) { - return index; - } -} diff --git a/web/src/app/entry/job/log/log.component.spec.ts b/web/src/app/entry/job/log/log.component.spec.ts deleted file mode 100644 index 5cc9eae3d2..0000000000 --- a/web/src/app/entry/job/log/log.component.spec.ts +++ /dev/null @@ -1,125 +0,0 @@ -// Licensed 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 { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatIconModule } from '@angular/material/icon'; -import { ActivatedRoute, convertToParamMap } from '@angular/router'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ApiService } from '@app/core/api'; -import { EventMessage, getMessage, SocketState } from '@app/core/store'; -import { Job, LogFile } from '@app/core/types'; -import { MemoizedSelector } from '@ngrx/store'; -import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { of } from 'rxjs/internal/observable/of'; - -import { JobInfoComponent } from '../job-info.component'; -import { LogComponent } from './log.component'; -import { TextComponent } from './text.component'; -import { JobService } from '@app/services/job.service'; - -const LogMock = { id: 1, name: 'log_test', type: 'stdout', content: 'First message', url: 'job/1' } as LogFile; -const JobMock = { id: 1, start_date: '2020-08-03T11:56:16.191363Z', finish_date: null, status: 'running', log_files: [LogMock] } as Job; - -describe('Job Module :: LogComponent', () => { - let fixture: ComponentFixture; - let component: LogComponent; - let service: ClusterService; - let store: MockStore; - let messageSelector: MemoizedSelector; - - beforeEach(async () => { - TestBed.configureTestingModule({ - imports: [MatIconModule], - declarations: [LogComponent, JobInfoComponent, TextComponent], - providers: [ - { provide: ApiService, useValue: { getOne: () => of(JobMock), get: () => of(LogMock) } }, - { provide: ActivatedRoute, useValue: { params: of({ log: 1 }), paramMap: of(convertToParamMap({ log: 1 })) } }, - JobService, - provideMockStore(), - ], - }).compileComponents(); - }); - - beforeEach(() => { - jasmine.clock().install(); - fixture = TestBed.createComponent(LogComponent); - store = TestBed.inject(MockStore); - messageSelector = store.overrideSelector(getMessage, { event: 'change_status' }); - component = fixture.componentInstance; - service = TestBed.inject(ClusterService); - }); - - afterEach(() => { - jasmine.clock().uninstall(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); - - it('content in the text-log should updating', () => { - service.getContext(convertToParamMap({ job: 1 })).subscribe(() => { - expect(service.Current.id).toBe(JobMock.id); - fixture.detectChanges(); - jasmine.clock().tick(100); - const text = fixture.nativeElement.querySelector('div.wrap app-log-text textarea'); - expect(text.innerHTML).toBe('First message'); - const e = { ...LogMock }; - e.content = 'Second message'; - component.currentLog$.next(e); - fixture.detectChanges(); - expect(fixture.nativeElement.querySelector('div.wrap app-log-text textarea').innerHTML).toBe('Second message'); - }); - }); - - it('if job status is running job-info should display start date and autorenew icon', () => { - service.getContext(convertToParamMap({ job: 1 })).subscribe((_) => { - expect(service.Current.id).toBe(JobMock.id); - fixture.detectChanges(); - const info = fixture.nativeElement.querySelector('app-job-info div.time-info'); - const start = info.querySelectorAll('div')[0].querySelector('span'); - const sd = new Date(Date.parse(JobMock.start_date)); - expect(start.innerText).toBe(sd.toLocaleTimeString()); - jasmine.clock().tick(100); - const icon = info.querySelectorAll('div')[1].querySelector('mat-icon'); - expect(icon.innerText).toBe('autorenew'); - }); - }); - - it('if add_job_log socket event should update job', () => { - service.getContext(convertToParamMap({ job: 1 })).subscribe((_) => { - expect(service.Current.id).toBe(JobMock.id); - fixture.detectChanges(); - - const value = { ...JobMock }; - /** ! change LogMock ! */ - value.log_files[0].content = 'Second message'; - - component.socketListener({ event: 'add_job_log', object: { type: 'job', id: 1, details: { type: '', value } } }); - fixture.detectChanges(); - - const text = fixture.nativeElement.querySelector('div.wrap app-log-text textarea'); - expect(text.innerHTML).toBe('Second message'); - }); - }); - - it('if change_job_status socket event should update icon in job-info', () => { - service.getContext(convertToParamMap({ job: 1 })).subscribe((_) => { - expect(service.Current.id).toBe(JobMock.id); - fixture.detectChanges(); - const JOB_STATUS = 'success'; - component.socketListener({ event: 'change_job_status', object: { type: 'job', id: 1, details: { type: '', value: JOB_STATUS } } }); - fixture.detectChanges(); - const icon = fixture.nativeElement.querySelector('app-job-info div.time-info').querySelectorAll('div')[1].querySelector('mat-icon'); - expect(icon.innerText).toBe('done_all'); - }); - }); -}); diff --git a/web/src/app/entry/job/log/log.component.ts b/web/src/app/entry/job/log/log.component.ts deleted file mode 100644 index ed6ec71f31..0000000000 --- a/web/src/app/entry/job/log/log.component.ts +++ /dev/null @@ -1,116 +0,0 @@ -// Licensed 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 { Component, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Subject } from 'rxjs'; -import { filter, switchMap } from 'rxjs/operators'; -import { BaseDirective } from '@app/adwp'; - -import { ClusterService } from '@app/core/services/cluster.service'; -import { Job, JobStatus, LogFile } from '@app/core/types'; -import { TextComponent } from './text.component'; -import { JobService } from '@app/services/job.service'; -import { EventMessage } from '@app/core/store'; - -export interface ITimeInfo { - start: string; - end: string; - time: string; -} - -@Component({ - selector: 'app-job-log', - styles: [ - ` - :host { - display: flex; - flex: 1; - padding: 10px 20px; - } - - div.wrap { - display: flex; - flex: 1; - } - - .accordion { - flex: 1; - display: flex; - flex-direction: column; - } - `, - ], - template: ` - - -
- - - - -
-
- `, -}) -export class LogComponent extends BaseDirective implements OnInit { - currentLog$ = new Subject(); - timeInfo: ITimeInfo; - logUrl: string; - - job: Job; - - @ViewChild(TextComponent, { static: true }) textComp: TextComponent; - - constructor( - private service: ClusterService, - private route: ActivatedRoute, - private jobService: JobService, - ) { - super(); - } - - socketListener(event: EventMessage) { - if (event.event === 'change_job_status') { - this.job.status = event.object.details.value as JobStatus; - this.job.finish_date = new Date().toISOString(); - this.timeInfo = this.service.getOperationTimeData(this.job); - if (this.textComp) this.textComp.update(this.job.status); - } - this.refresh(); - } - - startListenSocket() { - this.jobService.events().pipe( - this.takeUntil(), - filter(event => event?.object?.id === this.job?.id), - ).subscribe((event) => this.socketListener(event)); - } - - ngOnInit() { - this.route.paramMap.pipe( - this.takeUntil(), - switchMap(() => this.jobService.get(+this.route.parent.snapshot.paramMap.get('job'))), - ).subscribe((job) => { - this.job = job; - this.timeInfo = this.service.getOperationTimeData(this.job); - this.logUrl = this.job.log_files.find((log) => log.id === +this.route.snapshot.paramMap.get('log'))?.url; - this.refresh(); - }); - this.startListenSocket(); - } - - refresh() { - if (!this.logUrl) return; - this.service.getLog(this.logUrl).subscribe((a) => this.currentLog$.next(a)); - } - -} diff --git a/web/src/app/entry/job/log/text.component.ts b/web/src/app/entry/job/log/text.component.ts deleted file mode 100644 index 2b3811eee9..0000000000 --- a/web/src/app/entry/job/log/text.component.ts +++ /dev/null @@ -1,115 +0,0 @@ -// Licensed 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 { Component, DoCheck, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { interval, Subscription } from 'rxjs'; -import { BaseDirective } from '@app/adwp'; - -import { JobStatus } from '@app/core/types/task-job'; - -@Component({ - selector: 'app-log-text', - styles: [ - ` - :host { - display: flex; - flex: 1; - flex-direction: column; - } - .tools { - position: fixed; - right: 60px; - top: 150px; - } - textarea { - background-color: #424242; - border: 0; - color: #fff; - flex: 1; - } - `, - ], - template: ` -
- - - - -
- - `, -}) -export class TextComponent extends BaseDirective implements OnInit, DoCheck { - isScroll = false; - isRun = false; - isWatch = false; - watch: Subscription; - @Input() content: string; - @Input() status: JobStatus; - @Output() refresh = new EventEmitter(); - - @ViewChild('tea', { read: ElementRef }) textarea: ElementRef; - - ngOnInit(): void { - this.isRun = this.status === 'running'; - if (this.isRun) this.startWatch(); - } - - ngDoCheck(): void { - if (this.textarea) { - const el = this.textarea.nativeElement; - this.isScroll = el.offsetHeight < el.scrollHeight; - if (this.isScroll && this.isWatch) this.down(); - } - } - - update(status: JobStatus) { - this.isRun = status === 'running'; - if (!this.isRun && this.isWatch) { - this.isWatch = false; - this.watch.unsubscribe(); - } - } - - down() { - const el = this.textarea.nativeElement; - el.scrollTop = el.scrollHeight; - if (this.isRun && !this.isWatch) this.startWatch(); - } - - top() { - const el = this.textarea.nativeElement; - el.scrollTop = 0; - if (this.isRun && this.isWatch) { - this.isWatch = false; - this.watch.unsubscribe(); - } - } - - read(stop: { direct: -1 | 1 | 0 }) { - if (this.isRun && this.isWatch && stop.direct === -1) { - this.isWatch = false; - this.watch.unsubscribe(); - } - if (this.isRun && !this.isWatch && !stop.direct) this.startWatch(); - } - - startWatch() { - this.isWatch = true; - this.watch = interval(5000) - .pipe(this.takeUntil()) - .subscribe(_ => this.refresh.emit()); - } -} diff --git a/web/src/app/entry/task/hover.directive.spec.ts b/web/src/app/entry/task/hover.directive.spec.ts deleted file mode 100644 index ecac251e0e..0000000000 --- a/web/src/app/entry/task/hover.directive.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed 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 { Component, DebugElement } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SharedModule } from '@app/shared/shared.module'; - -import { HoverDirective } from './hover.directive'; - -@Component({ - template: ` - - ` -}) -export class TestComponent {} - -describe('HoverStatusTaskDirective', () => { - let fixture: ComponentFixture; - let debs: DebugElement[]; - let a: DebugElement; - - beforeEach(() => { - fixture = TestBed.configureTestingModule({ - imports: [SharedModule, NoopAnimationsModule], - declarations: [TestComponent, HoverDirective] - }).createComponent(TestComponent); - - fixture.detectChanges(); - - debs = fixture.debugElement.queryAll(By.directive(HoverDirective)); - a = debs[0]; - - }); - - it('can inject `HoverStatusTaskDirective` in 1st - -
OR
-
- -
- - -
- - - - - - -

- -

-
-
-

{{ message }}

- diff --git a/web/src/app/main/login/login.component.scss b/web/src/app/main/login/login.component.scss deleted file mode 100644 index 2fb565d34c..0000000000 --- a/web/src/app/main/login/login.component.scss +++ /dev/null @@ -1,63 +0,0 @@ -:host { - flex: 1; -} - -.container { - max-width: 900px; - background: #424242; - box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12); - border-radius: 4px; - padding-top: 32px; -} - -.double-auth { - display: flex; - justify-content: center; - align-items: center; - - & div { - flex-basis: 50%; - text-align: center; - } - - & .or { - flex: 0; - border: solid 1px #666; - border-radius: 42px; - padding: 8px; - line-height: 24px; - } -} - -.google-auth { - line-height: 46px; - padding: 0; - - & svg { - width: 46px; - height: 46px; - } - - & span { - padding: 0 16px; - } -} - -.form-auth { - width: 300px; - margin: 0 auto; - - & p { - text-align: right; - } - - & mat-form-field { - width: 100%; - } -} - -.warn { - width: 300px; - margin: 0 auto; - padding: 16px; -} diff --git a/web/src/app/main/login/login.component.ts b/web/src/app/main/login/login.component.ts deleted file mode 100644 index 776fc7e57c..0000000000 --- a/web/src/app/main/login/login.component.ts +++ /dev/null @@ -1,74 +0,0 @@ -// Licensed 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 { Component, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; -import { filter } from 'rxjs/operators'; -import { FormGroup, FormControl, Validators } from '@angular/forms'; - -import { AuthService } from '@app/core/auth/auth.service'; -import { authLogin, authLogout, AuthState, getAuthState } from '@app/core/auth/auth.store'; -import { clearProfile } from '@app/core/store'; -import { BaseDirective } from '@app/shared/directives'; - -@Component({ - selector: 'app-login', - templateUrl: './login.component.html', - styleUrls: ['./login.component.scss'], -}) -export class LoginComponent extends BaseDirective implements OnInit, OnDestroy { - authForm = new FormGroup({ login: new FormControl('', Validators.required), password: new FormControl('', Validators.required) }); - message: string; - checkGL$: Observable; - - constructor(private auth: AuthService, private router: Router, private store: Store, private route: ActivatedRoute) { - super(); - } - - ngOnInit() { - this.checkGL$ = this.auth.checkGoogle(); - this.store.dispatch(authLogout()); - - const a$ = this.store - .select(getAuthState) - .pipe(this.takeUntil()) - .subscribe(state => { - if (state.isValid) { - a$.unsubscribe(); - this.router.navigateByUrl('/admin'); - } else { - this.store.dispatch(clearProfile()); - this.message = state.message; - } - }); - - this.route.queryParams - .pipe( - filter(p => p['error_code'] === 'AUTH_ERROR'), - this.takeUntil() - ) - .subscribe(p => (this.message = p['error_msg'])); - } - - login() { - this.message = ''; - if (this.authForm.valid) { - const { login, password } = this.authForm.value; - this.store.dispatch(authLogin({ login, password })); - } - } - - google() { - window.location.href = '/social/login/google-oauth2/'; - } -} diff --git a/web/src/app/main/main.module.ts b/web/src/app/main/main.module.ts deleted file mode 100644 index 8871487b6d..0000000000 --- a/web/src/app/main/main.module.ts +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed 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 { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RouterModule } from '@angular/router'; - -import { SharedModule } from '@app/shared/shared.module'; -import { LoginComponent } from './login/login.component'; -import { ProfileComponent } from './profile/profile.component'; -import { SupportComponent } from './support/support.component'; -import { TopComponent } from './top/top.component'; -import { ProgressComponent } from './progress.component'; -import { PageNotFoundComponent, FatalErrorComponent, GatewayTimeoutComponent } from './server-status.component'; -import { BellComponent } from '@app/components/bell/bell.component'; -import { NotificationsComponent } from '@app/components/notifications/notifications.component'; -import { BellTaskLinkPipe } from '@app/pipes/bell-task-link.pipe'; -import { AdwpFormElementModule } from "@app/adwp"; - -@NgModule({ - imports: [ - CommonModule, - SharedModule, - RouterModule, - AdwpFormElementModule, - ], - declarations: [ - LoginComponent, - ProfileComponent, - SupportComponent, - FatalErrorComponent, - GatewayTimeoutComponent, - PageNotFoundComponent, - TopComponent, - ProgressComponent, - BellComponent, - NotificationsComponent, - BellTaskLinkPipe, - ], - exports: [ - TopComponent, - BellComponent, - ProgressComponent, - ], -}) -export class MainModule {} diff --git a/web/src/app/main/profile/profile.component.ts b/web/src/app/main/profile/profile.component.ts deleted file mode 100644 index 7864854297..0000000000 --- a/web/src/app/main/profile/profile.component.ts +++ /dev/null @@ -1,122 +0,0 @@ -// Licensed 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 { Component, OnDestroy, OnInit } from '@angular/core'; -import {AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators} from '@angular/forms'; -import { Router } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; - -import { getProfileSelector, ProfileService, ProfileState } from '@app/core/store'; -import { BaseDirective } from '@app/shared/directives'; -import { IConfig } from "@app/shared/configuration/types"; -import { ApiService } from "@app/core/api"; -import {CustomValidators} from "@app/shared/validators/custom-validators"; -import {passwordsConfirmValidator} from "@app/components/rbac/user-form/rbac-user-form.component"; - -@Component({ - selector: 'app-profile', - template: ` -
-
-

- You are authorized as [ {{ user.username }} ] -

-
-
-

Change Password

- - - - -
-
-
-
- `, - styles: [ - ':host {flex: 1 }', - '.container { padding-top: 40px; }', - 'hr { margin: 40px 0; border: 0; border-top: dashed 1px rgb(140, 140, 140); }', - 'h3, h4, h5 { font-weight: normal; }', - 'adwp-input { display: inline-flex; margin-right: 10px }' - ], -}) -export class ProfileComponent extends BaseDirective implements OnInit, OnDestroy { - link: string; - user$: Observable; - passMinLength = null; - passMaxLength = null; - - passwordsConfirmValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - const password = control.get('password'); - const confirm = control.get('confirm_password'); - - return password && confirm && password.value !== confirm.value ? { passwordsNotMatch: true } : null; - }; - - cpForm = new FormGroup({ - current_password: new FormControl(null, [CustomValidators.required]), - password: new FormControl(null, this.passwordValidators), - confirm_password: new FormControl(null, this.passwordValidators), - }, { validators: this.passwordsConfirmValidator }); - - get passwordValidators() { - return [ - CustomValidators.required, - Validators.minLength(this.passMinLength || 3), - Validators.maxLength(this.passMaxLength || 128), - Validators.pattern(new RegExp(/^[\s\S]*$/u)) - ] - } - - constructor(private router: Router, private store: Store, private service: ProfileService, private api: ApiService) { - super(); - } - - ngOnInit() { - this.user$ = this.store.select(getProfileSelector).pipe( - this.takeUntil() - ); - - this.getGlobalSettings() - .subscribe((resp) => { - this.passMinLength = resp.config['auth_policy'].min_password_length; - this.passMaxLength = resp.config['auth_policy'].max_password_length; - - this.setFormValidators(); - }, - (err) => { - console.error(`[ERROR]: Can't load global config`); - this.passMinLength = 12; - this.passMaxLength = 128; - - this.setFormValidators(); - }) - } - - setFormValidators() { - this.cpForm.controls['password'].setValidators(this.passwordValidators); - this.cpForm.controls['confirm_password'].setValidators(this.passwordValidators); - this.cpForm.updateValueAndValidity(); - } - - changePassword() { - const password = this.cpForm.get('password').value; - const currentPassword = this.cpForm.get('current_password').value; - this.service.setPassword(password, currentPassword).subscribe(() => this.router.navigate(['/login'])); - } - - getGlobalSettings() { - return this.api.get('/api/v1/adcm/1/config/current/?noview'); - } - -} diff --git a/web/src/app/main/progress.component.ts b/web/src/app/main/progress.component.ts deleted file mode 100644 index 90764d3a56..0000000000 --- a/web/src/app/main/progress.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed 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 { Component, OnInit } from '@angular/core'; -import { PreloaderService } from '@app/core/services'; -import { Observable, of } from 'rxjs'; -import { delay } from 'rxjs/operators'; - -@Component({ - selector: 'app-progress', - template: ` - - `, - styles: ['.progress-bar {position: absolute;width: 100%;height: 3px;z-index: 3;}'], -}) -export class ProgressComponent implements OnInit { - show$: Observable = of(false); - constructor(private preloader: PreloaderService) {} - ngOnInit() { - this.show$ = this.preloader.active$.pipe(delay(1)); - } -} diff --git a/web/src/app/main/server-status.component.ts b/web/src/app/main/server-status.component.ts deleted file mode 100644 index abdbb83f05..0000000000 --- a/web/src/app/main/server-status.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed 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 { Component } from '@angular/core'; - -const styleCSS = 'div { font-weight:bold; margin: 40px auto; width: 400px;}'; - -// http 500 -@Component({ - styles: [styleCSS], - template: '
Critical error on the server.

Contact to support.

', -}) -export class FatalErrorComponent {} - -// http 504 -@Component({ - styles: [styleCSS], - template: '
Gateway Timeout.
', -}) -export class GatewayTimeoutComponent {} - -// http 404 -@Component({ - styles: [styleCSS], - template: '
Page not found.
', -}) -export class PageNotFoundComponent {} diff --git a/web/src/app/main/support/support.component.html b/web/src/app/main/support/support.component.html deleted file mode 100644 index 2fcc56a2ea..0000000000 --- a/web/src/app/main/support/support.component.html +++ /dev/null @@ -1,3 +0,0 @@ -

- support works! -

diff --git a/web/src/app/main/support/support.component.scss b/web/src/app/main/support/support.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/main/support/support.component.ts b/web/src/app/main/support/support.component.ts deleted file mode 100644 index b8f29612b4..0000000000 --- a/web/src/app/main/support/support.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed 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 { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-support', - templateUrl: './support.component.html', - styleUrls: ['./support.component.scss'] -}) -export class SupportComponent implements OnInit { - - constructor() { } - - ngOnInit() { - } - -} diff --git a/web/src/app/main/top/top.component.html b/web/src/app/main/top/top.component.html deleted file mode 100644 index 78962c0bd9..0000000000 --- a/web/src/app/main/top/top.component.html +++ /dev/null @@ -1,63 +0,0 @@ - - - Arenadata cluster manager - - - - - CLUSTERS - - - HOSTPROVIDERS - - - HOSTS - - JOBS - - BUNDLES - - - - - - - - - - - - contact_support - Ask for help - - - - event_seat - Documentation - - - - - - - - settings_applications - Settings - - - - - - - diff --git a/web/src/app/main/top/top.component.scss b/web/src/app/main/top/top.component.scss deleted file mode 100644 index b66d161d8e..0000000000 --- a/web/src/app/main/top/top.component.scss +++ /dev/null @@ -1,55 +0,0 @@ -.mat-toolbar { - height: auto !important; - padding: 6px 16px !important; - background-color: #333c47 !important; - margin-bottom: 0; - display: block; -} - -.right-panel { - display: flex; - align-items: center; - justify-content: flex-end; -} - -app-bell { - margin-right: 8px; -} - -a { - display: flex; - align-items: center; - margin: 5px 0; - - img { - height: 40px; - vertical-align: bottom; - } - - &:hover { - text-decoration: none; - } -} - -.top-menu { - display: flex; - justify-content: center; - height: 50px; - justify-items: baseline; - - & a { - font-size: 14px; - } -} - -.job-status { - display: inline-block; - margin: 0 4px; - - & .mat-mini-fab { - margin: 0 4px; - width: 24px; - height: 24px; - line-height: 12px; - } -} diff --git a/web/src/app/main/top/top.component.ts b/web/src/app/main/top/top.component.ts deleted file mode 100644 index 6f711e9e26..0000000000 --- a/web/src/app/main/top/top.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed 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 { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { Observable, of } from 'rxjs'; - -import { authLogout, AuthState, isAuthenticated } from '@app/core/store'; - -@Component({ - selector: 'app-top', - templateUrl: './top.component.html', - styleUrls: ['./top.component.scss'], -}) -export class TopComponent implements OnInit { - isAuth$: Observable = of(false); - - constructor( - private router: Router, - private authStore: Store, - ) {} - - ngOnInit() { - this.isAuth$ = this.authStore.select(isAuthenticated); - } - - profile() { - this.router.navigate(['profile']); - } - - logout() { - this.authStore.dispatch(authLogout()); - } - -} diff --git a/web/src/app/models/action.ts b/web/src/app/models/action.ts deleted file mode 100644 index fe951219b9..0000000000 --- a/web/src/app/models/action.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface IActionConfig { - attr: any; - config: any[]; -} - -export interface IAction { - button: any; - config: IActionConfig; - display_name: string; - hostcomponentmap: any[]; - name: string; - run: string; -} diff --git a/web/src/app/models/bundle.ts b/web/src/app/models/bundle.ts deleted file mode 100644 index 95c53942a7..0000000000 --- a/web/src/app/models/bundle.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { AdcmEntity } from './entity'; -import { SignatureStatus } from '@app/components/columns/signature-column/signature-column.component'; - -export interface IBundle extends AdcmEntity { - adcm_min_version: string; - date: string; - description: string; - edition: string; - hash: string; - license: string; - license_hash: any; - license_path: any; - license_url: string; - name: string; - update: string; - url: string; - version: string; - signature_status: SignatureStatus; - -} diff --git a/web/src/app/models/cluster-service.ts b/web/src/app/models/cluster-service.ts deleted file mode 100644 index 38c8d5a279..0000000000 --- a/web/src/app/models/cluster-service.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { IComponent } from './component'; -import { BaseEntity } from '@app/core/types'; - -export interface IClusterService extends BaseEntity { - bind: string; - cluster_id: number; - component: string; - components: IComponent[]; - imports: string; - monitoring: string; - prototype: string; - version: string; -} diff --git a/web/src/app/models/cluster.ts b/web/src/app/models/cluster.ts deleted file mode 100644 index 6e632e7663..0000000000 --- a/web/src/app/models/cluster.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { BaseEntity } from '@app/core/types'; - -export interface ICluster extends BaseEntity { - bind: string; - edition: string; - host: string; - hostcomponent: string; - imports: string; - license: string; - name: string; - prototype: string; - service: string; - serviceprototype: string; - status_url: string; - upgradable: boolean; - upgrade: string; - group_config: string; -} diff --git a/web/src/app/models/component.ts b/web/src/app/models/component.ts deleted file mode 100644 index 5be6f42526..0000000000 --- a/web/src/app/models/component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { AdcmEntity } from './entity'; - -export interface IComponent extends AdcmEntity { - action: string; - bound_to: any; - config: string; - constraint: Array; - description: string; - monitoring: string; - prototype_id: number; - requires: any[]; - status: number; - url: string; -} diff --git a/web/src/app/models/concern/concern-reason.ts b/web/src/app/models/concern/concern-reason.ts deleted file mode 100644 index e6f46ecbfe..0000000000 --- a/web/src/app/models/concern/concern-reason.ts +++ /dev/null @@ -1,107 +0,0 @@ -export enum ConcernEventType { - Cluster = 'cluster-concerns', - Service = 'cluster-object-concerns', - Host = 'host-concerns', - HostProvider = 'host-provider-concerns', - ServiceComponent = 'service-component-concerns', -} - -export enum CauseType { - Config = 'config', - Job = 'job', - HostComponent = 'host-component', - Import = 'import', - Service = 'service', -} - -export enum IMPlaceholderItemType { - ComponentActionRun = 'component_action_run', - ComponentConfig = 'component_config', - Cluster = 'cluster', - Service = 'service', - Component = 'component', - HostProvider = 'provider', - Flag = 'flag', - Host = 'host', - Job = 'job', -} - -export interface IMPlaceholderItem { - name: string; - params: { - [id: string]: number; - }; - type?: IMPlaceholderItemType; -} - -export interface IMPlaceholderActionRun extends IMPlaceholderItem { - type: IMPlaceholderItemType.ComponentActionRun; - ids: { - cluster: number; - service: number; - component: number; - action: number; - }; -} - -export interface IMPlaceholderComponentConfig extends IMPlaceholderItem { - type: IMPlaceholderItemType.ComponentConfig; - ids: { - cluster: number; - service: number; - component: number; - }; -} - -export interface IMPlaceholderCluster extends IMPlaceholderItem { - type: IMPlaceholderItemType.Cluster; - ids: { - cluster: number; - }; -} - -export interface IMPlaceholderService extends IMPlaceholderItem { - type: IMPlaceholderItemType.Service; - ids: { - cluster: number; - service: number; - }; -} - -export interface IMPlaceholderComponent extends IMPlaceholderItem { - type: IMPlaceholderItemType.Component; - ids: { - cluster: number; - service: number; - component: number; - }; -} - -export interface IMPlaceholderHostProvider extends IMPlaceholderItem { - type: IMPlaceholderItemType.HostProvider; - ids: { - provider: number; - }; -} - -export interface IMPlaceholderHost extends IMPlaceholderItem { - type: IMPlaceholderItemType.Host; - ids: { - host: number; - provider: number; - }; -} - -export interface IMPlaceholderJob extends IMPlaceholderItem { - type: IMPlaceholderItemType.Job; - ids: number; -} - -export interface IMPlaceholder { - [itemKey: string]: IMPlaceholderItem; -} - -export interface ConcernReason { - message: string; - placeholder: IMPlaceholder; -} diff --git a/web/src/app/models/concern/concern.ts b/web/src/app/models/concern/concern.ts deleted file mode 100644 index 18ef2643ab..0000000000 --- a/web/src/app/models/concern/concern.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Entity } from '@app/adwp'; -import { ConcernReason } from './concern-reason'; - -export type ConcernType = 'issue' | 'lock'; - -export interface Concern extends Entity { - blocking: boolean; - reason: ConcernReason; - type: ConcernType; - url?: string; - cause: string; -} diff --git a/web/src/app/models/details.ts b/web/src/app/models/details.ts deleted file mode 100644 index 47603be8f2..0000000000 --- a/web/src/app/models/details.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { ICluster } from './cluster'; -import { IAction, JobObject, LogFile, TypeName } from '../core/types'; -import { IIssues } from './issue'; -import { AdcmTypedEntity } from './entity'; - -export interface IDetails { - parent?: ICluster; - typeName: TypeName; - id: number; - name: string; - upgradable: boolean; - upgrade: string; - status: string | number; - /** link to actionss */ - action: string; - actions: IAction[]; - issue: IIssues; - log_files?: LogFile[]; - objects: JobObject[]; - prototype_name: string; - prototype_display_name: string; - prototype_version: string; - provider_id: number; - provider_name: string; - bundle_id: number; - hostcomponent: string; - state: string; -} - -export interface INavItem { - id?: number; - title: string; - url: string; - issue?: string; - status?: number; - statusMessage?: string; - action?: () => void; - path?: string; - name?: string; -} - -export interface IStyledNavItem { - class?: string; - entity?: AdcmTypedEntity; -} diff --git a/web/src/app/models/entity-names.ts b/web/src/app/models/entity-names.ts deleted file mode 100644 index f9e9cdccec..0000000000 --- a/web/src/app/models/entity-names.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { TypeName } from '../core/types'; - -export const EntityNames: TypeName[] = ['servicecomponent', 'group_config', 'component', 'host', 'service', 'cluster', 'provider', 'job', 'task', 'bundle']; diff --git a/web/src/app/models/entity.ts b/web/src/app/models/entity.ts deleted file mode 100644 index 37745d8e23..0000000000 --- a/web/src/app/models/entity.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Entity } from '@app/adwp'; -import { TypeName } from '@app/core/types'; - -export interface AdcmEntity extends Entity { - name?: string; - display_name?: string; - fqdn?: string; -} - -export interface AdcmTypedEntity extends AdcmEntity { - typeName: TypeName; -} diff --git a/web/src/app/models/eventable-service.ts b/web/src/app/models/eventable-service.ts deleted file mode 100644 index bab47c9878..0000000000 --- a/web/src/app/models/eventable-service.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Observable } from 'rxjs'; - -import { EntityEvent, EventMessage } from '@app/core/store'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -export interface EventFilter { - events?: EntityEvent[]; -} - -export interface ConcernEventFilter extends EventFilter { - types?: ConcernEventType[]; -} - -export interface EventableService { - - events(eventFilter?: EventFilter): Observable; - -} diff --git a/web/src/app/models/host.ts b/web/src/app/models/host.ts deleted file mode 100644 index 15c207a4b0..0000000000 --- a/web/src/app/models/host.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { BaseEntity } from '@app/core/types'; - -export interface IHost extends BaseEntity { - cluster_id?: number; - cluster_url?: string; - cluster_name?: string; - clusters: any[]; - fqdn: string; - host_id: number; - host_url: string; - monitoring: string; - provider_id: number; - provider_name: number; - upgradable: boolean; -} diff --git a/web/src/app/models/issue.ts b/web/src/app/models/issue.ts deleted file mode 100644 index 6ec3d6e14a..0000000000 --- a/web/src/app/models/issue.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AdcmEntity } from '@app/models/entity'; - -export type IssueType = 'cluster' | 'service' | 'servicecomponent' | 'component'; - -export interface IssueEntity extends AdcmEntity { - issue: IIssues; -} - -export interface IIssues { - config?: boolean; - required_import?: boolean; - host_component?: false; - cluster?: IssueEntity[]; - service?: IssueEntity[]; -} diff --git a/web/src/app/models/list-result.ts b/web/src/app/models/list-result.ts deleted file mode 100644 index 4c15179b34..0000000000 --- a/web/src/app/models/list-result.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface ListResult { - count: number; - next?: string; - previous?: string; - results: T[]; -} diff --git a/web/src/app/models/rbac/rbac-audit-login.model.ts b/web/src/app/models/rbac/rbac-audit-login.model.ts deleted file mode 100644 index bf39c98891..0000000000 --- a/web/src/app/models/rbac/rbac-audit-login.model.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Entity } from "@app/adwp"; - -export interface RbacAuditLoginModel extends Entity { - id: number - login_details: LoginDetails; - login_result: string; - login_time: string; - url: string; - user_id: number; -} - -interface LoginDetails { - username: string; -} diff --git a/web/src/app/models/rbac/rbac-audit-operations.model.ts b/web/src/app/models/rbac/rbac-audit-operations.model.ts deleted file mode 100644 index 2e6270960a..0000000000 --- a/web/src/app/models/rbac/rbac-audit-operations.model.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Entity } from "@app/adwp"; - -export interface RbacAuditOperationsModel extends Entity { - id: number; - object_type: string; - object_name: string; - object_changes: AuditOperationsObjectChanges; - operation_name: string; - operation_type: string; - operation_result: string; - operation_time: string; - username: string; -} - -interface AuditOperationsObjectChanges { - current: { [key: string]: any }; - previous: { [key: string]: any }; -} - -export interface AuditOperationsChangesHistory { - attribute: string; - old_value: any; - new_value: any; -} diff --git a/web/src/app/models/rbac/rbac-group.model.ts b/web/src/app/models/rbac/rbac-group.model.ts deleted file mode 100644 index 50e2fed1a3..0000000000 --- a/web/src/app/models/rbac/rbac-group.model.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Entity } from '@app/adwp'; -import { RbacUserModel } from '@app/models/rbac/rbac-user.model'; - -export interface RbacGroupModel extends Entity { - id: number; - name: string; - description: string; - user: RbacUserModel[]; - url: string; - built_in: boolean; - type: string; -} diff --git a/web/src/app/models/rbac/rbac-object-candidate.ts b/web/src/app/models/rbac/rbac-object-candidate.ts deleted file mode 100644 index 590b2e4ae5..0000000000 --- a/web/src/app/models/rbac/rbac-object-candidate.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Entity } from '@app/adwp'; - -export interface IRbacObjectCandidateModel { - cluster: IRbacObjectCandidateClusterModel[]; - parent: IRbacObjectCandidateClusterModel[]; - provider: IRbacObjectCandidateProviderModel[]; - service: IRbacObjectCandidateServiceModel[]; - host: IRbacObjectCandidateHostModel[]; -} - -export interface IRbacObjectCandidateClusterModel extends Entity { - name: string; - type: 'cluster'; -} - -export interface IRbacObjectCandidateProviderModel extends Entity { - name: string; - type: 'provider'; -} - - -export interface IRbacObjectCandidateServiceModel extends Entity { - name: string; - type?: 'service', - clusters: IRbacObjectCandidateClusterModel[]; -} - -export interface IRbacObjectCandidateHostModel extends Entity { - name: string; - type: 'host'; -} diff --git a/web/src/app/models/rbac/rbac-permission.model.ts b/web/src/app/models/rbac/rbac-permission.model.ts deleted file mode 100644 index ec5affa17b..0000000000 --- a/web/src/app/models/rbac/rbac-permission.model.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Entity } from '@app/adwp'; - -export interface RbacPermissionModel extends Entity { - id: number; - display_name: string; -} diff --git a/web/src/app/models/rbac/rbac-policy.model.ts b/web/src/app/models/rbac/rbac-policy.model.ts deleted file mode 100644 index ed85c1ef8a..0000000000 --- a/web/src/app/models/rbac/rbac-policy.model.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Entity } from '@app/adwp'; -import { RbacRoleModel } from './rbac-role.model'; -import { RbacUserModel } from './rbac-user.model'; -import { RbacGroupModel } from './rbac-group.model'; - -export interface RbacPolicyModel extends Entity { - id: number; - name: string; - description: string; - object: unknown[]; - built_in: boolean; - role: Pick[]; - user: Pick[]; - group: Pick[]; - url: string; -} diff --git a/web/src/app/models/rbac/rbac-role.model.ts b/web/src/app/models/rbac/rbac-role.model.ts deleted file mode 100644 index 3748785c94..0000000000 --- a/web/src/app/models/rbac/rbac-role.model.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Entity } from '@app/adwp'; - -export type RbacRoleParametrizedBy = 'cluster' | 'service' | 'component' | 'provider' | 'host'; -export type RbacRoleType = 'hidden' | 'business' | 'role'; - -export interface RbacRoleModel extends Entity { - id: number; - name: string; - description: string; - display_name: string; - built_in: boolean; - type: RbacRoleType; - category: string[]; - parametrized_by_type: RbacRoleParametrizedBy[]; - child: Pick[]; - url: string; -} diff --git a/web/src/app/models/rbac/rbac-user.model.ts b/web/src/app/models/rbac/rbac-user.model.ts deleted file mode 100644 index 4375433b31..0000000000 --- a/web/src/app/models/rbac/rbac-user.model.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { RbacGroupModel } from '@app/models/rbac/rbac-group.model'; -import { IProfile } from '@app/core/store'; - -export interface RbacUserModel { - id: number; - username: string; - first_name: string; - last_name: string; - email: string; - is_active: boolean; - is_superuser: boolean; - password: string; - url: string; - profile: IProfile; - group: Pick[]; - built_in: boolean; - type: string; - failed_login_attempts: number; - - // - change_password: string; -} diff --git a/web/src/app/models/service-component.ts b/web/src/app/models/service-component.ts deleted file mode 100644 index cbbf39cb8d..0000000000 --- a/web/src/app/models/service-component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { IssueEntity } from '@app/models/issue'; -import { IAction } from '@app/models/action'; - -export interface IServiceComponent extends IssueEntity { - cluster_id: number; - service_id: number; - description: string; - constraint: Array; - monitoring: string; - prototype_id: number; - requires: Array; - bound_to: any; - status: number; - url: string; - state: string; - action: string; - config: string; - prototype: string; - actions: IAction[]; - version: string; -} diff --git a/web/src/app/models/status-tree.ts b/web/src/app/models/status-tree.ts deleted file mode 100644 index 7131c43a56..0000000000 --- a/web/src/app/models/status-tree.ts +++ /dev/null @@ -1,40 +0,0 @@ -export type StatusTreeLinkFunc = (id: number, tree: StatusTree[]) => string[]; - -export interface StatusTreeSubject { - id?: number; - name: string; - status?: number; - link?: StatusTreeLinkFunc; -} - -export interface HCStatusTreeSubject extends StatusTreeSubject { - service_id: number; -} - -export interface StatusTree { - subject: StatusTreeSubject; - children: StatusTree[]; -} - -export interface ClusterStatusTree extends StatusTreeSubject { - chilren: { - hosts: StatusTreeSubject[]; - services: ServiceStatusTree[]; - }; -} - -export interface ServiceStatusTree extends StatusTreeSubject { - hc: HostComponentStatusTree[]; -} - -export interface HostComponentStatusTree extends StatusTreeSubject { - hosts: StatusTreeSubject[]; -} - -export interface HostStatusTree extends StatusTreeSubject { - hc: HCStatusTreeSubject[]; -} - -export interface ServiceStatusTree extends StatusTreeSubject { - hc: HostComponentStatusTree[]; -} diff --git a/web/src/app/models/universal-adcm-event-data.ts b/web/src/app/models/universal-adcm-event-data.ts deleted file mode 100644 index 8080b65fc5..0000000000 --- a/web/src/app/models/universal-adcm-event-data.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface UniversalAdcmEventData { - event: MouseEvent; - action: 'getNextPageCluster' | 'getClusters' | 'addCluster'; - row: T; -} diff --git a/web/src/app/pipes/bell-task-link.pipe.ts b/web/src/app/pipes/bell-task-link.pipe.ts deleted file mode 100644 index b7d4eadb89..0000000000 --- a/web/src/app/pipes/bell-task-link.pipe.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import { TaskRaw } from '@app/core/types'; - -@Pipe({ - name: 'bellTaskLink' -}) -export class BellTaskLinkPipe implements PipeTransform { - - endStatuses = ['aborted', 'success', 'failed']; - - transform(task: TaskRaw): (string | number)[] { - if (task?.jobs?.length > 0) { - if (task.status === 'running') { - const runningJob = task.jobs.find(job => job.status === 'running'); - if (runningJob) { - return ['job', runningJob.id, 'main']; - } - - const createdJob = task.jobs.find(job => job.status === 'created'); - if (createdJob) { - return ['job', createdJob.id, 'main']; - } - - const descOrderedJobs = task.jobs.slice().reverse(); - const finishedJob = descOrderedJobs.find(job => this.endStatuses.includes(job.status)); - if (finishedJob) { - return ['job', finishedJob.id, 'main']; - } - } else if (this.endStatuses.includes(task.status)) { - const descOrderedJobs = task.jobs.slice().reverse(); - const finishedJob = descOrderedJobs.find(job => this.endStatuses.includes(job.status)); - if (finishedJob) { - return ['job', finishedJob.id, 'main']; - } - } - } - } - -} diff --git a/web/src/app/pipes/entity-status-to-status-tree.pipe.ts b/web/src/app/pipes/entity-status-to-status-tree.pipe.ts deleted file mode 100644 index c55500f4f2..0000000000 --- a/web/src/app/pipes/entity-status-to-status-tree.pipe.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import { StatusTree, StatusTreeSubject } from '@app/models/status-tree'; -import { HavingStatusTreeAbstractService } from '../abstract/having-status-tree.abstract.service'; -import { AdcmEntity } from '@app/models/entity'; - -@Pipe({ - name: 'entityStatusToStatusTree' -}) -export class EntityStatusToStatusTreePipe implements PipeTransform { - - transform( - value: StatusTreeType, - entityService: HavingStatusTreeAbstractService, - data: any, - ): StatusTree[] { - return value ? entityService.entityStatusTreeToStatusTree(value, data) : []; - } - -} diff --git a/web/src/app/pipes/has-selected.pipe.ts b/web/src/app/pipes/has-selected.pipe.ts deleted file mode 100644 index 11cf5cd0c9..0000000000 --- a/web/src/app/pipes/has-selected.pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'hasSelected', - // tslint:disable-next-line:no-pipe-impure - pure: false, -}) -export class HasSelectedPipe implements PipeTransform { - - transform(dataSource: { results: any[]; count: number; }): boolean { - return !!dataSource?.results?.filter((row) => (row as any).checked).length; - } - -} diff --git a/web/src/app/pipes/is-array.pipe.ts b/web/src/app/pipes/is-array.pipe.ts deleted file mode 100644 index 04f8bdcb23..0000000000 --- a/web/src/app/pipes/is-array.pipe.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'isArray' -}) -export class IsArrayPipe implements PipeTransform { - - transform(value: any): unknown { - return Array.isArray(value); - } - -} diff --git a/web/src/app/pipes/issue-message-placeholder.pipe.spec.ts b/web/src/app/pipes/issue-message-placeholder.pipe.spec.ts deleted file mode 100644 index feccd3e63a..0000000000 --- a/web/src/app/pipes/issue-message-placeholder.pipe.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IssueMessagePlaceholderPipe } from './issue-message-placeholder.pipe'; - -describe('IssueMessagePlaceholderPipe', () => { - it('create an instance', () => { - const pipe = new IssueMessagePlaceholderPipe(); - expect(pipe).toBeTruthy(); - }); - - it('getting some names', () => { - const pipe = new IssueMessagePlaceholderPipe(); - expect(pipe.transform('${component}')).toBe('component'); - expect(pipe.transform('${action}')).toBe('action'); - }); -}); diff --git a/web/src/app/pipes/issue-message-placeholder.pipe.ts b/web/src/app/pipes/issue-message-placeholder.pipe.ts deleted file mode 100644 index 9cfe229cab..0000000000 --- a/web/src/app/pipes/issue-message-placeholder.pipe.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'issueMessagePlaceholder' -}) -export class IssueMessagePlaceholderPipe implements PipeTransform { - - transform(value: string): string { - return value.replace(/(\$\{)|(\})/g, ''); - } - -} diff --git a/web/src/app/pipes/issue-path.pipe.ts b/web/src/app/pipes/issue-path.pipe.ts deleted file mode 100644 index a0f8757e4d..0000000000 --- a/web/src/app/pipes/issue-path.pipe.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { map } from 'rxjs/operators'; -import { Observable, of } from 'rxjs'; - -import { ServiceService } from '@app/services/service.service'; -import { IssueType } from '@app/models/issue'; -import { ServiceComponentService } from '@app/services/service-component.service'; - -@Pipe({ - name: 'issuePath' -}) -export class IssuePathPipe implements PipeTransform { - - constructor( - private serviceService: ServiceService, - private serviceComponentService: ServiceComponentService, - ) {} - - transform(issueName: string, issueType: IssueType, id: number): Observable { - let issue = issueName; - if (issue === 'required_import') { - issue = 'import'; - } - - if (issueType === 'service') { - return this.serviceService.get(id) - .pipe(map( - service => `/cluster/${service.cluster_id}/${issueType}/${id}/${issue}`, - )); - } else if (issueType === 'servicecomponent' || issueType === 'component') { - return this.serviceComponentService.get(id) - .pipe(map( - component => `/cluster/${component.cluster_id}/service/${component.service_id}/component/${id}/${issue}`, - )); - } { - return of(`/${issueType}/${id}/${issue}`); - } - } - -} diff --git a/web/src/app/pipes/keys.pipe.ts b/web/src/app/pipes/keys.pipe.ts deleted file mode 100644 index a96e420ad5..0000000000 --- a/web/src/app/pipes/keys.pipe.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'keys' -}) -export class KeysPipe implements PipeTransform { - - transform(value: any): unknown { - return Object.keys(value || {}); - } - -} diff --git a/web/src/app/pipes/nav-item.pipe.ts b/web/src/app/pipes/nav-item.pipe.ts deleted file mode 100644 index 8da8d24dee..0000000000 --- a/web/src/app/pipes/nav-item.pipe.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import { AdcmTypedEntity } from '@app/models/entity'; -import { IStyledNavItem } from '@app/models/details'; -import { ApiFlat, TypeName } from '@app/core/types'; - -@Pipe({ - name: 'navItem' -}) -export class NavItemPipe implements PipeTransform { - - getGroupName(typeName: TypeName): string { - switch (typeName) { - case 'cluster': - return 'clusters'; - case 'service': - return 'services'; - case 'servicecomponent': - return 'components'; - case 'component': - return 'components'; - case 'host': - return 'hosts'; - case 'provider': - return 'hostproviders'; - case 'group_config': - return 'groupconfigs'; - case 'job': - return 'jobs'; - case 'bundle': - return 'bundles'; - } - } - - getLink(path: AdcmTypedEntity[], index: number, group: boolean): string { - let cluster: AdcmTypedEntity; - - switch (path[index].typeName) { - case 'cluster': - return group ? `/${path[index].typeName}` : `/${path[index].typeName}/${path[index].id}`; - case 'service': - return group ? ( - `/${path[index - 1].typeName}/${path[index - 1].id}/service` - ) : ( - `/${path[index - 1].typeName}/${path[index - 1].id}/service/${path[index].id}` - ); - case 'servicecomponent': - case 'component': - return group ? ( - `/${path[index - 2].typeName}/${path[index - 2].id}/service/${path[index - 1].id}/component` - ) : ( - `/${path[index - 2].typeName}/${path[index - 2].id}/service/${path[index - 1].id}/component/${path[index].id}` - ); - case 'host': - cluster = path.find(item => item.typeName === 'cluster'); - if (cluster) { - return group ? ( - `/${cluster.typeName}/${cluster.id}/host` - ) : ( - `/${cluster.typeName}/${cluster.id}/host/${path[index].id}` - ); - - } - return group ? `/${path[index].typeName}` : `/${path[index].typeName}/${path[index].id}`; - case 'provider': - return group ? `/${path[index].typeName}` : `/${path[index].typeName}/${path[index].id}`; - case 'job': - return group ? `/task` : `/${path[index].typeName}/${path[index].id}/main`; - case 'bundle': - return group ? `/${path[index].typeName}` : `/${path[index].typeName}/${path[index].id}/main`; - case 'group_config': - cluster = path[0]; - const { object_type, object_id, id } = (path[index] as unknown as ApiFlat); - if (object_type === 'service') { - return group ? ( - `/${cluster.typeName}/${cluster.id}/${object_type}/${object_id}/group_config` - ) : ( - `/${cluster.typeName}/${cluster.id}/${object_type}/${object_id}/group_config/${id}` - ); - } else if (object_type === 'component') { - return group ? ( - `/${path[index - 3].typeName}/${path[index - 3].id}/service/${path[index - 2].id}/component/${path[index-1].id}/group_config` - ) : ( - `/${path[index - 3].typeName}/${path[index - 3].id}/service/${path[index - 2].id}/component/${path[index-1].id}/group_config/${id}` - ); - } - return group ? ( - `/${object_type}/${object_id}/group_config` - ) : ( - `/${object_type}/${object_id}/group_config/${id}` - ); - - } - } - - getEntityTitle(entity: AdcmTypedEntity): string { - return entity.typeName === 'host' ? entity.fqdn : entity.display_name || entity.name; - } - - transform(path: AdcmTypedEntity[]): IStyledNavItem[] { - return path?.reduce((acc, item, index) => { - return [ - ...acc, - { - title: this.getGroupName(item.typeName), - url: this.getLink(path, index, true), - class: 'type-name', - }, - { - title: this.getEntityTitle(item), - url: this.getLink(path, index, false), - class: 'entity', - entity: item, - } - ] as IStyledNavItem[]; - }, []); - } - -} diff --git a/web/src/app/pipes/object-link-column.pipe.ts b/web/src/app/pipes/object-link-column.pipe.ts deleted file mode 100644 index d8085f2384..0000000000 --- a/web/src/app/pipes/object-link-column.pipe.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { ILinkColumn } from '@app/adwp'; - -import { JobObject, Task } from '../core/types'; -import { ObjectsHelper } from '../helpers/objects-helper'; - -@Pipe({ - name: 'objectLinkColumn' -}) -export class ObjectLinkColumnPipe implements PipeTransform { - - url(object: JobObject, task: Task): string[] { - return ObjectsHelper.getObjectUrl(object, task.objects); - } - - transform(object: JobObject, task: Task): ILinkColumn { - return { - label: '', - type: 'link', - value: () => object.name, - url: () => this.url(object, task).join('/'), - }; - } - -} diff --git a/web/src/app/pipes/pick-keys.pipe.ts b/web/src/app/pipes/pick-keys.pipe.ts deleted file mode 100644 index a1808dd84e..0000000000 --- a/web/src/app/pipes/pick-keys.pipe.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'pickKeys' -}) -export class PickKeysPipe implements PipeTransform { - - transform(object: { [key: string]: any }, keys: string[]): { [key: string]: any } { - return keys.reduce((result, key) => ({ ...result, [key]: object[key] }), {}); - } - -} diff --git a/web/src/app/pipes/sort-objects.pipe.ts b/web/src/app/pipes/sort-objects.pipe.ts deleted file mode 100644 index cae6da58b4..0000000000 --- a/web/src/app/pipes/sort-objects.pipe.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import { JobObject } from '../core/types'; -import { ObjectsHelper } from '../helpers/objects-helper'; - -@Pipe({ - name: 'sortObjects' -}) -export class SortObjectsPipe implements PipeTransform { - - transform(objects: JobObject[]): JobObject[] { - return ObjectsHelper.sortObjects(objects); - } - -} diff --git a/web/src/app/pipes/status-tree-link.pipe.ts b/web/src/app/pipes/status-tree-link.pipe.ts deleted file mode 100644 index 8c4b5882f2..0000000000 --- a/web/src/app/pipes/status-tree-link.pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import { StatusTree, StatusTreeLinkFunc } from '@app/models/status-tree'; - -@Pipe({ - name: 'statusTreeLink' -}) -export class StatusTreeLinkPipe implements PipeTransform { - - transform(id: number, tree: StatusTree[], func: StatusTreeLinkFunc): string[] { - return func(id, tree); - } - -} diff --git a/web/src/app/pipes/to-data-source.pipe.ts b/web/src/app/pipes/to-data-source.pipe.ts deleted file mode 100644 index ebb54a135e..0000000000 --- a/web/src/app/pipes/to-data-source.pipe.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'toDataSource' -}) -export class ToDataSourcePipe implements PipeTransform { - - transform(model: { [key: string]: any }): { results: any[]; count: number; } { - if (!model) { - return { results: [], count: 0 }; - } - - const results = Object.entries(model) - .reduce((acc, [key, value]) => { - return [...acc, { key, value }]; - }, []); - - return { results, count: 0 }; - } - -} diff --git a/web/src/app/pipes/translate-object-keys.pipe.ts b/web/src/app/pipes/translate-object-keys.pipe.ts deleted file mode 100644 index 4e98817abd..0000000000 --- a/web/src/app/pipes/translate-object-keys.pipe.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; - -@Pipe({ - name: 'translateKeys' -}) -export class TranslateKeysPipe implements PipeTransform { - - constructor(private _translate: TranslateService) {} - - transform(object: { [key: string]: any }): { [key: string]: any } { - if (!object) { - return {}; - } - - return Object.entries(object) - .reduce((acc, [key, value]) => { - return { - ...acc, - [this._translate.instant(key)]: value - } - }, {}); - } - -} diff --git a/web/src/app/services/bundle.service.ts b/web/src/app/services/bundle.service.ts deleted file mode 100644 index 0168cea819..0000000000 --- a/web/src/app/services/bundle.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -import { EntityService } from '../abstract/entity-service'; -import { Bundle } from '../core/types'; -import { ApiService } from '../core/api'; -import { environment } from '@env/environment'; - -@Injectable({ - providedIn: 'root', -}) -export class BundleService extends EntityService { - - constructor( - protected api: ApiService, - ) { - super(api); - } - - get( - id: number, - params: { [key: string]: string } = {}, - ): Observable { - return this.api.get(`${environment.apiRoot}stack/bundle/${id}/`, params); - } - -} diff --git a/web/src/app/services/cluster-entity.service.ts b/web/src/app/services/cluster-entity.service.ts deleted file mode 100644 index 493a2d1e4d..0000000000 --- a/web/src/app/services/cluster-entity.service.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -import { EntityService } from '@app/abstract/entity-service'; -import { environment } from '@env/environment'; -import { ApiService } from '@app/core/api'; -import { ICluster } from '@app/models/cluster'; -import { ClusterStatusTree, StatusTree } from '@app/models/status-tree'; -import { HavingStatusTreeAbstractService } from '@app/abstract/having-status-tree.abstract.service'; - -@Injectable({ - providedIn: 'root', -}) -export class ClusterEntityService extends EntityService implements HavingStatusTreeAbstractService { - - constructor( - protected api: ApiService, - ) { - super(api); - } - - get( - id: number, - params: { [key: string]: string } = {}, - ): Observable { - return this.api.get(`${environment.apiRoot}cluster/${id}/`, params); - } - - getStatusTree(id: number): Observable { - return this.api.get(`${environment.apiRoot}cluster/${id}/status/`); - } - - entityStatusTreeToStatusTree(input: ClusterStatusTree): StatusTree[] { - const hostsStatus = input.chilren.hosts.every((host) => host.status === 0) ? 0 : 16; - const servicesStatus = input.chilren.services.every((service) => service.status === 0) ? 0 : 16; - - const hosts = input.chilren.hosts.map((host) => { - - return { - subject: { - id: host.id, - status: host.status, - name: host.name, - link: (id) => ['/cluster', input.id.toString(), 'host', id.toString(), 'status'], - }, - children: [], - }; - }); - - const services = input.chilren.services.map((service) => { - - return { - subject: { - id: service.id, - status: service.status, - name: service.name, - }, - children: service.hc.map(component => ({ - subject: { - id: component.id, - name: component.name, - status: component.status, - }, - children: component.hosts.map(host => ({ - subject: { - id: host.id, - status: host.status, - name: host.name, - link: (id) => ['/cluster', input.id.toString(), 'host', id.toString(), 'status'], - }, - children: [], - })), - })), - }; - }); - - return [{ - subject: { - id: input.id, - status: input.status, - name: input.name, - }, - children: [ - { - subject: { - name: 'Hosts', - status: hostsStatus - }, - children: hosts, - }, - { - subject: { - name: 'Services', - status: servicesStatus - }, - children: services, - } - ], - }]; - } - -} diff --git a/web/src/app/services/concern.service.ts b/web/src/app/services/concern.service.ts deleted file mode 100644 index 2872a59687..0000000000 --- a/web/src/app/services/concern.service.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; -import { filter } from 'rxjs/operators'; - -import { ConcernEventFilter, EventableService } from '@app/models/eventable-service'; -import { EventMessage, selectMessage, SocketState } from '@app/core/store'; - -@Injectable() -export class ConcernService implements EventableService { - - constructor( - private store: Store, - ) { } - - parse(issueMessage: string): string[] { - let result = []; - for (const item of issueMessage.matchAll(/(.*?)(\$\{.+?\})|(.+$)/g)) { - if (item.length) { - result = [ ...result, ...item.slice(1, item.length) ]; - } - } - - return result.filter(item => !!item); - } - - events(eventFilter?: ConcernEventFilter): Observable { - return this.store.pipe( - selectMessage, - filter(event => !!event), - filter(event => !eventFilter?.events || eventFilter.events.includes(event.event)), - filter(event => !eventFilter?.types || eventFilter.types.includes(event.object?.type as any)), - ); - } - -} diff --git a/web/src/app/services/host.service.ts b/web/src/app/services/host.service.ts deleted file mode 100644 index 2ce42d6cc5..0000000000 --- a/web/src/app/services/host.service.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -import { EntityService } from '../abstract/entity-service'; -import { IHost } from '../models/host'; -import { Host } from '../core/types'; -import { environment } from '@env/environment'; -import { ApiService } from '@app/core/api'; -import { HostStatusTree, StatusTree } from '@app/models/status-tree'; -import { HavingStatusTreeAbstractService } from '@app/abstract/having-status-tree.abstract.service'; - -@Injectable({ - providedIn: 'root', -}) -export class HostService extends EntityService implements HavingStatusTreeAbstractService { - - constructor( - protected api: ApiService, - ) { - super(api); - } - - get( - id: number, - params: { [key: string]: string } = {}, - ): Observable { - return this.api.get(`${environment.apiRoot}host/${id}/`, params); - } - - addToCluster(hostId: number, clusterId: number): Observable { - return this.api.post(`${environment.apiRoot}cluster/${clusterId}/host/`, { host_id: hostId }); - } - - getStatusTree(id: number): Observable { - return this.api.get(`${environment.apiRoot}host/${id}/status/`); - } - - entityStatusTreeToStatusTree(input: HostStatusTree, clusterId: number): StatusTree[] { - return [{ - subject: { - id: input.id, - status: input.status, - name: input.name, - }, - children: input.hc.map((hc) => ({ - subject: { - id: hc.id, - status: hc.status, - name: hc.name, - link: (id) => ['/cluster', clusterId.toString(), 'service', hc.service_id.toString(), 'component', id.toString(), 'status'], - }, - children: [], - })), - }]; - } - -} diff --git a/web/src/app/services/issue-message.service.spec.ts b/web/src/app/services/issue-message.service.spec.ts deleted file mode 100644 index d888501555..0000000000 --- a/web/src/app/services/issue-message.service.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ConcernService } from './concern.service'; -import { provideMockStore } from '@ngrx/store/testing'; - -describe('IssueMessageService', () => { - let service: ConcernService; - - const initialState = { socket: {} }; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - ConcernService, - provideMockStore({ initialState }), - ], - }); - service = TestBed.inject(ConcernService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - it('#parser should match', (done: DoneFn) => { - expect(service.parse('Hello ${action1} this is a ${component1}.')) - .toEqual(['Hello ', '${action1}', ' this is a ', '${component1}', '.']); - - expect(service.parse('${action1} this is a ${component1}.')) - .toEqual(['${action1}', ' this is a ', '${component1}', '.']); - - expect(service.parse('${action1}${component1}${component2}')) - .toEqual(['${action1}', '${component1}', '${component2}']); - - expect(service.parse('${action1}ttt${component2}')) - .toEqual(['${action1}', 'ttt', '${component2}']); - - expect(service.parse('Start with ${action1} this is a ${component1}')) - .toEqual(['Start with ', '${action1}', ' this is a ', '${component1}']); - - expect(service.parse('${action2}')) - .toEqual(['${action2}']); - - expect(service.parse('${action2}${action1}')) - .toEqual(['${action2}', '${action1}']); - - expect(service.parse('text')) - .toEqual(['text']); - - expect(service.parse('Test1 ${action1}test2${action2}test3${action3}test4')) - .toEqual(['Test1 ', '${action1}', 'test2', '${action2}', 'test3', '${action3}', 'test4']); - - done(); - }); -}); diff --git a/web/src/app/services/job.service.ts b/web/src/app/services/job.service.ts deleted file mode 100644 index da3de862e8..0000000000 --- a/web/src/app/services/job.service.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { filter } from 'rxjs/operators'; -import { Store } from '@ngrx/store'; - -import { EventableService, EventFilter } from '@app/models/eventable-service'; -import { EventMessage, selectMessage, SocketState } from '@app/core/store'; -import { EntityService } from '@app/abstract/entity-service'; -import { Job } from '@app/core/types'; -import { ApiService } from '@app/core/api'; -import { environment } from '@env/environment'; - -@Injectable() -export class JobService extends EntityService implements EventableService { - - constructor( - private store: Store, - protected api: ApiService, - ) { - super(api); - } - - get(id: number, params: { [key: string]: string } = {}): Observable { - return this.api.get(`${environment.apiRoot}job/${id}/`, params); - } - - events(eventFilter?: EventFilter): Observable { - return this.store.pipe( - selectMessage, - filter(event => event?.object?.type === 'job'), - filter(event => !eventFilter?.events || eventFilter.events.includes(event?.event)), - ); - } - -} diff --git a/web/src/app/services/provider.service.ts b/web/src/app/services/provider.service.ts deleted file mode 100644 index 780eb2015e..0000000000 --- a/web/src/app/services/provider.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -import { EntityService } from '../abstract/entity-service'; -import { Provider } from '../core/types'; -import { environment } from '../../environments/environment'; -import { ApiService } from '../core/api'; - -@Injectable({ - providedIn: 'root', -}) -export class ProviderService extends EntityService { - - constructor( - protected api: ApiService, - ) { - super(api); - } - - get( - id: number, - params: { [key: string]: string } = {}, - ): Observable { - return this.api.get(`${environment.apiRoot}provider/${id}/`, params); - } - -} diff --git a/web/src/app/services/rbac-audit-login.service.ts b/web/src/app/services/rbac-audit-login.service.ts deleted file mode 100644 index 15f184265c..0000000000 --- a/web/src/app/services/rbac-audit-login.service.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Injectable } from "@angular/core"; -import { EntityAbstractService } from "../abstract/entity.abstract.service"; -import { ApiService } from "../core/api"; -import { FormModel } from "../shared/add-component/add-service-model"; -import { Observable } from "rxjs"; -import { ListResult } from "../models/list-result"; -import { environment } from "../../environments/environment"; -import { map } from "rxjs/operators"; -import { RbacAuditLoginModel } from "../models/rbac/rbac-audit-login.model"; - -@Injectable() -export class RbacAuditLoginService implements EntityAbstractService { - constructor(protected api: ApiService) {} - - model(value?: any): FormModel { - return { - name: 'Audit Login', - value: value - }; - } - - getList(): Observable { - return this.api.get>(`${environment.apiRoot}audit/login/`) - .pipe(map((list) => list.results)); - } -} diff --git a/web/src/app/services/rbac-audit-operations.service.ts b/web/src/app/services/rbac-audit-operations.service.ts deleted file mode 100644 index 84587d07b3..0000000000 --- a/web/src/app/services/rbac-audit-operations.service.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { ApiService } from '@app/core/api'; -import { environment } from '@env/environment'; -import { FormModel } from '@app/shared/add-component/add-service-model'; -import { EntityAbstractService } from '@app/abstract/entity.abstract.service'; -import { ListResult } from '@app/models/list-result'; -import { map } from 'rxjs/operators'; -import { RbacAuditOperationsModel } from "../models/rbac/rbac-audit-operations.model"; - -@Injectable() -export class RbacAuditOperationsService implements EntityAbstractService { - constructor(protected api: ApiService) {} - - model(value?: any): FormModel { - return { - name: 'Audit Operations', - value: value - }; - } - - getList(): Observable { - return this.api.get>(`${environment.apiRoot}audit/operation/`) - .pipe(map((list) => list.results)); - } -} diff --git a/web/src/app/services/rbac-group.service.ts b/web/src/app/services/rbac-group.service.ts deleted file mode 100644 index a424dd3054..0000000000 --- a/web/src/app/services/rbac-group.service.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -import { ApiService } from '@app/core/api'; -import { environment } from '@env/environment'; -import { EntityAbstractService } from '@app/abstract/entity.abstract.service'; -import { FormModel } from '@app/shared/add-component/add-service-model'; -import { RbacGroupModel } from '@app/models/rbac/rbac-group.model'; -import { Params } from '@angular/router'; -import { ListResult } from '@app/models/list-result'; -import { map } from 'rxjs/operators'; - -@Injectable() -export class RbacGroupService implements EntityAbstractService { - constructor(protected api: ApiService) {} - - model(value?: any): FormModel { - return { - name: 'Group', - value: value - }; - } - - delete(id: number): Observable { - return this.api.delete(`${environment.apiRoot}rbac/group/${id}/`); - } - - add(group: Partial): Observable { - const params = { ...group }; - - return this.api.post(`${environment.apiRoot}rbac/group/`, params); - } - - update(url: string, params: Partial): Observable { - return this.api.put(url, params); - } - - getByUrl(url: string, params?: Params): Observable { - const p = { expand: 'user', ...params }; - - return this.api.get(url, p); - } - - getList(param?: Params): Observable { - return this.api.get>(`${environment.apiRoot}rbac/group/`, param) - .pipe(map((list) => list.results)); - } - -} diff --git a/web/src/app/services/rbac-object-candidate.service.ts b/web/src/app/services/rbac-object-candidate.service.ts deleted file mode 100644 index 56f44b57cb..0000000000 --- a/web/src/app/services/rbac-object-candidate.service.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Injectable } from '@angular/core'; -import { EntityAbstractService } from '../abstract/entity.abstract.service'; -import { Observable } from 'rxjs'; -import { IRbacObjectCandidateModel } from '../models/rbac/rbac-object-candidate'; -import { environment as env } from '@env/environment'; -import { ApiService } from '@app/core/api'; - - -@Injectable() -export class RbacObjectCandidateService implements EntityAbstractService { - constructor(protected api: ApiService) {} - - get(id: number): Observable { - return this.api.get(`${env.apiUI}rbac/role/${id}/object_candidate/`); - } - -} diff --git a/web/src/app/services/rbac-policy.service.ts b/web/src/app/services/rbac-policy.service.ts deleted file mode 100644 index 61b54082a4..0000000000 --- a/web/src/app/services/rbac-policy.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { ApiService } from '@app/core/api'; -import { environment } from '@env/environment'; -import { FormModel } from '@app/shared/add-component/add-service-model'; -import { EntityAbstractService } from '@app/abstract/entity.abstract.service'; -import { RbacPolicyModel } from '@app/models/rbac/rbac-policy.model'; -import { Params } from '@angular/router'; -import { ListResult } from '@app/models/list-result'; -import { map } from 'rxjs/operators'; - -@Injectable() -export class RbacPolicyService implements EntityAbstractService { - constructor(protected api: ApiService) {} - - model(value?: any): FormModel { - return { - name: 'Policy', - value: value - }; - } - - delete(id: number): Observable { - return this.api.delete(`${environment.apiRoot}rbac/policy/${id}/`); - } - - add(group: Partial): Observable { - const params = { ...group }; - - return this.api.post(`${environment.apiRoot}rbac/policy/`, params); - } - - update(url: string, params: Partial): Observable { - return this.api.put(url, params); - } - - getList(param?: Params): Observable { - const p = { 'built_in': 'false', ...param || {} }; - - return this.api.get>(`${environment.apiRoot}rbac/policy/`, p) - .pipe(map((list) => list.results)); - } - - getByUrl(url: string, params?: Params): Observable { - const p = { expand: 'object,role,user,group', ...params }; - - return this.api.get(url, p); - } - - get(id: number): Observable { - return this.api.get(`${environment.apiRoot}rbac/policy/${id}/`); - } -} diff --git a/web/src/app/services/rbac-role.service.ts b/web/src/app/services/rbac-role.service.ts deleted file mode 100644 index 3f16e9f28e..0000000000 --- a/web/src/app/services/rbac-role.service.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { ApiService } from '@app/core/api'; -import { environment } from '@env/environment'; -import { EntityAbstractService } from '@app/abstract/entity.abstract.service'; -import { FormModel } from '@app/shared/add-component/add-service-model'; -import { RbacRoleModel } from '@app/models/rbac/rbac-role.model'; -import { Params } from '@angular/router'; -import { ListResult } from '@app/models/list-result'; -import { map } from 'rxjs/operators'; - -@Injectable() -export class RbacRoleService implements EntityAbstractService { - constructor(protected api: ApiService) {} - - model(value?: any): FormModel { - return { - name: 'Role', - value: value - }; - } - - delete(id: number): Observable { - return this.api.delete(`${environment.apiRoot}rbac/role/${id}/`); - } - - add(group: Partial): Observable { - const params = { ...group }; - - return this.api.post(`${environment.apiRoot}rbac/role/`, params); - } - - update(url: string, params: Partial): Observable { - return this.api.put(url, params); - } - - getByUrl(url: string, params?: Params): Observable { - const p = { expand: 'child', ...params }; - - return this.api.get(url, p); - } - - getList(param?: Params): Observable { - return this.api.get>(`${environment.apiRoot}rbac/role/`, param) - .pipe(map((list) => list.results)); - } - - getCategories(): Observable { - return this.api.get(`${environment.apiRoot}rbac/role/category`); - } -} diff --git a/web/src/app/services/rbac-user.service.ts b/web/src/app/services/rbac-user.service.ts deleted file mode 100644 index f1610c4374..0000000000 --- a/web/src/app/services/rbac-user.service.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -import { ApiService } from '@app/core/api'; -import { environment } from '@env/environment'; -import { RbacUserModel } from '@app/models/rbac/rbac-user.model'; -import { Params } from '@angular/router'; -import { ListResult } from '@app/models/list-result'; -import { map } from 'rxjs/operators'; -import { EntityAbstractService } from '@app/abstract/entity.abstract.service'; -import { FormModel } from '@app/shared/add-component/add-service-model'; - -@Injectable() -export class RbacUserService implements EntityAbstractService { - constructor(protected api: ApiService) {} - - model(value?: any): FormModel { - return { - name: 'User', - value: value - }; - } - - delete(id: number): Observable { - return this.api.delete(`${environment.apiRoot}rbac/user/${id}/`); - } - - add(group: Partial): Observable { - const params = { ...group }; - - return this.api.post(`${environment.apiRoot}rbac/user/`, params); - } - - update(url: string, params: Partial): Observable { - return this.api.patch(url, params); - } - - getByUrl(url: string, params?: Params): Observable { - const p = { expand: 'group', ...params }; - - return this.api.get(url, p); - } - - getList(param?: Params): Observable { - return this.api.get>(`${environment.apiRoot}rbac/user/`, param) - .pipe( - map((list) => list.results.filter(({ is_active }) => is_active)), - ); - } - - resetLoginAttemps(id: number): Observable { - return this.api.post(`${environment.apiRoot}rbac/user/${id}/reset_failed_login_attempts/`, {}); - } - -} diff --git a/web/src/app/services/service-component.service.ts b/web/src/app/services/service-component.service.ts deleted file mode 100644 index b5ae630a74..0000000000 --- a/web/src/app/services/service-component.service.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -import { ApiService } from '@app/core/api'; -import { IServiceComponent } from '@app/models/service-component'; -import { EntityService } from '@app/abstract/entity-service'; -import { environment } from '@env/environment'; -import { HavingStatusTreeAbstractService } from '@app/abstract/having-status-tree.abstract.service'; -import { HostComponentStatusTree, StatusTree } from '@app/models/status-tree'; - -@Injectable({ - providedIn: 'root', -}) -export class ServiceComponentService extends EntityService implements HavingStatusTreeAbstractService { - - constructor( - protected api: ApiService, - ) { - super(api); - } - - get( - id: number, - params: { [key: string]: string } = {}, - ): Observable { - return this.api.get(`${environment.apiRoot}component/${id}`, params); - } - - getStatusTree(id: number): Observable { - return this.api.get(`${environment.apiRoot}component/${id}/status/`); - } - - entityStatusTreeToStatusTree(input: HostComponentStatusTree, clusterId: number): StatusTree[] { - return [{ - subject: { - id: input.id, - name: input.name, - status: input.status, - }, - children: input.hosts.map(host => ({ - subject: { - id: host.id, - name: host.name, - status: host.status, - link: (id) => ['/cluster', clusterId.toString(), 'host', id.toString(), 'status'], - }, - children: [], - })), - }]; - } - -} diff --git a/web/src/app/services/service.service.ts b/web/src/app/services/service.service.ts deleted file mode 100644 index 367495121f..0000000000 --- a/web/src/app/services/service.service.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -import { ApiService } from '@app/core/api'; -import { EntityService } from '@app/abstract/entity-service'; -import { environment } from '@env/environment'; -import { Service } from '@app/core/types'; -import { HavingStatusTreeAbstractService } from '@app/abstract/having-status-tree.abstract.service'; -import { ServiceStatusTree, StatusTree } from '@app/models/status-tree'; -import { filter, switchMap } from "rxjs/operators"; -import { DialogComponent } from "@app/shared/components"; -import { MatDialog } from "@angular/material/dialog"; - -@Injectable({ - providedIn: 'root', -}) -export class ServiceService extends EntityService implements HavingStatusTreeAbstractService { - - constructor( - protected api: ApiService, - public dialog: MatDialog, - ) { - super(api); - } - - get( - id: number, - params: { [key: string]: string } = {}, - ): Observable { - return this.api.get(`${environment.apiRoot}service/${id}/`, params); - } - - getStatusTree(id: number): Observable { - return this.api.get(`${environment.apiRoot}service/${id}/status/`); - } - - acceptServiceLicense(item) { - return this.api.root - .pipe( - switchMap((root) => - this.api.get<{ text: string }>(`/api/v1/stack/prototype/${item.prototype_id}/license/`) - .pipe( - switchMap((info) => - this.dialog - .open(DialogComponent, { - data: { - title: `Accept license agreement ${item.service_name}`, - text: info.text, - closeOnGreenButtonCLick: true, - controls: {label: 'Do you accept the license agreement?', buttons: ['Yes', 'No']}, - }, - }) - .beforeClosed() - .pipe( - filter((yes) => yes), - switchMap(() => - this.api.put(`/api/v1/stack/prototype/${item.prototype_id}/license/accept/`, {}).pipe() - ) - ) - ) - ) - ) - ) - } - - entityStatusTreeToStatusTree(input: ServiceStatusTree, clusterId: number): StatusTree[] { - return [{ - subject: { - id: input.id, - name: input.name, - status: input.status, - }, - children: input.hc.map(hc => ({ - subject: { - id: hc.id, - name: hc.name, - status: hc.status, - }, - children: hc.hosts.map(host => ({ - subject: { - id: host.id, - name: host.name, - status: host.status, - link: (id) => ['/cluster', clusterId.toString(), 'host', id.toString(), 'status'], - }, - children: [], - })), - })), - }]; - } - -} diff --git a/web/src/app/services/stats.service.ts b/web/src/app/services/stats.service.ts deleted file mode 100644 index 44ad9e1f08..0000000000 --- a/web/src/app/services/stats.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { environment } from '@env/environment'; - -export interface Stats { - failed: number; - success: number; - running: number; - aborted: number; -} - -@Injectable({ - providedIn: 'root' -}) -export class StatsService { - - constructor( - private http: HttpClient, - ) { } - - tasks(lastTaskId?: number): Observable { - return this.http.get(`${environment.apiRoot}/stats/task/${lastTaskId ?? 0}/`); - } - -} diff --git a/web/src/app/services/task.service.ts b/web/src/app/services/task.service.ts deleted file mode 100644 index 6fdf82c425..0000000000 --- a/web/src/app/services/task.service.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { filter } from 'rxjs/operators'; -import { Observable } from 'rxjs'; -import { IListResult } from '@app/adwp'; - -import { EventMessage, selectMessage, SocketState } from '@app/core/store'; -import { EventableService, EventFilter } from '@app/models/eventable-service'; -import { Task } from '@app/core/types'; -import { ApiService } from '@app/core/api'; -import { EntityService } from '@app/abstract/entity-service'; -import { environment } from '@env/environment'; - -@Injectable() -export class TaskService extends EntityService implements EventableService { - - constructor( - private store: Store, - protected api: ApiService, - ) { - super(api); - } - - get(id: number, params: { [key: string]: string } = {}): Observable { - return this.api.get(`${environment.apiRoot}task/${id}/`, params); - } - - list(params: { [key: string]: string } = {}): Observable> { - return this.api.get(`${environment.apiRoot}task/`, params); - } - - events(eventFilter?: EventFilter, objectType = 'task'): Observable { - return this.store.pipe( - selectMessage, - filter(event => event?.object?.type === objectType), - filter(event => !eventFilter?.events || eventFilter.events.includes(event?.event)), - ); - } -} diff --git a/web/src/app/shared/add-component/add-button.component.ts b/web/src/app/shared/add-component/add-button.component.ts deleted file mode 100644 index f3b23bd36b..0000000000 --- a/web/src/app/shared/add-component/add-button.component.ts +++ /dev/null @@ -1,91 +0,0 @@ -// Licensed 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 { Component, EventEmitter, Inject, Input, OnDestroy, Output, Type } from '@angular/core'; -import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; - -import { DialogComponent } from '@app/shared/components'; -import { BaseDirective } from '@app/shared/directives'; -import { AddFormComponent } from './add-form.component'; -import { ADD_SERVICE_PROVIDER, FormModel, IAddService } from '@app/shared/add-component/add-service-model'; -import { BaseFormDirective } from '@app/shared/add-component/base-form.directive'; - -export type AddButtonDialogConfig = Pick; - -const ADCM_DEFAULT_ADD_DIALOG_CONFIG: AddButtonDialogConfig = { - width: '75%', - maxWidth: '1400px', - position: { - top: '50px' - } -}; - -@Component({ - selector: 'app-add-button', - template: ` - - - - - - - `, - styles: ['button {margin-right: 6px;}'], -}) -export class AddButtonComponent extends BaseDirective implements OnDestroy { - @Input() asIcon = false; - @Input() name: string; - @Input() component: Type; - @Input() dialogConfig: AddButtonDialogConfig = {}; - @Input() clusterId: number; - @Output() added = new EventEmitter(); - - constructor(@Inject(ADD_SERVICE_PROVIDER) private service: IAddService, - private dialog: MatDialog) { - super(); - } - - showForm(data?: FormModel): void { - - const model: any = data || this.service?.model(this.name) || this.service.Cluster; - if (this.component) { - model.component = this.component; - } - - if (this.clusterId) { - model.clusterId = this.clusterId; - } - - const name = model.title || model.name; - let title; - - if (data) { - title = `Update ${name}`; - } else { - title = `${['cluster', 'provider', 'host'].includes(name) ? 'Create' : 'Add'} ${name}`; - } - - - this.dialog.open(DialogComponent, { - ...ADCM_DEFAULT_ADD_DIALOG_CONFIG, - ...this.dialogConfig, - data: { - title, - component: AddFormComponent, - model, - }, - }); - } -} diff --git a/web/src/app/shared/add-component/add-cluster.component.ts b/web/src/app/shared/add-component/add-cluster.component.ts deleted file mode 100644 index 9018381d43..0000000000 --- a/web/src/app/shared/add-component/add-cluster.component.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Licensed 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 { Component, OnInit, OnDestroy } from '@angular/core'; -import { Subscription } from 'rxjs'; -import { take } from 'rxjs/operators'; - -import { clearEmptyField, StackBase } from '@app/core/types'; -import { BaseFormDirective } from './base-form.directive'; -import { ICluster } from '@app/models/cluster'; -import {Validators} from "@angular/forms"; - -@Component({ - selector: 'app-add-cluster', - template: ` - - - - - - - `, -}) -export class AddClusterComponent extends BaseFormDirective implements OnInit, OnDestroy { - - sgn: Subscription; - private prototype: StackBase; - - ngOnInit() { - this.form = this.service.model('cluster').form; - this.form.controls['name'].setValidators([Validators.pattern(new RegExp(/^[a-z|A-Z]+(\w|\.|\-|\_|\s)*[a-z|A-Z|0-9]{1}$/))]); - this.sgn = this.service.genName(this.form); - } - - ngOnDestroy() { - this.sgn.unsubscribe(); - } - - prototypeChanged(event: StackBase) { - this.prototype = event; - } - - save() { - const data = clearEmptyField(this.form.value); - this.service - .add(data, 'cluster', this.prototype) - .pipe(take(1)) - .subscribe((_) => this.onCancel()); - } - -} diff --git a/web/src/app/shared/add-component/add-form.component.ts b/web/src/app/shared/add-component/add-form.component.ts deleted file mode 100644 index dfa76cf7a9..0000000000 --- a/web/src/app/shared/add-component/add-form.component.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed 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 { AfterViewInit, Component, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core'; - -import { ChannelService, keyChannelStrim } from '@app/core/services'; -import { DynamicComponent, DynamicDirective } from '@app/shared/directives'; -import { BaseFormDirective } from './base-form.directive'; -import { FormModel } from '@app/shared/add-component/add-service-model'; -import { RbacFormDirective } from '@app/shared/add-component/rbac-form.directive'; - -@Component({ - selector: 'app-add-form', - template: ` -
- - - - - - - - - - - - - - - - - -
- `, -}) -export class AddFormComponent implements DynamicComponent, AfterViewInit { - model: FormModel; - - instance: BaseFormDirective; - - constructor( - private channel: ChannelService, - public viewContainer: ViewContainerRef, - private componentFactoryResolver: ComponentFactoryResolver - ) {} - - @ViewChild('cc') container: BaseFormDirective; - - @ViewChild(DynamicDirective, { static: true }) dynamic: DynamicDirective; - - onEnterKey(): void { - if (this.container) { - if (this.container.form.valid) this.container.save(); - } - } - - message(m: string): void { - this.channel.next(keyChannelStrim.notifying, m); - } - - ngAfterViewInit(): void { - if (this.model.component) { - const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.model.component); - const viewContainerRef = this.dynamic.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - this.instance = componentRef.instance; - if (this.instance instanceof RbacFormDirective) { - this.instance.value = this.model.value; - } - } - } - -} diff --git a/web/src/app/shared/add-component/add-service-model.ts b/web/src/app/shared/add-component/add-service-model.ts deleted file mode 100644 index bf4dabb259..0000000000 --- a/web/src/app/shared/add-component/add-service-model.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { EventEmitter, InjectionToken, Type } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { Observable, Subscription } from 'rxjs'; -import { Host, Service, StackBase, TypeName } from '@app/core/types'; -import { Params } from '@angular/router'; -import { BaseFormDirective } from '@app/shared/add-component/base-form.directive'; -import { ICluster } from '@app/models/cluster'; -import { ListResult } from '@app/models/list-result'; - -export const ADD_SERVICE_PROVIDER = new InjectionToken('AddService'); - -export interface FormModel { - name: string; - value?: T; - title?: string; - form?: FormGroup; - success?: EventEmitter<{ flag: boolean; obj: any }>; - component?: Type; - clusterId?: number; -} - -export interface IAddService { - model(name?: string): FormModel; - - Cluster: ICluster; - - Current: any; - - add?(data: any, name?: TypeName, prototype?: StackBase): Observable; - - get?(id: number): Observable; - - update?(url: string, data: any): Observable; - - getList?(type: TypeName, param: Params): Observable; - - addHost?(host: Partial): Observable; - - genName?(form: FormGroup): Subscription; - - addHostInCluster?(ids: number[]): Observable; - - getListResults?(type: TypeName, param: Params): Observable>; - - getProtoServiceForCurrentCluster?(): Observable<{ name: string, id: number, url: string, version: string, edition: string, description: string, display_name: string, license: 'unaccepted' | 'accepted' | 'absent', bundle_id: number, bundle_edition: string, selected: boolean }[]>; - - addService?(data: { prototype_id: number }[]): Observable; - - addServiceInCluster?(data: { prototype_id: number }[]): Observable; -} diff --git a/web/src/app/shared/add-component/add.service.ts b/web/src/app/shared/add-component/add.service.ts deleted file mode 100644 index 4d466e7ead..0000000000 --- a/web/src/app/shared/add-component/add.service.ts +++ /dev/null @@ -1,254 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; -import { convertToParamMap, Params } from '@angular/router'; -import { environment } from '@env/environment'; -import { combineLatest, forkJoin, from, Observable, of, throwError } from 'rxjs'; -import { catchError, concatAll, concatMap, filter, map, switchMap, tap } from 'rxjs/operators'; - -import { StackInfo, StackService } from '@app/core/services'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ApiService } from '@app/core/api'; -import { Host, License, Prototype, PrototypeListResult, ServicePrototype, StackBase, TypeName } from '@app/core/types'; -import { DialogComponent } from '@app/shared/components/dialog.component'; -import { GenName } from './naming'; -import { MainService } from '@app/shared/configuration/main/main.service'; -import { FormModel, IAddService } from '@app/shared/add-component/add-service-model'; -import { ServiceService } from "@app/services/service.service"; - - -const fromBundle = () => - new FormGroup({ - prototype_id: new FormControl('', Validators.required), - name: new FormControl('', Validators.required), - description: new FormControl(), - }); - -const MODELS: { [key: string]: FormModel } = { - provider: { - name: 'provider', - form: fromBundle(), - }, - host: { - name: 'host', - form: new FormGroup({ - fqdn: new FormControl('', [ - Validators.required, - Validators.maxLength(253), - Validators.pattern(new RegExp(/^[A-Za-z0-9]{1}[A-Za-z0-9.-]*$/)) - ]), - cluster_id: new FormControl(), - provider_id: new FormControl('', Validators.required), - }), - }, - cluster: { - name: 'cluster', - form: fromBundle(), - }, - service: { - name: 'service', - title: 'services' - }, - host2cluster: { - name: 'host2cluster', - title: 'hosts', - }, -}; - -@Injectable({ - providedIn: 'root', -}) -export class AddService implements IAddService { - private _currentPrototype: StackBase; - set currentPrototype(a: StackBase) { - this._currentPrototype = a; - } - - get currentPrototype(): StackBase { - return this._currentPrototype; - } - - constructor(private api: ApiService, - private stack: StackService, - private cluster: ClusterService, - public dialog: MatDialog, - private main: MainService, - private service: ServiceService, - ) {} - - model(name: string) { - return MODELS[name]; - } - - get Cluster() { - return this.cluster.Cluster; - } - - get Current() { - return this.main.Current; - } - - genName(form: FormGroup) { - return form - .get('prototype_id') - .valueChanges.pipe(filter((v) => !!v)) - .subscribe(() => { - const field = form.get('name'); - if (!field.value) field.setValue(GenName.do()); - }); - } - - add(data: Partial, name: TypeName, prototype?: StackBase) { - const currentPrototype = prototype || this.currentPrototype; - if (currentPrototype?.license === 'unaccepted') { - return this.api.root.pipe( - switchMap((root) => - this.api.get<{ text: string }>(`${root.stack}bundle/${currentPrototype.bundle_id}/license/`).pipe( - switchMap((info) => - this.dialog - .open(DialogComponent, { - data: { - title: `Accept license agreement`, - text: info.text, - controls: { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] }, - }, - }) - .beforeClosed() - .pipe( - filter((yes) => yes), - switchMap(() => - this.api.put(`${root.stack}bundle/${currentPrototype.bundle_id}/license/accept/`, {}) - .pipe( - switchMap(() => this.api.post(root[name], data)) - ) - ) - ) - ) - ) - ) - ); - } else return this.api.root.pipe(switchMap((root) => this.api.post(root[name], data))); - } - - addHost(host: Partial): Observable { - const a$ = this.api.post(`${environment.apiRoot}provider/${host.provider_id}/host/`, { fqdn: host.fqdn }); - const b$ = a$.pipe( - map((h) => (host.cluster_id ? this.api.post(`${environment.apiRoot}cluster/${host.cluster_id}/host/`, { host_id: h.id }) : of(h))) - ); - return b$.pipe(concatAll()); - } - - addHostInCluster(ids: number[]) { - return forkJoin([...ids.map(id => this.cluster.addHost(id))]); - } - - addService(data: { prototype_id: number, service_name?: string, license?: string, license_url?: string }[]) { - return combineLatest(data.map((o) => { - if (o.license_url && o.license === 'unaccepted') { - return this.service.acceptServiceLicense(o) - .pipe( - switchMap(() => this.cluster.addServices({ prototype_id: o.prototype_id })) - ) - } else return this.cluster.addServices({ prototype_id: o.prototype_id }); - })) - } - - addServiceInCluster(services: { prototype_id: number, service_name?: string, license?: string, license_url?: string }[]) { - const serviceObj = {}; - - return from(services) - .pipe( - tap((service) => serviceObj[service.prototype_id] = { service_name: service.service_name, license: service.license }), - concatMap((service) => this.api.get(`/api/v1/stack/prototype/${service.prototype_id}/license/`).pipe()), - concatMap((result) => { - const prototype_id = result.accept.substring( - result.accept.lastIndexOf("prototype/") + 10, - result.accept.indexOf("/license") - ) as unknown as number; - - if (!serviceObj[prototype_id].license || serviceObj[prototype_id].license === 'absent') { - return this.cluster.addServices({ prototype_id }) - } - - return this.dialog - .open(DialogComponent, { - data: { - title: `Accept license agreement ${serviceObj[prototype_id].service_name}`, - text: result.text, - closeOnGreenButtonCLick: true, - controls: { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] }, - }, - }) - .beforeClosed() - .pipe( - filter((yes) => yes), - switchMap(() => { - return this.api.put(`/api/v1/stack/prototype/${prototype_id}/license/accept/`, {}).pipe( - switchMap(() => this.cluster.addServices({ prototype_id })) - ) - }) - ) - }) - ) - } - - getListResults(type: TypeName, param: Params = {}) { - const paramMap = convertToParamMap(param); - return this.api.root.pipe(switchMap((root) => this.api.getList(root[type], paramMap))); - } - - getList(type: TypeName, param: Params = {}): Observable { - return this.getListResults(type, param).pipe(map((list) => list.results)); - } - - getPrototype(name: StackInfo, param: { [key: string]: string | number }): Observable { - return this.stack.fromStack(name, param); - } - - getPrototypeList(name: StackInfo) { - return this.api.get(`${environment.apiUI}stack/${name}/?limit=500&ordering=display_name`).pipe( - map((response: PrototypeListResult) => response.results) - ) - } - - getProtoServiceForCurrentCluster() { - return this.api.get(this.cluster.Cluster?.serviceprototype).pipe( - map((a: ServicePrototype[]) => - a - .filter((b) => !b.selected) - .map((b) => ({ - ...b, - name: `${b.display_name} - ${b.version}`, - })) - ) - ); - } - - upload(data: FormData[]) { - return this.stack.upload(data).pipe(catchError((e) => throwError(e))); - } - - getHostListForCurrentCluster() { - return this.api.get(this.cluster.Cluster?.host).pipe( - map((hosts) => - hosts - .map((host) => ({ - ...host, - name: host.fqdn, - })) - ) - ); - } - -} diff --git a/web/src/app/shared/add-component/adding.module.ts b/web/src/app/shared/add-component/adding.module.ts deleted file mode 100644 index b53919c88d..0000000000 --- a/web/src/app/shared/add-component/adding.module.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { FormElementsModule } from '@app/shared/form-elements/form-elements.module'; -import { MaterialModule } from '@app/shared/material.module'; -import { StuffModule } from '@app/shared/stuff.module'; - -import { AddButtonComponent } from './add-button.component'; -import { AddFormComponent } from './add-form.component'; -import { BaseFormDirective } from './base-form.directive'; -import { AddClusterComponent } from './add-cluster.component'; -import { HostComponent } from './host.component'; -import { Host2clusterComponent } from './host2cluster.component'; -import { ProviderComponent } from './provider.component'; -import { ServiceComponent } from './service.component'; -import { ControlsComponent } from './controls.component'; -import { DynamicModule } from '@app/shared/directives/dynamic/dynamic.module'; -import { RbacFormDirective } from '@app/shared/add-component/rbac-form.directive'; - -@NgModule({ - declarations: [ - AddButtonComponent, - AddFormComponent, - AddClusterComponent, - HostComponent, - Host2clusterComponent, - ProviderComponent, - ServiceComponent, - BaseFormDirective, - RbacFormDirective, - ControlsComponent, - ], - imports: [CommonModule, MaterialModule, StuffModule, FormsModule, ReactiveFormsModule, FormElementsModule, DynamicModule], - exports: [ - AddButtonComponent, - ProviderComponent, - AddClusterComponent, - HostComponent, - ServiceComponent, - Host2clusterComponent, - BaseFormDirective, - RbacFormDirective, - ControlsComponent, - ], - entryComponents: [AddFormComponent] -}) -export class AddingModule { -} diff --git a/web/src/app/shared/add-component/base-form.directive.ts b/web/src/app/shared/add-component/base-form.directive.ts deleted file mode 100644 index ad0a4e7245..0000000000 --- a/web/src/app/shared/add-component/base-form.directive.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Licensed 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 { Directive, Inject } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; -import { BaseDirective } from '@app/adwp'; - -import { ADD_SERVICE_PROVIDER, IAddService } from '@app/shared/add-component/add-service-model'; -import { ApiService } from "@app/core/api"; - -@Directive({ - selector: '[appBaseForm]', -}) -export class BaseFormDirective extends BaseDirective { - form = new FormGroup({}); - - constructor( - @Inject(ADD_SERVICE_PROVIDER) public service: IAddService, - public dialog: MatDialog, - public api?: ApiService - ) { - super(); - } - - onCancel(): void { - this.form.reset(); - this.dialog.closeAll(); - } - - save() {} -} diff --git a/web/src/app/shared/add-component/controls.component.ts b/web/src/app/shared/add-component/controls.component.ts deleted file mode 100644 index 5f75eb3a51..0000000000 --- a/web/src/app/shared/add-component/controls.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed 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 { Component, EventEmitter, Input, Output, ViewChild, ElementRef } from '@angular/core'; - -@Component({ - selector: 'app-add-controls', - template: ` -

- - - -

- `, -}) -export class ControlsComponent { - @Input() title = 'Create'; - @Input() disabled: boolean; - @Output() cancel = new EventEmitter(); - @Output() save = new EventEmitter(); - - @ViewChild('btn', { static: true, read: ElementRef }) saveBtn: ElementRef; - - oncancel() { - this.cancel.emit(); - } - - onsave() { - this.save.emit(); - } -} diff --git a/web/src/app/shared/add-component/host.component.ts b/web/src/app/shared/add-component/host.component.ts deleted file mode 100644 index 33bd83ef44..0000000000 --- a/web/src/app/shared/add-component/host.component.ts +++ /dev/null @@ -1,198 +0,0 @@ -// Licensed 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 { Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { BehaviorSubject } from 'rxjs'; -import { filter, tap } from 'rxjs/operators'; -import { EventHelper } from '@app/adwp'; - -import { openClose } from '@app/core/animations'; -import { clearEmptyField, Host, Provider } from '@app/core/types'; -import { ActionsDirective } from '../components/actions/actions.directive'; -import { AddService } from './add.service'; -import { BaseFormDirective } from './base-form.directive'; -import { DisplayMode } from './provider.component'; -import { ICluster } from '@app/models/cluster'; - -@Component({ - selector: 'app-add-host', - template: ` - -
- - - ... - {{ p.name }} - - - - Hostprovider is required. If no hostprovider is available, add it here. - - -
- -
- -
- - - -
- - - - Fully qualified domain name is required - -
- - -
- - - ... - {{ c.name }} - - -
- -
-
- `, - styles: [ - ':host {display: block; margin-top: 10px;}', - '.inner {overflow: hidden; margin: 0 -6px;}', - '.inner app-add-provider {padding: 10px 24px; background-color: #4e4e4e;display:block;}', - '.row {display: flex;}', - ], - providers: [ActionsDirective], - animations: [openClose], -}) -export class HostComponent extends BaseFormDirective implements OnInit { - @Input() displayMode: DisplayMode = DisplayMode.default; - @Output() event = new EventEmitter(); - - @HostListener('keyup') changes() { - this.form.markAllAsTouched(); - } - - providers$ = new BehaviorSubject>([]); - clusters$ = new BehaviorSubject[]>([]); - expanded = false; - createdProviderId: number; - - pageCluster = 1; - pageProvider = 1; - limit = 10; - - constructor(private action: ActionsDirective, service: AddService, dialog: MatDialog) { - super(service, dialog); - } - - ngOnInit() { - this.form = this.service.model('host').form; - this.getProviders(); - this.getClusters(); - this.form - .get('provider_id') - .valueChanges.pipe( - this.takeUntil(), - filter((a) => a) - ) - .subscribe((value) => this.checkAction(+value)); - } - - isError(name: string) { - const fi = this.form.get(name); - return fi.invalid && (fi.dirty || fi.touched); - } - - showHostproviderForm(e: MouseEvent) { - EventHelper.stopPropagation(e); - this.expanded = !this.expanded; - this.form.get('provider_id').setValue(''); - } - - checkAction(provider_id: number) { - const ACTION_NAME = 'create_host'; - const provider = this.providers$.getValue().find((a) => a.id === provider_id); - - if (provider && provider.actions) { - const actions = provider.actions.filter((a) => a.button === ACTION_NAME); - if (actions && actions?.length) { - this.action.inputData = { actions }; - this.onCancel(); - this.action.onClick(); - } - } - } - - save() { - const data = clearEmptyField(this.form.value) as Host; - if (this.displayMode !== 0) data.cluster_id = this.service.Cluster?.id; - this.service - .addHost(data) - .pipe( - this.takeUntil(), - tap(() => this.form.controls['fqdn'].setValue('')) - ) - .subscribe((a) => this.event.emit(`Host [ ${a.fqdn} ] has been added successfully.`)); - } - - createdProvider(id: number) { - this.expanded = false; - this.service - .getList('provider', { limit: this.limit, page: this.pageProvider - 1 }) - .pipe(tap((_) => this.form.get('provider_id').setValue(id))) - .subscribe((list) => this.providers$.next(list)); - } - - getNextPageClusters() { - const count = this.clusters$.getValue()?.length; - if (count === this.pageCluster * this.limit) { - this.pageCluster++; - this.getClusters(); - } - } - - getNextPageProvider() { - const count = this.providers$.getValue()?.length; - if (count === this.pageProvider * this.limit) { - this.pageProvider++; - this.getProviders(); - } - } - - getProviders() { - this.service - .getList('provider', { limit: this.limit, page: this.pageProvider - 1 }) - .pipe(tap((list) => this.form.get('provider_id').setValue(list.length === 1 ? list[0].id : ''))) - .subscribe((list) => this.providers$.next([...this.providers$.getValue(), ...list])); - if (this.form.get('provider_id').value) this.expanded = false; - } - - getClusters() { - this.service - .getList('cluster', { limit: this.limit, page: this.pageCluster - 1 }) - .subscribe((list) => this.clusters$.next([...this.clusters$.getValue(), ...list])); - } -} diff --git a/web/src/app/shared/add-component/host2cluster.component.scss b/web/src/app/shared/add-component/host2cluster.component.scss deleted file mode 100644 index 8246121389..0000000000 --- a/web/src/app/shared/add-component/host2cluster.component.scss +++ /dev/null @@ -1,22 +0,0 @@ -.add-host2cluster { - flex: 1; -} - -.tools { - display: flex; - width: 100%; - align-items: center; - flex: 0 0 45px; - padding: 0 16px; - box-sizing: border-box; - - > .text { - display: flex; - width: 100%; - } - - > .actions { - display: flex; - align-items: center; - } -} diff --git a/web/src/app/shared/add-component/host2cluster.component.ts b/web/src/app/shared/add-component/host2cluster.component.ts deleted file mode 100644 index c9d16642e2..0000000000 --- a/web/src/app/shared/add-component/host2cluster.component.ts +++ /dev/null @@ -1,162 +0,0 @@ -// Licensed 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 { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; -import { MatCheckbox } from '@angular/material/checkbox'; -import { MatSelectionList, MatSelectionListChange } from '@angular/material/list'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; -import { openClose } from '@app/core/animations'; -import { Host } from '@app/core/types'; -import { BaseFormDirective } from './base-form.directive'; -import { HostComponent } from './host.component'; -import { DisplayMode } from './provider.component'; -import { ICluster } from "@app/models/cluster"; -import { tap } from "rxjs/operators"; - -@Component({ - selector: 'app-add-host2cluster', - template: ` -
- - -
- -
-
-
All
-
- -   - -
-
- - - {{ host.fqdn }} - - - - -
- `, - styleUrls: ['host2cluster.component.scss'], - animations: [openClose], -}) -export class Host2clusterComponent extends BaseFormDirective implements OnInit, OnDestroy { - list: Host[] = []; - showForm = false; - Count = 0; - displayMode: DisplayMode = DisplayMode.default; - @Input() clusterId: number; - @Output() event = new EventEmitter(); - @ViewChild('form') hostForm: HostComponent; - @ViewChild('listHosts') listHosts: MatSelectionList; - @ViewChild('cb') allCbx: MatCheckbox; - @ViewChild(MatPaginator) paginator: MatPaginator; - - selected: { [key: number]: boolean } = {}; - - get disabled() { - return !Object.keys(this.selected)?.length; - } - - ngOnInit() { - if (!this.service.Cluster) { - const cluster$ = this.service['api'].getOne('cluster', this.clusterId); - cluster$.pipe( - tap((cluster: ICluster) => (this.service['cluster'].Cluster = cluster)) - ).subscribe(() => this.getAvailableHosts()); - } else { - this.getAvailableHosts(); - } - } - - getAvailableHosts(pageIndex = 0, pageSize = 10) { - this.service - .getListResults('host', { limit: pageSize, page: pageIndex, cluster_is_null: 'true' }) - .pipe(this.takeUntil()) - .subscribe((r) => { - this.Count = r.count; - this.showForm = !r.count; - this.displayMode = r.count > 0 ? 2 : 1; - this.list = r.results; - if (this.listHosts?.options?.length) this.allCbx.checked = false; - }); - } - - selectAllHost(flag: boolean) { - if (!flag) { - this.listHosts.selectAll(); - this.listHosts.options.forEach((o) => { - this.selected[o.value] = true; - }); - } else { - this.listHosts.deselectAll(); - this.listHosts.options.forEach((o) => { - if (this.selected[o.value]) { - delete this.selected[o.value]; - } - }); - } - } - - save() { - if (this.hostForm.form.valid) { - const host = this.hostForm?.form?.value; - host.cluster_id = this.service?.Cluster?.id || this.clusterId; - this.service - .addHost(host) - .pipe(this.takeUntil()) - .subscribe((a) => { - this.hostForm.form.controls['fqdn'].setValue(''); - this.event.emit(`Host [ ${a.fqdn} ] has been added successfully.`); - }); - } - } - - addHost2Cluster() { - const value = Object.keys(this.selected); - - this.service - .addHostInCluster(value.map((a) => +a)) - .pipe(this.takeUntil()) - .subscribe(() => { - this.paginator.firstPage(); - this.getAvailableHosts(); - }); - } - - pageHandler(pageEvent: PageEvent) { - this.getAvailableHosts(pageEvent.pageIndex, pageEvent.pageSize); - } - - selectionChange(e: MatSelectionListChange): void { - const value = e.option.value; - if (this.selected[value]) { - delete this.selected[value]; - } else { - this.selected[value] = true; - } - } -} diff --git a/web/src/app/shared/add-component/index.ts b/web/src/app/shared/add-component/index.ts deleted file mode 100644 index bb42c423dc..0000000000 --- a/web/src/app/shared/add-component/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed 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 * from './add-button.component'; -export * from './add-form.component'; -export * from './base-form.directive'; -export * from './add-cluster.component'; -export * from './host.component'; -export * from './host2cluster.component'; -export * from './provider.component'; -export * from './service.component'; diff --git a/web/src/app/shared/add-component/interfaces/relation-list.ts b/web/src/app/shared/add-component/interfaces/relation-list.ts deleted file mode 100644 index 152bff6163..0000000000 --- a/web/src/app/shared/add-component/interfaces/relation-list.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Observable } from 'rxjs'; - -export interface RelationList { - [key: string]: Observable; -} diff --git a/web/src/app/shared/add-component/naming.ts b/web/src/app/shared/add-component/naming.ts deleted file mode 100644 index 9fb6a32465..0000000000 --- a/web/src/app/shared/add-component/naming.ts +++ /dev/null @@ -1,97 +0,0 @@ -// Licensed 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 { randomInteger } from '@app/core/types/func'; - -const rivers: string[] = [ - 'Amur', - 'Anadyr', - 'Angara', - 'Colorado', - 'Congo', - 'Desna', - 'Dnieper', - 'Don', - 'Irtysh', - 'Kama', - 'Limpopo', - 'Mekong', - 'Mississippi', - 'Nile', - 'Ob', - 'Oka', - 'Pechora', - 'Rhine', - 'Ural', - 'Volga', - 'Yangtze', - 'Yenisei', - 'Yukon', - 'Zambezi', -]; - -const adjectives: string[] = [ - 'Ancient', - 'Beautiful', - 'Big', - 'Blue', - 'Broad', - 'Clear', - 'Cold', - 'Dark', - 'Deep', - 'Distant', - 'Down', - 'Dry', - 'Famous', - 'Fear', - 'Flowing', - 'Frozen', - 'Great', - 'Holy', - 'Huge', - 'Icy', - 'Large', - 'Latter', - 'Longest', - 'Lovely', - 'Lower', - 'Mad', - 'Magnificent', - 'Majestic', - 'Middle', - 'Mighty', - 'Muddy', - 'Narrow', - 'Noble', - 'North', - 'Placid', - 'Polluted', - 'Quiet', - 'Rapid', - 'Sacred', - 'Shallow', - 'Slow', - 'Sluggish', - 'Small', - 'Swift', - 'Tidal', - 'Tributary', - 'Turbulent', - 'Wide', - 'Wild', -]; - -export class GenName { - public static do(prefix: string = '') { - return `${adjectives[randomInteger(adjectives.length - 1)]} ${rivers[randomInteger(rivers.length - 1)]}${prefix}`; - } -} diff --git a/web/src/app/shared/add-component/provider.component.ts b/web/src/app/shared/add-component/provider.component.ts deleted file mode 100644 index f3b42cb22e..0000000000 --- a/web/src/app/shared/add-component/provider.component.ts +++ /dev/null @@ -1,81 +0,0 @@ -// Licensed 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 { Component, Input, OnInit, EventEmitter, Output, OnDestroy } from '@angular/core'; -import { Subscription } from 'rxjs'; - -import { clearEmptyField, Provider, StackBase } from '@app/core/types'; -import { BaseFormDirective } from './base-form.directive'; - -export enum DisplayMode { - default, - inHost, - noCluster -} - -@Component({ - selector: 'app-add-provider', - template: ` - - - - - - - - -
- - - - Hostprovider name is required - -
-
-
- `, - styles: ['.row {display: flex;}'], -}) -export class ProviderComponent extends BaseFormDirective implements OnInit, OnDestroy { - sgn: Subscription; - private prototype: StackBase; - @Input() displayMode: DisplayMode = DisplayMode.default; - @Output() cancel = new EventEmitter(); - - ngOnInit() { - this.form = this.service.model('provider').form; - this.sgn = this.service.genName(this.form); - } - - ngOnDestroy() { - this.sgn.unsubscribe(); - } - - prototypeChanged(event: StackBase) { - this.prototype = event; - } - - save() { - const data = clearEmptyField(this.form.value); - this.service - .add(data, 'provider', this.prototype) - .pipe(this.takeUntil()) - .subscribe((x) => { - if (this.displayMode === 0) this.onCancel(); - else { - this.form.reset(); - this.cancel.emit(x.id); - } - }); - } -} diff --git a/web/src/app/shared/add-component/rbac-form.directive.ts b/web/src/app/shared/add-component/rbac-form.directive.ts deleted file mode 100644 index 061bccdcee..0000000000 --- a/web/src/app/shared/add-component/rbac-form.directive.ts +++ /dev/null @@ -1,73 +0,0 @@ -// Licensed 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 { Directive, Input, OnInit } from '@angular/core'; -import { clearEmptyField } from '@app/core/types'; -import { BaseFormDirective } from '@app/shared/add-component/base-form.directive'; -import { take } from 'rxjs/operators'; -import { Params } from '@angular/router'; -import { IConfig } from "@app/shared/configuration/types"; -import { FormGroup } from '@angular/forms'; - -@Directive({ - selector: '[appRbacForm]', -}) -export class RbacFormDirective extends BaseFormDirective implements OnInit { - @Input() - value: T; - - filter: Params = {}; - - get title(): string { - return this.value ? 'Update' : 'Add'; - } - - ngOnInit(): void { - if (this.value) { - // ToDo(lihih) the "adwp-list" should not change the composition of the original model. - // Now he adds the "checked" key to the model - const formValue = { ...this.value }; - Object.keys(formValue).forEach((prop) => { - if (!this.form.controls.hasOwnProperty(prop)) delete formValue[prop]; - }) - this.form.setValue(formValue); - } - } - - rbacBeforeSave(form: FormGroup): Partial { - return form.value; - } - - save(): void { - const data = clearEmptyField(this.rbacBeforeSave(this.form)); - - if (this.value) { - this.service - .update(this.value.url, data) - .pipe(take(1)) - .subscribe((_) => this.onCancel()); - } else { - this.service - .add(data) - .pipe(take(1)) - .subscribe((_) => this.onCancel()); - } - } - - updateFilter(key: string, value: string): void { - this.filter = { ...this.filter, [key]: value?.trim() }; - } - - getGlobalSettings() { - return this.api.get('/api/v1/adcm/1/config/current/?noview') - } - -} diff --git a/web/src/app/shared/add-component/service.component.ts b/web/src/app/shared/add-component/service.component.ts deleted file mode 100644 index 9c40f0ada2..0000000000 --- a/web/src/app/shared/add-component/service.component.ts +++ /dev/null @@ -1,153 +0,0 @@ -// Licensed 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 { Component, OnInit, ViewChild } from '@angular/core'; -import { MatSelectionList, MatSelectionListChange } from '@angular/material/list'; -import { SelectOption } from '@app/core/types'; -import { Observable, of } from 'rxjs'; -import { BaseFormDirective } from './base-form.directive'; -import { filter, finalize, switchMap } from "rxjs/operators"; -import { DialogComponent } from '../components/dialog.component'; -import { DependenciesComponent } from '../host-components-map/dependencies.component'; - -@Component({ - selector: 'app-add-service', - template: ` - - - All - - {{ proto.name }} - - - - - -

- - There are no new services. Your cluster already has all of them. - -

-
- ` -}) -export class ServiceComponent extends BaseFormDirective implements OnInit { - options: SelectOption[]; - addedServices: any[] = []; - addedRequires: any[] = []; - - @ViewChild('listServices') - private listServices: MatSelectionList; - - ngOnInit() { - this.service.getProtoServiceForCurrentCluster() - .subscribe((options) => { - this.options = options - }); - } - - - selectAll(e: MatSelectionListChange) { - if (!e.option.value) { - if (e.option.selected) this.listServices.selectAll(); - else this.listServices.deselectAll(); - } - } - - addServiceToList(services, unshift?: boolean) { - if (!services?.length || services?.length === 0) return; - - services.forEach((service) => { - const selectedService = this.options.filter((option: any) => option?.id === service)[0] as any; - - if (!selectedService) return; - - if (unshift) { - if (!this.addedRequires?.find((options) => selectedService?.id === options?.id)) { - this.addedRequires.unshift(selectedService); - } - } else { - if (!this.addedServices?.find((options) => selectedService?.id === options?.id)) { - this.addedServices.push(selectedService); - } - } - - if (selectedService?.requires?.length > 0) { - this.addServiceToList(selectedService.requires.map((require) => require.prototype_id), true); - } - }) - - } - - buildServicesList() { - const selected = this.listServices.selectedOptions.selected.filter(a => a.value).map((service) => service.value.id); - - this.addServiceToList(selected); - - this.addedRequires = this.addedRequires.filter((service) => { - return !this.addedServices.includes(service); - } ); - - return selected; - } - - requestApprove(requires) { - if (requires.length === 0) return of(true); - - return this.dialog - .open(DialogComponent, { - data: { - title: 'This service cannot be added without the following dependencies.', - component: DependenciesComponent, - model: requires.sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true })), - controls: ['Add All', 'Cancel'], - }, - }) - .beforeClosed() - .pipe( - filter((a) => a), - switchMap(() =>{ - return of(true) - }) - ) - } - - save() { - const selectedServices = this.buildServicesList(); - - if (selectedServices.length === 0) { - this.dialog.closeAll(); - return; - } - - const result = [...this.addedRequires, ...this.addedServices]?.map((options) => ({ - prototype_id: +options.id, - service_name: options.name, - license: options.license, - license_url: options.license_url, - })) - - this.requestApprove(this.addedRequires) - .pipe( - finalize(() => { - this.addedServices = this.addedServices.filter((service) => service.prototype_id); - this.addedRequires = [] - }) - ) - .subscribe(() => { - this.service - .addServiceInCluster(result) - .pipe( - finalize(() => this.dialog.closeAll())) - .subscribe(); - }) - } -} diff --git a/web/src/app/shared/components/actions/action-list/action-list.component.html b/web/src/app/shared/components/actions/action-list/action-list.component.html deleted file mode 100644 index 780bb0cae7..0000000000 --- a/web/src/app/shared/components/actions/action-list/action-list.component.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - diff --git a/web/src/app/shared/components/actions/action-list/action-list.component.scss b/web/src/app/shared/components/actions/action-list/action-list.component.scss deleted file mode 100644 index eb4bd276c4..0000000000 --- a/web/src/app/shared/components/actions/action-list/action-list.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -::ng-deep .crumbs-action-button { - app-action-list { - mat-icon { - margin-bottom: 5px; - } - } -} diff --git a/web/src/app/shared/components/actions/action-list/action-list.component.spec.ts b/web/src/app/shared/components/actions/action-list/action-list.component.spec.ts deleted file mode 100644 index 31b58a7ec3..0000000000 --- a/web/src/app/shared/components/actions/action-list/action-list.component.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed 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 { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatIconModule } from '@angular/material/icon'; -import { MatMenuModule } from '@angular/material/menu'; - -import { ApiService } from '../../../../core/api/api.service'; -import { ActionListComponent } from './action-list.component'; -import { MenuItemComponent } from './menu-item/menu-item.component'; - -describe('ActionListComponent', () => { - let component: ActionListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - TestBed.configureTestingModule({ - imports: [MatMenuModule, MatIconModule], - providers: [{ provide: ApiService, useValue: {} }], - declarations: [ActionListComponent, MenuItemComponent], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ActionListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/components/actions/action-list/action-list.component.ts b/web/src/app/shared/components/actions/action-list/action-list.component.ts deleted file mode 100644 index 5a95874085..0000000000 --- a/web/src/app/shared/components/actions/action-list/action-list.component.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed 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 { Component, Input } from '@angular/core'; -import { IAction } from '@app/core/types'; -import { Observable } from 'rxjs'; - -import { ActionsService } from '../actions.service'; - -@Component({ - selector: 'app-action-list', - templateUrl: './action-list.component.html', - styleUrls: ['./action-list.component.scss'] -}) -export class ActionListComponent { - @Input() cluster: { id: number; hostcomponent: string }; - @Input() disabled: boolean; - @Input() asButton = false; - @Input() actionLink: string; - @Input() state: string; - - /** - * @deprecated in the fight against caching - */ - @Input() actions = []; - - actions$: Observable; - - constructor(private service: ActionsService) {} - - getData(): void { - // if (!this.actions.length) ADCM-1505 it's possible cache after finished job - this.actions$ = this.service.getActions(this.actionLink); //.subscribe((a) => (this.actions = a)); - } -} diff --git a/web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.scss b/web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.scss deleted file mode 100644 index 6c5c741c33..0000000000 --- a/web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -.mat-menu-item-submenu-trigger::after { - left: 6px; - transform: rotate(180deg) translateY(50%); -} diff --git a/web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.spec.ts b/web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.spec.ts deleted file mode 100644 index e288a3c321..0000000000 --- a/web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed 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 { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatMenuModule } from '@angular/material/menu'; - -import { ApiService } from '../../../../../core/api/api.service'; -import { MenuItemComponent } from './menu-item.component'; - -describe('MenuItemComponent', () => { - let component: MenuItemComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - TestBed.configureTestingModule({ - imports: [MatMenuModule], - declarations: [MenuItemComponent], - providers: [{ provide: ApiService, useValue: {} }], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(MenuItemComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.ts b/web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.ts deleted file mode 100644 index eff5ceb4c4..0000000000 --- a/web/src/app/shared/components/actions/action-list/menu-item/menu-item.component.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed 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 { Component, Input, ViewChild } from '@angular/core'; -import { IAction } from '@app/core/types/actions'; -import { MatMenu } from '@angular/material/menu'; - -@Component({ - selector: 'app-menu-item', - styleUrls: ['./menu-item.component.scss'], - template: ` -
- No actions -
- - -
- -
- - - - -
-
-
`, -}) -export class MenuItemComponent { - @Input() items: IAction[] = []; - @Input() cluster: { id: number; hostcomponent: string }; - @ViewChild('menu', { static: true }) menu: MatMenu; -} diff --git a/web/src/app/shared/components/actions/actions.component.scss b/web/src/app/shared/components/actions/actions.component.scss deleted file mode 100644 index f5573b382e..0000000000 --- a/web/src/app/shared/components/actions/actions.component.scss +++ /dev/null @@ -1,24 +0,0 @@ -:host { - display: flex; - overflow: hidden; - width: 100%; - justify-content: flex-end; - - & > div { - overflow: hidden; - margin-top: 4px; - } -} - -.button-more { - display: none; -} - -.menu-more-action { - display: block; - margin: 4px; -} - -button { - margin-left: 10px; -} diff --git a/web/src/app/shared/components/actions/actions.component.spec.ts b/web/src/app/shared/components/actions/actions.component.spec.ts deleted file mode 100644 index 5570616a7e..0000000000 --- a/web/src/app/shared/components/actions/actions.component.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed 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 { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MaterialModule } from '@app/shared/material.module'; - -import { ActionsComponent } from './actions.component'; - -describe('ActionsComponent', () => { - let component: ActionsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - TestBed.configureTestingModule({ - imports: [MaterialModule], - declarations: [ActionsComponent] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ActionsComponent); - component = fixture.componentInstance; - component.source = []; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('Func `calcWidth` when the width of the window is greater than the buttons width sum', () => { - const arr = [40, 30, 60]; - const result = component.calcWidth(1200, arr); - expect(result).toEqual([arr?.length, 130, false]); - }); - - it('Func `calcWidth` when the width of the window is less than the buttons width sum', () => { - const result = component.calcWidth(1189, [132, 157, 292, 101, 169, 123, 133, 124, 76, 146, 74]); - expect(result).toEqual([7, 1107, true]); - - const result2 = component.calcWidth(1240, [132, 157, 292, 101, 169, 123, 133, 124, 76, 146, 74]); - expect(result2).toEqual([8, 1231, true]); - - const result3 = component.calcWidth(1305, [132, 157, 292, 101, 169, 123, 133, 124, 76, 146, 74]); - expect(result3).toEqual([8, 1231, true]); - - const result4 = component.calcWidth(1310, [132, 157, 292, 101, 169, 123, 133, 124, 76, 146, 74]); - expect(result4).toEqual([9, 1307, true]); - - // 1307 + 76 - const result5 = component.calcWidth(1390, [132, 157, 292, 101, 169, 123, 133, 124, 76, 146, 74]); - expect(result5).toEqual([9, 1307, true]); - }); -}); diff --git a/web/src/app/shared/components/actions/actions.component.ts b/web/src/app/shared/components/actions/actions.component.ts deleted file mode 100644 index 64778ef990..0000000000 --- a/web/src/app/shared/components/actions/actions.component.ts +++ /dev/null @@ -1,109 +0,0 @@ -// Licensed 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 { AfterViewChecked, Component, ElementRef, Input, OnInit, QueryList, Renderer2, ViewChild, ViewChildren } from '@angular/core'; -import { MatMenuTrigger } from '@angular/material/menu'; -import { IAction } from '@app/core/types'; -import { fromEvent } from 'rxjs'; -import { debounceTime, tap } from 'rxjs/operators'; - -import { BaseDirective } from '../../directives/base.directive'; - -@Component({ - selector: 'app-actions', - template: ` -
- -
- - - - - `, - styleUrls: ['./actions.component.scss'], -}) -export class ActionsComponent extends BaseDirective implements OnInit, AfterViewChecked { - actions: IAction[] = []; - - @Input() isIssue: boolean; - @Input() cluster: { id: number; hostcomponent: string }; - @Input() set source(actions: IAction[]) { - this.actions = actions; - if (!actions?.length) this.render.setStyle(this.more.nativeElement, 'display', 'none'); - } - - stateButtons = 0; - forMenu: IAction[] = []; - - @ViewChild('wrap', { read: ElementRef, static: true }) wrap: ElementRef; - @ViewChild('more', { read: ElementRef, static: true }) more: ElementRef; - @ViewChildren('button', { read: ElementRef }) buttons: QueryList; - @ViewChild(MatMenuTrigger, { static: true }) trigger: MatMenuTrigger; - - constructor(private render: Renderer2, private el: ElementRef) { - super(); - } - - ngOnInit() { - fromEvent(window, 'resize') - .pipe( - this.takeUntil(), - tap(() => this.trigger.closeMenu()), - debounceTime(500) - ) - .subscribe(() => this.onresize()); - } - - ngAfterViewChecked(): void { - if (this.stateButtons !== this.buttons?.length) { - this.stateButtons = this.buttons?.length; - setTimeout(() => this.onresize(), 0); - } - } - - onresize() { - const bw = this.buttons.map((b) => b.nativeElement.offsetWidth + 10); - const elWidth = +this.el.nativeElement.clientWidth - 50; - const dw = this.calcWidth(elWidth, bw); - // - this.forMenu = this.actions.slice(dw[0]); - this.render.setStyle(this.wrap.nativeElement, 'width', `${dw[1]}px`); - this.render.setStyle(this.more.nativeElement, 'display', dw[2] ? 'block' : 'none'); - } - - calcWidth(w: number, bw: number[]): [number, number, boolean] { - return bw.reduce((p, c, i) => (p[2] || p[1] + c > w ? [p[0], p[1], true] : [i + 1, p[1] + c, false]), [0, 0, false]); - } -} diff --git a/web/src/app/shared/components/actions/actions.directive.spec.ts b/web/src/app/shared/components/actions/actions.directive.spec.ts deleted file mode 100644 index dc8379b039..0000000000 --- a/web/src/app/shared/components/actions/actions.directive.spec.ts +++ /dev/null @@ -1,93 +0,0 @@ -// Licensed 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 { Component, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatDialogModule } from '@angular/material/dialog'; -import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ApiService } from '@app/core/api'; -import { FieldService } from '@app/shared/configuration/services/field.service'; - -import { ActionParameters, ActionsDirective } from './actions.directive'; -import { ActionMasterComponent } from '@app/shared/components'; - -const TestParams: ActionParameters = { - cluster: { id: 1, hostcomponent: '' }, - actions: [ - { - name: 'test', - description: '', - display_name: 'display_name_test', - start_impossible_reason: null, - run: 'url', - config: null, - hostcomponentmap: null, - button: null, - ui_options: null, - }, - ], -}; - -@Component({ - template: '', -}) -class TestComponent { - testParams: ActionParameters; -} - -describe('ActionsDirective', () => { - let fixture: ComponentFixture; - let component: TestComponent; - let de: DebugElement; - let directive: ActionsDirective; - - beforeEach(() => { - fixture = TestBed.configureTestingModule({ - imports: [MatDialogModule, NoopAnimationsModule], - declarations: [TestComponent, ActionsDirective], - providers: [ActionsDirective, { provide: ApiService, useValue: {} }, { provide: FieldService, useValue: {} }], - schemas: [NO_ERRORS_SCHEMA], - }).createComponent(TestComponent); - - component = fixture.componentInstance; - component.testParams = TestParams; - de = fixture.debugElement.query(By.directive(ActionsDirective)); - directive = de.injector.get(ActionsDirective); - fixture.detectChanges(); - }); - - it('should show dialog with error message', () => { - directive.inputData = { actions: [] /* undefined */ }; - de.triggerEventHandler('click', {}); - fixture.detectChanges(); - const result = directive.prepare(); - expect(result).toEqual({ - data: { title: 'No parameters for run the action', model: null, component: null }, - }); - }); - - it('should show empty dialog with action parameters', () => { - directive.inputData = TestParams; - de.triggerEventHandler('click', {}); - fixture.detectChanges(); - const result = directive.prepare(); - expect(result).toEqual({ - width: '400px', - maxWidth: '1400px', - data: { - title: 'Run an action [ display_name_test ]?', - model: TestParams, - component: ActionMasterComponent, - }, - }); - }); -}); diff --git a/web/src/app/shared/components/actions/actions.directive.ts b/web/src/app/shared/components/actions/actions.directive.ts deleted file mode 100644 index eeaadbbe01..0000000000 --- a/web/src/app/shared/components/actions/actions.directive.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Licensed 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 { Directive, HostListener, Input } from '@angular/core'; -import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; -import { IAction } from '@app/core/types'; - -import { DialogComponent } from '../dialog.component'; -import { ActionMasterComponent as component } from './master/master.component'; - -export interface ActionParameters { - cluster?: { - id: number; - hostcomponent: string; - }; - actions: IAction[]; -} - -@Directive({ - selector: '[appActions]' -}) -export class ActionsDirective { - @Input('appActions') inputData: ActionParameters; - - constructor(private dialog: MatDialog) {} - - @HostListener('click') - onClick() { - this.dialog.closeAll(); - const dialogModel: MatDialogConfig = this.prepare(); - this.dialog.open(DialogComponent, dialogModel); - } - - prepare(): MatDialogConfig { - const maxWidth = '1400px'; - const model = this.inputData; - - if (!model.actions?.length) return { data: { title: 'No parameters for run the action', model: null, component: null } }; - - const act = model.actions[0]; - const isMulty = model.actions?.length > 1; - - const width = isMulty || act.config?.config?.length || act.hostcomponentmap?.length ? '90%' : '400px'; - const title = act.ui_options?.disclaimer ? act.ui_options.disclaimer : isMulty ? 'Run actions?' : `Run an action [ ${act.display_name} ]?`; - - return { - width, - maxWidth, - data: { - title, - model, - component, - } - }; - } -} diff --git a/web/src/app/shared/components/actions/actions.service.spec.ts b/web/src/app/shared/components/actions/actions.service.spec.ts deleted file mode 100644 index ccfdf9a92d..0000000000 --- a/web/src/app/shared/components/actions/actions.service.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed 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 { TestBed } from '@angular/core/testing'; -import { ApiService } from '@app/core/api/api.service'; - -import { ActionsService } from './actions.service'; - -describe('ActionsService', () => { - let service: ActionsService; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{provide: ApiService, useValue: {}}] - }); - service = TestBed.inject(ActionsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/components/actions/actions.service.ts b/web/src/app/shared/components/actions/actions.service.ts deleted file mode 100644 index 64e9e895be..0000000000 --- a/web/src/app/shared/components/actions/actions.service.ts +++ /dev/null @@ -1,57 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { ApiService } from '@app/core/api'; - -// export const fruit = { -// display_name: 'Fruit', -// desctiption: 'fruit description', -// children: [ -// { display_name: 'Apple', description: 'description or some description about this action description or some description about this action' }, -// { display_name: 'Banana', description: 'description or some description about this action bannana' }, -// { display_name: 'Fruit loops', description: '' }, -// ], -// }; - -// export const vegetable = { -// display_name: 'Vegetables', -// desctiption: 'description or some description about this action some description about this action Vegetables', -// children: [ -// { -// display_name: 'Green', -// description: 'description or some description about this action description or some description about this action', -// children: [ -// { display_name: 'Broccoli', description: 'description or some description about this action description or some description about this action' }, -// { display_name: 'Brussels sprouts', description: 'description or some description about this action bannana' }, -// ], -// }, -// { -// display_name: 'Orange', -// description: 'description or some description about this action bannana', -// children: [ -// { display_name: 'Pumpkins', description: 'description or some description about this action description or some description about this action' }, -// { display_name: 'Carrots', description: 'description or some description about this action bannana' }, -// ], -// }, -// ], -// }; - -@Injectable({ - providedIn: 'root', -}) -export class ActionsService { - constructor(private api: ApiService) {} - - getActions(url: string) { - return this.api.get(url); //.pipe(map((a) => [fruit, vegetable, ...a])); - } -} diff --git a/web/src/app/shared/components/actions/master/action-master-config.component.ts b/web/src/app/shared/components/actions/master/action-master-config.component.ts deleted file mode 100644 index a5eaacf8f2..0000000000 --- a/web/src/app/shared/components/actions/master/action-master-config.component.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed 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 { Component, Input, ViewChild } from '@angular/core'; -import { IAction } from '@app/core/types'; -import { FieldService } from '@app/shared/configuration/services/field.service'; -import { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component'; - -@Component({ - selector: 'app-action-master-config', - template: ` -
- Advanced -
- - `, -}) -export class ActionMasterConfigComponent { - @Input() action: IAction; - - @ViewChild('fields') fields: ConfigFieldsComponent = {} as ConfigFieldsComponent; - - set advanced(value: boolean) { - this.config.filterApply(this.fields.dataOptions, { advanced: value, search: '' }); - } - - constructor(private config: FieldService) {} -} diff --git a/web/src/app/shared/components/actions/master/master.component.html b/web/src/app/shared/components/actions/master/master.component.html deleted file mode 100644 index d1180fca03..0000000000 --- a/web/src/app/shared/components/actions/master/master.component.html +++ /dev/null @@ -1,69 +0,0 @@ - -

No data for the action!

-
- - - Let's choose first - - - -

-
- - -
- -
- -
- - -
- -
- - -
- - - - Configuration - -
- - -
-
- - Host Components - - - - - -
- -
- - -
- - Verbose - -
- - - - - - - -
- -
-
diff --git a/web/src/app/shared/components/actions/master/master.component.spec.ts b/web/src/app/shared/components/actions/master/master.component.spec.ts deleted file mode 100644 index cd6692e549..0000000000 --- a/web/src/app/shared/components/actions/master/master.component.spec.ts +++ /dev/null @@ -1,225 +0,0 @@ -// Licensed 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 { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { MatListModule } from '@angular/material/list'; -import { ApiService } from '@app/core/api/api.service'; -import { FieldService } from '@app/shared/configuration/services/field.service'; -import { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component'; -import { ServiceHostComponent } from '@app/shared/host-components-map/services2hosts/service-host.component'; - -import { ActionMasterConfigComponent } from './action-master-config.component'; -import { ActionMasterComponent as MasterComponent } from './master.component'; -import { MasterService } from './master.service'; - -describe('MasterComponent', () => { - let component: MasterComponent; - let fixture: ComponentFixture; - - let ApiServiceStub: Partial; - let FieldServiceStub: Partial; - - beforeEach(async () => { - ApiServiceStub = {}; - FieldServiceStub = new FieldService({} as FormBuilder); - - TestBed.configureTestingModule({ - imports: [MatListModule], - declarations: [MasterComponent, ActionMasterConfigComponent], - providers: [MasterService, { provide: ApiService, useValue: ApiServiceStub }, { provide: FieldService, useValue: FieldServiceStub }], - schemas: [NO_ERRORS_SCHEMA] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(MasterComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('input data for model property must be defined', () => { - component.model = { actions: [] }; - fixture.detectChanges(); - expect(component.model).toBeDefined(); - }); - - it('input data for model.actons property must be array', () => { - component.model = { actions: [] }; - fixture.detectChanges(); - expect(component.model.actions).toBeDefined(); - expect(component.model.actions).toEqual(jasmine.any(Array)); - }); - - it('should be show template if model.actions.length === 0', () => { - component.model = { actions: [] }; - fixture.detectChanges(); - const compHost: HTMLElement = fixture.debugElement.nativeElement; - expect(compHost.querySelector('p').textContent).toBe('No data for the action!'); - }); - - it('should be show template for current action if model.actions.length === 1 and config = null and host-map = null', () => { - component.model = { - actions: [{ name: 'a1', description: '', display_name: 'display a1', start_impossible_reason: null, run: 'url a1', ui_options: null, config: null, hostcomponentmap: null, button: null }] - }; - fixture.detectChanges(); - const compHost: HTMLElement = fixture.debugElement.nativeElement; - const cancelButton = compHost.querySelector('button[color="primary"]'); - expect(cancelButton).toBeTruthy(); - expect(cancelButton.textContent).toContain('Cancel'); - const runButton = compHost.querySelector('button[color="accent"]'); - expect(runButton).toBeTruthy(); - expect(runButton.textContent).toContain('Run'); - }); - - it('should be show actions list for choose current action if model.actions.length > 1', () => { - component.model = { - actions: [ - { name: 'a1', description: '', display_name: 'display a1', start_impossible_reason: null, run: 'url a1', ui_options: null, config: null, hostcomponentmap: null, button: null }, - { name: 'a2', description: '', display_name: 'display a2', start_impossible_reason: null, run: 'url a2', ui_options: null, config: null, hostcomponentmap: null, button: null } - ] - }; - fixture.detectChanges(); - const compHost: HTMLElement = fixture.debugElement.nativeElement; - // expect(compHost.querySelector('i').textContent).toBe("Let's choose first"); - const buttonsLength = compHost.querySelector('mat-action-list').getElementsByTagName('button')?.length; - expect(buttonsLength).toBeGreaterThan(1); - }); - - it('should be show template for current action if config exist only', () => { - component.model = { - actions: [ - { - name: 'a1', - description: '', - display_name: 'display a1', - start_impossible_reason: null, - run: 'url a1', - ui_options: null, - config: { - config: [ - { - type: 'string', - name: 'test', - display_name: 'display name test', - subname: '', - default: null, - value: null, - required: false, - description: '', - read_only: false, - activatable: false, - group_config: null, - } - ] - }, - hostcomponentmap: null, - button: null - } - ] - }; - fixture.detectChanges(); - const de = fixture.debugElement.nativeElement; - const config = de.querySelector('app-action-master-config'); - const hm = de.querySelector('app-service-host'); - expect(hm).toBeNull(); - expect(config).toBeTruthy(); - }); - - it('should be show template for current action if host-map exist only', () => { - component.model = { - actions: [ - { name: 'a1', description: '', display_name: 'display a1', start_impossible_reason: null, run: 'url a1', ui_options: null, config: null, hostcomponentmap: [{ component: '', action: 'add', service: '' }], button: null } - ] - }; - fixture.detectChanges(); - const de = fixture.debugElement.nativeElement; - const config = de.querySelector('app-action-master-config'); - const hm = de.querySelector('app-service-host'); - expect(config).toBeNull(); - expect(hm).toBeTruthy(); - }); - - it('should be show template for current action with config and host-map', () => { - component.model = { - actions: [ - { - name: 'a1', - description: '', - display_name: 'display a1', - start_impossible_reason: null, - run: 'url a1', - ui_options: null, - config: { - config: [ - { - type: 'string', - name: 'test', - display_name: 'display name test', - subname: '', - default: null, - value: null, - required: false, - description: '', - read_only: false, - activatable: false, - group_config: null, - } - ] - }, - hostcomponentmap: [{ component: '', action: 'add', service: '' }], - button: null - } - ] - }; - fixture.detectChanges(); - const de = fixture.debugElement.nativeElement; - const config = de.querySelector('app-action-master-config'); - const hm = de.querySelector('app-service-host'); - expect(config).toBeTruthy(); - expect(hm).toBeTruthy(); - }); - - it('should be undefined value if ServiceHostComponent ConfigFieldComponent not exist', () => { - const service = fixture.debugElement.injector.get(MasterService); - const result = service.parseData(undefined); - expect(result).toBeUndefined(); - }); - - it('check value when ConfigFieldComponent exist', () => { - const service = fixture.debugElement.injector.get(MasterService); - - const config = { - form: new FormGroup({ string_ctr: new FormControl('string_test'), bool_ctr: new FormControl(true) }), - rawConfig: { - config: [ - { name: 'string_ctr', type: 'string', value: 'string_test' }, - { name: 'bool_ctr', type: 'boolean', value: true } - ] - } - } as ConfigFieldsComponent; - - const result = service.parseData({ config }); - expect(result).toEqual({ config: { string_ctr: 'string_test', bool_ctr: true }, hc: undefined, attr: undefined }); - }); - - it('check value when ServiceHostComponent exist', () => { - const service = fixture.debugElement.injector.get(MasterService); - const hc = [{ host_id: 1, service_id: 4, component_id: 1, id: 9 }]; - const hostmap = { statePost: { data: hc } } as ServiceHostComponent; - const result = service.parseData({ hostmap }); - expect(result).toEqual({ config: undefined, hc, attr: undefined }); - }); -}); diff --git a/web/src/app/shared/components/actions/master/master.component.ts b/web/src/app/shared/components/actions/master/master.component.ts deleted file mode 100644 index 8b23e7f309..0000000000 --- a/web/src/app/shared/components/actions/master/master.component.ts +++ /dev/null @@ -1,89 +0,0 @@ -// Licensed 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 { Component, ElementRef, EventEmitter, OnInit, ViewChild } from '@angular/core'; -import { IAction } from '@app/core/types'; -import { DynamicComponent, DynamicEvent } from '@app/shared/directives/dynamic/dynamic.directive'; - -import { BaseDirective } from '@app/shared/directives'; -import { ActionParameters } from '../actions.directive'; - -import { IMasterData, IValue, MasterService, whatShow } from './master.service'; - -@Component({ - selector: 'app-master', - templateUrl: './master.component.html', - styles: [ - ` - .action-button { - background: none !important; - margin: 6px 0; - - &:hover { - background: rgba(255, 255, 255, 0.04) !important; - } - } - - .controls-container { - display: flex; - justify-content: space-between; - align-items: center; - } - `, - ], - providers: [MasterService], -}) -export class ActionMasterComponent extends BaseDirective implements DynamicComponent, OnInit { - event: EventEmitter = new EventEmitter(); - model: ActionParameters; - action: IAction; - show: whatShow; - - verbose = false; - - @ViewChild('runBtn', { read: ElementRef }) runBtn: ElementRef; - - constructor(private service: MasterService) { - super(); - } - - ngOnInit(): void { - if (this.model?.actions?.length === 1) this.choose(this.model.actions[0]); - } - - choose(action: IAction) { - this.action = action; - this.show = this.service.spotShow(action); - } - - isDisabled(value: IValue) { - return value && ((value.hostmap && value.hostmap.noValid) || (value.config && !value.config.form?.valid)); - } - - run(value: IValue = {}) { - const data: IMasterData = this.service.parseData(value); - if (data) { - data.verbose = this.verbose; - } - this.service - .send(this.action.run, data) - .pipe(this.takeUntil()) - .subscribe(() => this.cancel()); - } - - onEnterKey() { - this.runBtn.nativeElement.click(); - } - - cancel() { - this.event.emit({ name: 'cancel' }); - } -} diff --git a/web/src/app/shared/components/actions/master/master.service.ts b/web/src/app/shared/components/actions/master/master.service.ts deleted file mode 100644 index cfc1f88b50..0000000000 --- a/web/src/app/shared/components/actions/master/master.service.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { ApiService } from '@app/core/api'; -import { IAction } from '@app/core/types'; -import { FieldService } from '@app/shared/configuration/services/field.service'; -import { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component'; -import { ServiceHostComponent } from '@app/shared/host-components-map/services2hosts/service-host.component'; -import { Post } from '@app/shared/host-components-map/types'; -import { IConfigAttr } from '@app/shared/configuration/types'; -import { IOutput } from '@app/shared/configuration/services/field.service'; - -export interface IValue { - config?: ConfigFieldsComponent; - hostmap?: ServiceHostComponent; -} - -export enum whatShow { - none = 'none', - config = 'config', - hostMap = 'hostmap', - stepper = 'stepper', -} - -export interface IMasterData { - attr: IConfigAttr; - config: IOutput; - hc: Post[]; - verbose?: boolean; -} - -@Injectable() -export class MasterService { - constructor(private api: ApiService, private configService: FieldService) {} - - spotShow(action: IAction): whatShow { - const config = action.config?.config?.length; - const hm = action.hostcomponentmap?.length; - return config ? (hm ? whatShow.stepper : whatShow.config) : hm ? whatShow.hostMap : whatShow.none; - } - - parseData(v: IValue): IMasterData { - const getData = (attr: IConfigAttr, c: ConfigFieldsComponent, h: ServiceHostComponent) => { - const config = c ? this.configService.parseValue(c.form.value, c.rawConfig.config) : undefined; - const hc = h?.statePost.data; - return { attr, config, hc }; - }; - return v ? getData(v.config?.attr, v.config, v.hostmap) : undefined; - } - - send(url: string, value: { config: any; hc: Post[] }) { - return this.api.post(url, value); - } -} diff --git a/web/src/app/shared/components/button-spinner.component.ts b/web/src/app/shared/components/button-spinner.component.ts deleted file mode 100644 index 485f43a2af..0000000000 --- a/web/src/app/shared/components/button-spinner.component.ts +++ /dev/null @@ -1,56 +0,0 @@ -// Licensed 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 { Component, Input, EventEmitter, Output } from '@angular/core'; -import { ThemePalette } from '@angular/material/core'; - -@Component({ - selector: 'app-button-spinner', - template: ``, - styles: ['.spinner {position: relative; bottom: 5px; display: inline; }'], -}) -export class ButtonSpinnerComponent { - @Input() title: string; - @Input() color: ThemePalette; - @Input() disabled: boolean; - @Input() - set spinner(flag) { - this._showSpinner = flag; - } - @Output() clickHandler = new EventEmitter(); - - _showSpinner = false; - private _timer: any; - - send() { - this.showSpinner(); - this.clickHandler.emit(this); - this._timer = setTimeout(() => this.hideSpinner(), 5000); - } - - public hideSpinner() { - this.disabled = false; - this._showSpinner = false; - clearTimeout(this._timer); - } - - public showSpinner() { - this.disabled = true; - this._showSpinner = true; - } -} diff --git a/web/src/app/shared/components/crumbs/crumbs.component.scss b/web/src/app/shared/components/crumbs/crumbs.component.scss deleted file mode 100644 index 68e1622654..0000000000 --- a/web/src/app/shared/components/crumbs/crumbs.component.scss +++ /dev/null @@ -1,14 +0,0 @@ -:host { - font-size: 0.8em; - margin-left: 8px; -} -mat-nav-list { - display: flex; - align-items: center; -} -a { - line-height: normal; -} -mat-icon { - margin-bottom: 5px; -} diff --git a/web/src/app/shared/components/crumbs/crumbs.component.ts b/web/src/app/shared/components/crumbs/crumbs.component.ts deleted file mode 100644 index a9746b65ed..0000000000 --- a/web/src/app/shared/components/crumbs/crumbs.component.ts +++ /dev/null @@ -1,48 +0,0 @@ -// Licensed 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.apacoftware -// 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 { Component, Input } from '@angular/core'; -import { INavItem } from '../../../models/details'; - -@Component({ - selector: 'app-crumbs', - template: ` - - apps -  {{ this.rootBreadcrumb() }}  - - - - - {{ item.title | uppercase }} - priority_hight -  /  - - - `, - styleUrls: ['./crumbs.component.scss'], -}) -export class CrumbsComponent { - @Input() navigation: INavItem[]; - @Input() actionsUrl: string; - - isAdminPage(): boolean { - return this.navigation.length == 1 && this.navigation[0]?.path?.includes('admin'); - } - - rootBreadcrumb(): string { - return this.isAdminPage() ? '/ ADCM' : '/'; - } - - trackBy(index: number, item: INavItem): string { - return item.url; - } -} diff --git a/web/src/app/shared/components/dialog.component.ts b/web/src/app/shared/components/dialog.component.ts deleted file mode 100644 index 34869e36cb..0000000000 --- a/web/src/app/shared/components/dialog.component.ts +++ /dev/null @@ -1,158 +0,0 @@ -// Licensed 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 { Component, ComponentFactoryResolver, EventEmitter, Inject, OnInit, Type, ViewChild, HostListener } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; - -import { DynamicComponent, DynamicDirective, DynamicEvent } from '@app/shared/directives'; -import { ChannelService } from '@app/core/services'; -import { keyChannelStrim } from '@app/core/services'; -import { ActionParameters } from '@app/shared/components/actions/actions.directive'; - -type disabledFunction = (args: any) => boolean; - -export interface DialogData { - title: string; - component: Type; - model?: ActionParameters | any; - event?: EventEmitter; - text?: string; - controls?: any[] | any; - disabled?: disabledFunction | boolean; -} - -@Component({ - selector: 'app-dialog', - template: ` -

{{ _title() }}

- -
{{ data.text }}
- -
- - - - - - - - - - - - - - - - - - - `, - styles: [` - mat-dialog-content { - height: 100%; - } - pre { - overflow: hidden; - white-space: pre-wrap; - word-break: break-word; - } - `], -}) -export class DialogComponent implements OnInit { - controls: string[]; - noClose: boolean | undefined; - - instance: DynamicComponent; - - @ViewChild(DynamicDirective, { static: true }) dynamic: DynamicDirective; - - @HostListener('window:keydown', ['$event']) - handleKeyDown(event: KeyboardEvent) { - if (event.key === 'Enter') { - const c = this.instance; - if (c?.onEnterKey) c.onEnterKey(); - } - } - - constructor( - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: DialogData, - private componentFactoryResolever: ComponentFactoryResolver, - private channel: ChannelService - ) {} - - controlsIsArray() { - return Array.isArray(this.data.controls); - } - - ngOnInit(): void { - if (this._isTypeLdap() && this._isGroupDialog()) { - this.data.disabled = true; - } - - if (this.data.component) { - const componentFactory = this.componentFactoryResolever.resolveComponentFactory(this.data.component); - const viewContainerRef = this.dynamic.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - this.instance = componentRef.instance; - this.instance.model = this.data.model; - // event define in the component - if (this.instance.event) this.instance.event.subscribe((e: DynamicEvent) => this.dialogRef.close(e)); - - if (this.data.event) this.instance.event = this.data.event; - } - } - - scroll(stop: { direct: -1 | 1 | 0; screenTop: number }) { - this.channel.next(keyChannelStrim.scroll, stop); - } - - _close() { - if (this.data.controls?.closeOnGreenButtonCLick) { - this.dialogRef.close(); - } - } - - _noClick(): void { - this.dialogRef.close(); - } - - _isTypeLdap() { - return this.data?.model?.value?.type === 'ldap' - } - - _title(): string { - if (this._isTypeLdap() && this._isGroupDialog()) return 'Group Info'; - if (this._isUserInactive()) return 'User info'; - return this.data.title || 'Notification'; - } - - _isGroupDialog() { - return this.data.model.name === 'Group'; - } - - _isUserDialog() { - return this.data.model.name === 'user'; - } - - _isUserInactive() { - return this.data?.model?.value?.is_active === false; - } - - _getDisabledValue() { - return typeof this.data?.disabled === 'function' ? this.data?.disabled(this.data?.model) : this.data?.disabled; - } -} diff --git a/web/src/app/shared/components/import/import.component.scss b/web/src/app/shared/components/import/import.component.scss deleted file mode 100644 index 7749c7215c..0000000000 --- a/web/src/app/shared/components/import/import.component.scss +++ /dev/null @@ -1,24 +0,0 @@ -:host { - padding: 0 20px; -} - -.controls { - position: fixed; - top: 110px; - right: 80px; -} - -.group { - margin: 0.2em; -} - -.items { - display: flex; - flex-wrap: wrap; -} - -mat-error { - display: block; - margin-top: 6px; - font-weight: normal; -} \ No newline at end of file diff --git a/web/src/app/shared/components/import/import.component.ts b/web/src/app/shared/components/import/import.component.ts deleted file mode 100644 index b65e375a76..0000000000 --- a/web/src/app/shared/components/import/import.component.ts +++ /dev/null @@ -1,144 +0,0 @@ -// Licensed 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 { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl, FormControl, FormGroup, ValidatorFn } from '@angular/forms'; -import { MatCheckboxChange } from '@angular/material/checkbox'; -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; - -import { ChannelService } from '@app/core/services'; -import { keyChannelStrim } from '@app/core/services'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { IExport, IImport } from '@app/core/types'; - -interface IComposite { - [key: string]: number; -} - -const trueOnly = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (control.value ? null : { trueOnly: !control.value }); - -const requiredObject = (): ValidatorFn => (control: AbstractControl): { [key: string]: boolean } | null => - Object.keys(control.value).some((key) => control.value[key]) ? null : { requiered: true }; - -@Component({ - selector: 'app-exports', - template: ` - - -
- {{ item.obj_name }} -
{{ item.bundle_name }} {{ item.bundle_version }}
-
-
-
- `, - styles: ['.component {padding: 6px 8px; margin-bottom: 18px; font-size: 18px;}', '.component div {font-size: 12px;margin-left: 24px; margin-top: 4px;}'], -}) -export class ExportComponent { - @Input() form: FormGroup; - @Input() import: IImport; - - getKey(id: IComposite) { - return JSON.stringify(id); - } - - change(e: MatCheckboxChange, item: IExport) { - if (!this.import.multibind) { - const group = this.form.controls[this.getKey({ import_id: this.import.id })] as FormGroup; - - if (e.checked) - Object.keys(group.controls) - .map((key) => { - group.controls[key].clearValidators(); - return key; - }) - .filter((key) => key !== this.getKey(item.id)) - .map((key) => group.controls[key].setValue(false)); - else if (this.import.required) { - Object.keys(group.controls).map((key) => { - const c = group.controls[key]; - c.setValidators(trueOnly()); - c.updateValueAndValidity(); - }); - } - } - } -} - -@Component({ - selector: 'app-import', - template: ` -

- -

-
-
-

- {{ item.name }} - This import is required! -

- -
-
- `, - styleUrls: ['./import.component.scss'], -}) -export class ImportComponent implements OnInit { - form = new FormGroup({}); - data$: Observable; - asIs = false; - - constructor(private current: ClusterService, private channel: ChannelService) {} - - getKey(id: IComposite) { - return JSON.stringify(id); - } - - hasError(id: number) { - return this.form.get(this.getKey({ import_id: id })).invalid; - } - - ngOnInit() { - this.data$ = this.current.getImportData().pipe( - tap((a) => (this.asIs = !!a.length)), - tap((a) => - a.map((i: IImport) => { - const validFlag = i.required && !i.multibind && i.exports.every((e) => !e.binded); - const exportGroup = i.exports.reduce((p, c) => { - const fc = {}; - fc[`${this.getKey(c.id)}`] = new FormControl(c.binded, validFlag ? trueOnly() : null); - return { ...p, ...fc }; - }, {}); - const import_id = this.getKey({ import_id: i.id }); - this.form.addControl(import_id, new FormGroup(exportGroup, i.required ? requiredObject() : null)); - }) - ) - ); - } - - go() { - if (!this.form.invalid) { - let bind = []; - Object.keys(this.form.controls) - .filter((a) => Object.keys(this.form.controls[a].value).length) - .map((key) => { - const obj = JSON.parse(key); - const value = this.form.controls[key].value; - const items = Object.keys(value) - .filter((a) => value[a] === true) - .map((a) => ({ ...obj, export_id: JSON.parse(a) })); - bind = [...bind, ...items]; - }); - this.current.bindImport({ bind }).subscribe((_) => this.channel.next(keyChannelStrim.notifying, 'Successfully saved')); - } - } -} diff --git a/web/src/app/shared/components/index.ts b/web/src/app/shared/components/index.ts deleted file mode 100644 index cf07f6cfa0..0000000000 --- a/web/src/app/shared/components/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed 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 * from './button-spinner.component'; -export * from './issue-info.component'; -export * from './status-info.component'; -export * from './crumbs/crumbs.component'; -export * from './dialog.component'; -export * from './main-info.component'; -export * from './upgrades/upgrade.component'; -export * from './actions/actions.component'; -export * from './actions/master/master.component'; -export * from './import/import.component'; diff --git a/web/src/app/shared/components/issue-info.component.spec.ts b/web/src/app/shared/components/issue-info.component.spec.ts deleted file mode 100644 index 10c0d86756..0000000000 --- a/web/src/app/shared/components/issue-info.component.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -// Licensed 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 { EventEmitter } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; - -import { IssueInfoComponent } from './issue-info.component'; -import { ComponentData } from './tooltip/tooltip.service'; - -class MockComponentData { - path = 'cluster'; - current = { id: 1 }; - emitter = new EventEmitter(); -} - -describe('Issue-info component', () => { - let fixture: ComponentFixture; - let component: IssueInfoComponent; - let os = require("os"); - let hostname = os.hostname(); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [RouterTestingModule], - declarations: [IssueInfoComponent], - providers: [{ provide: ComponentData, useClass: MockComponentData }], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(IssueInfoComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('issue at the current element', () => { - component.current.issue = { host_component: false }; - fixture.detectChanges(); - const href = fixture.nativeElement.querySelector('div:last-child a').getAttribute('href'); - const c = component.current; - const hostlessHref = href.slice(href.indexOf(c.path)-1); - const issueName = Object.keys(c.issue)[0]; - expect(hostlessHref).toBe(`/${c.path}/${c.id}/${issueName}`); - }); - - it('issue at the daughter elements', () => { - component.current.issue = { service: [{ id: 1, name: 'Service_Name', issue: { config: false } }] }; - fixture.detectChanges(); - const href = fixture.nativeElement.querySelector('div:last-child a').getAttribute('href'); - const c = component.current; - const hostlessHref = href.slice(href.indexOf(c.path)-1); - const daughterName = Object.keys(c.issue)[0]; - const daughterObj = c.issue[daughterName][0]; - const issueName = Object.keys(daughterObj.issue)[0]; - expect(hostlessHref).toBe(`/${c.path}/${c.id}/${daughterName}/${daughterObj.id}/${issueName}`); - }); - - it('issue at the parent element', () => { - component.current = { id: 2, cluster_id: 1, issue: { cluster: [{ id: 1, name: 'Cluster_Name', issue: { config: false } }] } }; - fixture.detectChanges(); - const href = fixture.nativeElement.querySelector('div:last-child a').getAttribute('href'); - const c = component.current; - const parentName = Object.keys(c.issue)[0]; - const parentObj = c.issue[parentName][0]; - const hostlessHref = href.slice(href.indexOf(parentObj.path)-1); - const issueName = Object.keys(parentObj.issue)[0]; - expect(hostlessHref).toBe(`/${parentObj.path}/${parentObj.id}/${issueName}`); - }); -}); diff --git a/web/src/app/shared/components/issue-info.component.ts b/web/src/app/shared/components/issue-info.component.ts deleted file mode 100644 index 6ac1fb9e75..0000000000 --- a/web/src/app/shared/components/issue-info.component.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Licensed 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 { Component, Input, OnInit } from '@angular/core'; - -import { ComponentData } from './tooltip/tooltip.service'; -import { IIssues } from '@app/models/issue'; - -export interface IIssueInfo { - id: number; - issue: IIssues; - cluster_id?: number; - name?: string; - path?: string; -} - -@Component({ - selector: 'app-issue-info', - template: ` -
{{ intro }}
-
- -
- {{ name }}: - - {{ o.name }} - -
-
- - {{ IssueNames[name] || name }} - -
- `, - styles: ['a, .item-step { display: block; margin: 6px 0 8px 12px; white-space: nowrap;}'], -}) -export class IssueInfoComponent implements OnInit { - - @Input() intro = 'Issues in:'; - @Input() path: string; - @Input() current: IIssueInfo; - @Input() parent: IIssueInfo; - - IssuePatch = { - required_service: 'service', - required_import: 'import', - }; - - IssueNames = { - config: 'Configuration', - host_component: 'Host - Components', - required_service: 'Required a service', - required_import: 'Required a import', - }; - - constructor(private componentData: ComponentData) {} - - ngOnInit(): void { - this.current = this.current || this.componentData.current; - this.path = this.path || this.componentData.path; - this.current.path = this.path; - this.componentData.emitter.emit('Done'); - } - - get Path() { - return this.parent && this.parent.cluster_id !== this.current.id ? `${this.parent.path}/${this.parent.id}/${this.path}` : this.path; - } - - isArray(issue: [] | false): boolean { - return Array.isArray(issue); - } - - get namesIssue() { - return Object.keys(this.current.issue || {}); - } -} diff --git a/web/src/app/shared/components/list/base-list.directive.ts b/web/src/app/shared/components/list/base-list.directive.ts deleted file mode 100644 index b20039238f..0000000000 --- a/web/src/app/shared/components/list/base-list.directive.ts +++ /dev/null @@ -1,287 +0,0 @@ -// Licensed 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 { MatDialog } from '@angular/material/dialog'; -import { ParamMap } from '@angular/router'; -import { select, Store } from '@ngrx/store'; -import { filter, mergeMap, switchMap, takeUntil, tap } from 'rxjs/operators'; -import { IListResult } from '@app/adwp'; -import { Sort } from '@angular/material/sort'; -import { Observable, Subject } from 'rxjs'; -import { clearMessages, EventMessage, getMessage, SocketState } from '@app/core/store'; -import { Bundle, EmmitRow, Entities, Host as AdcmHost, TypeName } from '@app/core/types'; -import { DialogComponent } from '@app/shared/components'; -import { ListResult } from '@app/models/list-result'; -import { ListService } from './list.service'; -import { ListDirective } from '@app/abstract-directives/list.directive'; -import { ICluster } from '@app/models/cluster'; - -const TemporaryEntityNameConverter = (currentName: Partial): string => { - - if (currentName === 'group_config') return 'group-config'; - if (currentName === 'group_config_hosts') return 'group-config-hosts'; - - return currentName; -}; - -interface IRowHost extends AdcmHost { - clusters: Partial[]; - page: number; -} - -export class BaseListDirective { - - socket$: Observable; - destroy$ = new Subject(); - - row: Entities; - listParams: ParamMap; - limit = 10; - typeName: TypeName; - - reload: (result: ListResult) => void; - - constructor( - protected parent: ListDirective, - protected service: ListService, - protected store: Store, - ) {} - - takeUntil() { - return takeUntil(this.destroy$); - } - - startListenSocket(): void { - this.socket$.pipe(tap(m => this.socketListener(m))).subscribe(); - } - - initSocket() { - this.socket$ = this.store.pipe( - this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object)); - } - - initColumns() { - this.parent.columns = this.service.initInstance(this.typeName).columns; - } - - initListItemEvent() { - this.parent.listItemEvt - .pipe(this.takeUntil()) - .subscribe({ next: (event: EmmitRow) => this.listEvents(event) }); - } - - calcSort(ordering: string): Sort { - let sort: Sort; - if (ordering) { - sort = { - direction: ordering[0] === '-' ? 'desc' : 'asc', - active: ordering[0] === '-' ? ordering.substr(1) : ordering, - }; - } - - return sort; - } - - routeListener(limit: number, page: number, ordering: string, params: ParamMap) { - this.parent.paginator.pageSize = limit; - if (page === 0) { - this.parent.paginator.firstPage(); - } else { - this.parent.paginator.pageIndex = page; - } - if (ordering && !this.parent.sort.active) { - this.parent.sort.direction = ordering[0] === '-' ? 'desc' : 'asc'; - this.parent.sort.active = ordering[0] === '-' ? ordering.substr(1) : ordering; - this.parent.sortParam = ordering; - } - - this.listParams = params; - this.refresh(); - } - - initRouteListener() { - this.parent.route.paramMap - .pipe( - this.takeUntil(), - filter((p) => this.checkParam(p)) - ) - .subscribe((p) => this.routeListener(+p.get('limit'), +p.get('page'), p.get('ordering'), p)); - } - - init(): void { - this.initSocket(); - this.initColumns(); - this.initListItemEvent(); - this.initRouteListener(); - this.startListenSocket(); - } - - destroy() { - this.parent.listItemEvt.complete(); - - this.destroy$.next(); - this.destroy$.complete(); - - this.store.dispatch(clearMessages()); - } - - checkParam(p: ParamMap): boolean { - const listParamStr = localStorage.getItem('list:param'); - - if (!p?.keys?.length && listParamStr) { - const json = JSON.parse(listParamStr); - - if (json[this.typeName]) { - delete json[this.typeName]?.page; - this.parent.router.navigate(['./', json[this.typeName]], { - relativeTo: this.parent.route, - replaceUrl: true, - }); - return false; - } - } - return true; - } - - checkType(typeName: string, referenceTypeName: TypeName): boolean { - return (referenceTypeName ? referenceTypeName.split('2')[0] : referenceTypeName) === typeName; - } - - socketListener(m: EventMessage): void { - const stype = (x: string) => `${m.object.type}${m.object.details.type ? `2${m.object.details.type}` : ''}` === x; - const changeList = (name?: string) => stype(name ?? this.typeName) && (m.event === 'create' || m.event === 'delete' || m.event === 'add' || m.event === 'remove'); - const createHostPro = () => stype('host2provider') && m.event === 'create'; - const jobComplete = () => (m.event === 'change_job_status') && m.object.type === 'task' && m.object.details.value === 'success'; - const rewriteRow = (row: Entities) => this.service.checkItem(row).subscribe((item) => Object.keys(row).map((a) => (row[a] = item[a]))); - - const checkUpgradable = () => { - const events = ['create', 'delete']; - const pairs = { - bundle: ['cluster'], - service: ['service2cluster'] - }; - - return events.includes(m.event) && pairs[m.object.type]?.includes(this.typeName); - } - - if (checkUpgradable() || changeList(TemporaryEntityNameConverter(this.typeName)) || createHostPro() || jobComplete()) { - this.refresh(m.object.id); - return; - } - // events for the row of list - if (this.parent.data.data.length) { - const row = this.parent.data.data.find((a) => a.id === m.object.id); - if (!row) return; - - if (m.event === 'add' && stype('host2cluster')) rewriteRow(row); - - if (this.checkType(m.object.type, this.typeName)) { - if (m.event === 'change_state') row.state = m.object.details.value; - if (m.event === 'change_status') row.status = +m.object.details.value; - if (m.event === 'change_job_status') row.status = m.object.details.value; - if (m.event === 'upgrade') rewriteRow(row); - if (m.event === 'update') this.refresh(); - } - } - } - - refresh(id?: number, filter_params?: ParamMap) { - if (id) this.parent.current = { id }; - if (!filter_params) { - let ls = localStorage.getItem('list:param'); - let filters = ls ? JSON.parse(ls) : {}; - if (filters[this.typeName]) this.listParams['params'] = { ...this.listParams['params'], ...filters[this.typeName] } - } - this.service.getList(filter_params || this.listParams, this.typeName).subscribe((list: IListResult) => { - if (this.reload) { - this.reload(list); - } - this.parent.dataSource = list; - }); - } - - listEvents(event: EmmitRow) { - const createUrl = (a: string[]) => this.parent.router.createUrlTree(['./', this.row.id, ...a], { relativeTo: this.parent.route }); - const nav = (a: string[]) => this.parent.router.navigateByUrl(createUrl(a)); - - this.row = event.row; - const { cmd, row, item } = event; - - if (['title', 'status', 'config', 'import'].includes(cmd)) { - nav(cmd === 'title' ? [] : [cmd]); - } else if (cmd === 'new-tab') { - const url = this.parent.router.serializeUrl(createUrl([])); - window.open(url, '_blank'); - } else { - this[cmd](row || item); - } - } - - onLoad() {} - - maintenanceModeToggle(row) { - this.service.setMaintenanceMode(row).subscribe(); - } - - license() { - const row = this.row as Bundle; - - const closedDialog$ = (text: string, dialog: MatDialog) => - dialog - .open(DialogComponent, { - data: { - title: `Accept license agreement`, - text, - controls: { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] }, - }, - }) - .beforeClosed(); - - const showDialog = (info: { text: string }) => - closedDialog$(info.text, this.parent.dialog).pipe( - filter((yes) => yes), - switchMap(() => this.service.acceptLicense(`${row.license_url}accept/`).pipe(tap((_) => (row.license = 'accepted')))) - ); - - this.service.getLicenseInfo(row.license_url).pipe(this.takeUntil(), mergeMap(showDialog)).subscribe(); - } - - delete(item?: Entities) { - this.service - .delete(item ?? this.row) - .pipe(this.takeUntil()) - .subscribe(() => (this.parent.current = null)); - } - - // host - getClusters() { - const row = this.row as IRowHost; - if (!row.clusters) { - row.page = 0; - this.service - .getClustersForHost({ limit: this.limit, page: 0 }) - .pipe(this.takeUntil()) - .subscribe((list) => (row.clusters = list)); - } - } - - getNextPageCluster() { - const row = this.row as IRowHost; - const count = row.clusters.length; - if (count === (row.page + 1) * this.limit) { - row.page++; - this.service - .getClustersForHost({ limit: this.limit, page: row.page }) - .pipe(this.takeUntil()) - .subscribe((list) => (row.clusters = [...row.clusters, ...list])); - } - } -} diff --git a/web/src/app/shared/components/list/list-service-token.ts b/web/src/app/shared/components/list/list-service-token.ts deleted file mode 100644 index 1310365bbf..0000000000 --- a/web/src/app/shared/components/list/list-service-token.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { InjectionToken } from '@angular/core'; -import { TypeName } from '@app/core/types'; -import { ParamMap } from '@angular/router'; -import { Observable } from 'rxjs'; -import { ListResult } from '@app/models/list-result'; - -export const LIST_SERVICE_PROVIDER = new InjectionToken>('ListService'); - -export interface ListInstance { - typeName: TypeName; - columns: string[]; -} - -export interface IListService { - current: ListInstance; - - initInstance(typeName?: TypeName): ListInstance; - - getList(p: ParamMap, typeName?: string): Observable> - - delete(row: T): Observable; -} diff --git a/web/src/app/shared/components/list/list.service.ts b/web/src/app/shared/components/list/list.service.ts deleted file mode 100644 index 8af1af6633..0000000000 --- a/web/src/app/shared/components/list/list.service.ts +++ /dev/null @@ -1,141 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { convertToParamMap, ParamMap, Params } from '@angular/router'; -import { map, switchMap, tap } from 'rxjs/operators'; -import { Observable } from 'rxjs'; -import { environment } from '@env/environment'; -import { ApiService } from '@app/core/api'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { BaseEntity, Bundle, Entities, IAction, Service, TypeName } from '@app/core/types'; -import { IListService, ListInstance } from '@app/shared/components/list/list-service-token'; -import { ListResult } from '@app/models/list-result'; -import { ICluster } from '@app/models/cluster'; - -const COLUMNS_SET = { - cluster: ['name', 'prototype_version', 'description', 'state', 'status', 'actions', 'import', 'upgrade', 'config', 'controls'], - host2cluster: ['fqdn', 'provider_name', 'state', 'status', 'actions', 'config', 'maintenance_mode', 'remove'], - service2cluster: ['display_name', 'version_no_sort', 'state', 'status', 'actions', 'import', 'config'], - host: ['fqdn', 'provider_name', 'host2cluster', 'state', 'status', 'actions', 'config', 'maintenance_mode', 'controls'], - provider: ['name', 'prototype_version', 'state', 'actions', 'upgrade', 'config', 'controls'], - job: ['action', 'objects', 'start_date', 'finish_date', 'status'], - task: ['id', 'start_date', 'finish_date', 'status'], - bundle: ['name', 'version', 'edition', 'description', 'controls'], -}; - -@Injectable({ - providedIn: 'root', -}) -export class ListService implements IListService { - current: ListInstance; - - constructor(private api: ApiService, private detail: ClusterService) {} - - initInstance(typeName: TypeName): ListInstance { - this.current = { typeName, columns: COLUMNS_SET[typeName] }; - return this.current; - } - - getList(p: ParamMap, typeName: TypeName): Observable> { - const listParamStr = localStorage.getItem('list:param'); - - if (p?.keys?.length > 0) { - const param = p.keys.reduce((a, c) => ({ ...a, [c]: p.get(c) }), {}); - delete param['page']; - - if (listParamStr) { - const json = JSON.parse(listParamStr); - json[typeName] = param; - localStorage.setItem('list:param', JSON.stringify(json)); - } else localStorage.setItem('list:param', JSON.stringify({ [typeName]: param })); - } - - let params = { ...(p || {}) }; - - switch (typeName) { - case 'host2cluster': - return this.detail.getHosts(p); - case 'service2cluster': - return this.detail.getServices(p); - case 'bundle': - return this.api.getList(`${environment.apiRoot}stack/bundle/`, p); - case 'servicecomponent': - return this.api.getList(`${environment.apiRoot}cluster/${(this.detail.Current as Service).cluster_id}/service/${this.detail.Current.id}/component`, p); - case 'user': - params = { ...params['params'], 'expand': 'group' }; - return this.api.getList(`${environment.apiRoot}rbac/user/`, convertToParamMap(params)); - case 'group': - params = { ...params['params'], 'expand': 'user' }; - return this.api.getList(`${environment.apiRoot}rbac/group/`, convertToParamMap(params)); - case 'role': - params = { ...params['params'], 'expand': 'child' }; - return this.api.getList(`${environment.apiRoot}rbac/role/`, convertToParamMap(params), { type: 'role' }); - case 'policy': - params = { ...params['params'], 'expand': 'child,role,user,group,object', 'built_in': 'false' }; - return this.api.getList(`${environment.apiRoot}rbac/policy/`, convertToParamMap(params)); - case 'audit_operations': - params = { ...params['params'], 'expand': null }; - return this.api.getList(`${environment.apiRoot}audit/operation`, convertToParamMap(params)); - case 'audit_login': - params = { ...params['params'], 'expand': null }; - return this.api.getList(`${environment.apiRoot}audit/login`, convertToParamMap(params)); - default: - return this.api.root.pipe(switchMap((root) => this.api.getList(root[this.current.typeName], p))); - } - } - - getCrumbs() { - return [{ path: '/cluster', name: 'clusters' }]; - } - - getActions(row: Entities) { - this.api - .get(row.action) - .pipe(tap((actions) => (row.actions = actions))) - .subscribe(); - } - - delete(row: Entities) { - return this.api.delete(row.url); - } - - // host - getClustersForHost(param: Params): Observable<{ id: number; title: string }[]> { - return this.api.root - .pipe(switchMap((root) => this.api.getList(root.cluster, convertToParamMap(param)))) - .pipe(map((res) => res.results.map((a) => ({ id: a.id, title: a.name })))); - } - - checkItem(item: BaseEntity) { - return this.api.get(item.url); - } - - acceptLicense(url: string) { - return this.api.put(url, {}); - } - - getLicenseInfo(url: string) { - return this.api.get<{ text: string }>(url); - } - - setMaintenanceMode(row: Entities) { - return this.api.post(`/api/v1/${row['type']}/${row.id}/maintenance-mode/`, { maintenance_mode: row['maintenance_mode'] }); - } - - renameHost(column: string, value: any, id: number) { - return this.api.patch(`/api/v1/host/${id}/`, { [column]: value }); - } - - renameCluster(column: string, value: any, id: number) { - return this.api.patch(`/api/v1/cluster/${id}/`, { [column]: value }); - } -} diff --git a/web/src/app/shared/components/list/multi-sort.directive.ts b/web/src/app/shared/components/list/multi-sort.directive.ts deleted file mode 100644 index 67781d4596..0000000000 --- a/web/src/app/shared/components/list/multi-sort.directive.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed 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 { Directive, ElementRef, EventEmitter, HostListener, Input, Output, Renderer2 } from '@angular/core'; - -@Directive({ - selector: '[appMultiSort]', -}) -export class MultiSortDirective { - shiftKey = false; - private params: string[] = []; - - @Input('appMultiSort') set sortParam(param: string) { - const el = this.el.nativeElement; - this.params = param.split(','); - this.hideAllArrows(el); - setTimeout(() => this.params.map((p) => this.preCell(p, el)), 0); - } - - @Output() mousedownevent = new EventEmitter(); - - @HostListener('mousedown', ['$event']) onmousedown(e: MouseEvent) { - this.shiftKey = e.shiftKey; - this.mousedownevent.emit(e.shiftKey); - } - - @HostListener('mouseover', ['$event.target']) onmouseover(h: HTMLElement) { - const el = this.el.nativeElement; - this.params.map((p) => this.preCell(p, el)); - } - - @HostListener('mouseout', ['$event.target']) mouseleave(row: HTMLElement) { - const el = this.el.nativeElement; - setTimeout(() => this.params.map((p) => this.preCell(p, el)), 300); - } - - constructor(private el: ElementRef, private renderer: Renderer2) {} - - hideAllArrows(el: any) { - Array.from(el.getElementsByTagName('mat-header-cell')).forEach((e) => { - const a = e.querySelector('div.mat-sort-header-container>div.mat-sort-header-arrow'); - if (a) this.renderer.setStyle(a, 'opacity', 0); - }); - } - - preCell(p: string, el: HTMLElement) { - const direction = p[0] === '-' ? 'descending' : 'ascending', - active = p[0] === '-' ? p.substr(1) : p; - - const column = el.querySelector(`mat-header-cell.mat-column-${active}`) || el.querySelector(`mat-header-cell[mat-sort-header="${active}"]`); - if (p && column) { - this.renderer.setAttribute(column, 'aria-sort', direction); - - const container = column.querySelector('div.mat-sort-header-container'); - this.renderer.addClass(container, 'mat-sort-header-sorted'); - - const arrow = container.querySelector('div.mat-sort-header-arrow'); - if (arrow) { - this.renderer.setStyle(arrow, 'opacity', 1); - this.renderer.setStyle(arrow, 'transform', 'translateY(0px)'); - - const indicator = arrow.querySelector('div.mat-sort-header-indicator'); - this.renderer.setStyle(indicator, 'transform', direction === 'descending' ? 'translateY(10px)' : 'translateY(0px)'); - - if (direction === 'descending') { - const left = indicator.querySelector('.mat-sort-header-pointer-left'); - this.renderer.setStyle(left, 'transform', 'rotate(45deg)'); - - const right = indicator.querySelector('.mat-sort-header-pointer-right'); - this.renderer.setStyle(right, 'transform', 'rotate(-45deg)'); - } - } - } - } -} diff --git a/web/src/app/shared/components/main-info.component.ts b/web/src/app/shared/components/main-info.component.ts deleted file mode 100644 index d5763dfa88..0000000000 --- a/web/src/app/shared/components/main-info.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed 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 { Component, OnInit } from '@angular/core'; -import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; - -import { ClusterService } from '@app/core/services/cluster.service'; - -@Component({ - selector: 'app-main-info', - template: '
', - styles: [':host {padding: 0 20px;}'], -}) -export class MainInfoComponent implements OnInit { - value: SafeHtml; - - constructor(private service: ClusterService, private sanitizer: DomSanitizer) {} - - ngOnInit() { - this.value = this.sanitizer.bypassSecurityTrustHtml(this.service.getMainInfo()); - } -} diff --git a/web/src/app/shared/components/status-info.component.ts b/web/src/app/shared/components/status-info.component.ts deleted file mode 100644 index 58640a2b4e..0000000000 --- a/web/src/app/shared/components/status-info.component.ts +++ /dev/null @@ -1,81 +0,0 @@ -// Licensed 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 { Component, OnInit } from '@angular/core'; -import { BaseEntity } from '@app/core/types/api'; -import { Observable, of } from 'rxjs'; -import { switchMap, tap, map } from 'rxjs/operators'; - -import { StatusService } from './status/status.service'; -import { ComponentData } from './tooltip/tooltip.service'; -import { ICluster } from '@app/models/cluster'; - -@Component({ - selector: 'app-status-info', - template: ` -
- Nothing to display - - {{ (c.display_name || c.name || c.component_display_name || c.component).toUpperCase() }}  - - - check_circle_outline - error_outline - -
- `, - styles: ['mat-icon {vertical-align: middle;}', 'a.component {display: block; padding: 6px 8px;}'], -}) -export class StatusInfoComponent implements OnInit { - path: string; - cluster: ICluster; - current: BaseEntity; - statusInfo$: Observable; - - constructor(private service: StatusService, private componentData: ComponentData) {} - - ngOnInit(): void { - this.current = this.current || this.componentData.current; - this.path = this.path || this.componentData.path; - - const [name] = this.path.split('/').reverse(); - - let req$ = of([]); - - switch (name) { - case 'cluster': - this.cluster = this.current as ICluster; - req$ = this.service.getServiceComponentsByCluster(this.cluster); - break; - case 'service': - req$ = this.service.getClusterById((this.current).cluster_id).pipe( - tap((c) => (this.cluster = c)), - switchMap((cluster) => this.service.getServiceComponentsByCluster(cluster, this.current.id)) - ); - break; - case 'host': - if ((this.current).cluster_id) - req$ = this.service.getClusterById((this.current).cluster_id).pipe( - tap((c) => (this.cluster = c)), - switchMap((cluster) => this.service.getStatusInfo(cluster.id, cluster.hostcomponent).pipe(map((a) => this.service.getComponentsOnly(a, this.current.id)))) - ); - break; - } - - this.statusInfo$ = req$.pipe(tap(() => this.componentData.emitter.emit('onLoad'))); - } - - onClick(): void { - this.componentData.emitter.emit('onClose'); - } -} diff --git a/web/src/app/shared/components/status/status.service.ts b/web/src/app/shared/components/status/status.service.ts deleted file mode 100644 index f6eafc2c7f..0000000000 --- a/web/src/app/shared/components/status/status.service.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { combineLatest, Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; - -import { ApiService } from '@app/core/api'; -import { IComponent, Host, HostComponent } from '@app/core/types'; -import { ICluster } from '@app/models/cluster'; - -interface IStatus { - [key: number]: { status: number }; -} - -export interface IAllStatus { - hosts: IStatus; - services: { details: [{ host: string | number; component: string | number; status: number }]; status: number }[]; - components: IStatus; - status: number; -} - -@Injectable({ - providedIn: 'root', -}) -export class StatusService { - constructor(private api: ApiService) { } - - getStatusInfo(id: number, hostcomponent_link: string) { - const statuses$ = this.getAllClusterStatus(id), - host_components$ = this.getHostComponents(hostcomponent_link); - return combineLatest([statuses$, host_components$]); - } - - getHostComponents(url: string): Observable { - return this.api - .get<{ host: Host[]; hc: HostComponent[]; component: IComponent[] }>(url) - .pipe(map((a) => a.hc.map((hc) => ({ ...hc, monitoring: a.component.find((b) => b.id === hc.component_id).monitoring })))); - } - - getServiceComponentsByCluster(cluster: ICluster, service_id?: number): Observable { - return this.api.get(cluster.status_url).pipe(map((s) => s.filter((se) => (service_id ? se.service_id === service_id : true)))); - } - - getHostcomponentStatus(k: HostComponent, all: IAllStatus) { - const c = all.services[k.service_id]?.details.find((e) => +e.host === k.host_id && +e.component === k.component_id); - return c ? c.status : null; - } - - getComponentsOnly(a: [IAllStatus, HostComponent[]], host_id?: number) { - const all: IAllStatus = a[0], - hc: HostComponent[] = a[1]; - return hc - .filter((h) => (host_id ? host_id === h.host_id : true)) - .reduce((acc, cur) => (!acc.some((c) => c.host_id === cur.host_id && c.service_id === cur.service_id) ? [...acc, cur] : acc), []) - .map((k) => ({ ...k, status: this.getHostcomponentStatus(k, all) })) - .filter((b) => b.status !== 0); - } - - getClusterById(id: number) { - return this.api.getOne('cluster', id); - } - - getAllClusterStatus(id: number) { - return this.api.get(`/status/api/v1/cluster/${id}/`); - } - -} diff --git a/web/src/app/shared/components/tooltip/index.ts b/web/src/app/shared/components/tooltip/index.ts deleted file mode 100644 index 193a69a139..0000000000 --- a/web/src/app/shared/components/tooltip/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed 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 * from './tooltip.component'; -export * from './tooltip.directive'; diff --git a/web/src/app/shared/components/tooltip/tooltip.component.scss b/web/src/app/shared/components/tooltip/tooltip.component.scss deleted file mode 100644 index 40dbf6af02..0000000000 --- a/web/src/app/shared/components/tooltip/tooltip.component.scss +++ /dev/null @@ -1,24 +0,0 @@ -:host { - line-height: normal; - text-align: left; - font-family: Roboto, "Helvetica Neue", sans-serif; - color: #fff; - font-size: 14px; - position: absolute; - display: block; - border: solid 1px #455A64; - padding: 8px 14px; - background-color: #37474F; - border-radius: 5px; - box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), - 0px 2px 2px 0px rgba(0, 0, 0, 0.14), - 0px 1px 5px 0px rgba(0, 0, 0, 0.12); - opacity: 0; - height: auto; - // -webkit-transition: .2s ease-in-out; - // -moz-transition: .2s ease-in-out; - // -o-transition: .2s ease-in-out; - //transition: .2s ease-in-out; - z-index: 1100; - overflow: auto; -} diff --git a/web/src/app/shared/components/tooltip/tooltip.component.ts b/web/src/app/shared/components/tooltip/tooltip.component.ts deleted file mode 100644 index e91fe8f4c7..0000000000 --- a/web/src/app/shared/components/tooltip/tooltip.component.ts +++ /dev/null @@ -1,156 +0,0 @@ -// Licensed 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 { - Component, - ElementRef, - EventEmitter, - HostListener, - Injector, - Input, - OnDestroy, - OnInit, - Renderer2, - Type, -} from '@angular/core'; -import { Router } from '@angular/router'; -import { BaseDirective } from '@app/shared/directives'; -import { delay } from 'rxjs/operators'; - -import { IssueInfoComponent } from '../issue-info.component'; -import { StatusInfoComponent } from '../status-info.component'; -import { ComponentData, TooltipOptions, TooltipService } from './tooltip.service'; - -const POSITION_MARGIN = 16; - -@Component({ - selector: 'app-simple-text', - template: '{{ current }}', -}) -export class SimpleTextComponent implements OnInit { - @Input() current: any; - constructor(private componentData: ComponentData) {} - ngOnInit(): void { - this.current = this.current || this.componentData.current; - this.componentData.emitter.emit('Done'); - } -} - -const kit = { issue: IssueInfoComponent, status: StatusInfoComponent }; -@Component({ - selector: 'app-tooltip', - template: '', - styleUrls: ['./tooltip.component.scss'], -}) -export class TooltipComponent extends BaseDirective implements OnInit, OnDestroy { - private options: TooltipOptions; - source: HTMLElement; - - CurrentComponent: Type; - componentInjector: Injector; - - constructor( - private el: ElementRef, - private service: TooltipService, - private renderer: Renderer2, - private router: Router, - private parentInjector: Injector - ) { - super(); - } - - @HostListener('mouseenter', ['$event']) menter() { - this.service.mouseEnterTooltip(); - } - - @HostListener('mouseleave') mleave() { - this.service.mouseLeaveTooltip(); - } - - ngOnInit(): void { - this.service.position$.pipe(this.takeUntil()).subscribe((o) => { - if (o) { - this.clear(); - this.buildComponent(o); - } else this.hide(); - }); - } - - hide() { - this.renderer.setAttribute(this.el.nativeElement, 'style', `opacity: 0; height: auto;`); - this.clear(); - } - - clear() { - if (this.source) { - this.source = null; - this.CurrentComponent = null; - } - } - - position() { - const o = this.options; - const el = this.el.nativeElement; - const root = document.querySelector('app-root'); - const position = { left: 0, top: 0, bottom: 0, right: 0, height: 0 }; - const offsetParent = (s: HTMLElement) => s.offsetParent as HTMLElement; - const offset = (s: HTMLElement) => ({ top: s.offsetTop, left: s.offsetLeft }); - const increment = (a: { top: number; left: number }, b: { top: number; left: number }) => ({ top: a.top + b.top, left: a.left + b.left }); - const offsetSum = (s: HTMLElement) => (offsetParent(s) ? increment(offset(s), offsetSum(offsetParent(s))) : offset(s)); - const os = offsetSum(o.source); - position.top = os.top + o.source.offsetHeight; - - // TODO: maybe let's up tooltip? - // this height for tooltip for scrolling - position.height = o.event.y > root.offsetHeight - el.offsetHeight ? root.offsetHeight - position.top - POSITION_MARGIN : 0; - - switch (o.options.position) { - case 'bottom': - if (o.event.x + el.offsetWidth > root.offsetWidth) position.right = POSITION_MARGIN * 2; - else position.left = os.left + o.source.clientWidth; - break; - case 'left': - position.left = o.event.x < el.clientWidth ? POSITION_MARGIN * 2 : os.left - el.clientWidth; - break; - } - - this.renderer.setAttribute(el, 'style', `opacity: .9; ${this.getPositionString(position)}`); - } - - getPositionString(po: any) { - return Object.keys(po).reduce((p, c) => p + (po[c] ? `${c}: ${po[c]}px;` : ''), ''); - } - - buildComponent(o: TooltipOptions) { - this.options = o; - this.source = this.options.source; - this.CurrentComponent = kit[this.options.options.componentName] || SimpleTextComponent; - - const emitter = new EventEmitter(); - emitter.pipe(delay(100), this.takeUntil()).subscribe(() => this.position()); - - const parse = (url: string) => - url - .split('/') - .map((b) => b.split(';')[0]) - .join('/'); - - this.componentInjector = Injector.create({ - providers: [ - { - provide: ComponentData, - useValue: { path: parse(this.router.url), current: this.options.options.content, emitter: emitter }, - }, - ], - parent: this.parentInjector, - }); - } -} diff --git a/web/src/app/shared/components/tooltip/tooltip.directive.ts b/web/src/app/shared/components/tooltip/tooltip.directive.ts deleted file mode 100644 index 525b8d29f2..0000000000 --- a/web/src/app/shared/components/tooltip/tooltip.directive.ts +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed 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 { Directive, ElementRef, HostListener, Input } from '@angular/core'; -import { EventHelper } from '@app/adwp'; - -import { BaseEntity } from '@app/core/types/api'; -import { ComponentName, PositionType, TooltipService } from '../tooltip/tooltip.service'; - -@Directive({ - selector: '[appTooltip]', -}) -export class TooltipDirective { - @Input() appTooltip: string | BaseEntity; - @Input() appTooltipPosition: PositionType = 'bottom'; - @Input() appTooltipComponent: ComponentName; - - /** - * TODO: To show tooltip by condition [04.12.2019] - * ConditionType - under construction, - * Now - one the condition this is width and scroll of source - * tooltip.component.ts line: 118 checkBuild() - */ - @Input() appTooltipShowByCondition: boolean; - - constructor(private el: ElementRef, private tooltip: TooltipService) {} - - @HostListener('mouseenter', ['$event']) menter(e: MouseEvent): void { - EventHelper.stopPropagation(e); - const options = { - content: this.appTooltip, - componentName: this.appTooltipComponent, - position: this.appTooltipPosition, - condition: this.appTooltipShowByCondition, - }; - if (this.appTooltip) this.tooltip.show(e, this.el.nativeElement, options); - } - - @HostListener('mouseleave') mleave(): void { - this.tooltip.hide(); - } - - @HostListener('click') mclick(): void { - this.tooltip.hide(true); - } -} diff --git a/web/src/app/shared/components/tooltip/tooltip.module.ts b/web/src/app/shared/components/tooltip/tooltip.module.ts deleted file mode 100644 index 44775bb75d..0000000000 --- a/web/src/app/shared/components/tooltip/tooltip.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { SimpleTextComponent, TooltipComponent } from './tooltip.component'; -import { TooltipDirective } from './tooltip.directive'; - - -@NgModule({ - declarations: [TooltipComponent, SimpleTextComponent, TooltipDirective], - imports: [ - CommonModule - ], - exports: [TooltipComponent, SimpleTextComponent, TooltipDirective] -}) -export class TooltipModule { -} diff --git a/web/src/app/shared/components/tooltip/tooltip.service.ts b/web/src/app/shared/components/tooltip/tooltip.service.ts deleted file mode 100644 index d57e2d2ee4..0000000000 --- a/web/src/app/shared/components/tooltip/tooltip.service.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed 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 { EventEmitter, Injectable } from '@angular/core'; -import { BaseEntity } from '@app/core/types/api'; -import { Subject } from 'rxjs'; - -export type ComponentName = 'issue' | 'status' | undefined; -export type PositionType = 'top' | 'right' | 'bottom' | 'left'; -export interface TooltipOptions { - event: MouseEvent; - source: HTMLElement; - options: TooltipDisplayOptions; -} - -export interface TooltipDisplayOptions { - content: string | BaseEntity; - componentName: ComponentName; - position: PositionType; - condition: boolean; -} - -@Injectable() -export class ComponentData { - path: string; - current: any; - emitter: EventEmitter; -} - -@Injectable({ - providedIn: 'root' -}) -export class TooltipService { - private positionSource = new Subject(); - position$ = this.positionSource.asObservable(); - timeOut: any; - - /** - * TODO: show a tooltip if there is a condition - * - * @returns - * @memberof TooltipComponent - */ - isShow(source: HTMLElement, options: TooltipDisplayOptions) { - if (options.condition) { - return source.offsetWidth !== source.scrollWidth; - } - return true; - } - - show(event: MouseEvent, source: HTMLElement, options: TooltipDisplayOptions) { - this.positionSource.next(); - clearTimeout(this.timeOut); - if (this.isShow(source, options)) { - this.positionSource.next({ event, source, options }); - } - } - - hide(withoutTimout = false, timeout = 500) { - if (withoutTimout) { - this.positionSource.next(); - return; - } - - this.timeOut = setTimeout(() => this.positionSource.next(), timeout); - } - - mouseEnterTooltip() { - clearTimeout(this.timeOut); - } - - mouseLeaveTooltip() { - this.hide(); - } -} diff --git a/web/src/app/shared/components/upgrades/master/master.component.html b/web/src/app/shared/components/upgrades/master/master.component.html deleted file mode 100644 index 2e6b13121a..0000000000 --- a/web/src/app/shared/components/upgrades/master/master.component.html +++ /dev/null @@ -1,70 +0,0 @@ - -

No data for the upgrades!

-
- - - Let's choose first - - - -

-
- - -
- -
- -
- - -
- -
- - -
- - - - Configuration - -
- Verbose -
- - -
-
-
- - Host Components - - - - - -
- -
- - -
- - Verbose - -
- - - - - - - -
- -
-
diff --git a/web/src/app/shared/components/upgrades/master/master.component.scss b/web/src/app/shared/components/upgrades/master/master.component.scss deleted file mode 100644 index 96d0fd8a14..0000000000 --- a/web/src/app/shared/components/upgrades/master/master.component.scss +++ /dev/null @@ -1,18 +0,0 @@ -.action-button { - background: none !important; - margin: 6px 0; - - &:hover { - background: rgba(255, 255, 255, 0.04) !important; - } -} - -.controls-container { - display: flex; - justify-content: space-between; - align-items: center; - - &.margin { - margin-top: 26px !important; - } -} diff --git a/web/src/app/shared/components/upgrades/master/master.component.spec.ts b/web/src/app/shared/components/upgrades/master/master.component.spec.ts deleted file mode 100644 index 8d26d25d36..0000000000 --- a/web/src/app/shared/components/upgrades/master/master.component.spec.ts +++ /dev/null @@ -1,299 +0,0 @@ -// Licensed 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 { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { MatListModule } from '@angular/material/list'; -import { ApiService } from '@app/core/api/api.service'; -import { FieldService } from '@app/shared/configuration/services/field.service'; -import { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component'; -import { ServiceHostComponent } from '@app/shared/host-components-map/services2hosts/service-host.component'; -import { UpgradeMasterConfigComponent } from './upgrade-master-config.component'; -import { UpgradeMasterComponent as MasterComponent } from './master.component'; -import { MasterService } from './master.service'; -import {IConfig} from "@app/shared/configuration/types"; -import {IActionParameter, IUIOptions} from "@app/core/types"; - -describe('MasterComponent', () => { - let component: MasterComponent; - let fixture: ComponentFixture; - - let ApiServiceStub: Partial; - let FieldServiceStub: Partial; - - beforeEach(async () => { - ApiServiceStub = {}; - FieldServiceStub = new FieldService({} as FormBuilder); - - TestBed.configureTestingModule({ - imports: [MatListModule], - declarations: [MasterComponent, UpgradeMasterConfigComponent], - providers: [MasterService, {provide: ApiService, useValue: ApiServiceStub}, { - provide: FieldService, - useValue: FieldServiceStub - }], - schemas: [NO_ERRORS_SCHEMA] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(MasterComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('input data for model property must be defined', () => { - component.model = {upgrades: []}; - fixture.detectChanges(); - expect(component.model).toBeDefined(); - }); - - it('input data for model.actons property must be array', () => { - component.model = {upgrades: []}; - fixture.detectChanges(); - expect(component.model.upgrades).toBeDefined(); - expect(component.model.upgrades).toEqual(jasmine.any(Array)); - }); - - it('should be show template if model.upgrades.length === 0', () => { - component.model = {upgrades: []}; - fixture.detectChanges(); - const compHost: HTMLElement = fixture.debugElement.nativeElement; - expect(compHost.querySelector('p').textContent).toBe('No data for the upgrades!'); - }); - - it('should be show template for current upgrade if model.upgrades.length === 1 and config = null and host-map = null', () => { - component.model = { - upgrades: [{ - bundle_id: 1, - config: null, - description: '', - do: 'url', - from_edition: ['community'], - hostcomponentmap: null, - id: 1, - license: '', - license_url: '', - max_strict: true, - max_version: '', - min_strict: false, - min_version: '', - name: '', - display_name: '', - state_available: '', - state_on_success: '', - ui_options: null, - upgradable: true, - url: '' - }] - }; - fixture.detectChanges(); - const compHost: HTMLElement = fixture.debugElement.nativeElement; - const cancelButton = compHost.querySelector('button[color="primary"]'); - const runButton = compHost.querySelector('button[color="accent"]'); - expect(runButton).toBeTruthy(); - expect(cancelButton).toBeTruthy(); - expect(cancelButton.textContent).toContain('Cancel'); - expect(runButton.textContent).toContain('Run'); - }); - - it('should be show upgrades list for choose current upgrade if model.upgrades.length > 1', () => { - component.model = { - upgrades: [ - { - bundle_id: 1, - config: {} as IConfig, - description: '', - do: 'url', - from_edition: ['community'], - hostcomponentmap: [] as IActionParameter[], - id: 1, - license: '', - license_url: '', - max_strict: true, - max_version: '', - min_strict: false, - min_version: '', - name: '', - display_name: '', - state_available: '', - state_on_success: '', - ui_options: {} as IUIOptions, - upgradable: true, - url: '' - }, - { - bundle_id: 1, - config: {} as IConfig, - description: '', - do: 'url', - from_edition: ['community'], - hostcomponentmap: [] as IActionParameter[], - id: 1, - license: '', - license_url: '', - max_strict: true, - max_version: '', - min_strict: false, - min_version: '', - name: '', - display_name: '', - state_available: '', - state_on_success: '', - ui_options: {} as IUIOptions, - upgradable: true, - url: '' - } - ] - }; - fixture.detectChanges(); - const compHost: HTMLElement = fixture.debugElement.nativeElement; - // expect(compHost.querySelector('i').textContent).toBe("Let's choose first"); - const buttonsLength = compHost.querySelector('mat-action-list').getElementsByTagName('button').length; - expect(buttonsLength).toBeGreaterThan(1); - }); - - it('should be show template for current upgrade if config exist only', () => { - component.model = { - upgrades: [ - { - bundle_id: 1, - config: { - config: [ - { - type: 'string', - name: 'test', - display_name: 'display name test', - subname: '', - default: null, - value: null, - required: false, - description: '', - read_only: false, - activatable: false, - group_config: null, - } - ] - } as IConfig, - description: '', - do: 'url', - from_edition: ['community'], - hostcomponentmap: null, - id: 1, - license: '', - license_url: '', - max_strict: true, - max_version: '', - min_strict: false, - min_version: '', - name: '', - display_name: '', - state_available: '', - state_on_success: '', - ui_options: {} as IUIOptions, - upgradable: true, - url: '' - } - ] - }; - fixture.detectChanges(); - const de = fixture.debugElement.nativeElement; - const config = de.querySelector('app-upgrade-master-config'); - const hm = de.querySelector('app-service-host'); - expect(hm).toBeNull(); - expect(config).toBeTruthy(); - }); - - it('should be show template for current upgrade if host-map exist only', () => { - component.model = { - upgrades: [{ - bundle_id: 1, config: null, description: '', do: 'url', from_edition: ['community'], - hostcomponentmap: [{component: '', action: 'add', service: ''}] as IActionParameter[], id: 1, license: '', - license_url: '', max_strict: true, max_version: '', min_strict: false, min_version: '', name: '', display_name: '', - state_available: '', state_on_success: '', ui_options: {} as IUIOptions, upgradable: true, url: '' - }] - }; - fixture.detectChanges(); - const de = fixture.debugElement.nativeElement; - const config = de.querySelector('app-upgrade-master-config'); - const hm = de.querySelector('app-service-host'); - expect(config).toBeNull(); - expect(hm).toBeTruthy(); - }); - - it('should be show template for current upgrade with config and host-map', () => { - component.model = { - upgrades: [{ - bundle_id: 1, config: { - config: [ - { - type: 'string', - name: 'test', - display_name: 'display name test', - subname: '', - default: null, - value: null, - required: false, - description: '', - read_only: false, - activatable: false, - group_config: null, - } - ] - } as IConfig, description: '', do: 'url', from_edition: ['community'], - hostcomponentmap: [{component: '', action: 'add', service: ''}] as IActionParameter[], id: 1, license: '', - license_url: '', max_strict: true, max_version: '', min_strict: false, min_version: '', name: '', display_name: '', - state_available: '', state_on_success: '', ui_options: {} as IUIOptions, upgradable: true, url: '' - }] - }; - fixture.detectChanges(); - const de = fixture.debugElement.nativeElement; - const config = de.querySelector('app-upgrade-master-config'); - const hm = de.querySelector('app-service-host'); - expect(config).toBeTruthy(); - expect(hm).toBeTruthy(); - }); - - it('should be undefined value if ServiceHostComponent ConfigFieldComponent not exist', () => { - const service = fixture.debugElement.injector.get(MasterService); - const result = service.parseData(undefined); - expect(result).toBeUndefined(); - }); - - it('check value when ConfigFieldComponent exist', () => { - const service = fixture.debugElement.injector.get(MasterService); - - const config = { - form: new FormGroup({string_ctr: new FormControl('string_test'), bool_ctr: new FormControl(true)}), - rawConfig: { - config: [ - {name: 'string_ctr', type: 'string', value: 'string_test'}, - {name: 'bool_ctr', type: 'boolean', value: true} - ] - } - } as ConfigFieldsComponent; - - const result = service.parseData({config}); - expect(result).toEqual({config: {string_ctr: 'string_test', bool_ctr: true}, hc: undefined, attr: undefined}); - }); - - it('check value when ServiceHostComponent exist', () => { - const service = fixture.debugElement.injector.get(MasterService); - const hc = [{host_id: 1, service_id: 4, component_id: 1, id: 9}]; - const hostmap = {statePost: {data: hc}} as ServiceHostComponent; - const result = service.parseData({hostmap}); - expect(result).toEqual({config: undefined, hc, attr: undefined}); - }); -}); diff --git a/web/src/app/shared/components/upgrades/master/master.component.ts b/web/src/app/shared/components/upgrades/master/master.component.ts deleted file mode 100644 index 3f56dabc38..0000000000 --- a/web/src/app/shared/components/upgrades/master/master.component.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed 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 { Component, ElementRef, EventEmitter, OnInit, ViewChild } from '@angular/core'; -import { DynamicComponent, DynamicEvent } from '@app/shared/directives/dynamic/dynamic.directive'; -import { BaseDirective } from '@app/shared/directives'; -import { IMasterData, IValue, MasterService, whatShow } from './master.service'; -import { IUpgrade } from "@app/shared/components"; -import { UpgradeParameters } from "@app/shared/components/upgrades/upgrade.directive"; - -@Component({ - selector: 'app-master', - templateUrl: './master.component.html', - styleUrls: ['./master.component.scss'], - providers: [MasterService], -}) -export class UpgradeMasterComponent extends BaseDirective implements DynamicComponent, OnInit { - event: EventEmitter = new EventEmitter(); - model: UpgradeParameters; - upgrade: IUpgrade; - show: whatShow; - - verbose = false; - - @ViewChild('runBtn', { read: ElementRef }) runBtn: ElementRef; - - constructor(private service: MasterService) { - super(); - } - - ngOnInit(): void { - if (this.model.upgrades?.length === 1) this.choose(this.model.upgrades[0]); - } - - choose(upgrade: IUpgrade) { - this.upgrade = upgrade; - this.show = this.service.spotShow(upgrade); - } - - isDisabled(value: IValue) { - return value && ((value.hostmap && value.hostmap.noValid) || (value.config && !value.config.form?.valid)); - } - - run(value: IValue = {}) { - const data: IMasterData = this.service.parseData(value); - - if (data) { - data.verbose = this.verbose; - } - - this.service - .send(this.upgrade.do, data) - .pipe(this.takeUntil()) - .subscribe(() => this.cancel()); - } - - onEnterKey() { - this.runBtn.nativeElement.click(); - } - - cancel() { - this.event.emit({ name: 'cancel' }); - } - - needMargin() { - return !(this?.model?.upgrades[0]?.config?.config?.length > 0 && this?.model?.upgrades[0]?.hostcomponentmap?.length > 0); - } -} diff --git a/web/src/app/shared/components/upgrades/master/master.service.ts b/web/src/app/shared/components/upgrades/master/master.service.ts deleted file mode 100644 index d99e6f599f..0000000000 --- a/web/src/app/shared/components/upgrades/master/master.service.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { ApiService } from '@app/core/api'; -import { FieldService } from '@app/shared/configuration/services/field.service'; -import { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component'; -import { ServiceHostComponent } from '@app/shared/host-components-map/services2hosts/service-host.component'; -import { Post } from '@app/shared/host-components-map/types'; -import { IConfigAttr } from '@app/shared/configuration/types'; -import { IOutput } from '@app/shared/configuration/services/field.service'; -import { IUpgrade } from "@app/shared/components"; - -export interface IValue { - config?: ConfigFieldsComponent; - hostmap?: ServiceHostComponent; -} - -export enum whatShow { - none = 'none', - config = 'config', - hostMap = 'hostmap', - stepper = 'stepper', -} - -export interface IMasterData { - attr: IConfigAttr; - config: IOutput; - hc: Post[]; - verbose?: boolean; -} - -@Injectable() -export class MasterService { - constructor(private api: ApiService, private configService: FieldService) {} - - spotShow(upgrade: IUpgrade): whatShow { - const config = upgrade.config?.config?.length; - const hm = upgrade.hostcomponentmap?.length; - return config ? (hm ? whatShow.stepper : whatShow.config) : hm ? whatShow.hostMap : whatShow.none; - } - - parseData(v: IValue): IMasterData { - const getData = (attr: IConfigAttr, c: ConfigFieldsComponent, h: ServiceHostComponent) => { - const config = c ? this.configService.parseValue(c.form.value, c.rawConfig.config) : undefined; - const hc = h?.statePost.data; - return { attr, config, hc }; - }; - return v ? getData(v.config?.attr, v.config, v.hostmap) : undefined; - } - - send(url: string, value: { config: any; hc: Post[] }) { - return this.api.post(url, value); - } -} diff --git a/web/src/app/shared/components/upgrades/master/upgrade-master-config.component.ts b/web/src/app/shared/components/upgrades/master/upgrade-master-config.component.ts deleted file mode 100644 index c8c515ee29..0000000000 --- a/web/src/app/shared/components/upgrades/master/upgrade-master-config.component.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed 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 { Component, Input, ViewChild } from '@angular/core'; -import { FieldService } from '@app/shared/configuration/services/field.service'; -import { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component'; -import { IUpgrade } from "@app/shared/components"; - -@Component({ - selector: 'app-upgrade-master-config', - template: ` -
- Advanced -
- - `, -}) -export class UpgradeMasterConfigComponent { - @Input() upgrade: IUpgrade; - - @ViewChild('fields') fields: ConfigFieldsComponent = {} as ConfigFieldsComponent; - - set advanced(value: boolean) { - this.config.filterApply(this.fields.dataOptions, { advanced: value, search: '' }); - } - - constructor(private config: FieldService) {} -} diff --git a/web/src/app/shared/components/upgrades/upgrade.component.ts b/web/src/app/shared/components/upgrades/upgrade.component.ts deleted file mode 100644 index c51f1820ab..0000000000 --- a/web/src/app/shared/components/upgrades/upgrade.component.ts +++ /dev/null @@ -1,101 +0,0 @@ -// Licensed 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 { Component, EventEmitter, Input, Output } from '@angular/core'; -import { ApiService } from '../../../core/api'; -import { EmmitRow, IActionParameter, IUIOptions } from '../../../core/types'; -import { Observable } from 'rxjs'; -import { filter } from 'rxjs/operators'; -import { EventHelper } from '@app/adwp'; -import { IIssues } from '../../../models/issue'; -import { IssueHelper } from '../../../helpers/issue-helper'; -import { IConfig } from "../../configuration/types"; - -export interface UpgradeItem { - upgradable: boolean; - upgrade: string; - issue: IIssues; -} - -export interface IUpgrade { - bundle_id: number; - config: IConfig; - description: string; - do: string; - from_edition: string[] - hostcomponentmap:IActionParameter[]; - id: number; - license: string; - license_url: string; - max_strict: boolean; - max_version: string; - min_strict: boolean; - min_version: string; - name: string; - display_name: string; - state_available: string; - state_on_success: string; - ui_options: IUIOptions; - upgradable: boolean; - url: string; -} - -@Component({ - selector: 'app-upgrade', - template: ` - - - - - - - ` -}) -export class UpgradeComponent { - EventHelper = EventHelper; - list$: Observable; - pRow: UpgradeItem = { upgradable: false, upgrade: '', issue: null }; - - @Input() xPosition = 'before'; - @Input() type: string; - - @Input() - set row(row: UpgradeItem) { - this.pRow = row; - this.list$ = this.getUpgrades(this.pRow.upgrade); - } - - @Output() - refresh: EventEmitter = new EventEmitter(); - - constructor(private api: ApiService) {} - - checkIssue() { - return this.pRow.upgradable && !IssueHelper.isIssue(this.pRow.issue); - } - - getUpgrades(upgrade: string): Observable { - return this.api.get(`${upgrade}?ordering=-name`).pipe( - filter((list: IUpgrade[]) => !!list.length) - ); - } -} diff --git a/web/src/app/shared/components/upgrades/upgrade.directive.ts b/web/src/app/shared/components/upgrades/upgrade.directive.ts deleted file mode 100644 index 19f591cc8e..0000000000 --- a/web/src/app/shared/components/upgrades/upgrade.directive.ts +++ /dev/null @@ -1,342 +0,0 @@ -// Licensed 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 { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core'; -import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; -import { DialogComponent } from '../dialog.component'; -import { IUpgrade } from "./upgrade.component"; -import { concat, from, Observable, of } from "rxjs"; -import {concatMap, filter, map, switchMap, tap } from "rxjs/operators"; -import { ApiService } from "@app/core/api"; -import { EmmitRow, Entities, License } from "@app/core/types"; -import { BaseDirective } from "../../directives"; -import { UpgradeMasterComponent as component } from "../upgrades/master/master.component"; -import { AddService } from "@app/shared/add-component/add.service"; -import { IRawHosComponent } from "@app/shared/host-components-map/types"; -import { ListResult } from "@app/models/list-result"; -import { ClusterService } from "@app/core/services/cluster.service"; -import { ICluster } from "@app/models/cluster"; -import { ServiceService } from "@app/services/service.service"; - -export interface UpgradeParameters { - cluster?: { - id: number; - hostcomponent: IRawHosComponent; - }; - upgrades: IUpgrade[]; -} - -@Directive({ - selector: '[appUpgrades]' -}) -export class UpgradesDirective extends BaseDirective { - @Input('appUpgrades') inputData: IUpgrade; - @Input() clusterId: number; - @Input() bundleId: number; - @Input() type: string; - @Output() refresh: EventEmitter = new EventEmitter(); - - hc: IRawHosComponent; - needPrototype = false; - needLicenseAcceptance = []; - - - constructor(private api: ApiService, - private dialog: MatDialog, - private add: AddService, - private service: ServiceService, - private cluster: ClusterService) { - super(); - } - - @HostListener('click') - onClick() { - this.dialog.closeAll(); - this.checkServicesAndPrepare(); - } - - get hasConfig(): boolean { - return this?.inputData?.config?.config?.length > 0 - } - - get hasHostComponent(): boolean { - return this?.inputData?.hostcomponentmap?.length > 0 - } - - get hasDisclaimer(): boolean { - return !!this?.inputData?.ui_options['disclaimer'] - } - - prepare(): void { - let dialogModel: MatDialogConfig - const maxWidth = '1400px'; - const isMulty = this?.inputData.upgradable; - const width = isMulty || this.hasConfig || this.hasHostComponent ? '90%' : '400px'; - const title = this?.inputData.ui_options['disclaimer'] ? this?.inputData.ui_options['disclaimer'] : isMulty ? 'Run upgrades?' : `Run upgrade [ ${this?.inputData.name} ]?`; - const data: IUpgrade = this.inputData as IUpgrade; - const model: UpgradeParameters = { - cluster: { - id: this.clusterId, - hostcomponent: this.hc, - }, - upgrades: [this.inputData], - } - - dialogModel = { - width, - maxWidth, - data: { - title, - model, - component, - } - }; - - if (this.hasDisclaimer) { - if (this.hasConfig || this.hasHostComponent) { - this.runUpgrade(data, dialogModel); - } else if (!this.hasConfig && !this.hasHostComponent) { - this.runOldUpgrade(data); - } - } else { - if (!this.hasConfig && !this.hasHostComponent) { - dialogModel.maxWidth = '1400px'; - dialogModel.width = '400px'; - dialogModel.minHeight = '180px'; - dialogModel.data.title = 'Are you sure you want to upgrade?' - dialogModel.data.text = 'The cluster will be prepared for upgrade'; - } - - if (this.needLicenseAcceptance.length > 0) { - this.licenseCheckOnUpgrade() - .subscribe(null, (e) => console.log(e), () => this.dialog.open(DialogComponent, dialogModel)); - } else { - this.dialog.open(DialogComponent, dialogModel); - } - - } - } - - runUpgrade(item: IUpgrade, dialogModel: MatDialogConfig) { - this.fork(item) - .pipe( - tap(text => { - return this.dialog - .open(DialogComponent, { - data: { - title: 'Are you sure you want to upgrade?', - text: item.ui_options['disclaimer'] || text, - disabled: !item.upgradable, - controls: item.license === 'unaccepted' ? { - label: 'Do you accept the license agreement?', - buttons: ['Yes', 'No'] - } : ['Yes', 'No'] - } - }) - .afterClosed() - .pipe( - filter(yes => yes) - ) - .subscribe(() => { - if (this.needLicenseAcceptance.length > 0) { - this.licenseCheckOnUpgrade() - .subscribe(null, (e) => console.log(e), () => this.dialog.open(DialogComponent, dialogModel)) - } else { - this.dialog.open(DialogComponent, dialogModel); - } - }) - } - ) - ).subscribe(); - } - - runOldUpgrade(item: IUpgrade) { - const license$ = item.license === 'unaccepted' ? this.api.put(`${item.license_url}accept/`, {}) : of(); - const do$ = this.api.post<{ id: number }>(item.do, {}); - - this.fork(item) - .pipe( - tap(text => - this.dialog - .open(DialogComponent, { - data: { - title: 'Are you sure you want to upgrade?', - text: item.ui_options['disclaimer'] || text, - disabled: !item.upgradable, - controls: item.license === 'unaccepted' ? { - label: 'Do you accept the license agreement?', - buttons: ['Yes', 'No'] - } : ['Yes', 'No'] - } - }) - .afterClosed() - .pipe( - filter(yes => yes), - switchMap(() => concat(license$, do$)) - ) - .subscribe((row) => { - if (this.needLicenseAcceptance.length > 0) { - this.licenseCheckOnUpgrade() - .subscribe(null, (e) => console.log(e), () => this.refresh.emit({ cmd: 'refresh', row })); - } else { - this.refresh.emit({ cmd: 'refresh', row }); - } - }) - ) - ) - .subscribe(); - } - - fork(item: IUpgrade) { - const flag = item.license === 'unaccepted'; - return flag ? this.api.get<{ text: string }>(item.license_url).pipe(map(a => a.text)) : of(item.description); - } - - preparePrototypesForUpgrade(addedServicesArray = null) { - this.getPrototype({ - bundle_id: this.inputData.bundle_id, - license: 'unaccepted', - limit: 500, - }).subscribe((res) => { - this.needLicenseAcceptance = res - .filter((item) => - addedServicesArray - ? item.type === 'cluster' || addedServicesArray.includes(item.name) - : item.type === 'provider' - ) - .map((item) => ({ - prototype_id: item.id, - entity_name: item.name, - license: item.license, - license_url: item.license_url, - })); - if (this.hasHostComponent) { - this.checkHostComponents(); - } else { - this.prepare(); - } - }); - } - - checkServicesAndPrepare() { - if (this.type === 'cluster') { - if (!this.add.Cluster) { - this.getCluster().pipe( - tap((res: ICluster) => this.cluster.Cluster = res) - ).subscribe(); - } - - this.getClusterServices().subscribe(res => { - const addedServicesToCluster = res.map((service) => service.name); - this.preparePrototypesForUpgrade(addedServicesToCluster); - }); - } else { - this.preparePrototypesForUpgrade(); - } - } - - licenseCheckOnUpgrade() { - const licenseObj = {}; - - return from(this.needLicenseAcceptance) - .pipe( - tap((entity) => licenseObj[entity.prototype_id] = { entity_name: entity.entity_name, license: entity.license }), - concatMap((entity) => this.api.get(`/api/v1/stack/prototype/${entity.prototype_id}/license/`).pipe()), - concatMap((result) => { - const prototype_id = result.accept.substring( - result.accept.lastIndexOf("prototype/") + 10, - result.accept.indexOf("/license") - ) as unknown as number; - - return this.dialog - .open(DialogComponent, { - data: { - title: `Accept license agreement ${licenseObj[prototype_id].entity_name}`, - text: result.text, - closeOnGreenButtonCLick: true, - controls: { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] }, - }, - }) - .beforeClosed() - .pipe( - tap((result) => { - if (!result) throw new Error(`License was declined`) // hack to end the flow if license declined - }), - filter((yes) => yes), - switchMap(() => { - return this.api.put(`/api/v1/stack/prototype/${prototype_id}/license/accept/`, {}).pipe() - }) - ) - }) - ) - } - - checkHostComponents() { - this.getClusterInfo() - .pipe( - tap((cluster): any => { - const hostComponentMap = this.inputData.hostcomponentmap; - - hostComponentMap.forEach((hc, index) => { - if (!cluster.component.find(c => c.name === hc.component)) { - this.needPrototype = true; - const params = { - bundle_id: this.inputData.bundle_id, - type: 'component', - name: hc.component, - parent_name: hc.service, - limit: 50, - offset: 0 - }; - - // fix later - this.add.getPrototype('prototype', params).subscribe((prototype): any => { - if (prototype[0]) { - cluster.component.push(prototype[0]); - this.hc = cluster; - } - - if (hostComponentMap.length === index + 1) { - if (!this.hc) this.hc = cluster; - this.prepare(); - } - }) - } - }) - - if (!this.needPrototype) { - this.hc = cluster; - this.prepare(); - } - }), - ).subscribe(); - } - - getCluster(): Observable { - return this.api.get(`api/v1/cluster/${this.clusterId}/`); - } - - getClusterInfo(): Observable { - return this.api.get(`api/v1/cluster/${this.clusterId}/hostcomponent/`); - } - - getPrototype(params): Observable { - return this.add.getPrototype('prototype', params); - } - - getClusterServices(): Observable { - return this.api.get>(`api/v1/cluster/${this.clusterId}/service/`); - } - - getPrototypeServices(): Observable { - return this.api.get>('/api/v1/stack/service/'); - } -} diff --git a/web/src/app/shared/configuration/attributes/attribute-provider.component.scss b/web/src/app/shared/configuration/attributes/attribute-provider.component.scss deleted file mode 100644 index 92669017ba..0000000000 --- a/web/src/app/shared/configuration/attributes/attribute-provider.component.scss +++ /dev/null @@ -1,19 +0,0 @@ -@import "src/mixins"; - -:host { - display: flex; - width: 100%; - margin-bottom: 20px; -} - -:host:last-child { - margin-bottom: 0; -} - -:host:nth-child(odd) { - background-color: #4e4e4e; -} - -:host.read-only { - @include read-only-field; -} diff --git a/web/src/app/shared/configuration/attributes/attribute-provider.component.ts b/web/src/app/shared/configuration/attributes/attribute-provider.component.ts deleted file mode 100644 index ad03cfd242..0000000000 --- a/web/src/app/shared/configuration/attributes/attribute-provider.component.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { - AfterViewInit, - ChangeDetectorRef, - Component, - ComponentFactory, - ComponentFactoryResolver, - ComponentRef, - ContentChild, - ContentChildren, - HostBinding, - Input, OnChanges, - QueryList, SimpleChanges, - TemplateRef, - ViewChild, - ViewContainerRef -} from '@angular/core'; -import { ConfigFieldMarker } from '@app/shared/configuration/attributes/config-field.directive'; -import { AttributeService, AttributeWrapper } from '@app/shared/configuration/attributes/attribute.service'; -import { FormGroup } from '@angular/forms'; -import { IFieldOptions } from '@app/shared/configuration/types'; -import { CONFIG_FIELD, FieldComponent } from '@app/shared/configuration/field/field.component'; - -@Component({ - selector: 'app-config-field-attribute-provider', - template: ` - - - - - - `, - styleUrls: ['./attribute-provider.component.scss'], -}) -export class ConfigFieldAttributeProviderComponent implements OnChanges, AfterViewInit { - - template: TemplateRef; - - containerRef: ComponentRef; - - @Input('form') - parametersForm: FormGroup; - - @Input() - options: IFieldOptions; - - @Input() - uniqId: string; - - @HostBinding('class.read-only') get readOnly() { - return this.options.read_only; - } - - @ViewChild('container', { read: ViewContainerRef }) - container: ViewContainerRef; - - @ContentChild(ConfigFieldMarker) - field: ConfigFieldMarker; - - @ContentChildren(CONFIG_FIELD, { descendants: true }) - fieldComponent: QueryList; - - constructor(private componentFactoryResolver: ComponentFactoryResolver, - public attributesSrv: AttributeService, - private _cdr: ChangeDetectorRef) {} - - ngOnChanges(changes: SimpleChanges) { - this.containerRef?.instance['repairControlsAfterSave'](changes['parametersForm']['currentValue']); - } - - ngAfterViewInit(): void { - this.container.clear(); - if (this.attributesSrv.attributes[this.uniqId]) { - this.attributesSrv.attributes[this.uniqId].forEach((attribute) => { - if (attribute.wrapper) { - const factory: ComponentFactory = this.componentFactoryResolver.resolveComponentFactory(attribute.wrapper); - this.containerRef = this.container.createComponent(factory); - this.containerRef.instance.uniqId = this.uniqId; - this.containerRef.instance.fieldTemplate = this.field.template; - this.containerRef.instance.wrapperOptions = attribute.options; - this.containerRef.instance.fieldOptions = this.options; - this.containerRef.instance.attributeForm = attribute.form; - this.containerRef.instance.parametersForm = this.parametersForm; - setTimeout(() => this.containerRef.instance.field = this.fieldComponent.first, 0); - } - }); - } else { - this.template = this.field.template; - } - } -} diff --git a/web/src/app/shared/configuration/attributes/attribute.service.ts b/web/src/app/shared/configuration/attributes/attribute.service.ts deleted file mode 100644 index 1a07fe464f..0000000000 --- a/web/src/app/shared/configuration/attributes/attribute.service.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { Inject, Injectable, InjectionToken, TemplateRef, Type } from '@angular/core'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { IFieldOptions } from '@app/shared/configuration/types'; -import { isBoolean, isEmptyObject } from '@app/core/types'; -import { FieldComponent } from '@app/shared/configuration/field/field.component'; - -export const ATTRIBUTES_OPTIONS = new InjectionToken('Attributes options'); - -export interface AttributeOptions { - name: ConfigAttributeNames; - wrapper?: Type; - options?: ConfigAttributeOptions; -} - -export type AttributesOptions = Record - -export interface AttributeWrapper { - uniqId: string; - fieldTemplate: TemplateRef; - wrapperOptions: ConfigAttributeOptions; - fieldOptions: IFieldOptions; - attributeForm: FormGroup; - parametersForm: FormGroup; - field: FieldComponent; -} - -export enum ConfigAttributeNames { - // an attribute for adding config parameters to group - GROUP_KEYS = 'group_keys', - // an attribute for config parameters that determines whether this parameter can be added to the config group - CUSTOM_GROUP_KEYS = 'custom_group_keys' -} - -export interface ConfigAttributesJSON { - [key: string]: any; -} - -export interface ConfigAttributeOptions { - tooltipText?: string; - - [key: string]: any; -} - -export type ConfigAttribute = AttributeOptions & { value: ConfigAttributesJSON, form: FormGroup }; - -export type Attributes = Map; - -@Injectable() -export class AttributeService { - - private readonly _activeAttributes: Partial[] = [ - ConfigAttributeNames.GROUP_KEYS, - ConfigAttributeNames.CUSTOM_GROUP_KEYS - ]; - - get attributes(): Attributes[] { - return this._attributes; - } - - private _attributes: Attributes[] = []; - - constructor(@Inject(ATTRIBUTES_OPTIONS) private _configs: AttributesOptions, private _fb: FormBuilder) { - } - - init(json: ConfigAttributesJSON): string { - const uniqId = Math.random().toString(36).slice(2); - this._attributes[uniqId] = this._createAttributes(this._activeAttributes, json, this._configs); - - return uniqId; - } - - getByName(name: ConfigAttributeNames, uniqId): ConfigAttribute { - return this._attributes[uniqId].has(name) ? this._attributes[uniqId].get(name) : undefined; - } - - groupCheckboxToggle(groupName, value, uniqId): void { - this.attributes[uniqId].get(ConfigAttributeNames.GROUP_KEYS).value[groupName].value = value - } - - private _createAttributes(_activeAttributes: Partial[], json: ConfigAttributesJSON, configs: AttributesOptions): Attributes { - const isEmptyAttrs = !Object.keys(json || {}).length; - const isActiveAttrsPresent = !!Object.keys(json || {}).filter((x: ConfigAttributeNames) => this._activeAttributes.includes(x)).length; - if (isEmptyAttrs || !isActiveAttrsPresent) { - return; - } - - return new Map(this._activeAttributes.map((attr) => [ - attr, - new ConfigAttributeFactory(this._fb).create(attr, json[attr], configs[attr], json), - ])); - } - - removeAttributes(uniqId) { - delete this._attributes[uniqId]; - } - - rawAttributes(uniqId) { - let json = {}; - if (this._attributes[uniqId]) { - for (const [key, value] of this._attributes[uniqId].entries()) { - json = { - ...json, - [key]: this.makeValue(value) - }; - } - } - - return json; - } - - makeValue(values) { - let json = {}; - const formValue = values.form.getRawValue(); - - Object.keys(values.value).forEach((key, index) => { - json = { - ...json, - [key]: values.value[key]?.['fields'] ? { fields: formValue[key], value: values.value[key]?.value } : formValue[key] - } - }) - - return json; - } -} - -export const createFormForAttribute = (fb: FormBuilder, json: ConfigAttributesJSON, attr: ConfigAttributeNames, disabled: boolean = false): FormGroup => { - const buildFormGroup = (json: boolean | ConfigAttributesJSON) => { - const data = Object.entries(json).map(([key, value]) => [key, value]).reduce((acc, [key, value]: [string, boolean | ConfigAttributesJSON]) => { - - if (isBoolean(value) || isEmptyObject(value)) { - return { - ...acc, - [key]: { value, disabled } - }; - } else if (!isEmptyObject(value)) { - return { ...acc, [key]: buildFormGroup(value['fields']) }; - } - - }, {}); - - return fb.group(data); - }; - - return buildFormGroup(json[attr]); -}; - - -export class ConfigAttributeFactory { - - constructor(private fb: FormBuilder) {} - - create(name: ConfigAttributeNames, value: ConfigAttributesJSON, options: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute { - if (!this[name]) { - return; - } - - return this[name](value, options, json); - } - - [ConfigAttributeNames.GROUP_KEYS](value: ConfigAttributesJSON, { - name, - options, - wrapper - }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute { - - const form = createFormForAttribute(this.fb, json, name); - - return { - name, - value, - wrapper, - options, - form - }; - } - - [ConfigAttributeNames.CUSTOM_GROUP_KEYS](value: ConfigAttributesJSON, { - name, - options - }: AttributeOptions, json: ConfigAttributesJSON): ConfigAttribute { - - const form = createFormForAttribute(this.fb, json, name); - - return { name, value, options, form }; - } - -} diff --git a/web/src/app/shared/configuration/attributes/attributes.module.ts b/web/src/app/shared/configuration/attributes/attributes.module.ts deleted file mode 100644 index 11b57da5f7..0000000000 --- a/web/src/app/shared/configuration/attributes/attributes.module.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ModuleWithProviders, NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ReactiveFormsModule } from '@angular/forms'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { MatPseudoCheckboxModule } from '@angular/material/core'; -import { MatCheckboxModule } from '@angular/material/checkbox'; - -import { ATTRIBUTES_OPTIONS, AttributeService, AttributesOptions } from './attribute.service'; -import { GroupKeysWrapperComponent } from './attributes/group-keys/group-keys-wrapper.component'; -import { ConfigFieldMarker } from './config-field.directive'; -import { ConfigFieldAttributeProviderComponent } from './attribute-provider.component'; -import { TooltipModule } from '@app/shared/components/tooltip/tooltip.module'; - -@NgModule({ - declarations: [ - GroupKeysWrapperComponent, - ConfigFieldMarker, - ConfigFieldAttributeProviderComponent, - ], - imports: [ - CommonModule, - MatPseudoCheckboxModule, - MatCheckboxModule, - MatTooltipModule, - TooltipModule, - ReactiveFormsModule, - ], - exports: [ - ConfigFieldAttributeProviderComponent, - ConfigFieldMarker - ], - providers: [AttributeService] -}) -export class AttributesModule { - static forRoot(attributeConfig: AttributesOptions): ModuleWithProviders { - return { - ngModule: AttributesModule, - providers: [{ provide: ATTRIBUTES_OPTIONS, useValue: attributeConfig }] - }; - } -} diff --git a/web/src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.scss b/web/src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.scss deleted file mode 100644 index 3ccbe55c92..0000000000 --- a/web/src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -:host, .group-field, .group-keys-wrapper { - display: flex; - width: 100%; -} - -.group-checkbox { - display: flex; - align-items: center; - padding: 0 0 0 20px; -} - diff --git a/web/src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.ts b/web/src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.ts deleted file mode 100644 index e1e0f391b5..0000000000 --- a/web/src/app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { Component, Input, OnInit, TemplateRef } from '@angular/core'; -import { - AttributeService, - AttributeWrapper, - ConfigAttributeNames, - ConfigAttributeOptions -} from '@app/shared/configuration/attributes/attribute.service'; -import { FormControl, FormGroup } from '@angular/forms'; -import { IFieldOptions } from '@app/shared/configuration/types'; -import { BaseDirective } from '@app/adwp'; -import { MatCheckboxChange } from '@angular/material/checkbox'; -import { FieldComponent } from '@app/shared/configuration/field/field.component'; - -@Component({ - selector: 'app-group-keys-wrapper', - template: ` -
-
- -
-
- -
-
- `, - styleUrls: ['group-keys-wrapper.component.scss'], -}) -export class GroupKeysWrapperComponent extends BaseDirective implements AttributeWrapper, OnInit { - tooltipText: string = ''; - - groupControl: FormControl; - - parameterControl: () => FormControl; - - @Input() uniqId: string; - - @Input() fieldTemplate: TemplateRef; - - @Input() wrapperOptions: ConfigAttributeOptions; - - @Input() attributeForm: FormGroup; - - @Input() parametersForm: FormGroup; - - @Input() fieldOptions: IFieldOptions; - - @Input() field: FieldComponent; - - private _disabled: boolean; - - constructor(private _attributeSrv: AttributeService) { - super(); - } - - ngOnInit(): void { - this._resolveAndSetupControls(this.attributeForm, this.parametersForm, this.fieldOptions); - Promise.resolve().then(() => { - this._restoreStatus(); - this.disableIfReadOnly(); - }); - } - - repairControlsAfterSave(currentParametersForm) { - this._resolveAndSetupControls(this.attributeForm, currentParametersForm, this.fieldOptions); - } - - private disableIfReadOnly() { - if (this.field?.options?.read_only) { - this.groupControl.disable(); - } - } - - private _resolveAndSetupControls(attributeForm: FormGroup, parametersForm: FormGroup, fieldOptions: IFieldOptions): void { - let attributeControl: FormGroup = attributeForm; - let parameterControl: FormGroup = parametersForm; - let enabled = this._attributeSrv.attributes[this.uniqId].get(ConfigAttributeNames.CUSTOM_GROUP_KEYS).value; - let text = this._attributeSrv.attributes[this.uniqId].get(ConfigAttributeNames.CUSTOM_GROUP_KEYS).options.tooltipText; - - const path = fieldOptions.key?.split('/').reverse(); - - this.groupControl = attributeControl.get(path) as FormControl; - this.parameterControl = () => parameterControl.get(path) as FormControl; - - if (!this.groupControl || !this.parameterControl()) return; - - path.forEach((part) => { - enabled = this._getFieldValue(enabled, part); - }); - - if (!enabled) { - Promise.resolve().then(() => { - this.groupControl.disable(); - this.parameterControl().disable(); - - this.tooltipText = text; - }); - } else { - Promise.resolve().then(() => { - this.groupControl.enable(); - if (this.groupControl.value) { - this.parameterControl().enable(); - if (this.field) this.field.disabled = false; - } else { - this.parameterControl().disable(); - if (this.field) this.field.disabled = true; - } - this.disableIfReadOnly(); - }) - - this.tooltipText = this.wrapperOptions.tooltipText; - this._disabled = !attributeControl.value; - } - } - - onChange(e: MatCheckboxChange) { - if (e.checked) { - this.parameterControl().enable(); - this.field.disabled = false; - } else { - this.parameterControl().disable(); - this.field.disabled = true; - } - } - - private _restoreStatus() { - if (this.field?.disabled) { - this.field.disabled = this._disabled; - } - } - - private _getFieldValue(attr, key) { - if (attr?.fields) return attr?.fields[key] - - return attr[key]; - } -} diff --git a/web/src/app/shared/configuration/attributes/config-field.directive.ts b/web/src/app/shared/configuration/attributes/config-field.directive.ts deleted file mode 100644 index 87d9e036b1..0000000000 --- a/web/src/app/shared/configuration/attributes/config-field.directive.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Directive, TemplateRef } from '@angular/core'; - -@Directive({ - selector: '[configField]' -}) -export class ConfigFieldMarker { - constructor(public template: TemplateRef) { - } - -} diff --git a/web/src/app/shared/configuration/configuration.module.ts b/web/src/app/shared/configuration/configuration.module.ts deleted file mode 100644 index 20d3c7dc08..0000000000 --- a/web/src/app/shared/configuration/configuration.module.ts +++ /dev/null @@ -1,90 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MaterialModule } from "@app/shared/material.module"; -import { FormElementsModule } from '../form-elements/form-elements.module'; -import { StuffModule } from '../stuff.module'; -import { FieldService } from './services/field.service'; -import { FieldComponent } from './field/field.component'; -import { ConfigFieldsComponent } from './fields/fields.component'; -import { GroupFieldsComponent } from './group-fields/group-fields.component'; -import { ConfigComponent } from './main/config.component'; -import { ItemComponent } from './scheme/item.component'; -import { RootComponent } from './scheme/root.component'; -import { SchemeComponent } from './scheme/scheme.component'; -import { SchemeService } from './scheme/scheme.service'; -import { ColorOptionDirective } from './tools/color-option.directive'; -import { HistoryComponent } from './tools/history.component'; -import { SearchComponent } from './tools/search.component'; -import { ToolsComponent } from './tools/tools.component'; -import { YspecService } from './yspec/yspec.service'; -import { AdwpListModule } from '@app/adwp'; -import { AddingModule } from '@app/shared/add-component/adding.module'; -import { ConfigService } from '@app/shared/configuration/services/config.service'; -import { ConfigGroupModule } from '@app/config-groups'; -import { AttributesModule } from '@app/shared/configuration/attributes/attributes.module'; -import { ConfigAttributeNames } from '@app/shared/configuration/attributes/attribute.service'; -import { GroupKeysWrapperComponent } from '@app/shared/configuration/attributes/attributes/group-keys/group-keys-wrapper.component'; -import { FilterComponent } from "@app/shared/configuration/tools/filter/filter.component"; -import { FilterListComponent } from "@app/shared/configuration/tools/filter/filter-list/filter-list.component"; -import { ServerFilterComponent } from './tools/server-filter/server-filter.component'; - -@NgModule({ - declarations: [ - FieldComponent, - ConfigFieldsComponent, - GroupFieldsComponent, - ConfigComponent, - HistoryComponent, - SearchComponent, - FilterComponent, - FilterListComponent, - ColorOptionDirective, - ToolsComponent, - SchemeComponent, - RootComponent, - ItemComponent, - ServerFilterComponent - ], - imports: [ - CommonModule, - FormsModule, - ReactiveFormsModule, - StuffModule, - FormElementsModule, - MaterialModule, - AdwpListModule, - AddingModule, - ConfigGroupModule, - AttributesModule.forRoot({ - group_keys: { - name: ConfigAttributeNames.GROUP_KEYS, - wrapper: GroupKeysWrapperComponent, - options: { - tooltipText: 'Group parameter' - } - }, - custom_group_keys: { - name: ConfigAttributeNames.CUSTOM_GROUP_KEYS, - options: { - tooltipText: 'This parameter can not be added to config group' - } - } - }), - ], - exports: [ConfigComponent, ConfigFieldsComponent, FilterComponent, FilterListComponent, ServerFilterComponent], - providers: [FieldService, YspecService, SchemeService, ConfigService], -}) -export class ConfigurationModule { -} diff --git a/web/src/app/shared/configuration/field/field.component.html b/web/src/app/shared/configuration/field/field.component.html deleted file mode 100644 index d3432548aa..0000000000 --- a/web/src/app/shared/configuration/field/field.component.html +++ /dev/null @@ -1,70 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - info_outline - - - - -
- - - more_vert - - {{ item.date | date: 'short' }} -  ----  {{ outputValue(item.value, true) }} - - diff --git a/web/src/app/shared/configuration/field/field.component.scss b/web/src/app/shared/configuration/field/field.component.scss deleted file mode 100644 index 4a46b166ac..0000000000 --- a/web/src/app/shared/configuration/field/field.component.scss +++ /dev/null @@ -1,64 +0,0 @@ -@import "src/mixins"; - -:host { - flex-wrap: wrap; - - .field { - display: flex; - align-items: center; - padding: 0 20px; - - &.advanced { - label { - border-bottom: dotted 1px #00e676 !important; - } - } - - & label { - font-size: 16px; - flex-basis: 25%; - border-bottom: dotted 1px #606060; - margin-right: 10px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - & label + * { - width: 100%; - display: flex; - align-items: center; - } - } - - & > .read-only { - @include read-only-field; - } - - .compare-list-container { - .compare-list { - .label { - margin: 0 10px; - } - } - } - - .info { - margin-left: 10px; - display: flex; - align-items: center; - - & > mat-icon { - margin-top: 3px; - } - - .icon-info { - vertical-align: middle; - } - } -} - -.break { - flex-basis: 100%; - height: 0; -} diff --git a/web/src/app/shared/configuration/field/field.component.ts b/web/src/app/shared/configuration/field/field.component.ts deleted file mode 100644 index 0a2ae3ad48..0000000000 --- a/web/src/app/shared/configuration/field/field.component.ts +++ /dev/null @@ -1,168 +0,0 @@ -// Licensed 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 { Component, HostBinding, InjectionToken, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { FieldDirective } from '@app/shared/form-elements/field.directive'; -import { BaseMapListDirective } from '@app/shared/form-elements/map.component'; - -import { SchemeComponent } from '../scheme/scheme.component'; -import { IFieldOptions } from '../types'; -import { BaseDirective } from '@app/adwp'; -import { PasswordComponent } from "@app/shared/form-elements/password/password.component"; -import { SecretTextComponent } from "@app/shared/form-elements/secret-text/secret-text.component"; -import { SecretFileComponent } from "@app/shared/form-elements/secret-file/secret-file.component"; - -export const CONFIG_FIELD = new InjectionToken('Config field'); - -@Component({ - selector: 'app-field', - templateUrl: './field.component.html', - styleUrls: ['./field.component.scss'], - providers: [ - { provide: CONFIG_FIELD, useExisting: FieldComponent } - ] -}) -export class FieldComponent extends BaseDirective implements OnInit, OnChanges { - @Input() - options: IFieldOptions; - - @HostBinding('class.read-only') get readOnly() { - return this.options.read_only; - } - @HostBinding('class') hostClass = 'field-row w100 d-flex'; - - @Input() - form: FormGroup; - currentFormGroup: FormGroup; - - noRefreshButtonFields = ['password', 'secrettext', 'secretmap', 'secretfile']; - disabled: boolean = false; - - @ViewChild('cc') inputControl: FieldDirective; - @ViewChild('pass') passControl: FieldDirective; - @ViewChild('sc') secretTextControl: FieldDirective; - @ViewChild('sf') secretFileControl: FieldDirective - - ngOnInit() { - this.initCurrentGroup(); - } - - ngOnChanges(changes: SimpleChanges): void { - if (!changes.form.firstChange) this.initCurrentGroup(); - } - - isSecretField(): boolean { - return this.noRefreshButtonFields.includes(this.options.controlType); - } - - initCurrentGroup() { - const [_, name] = this.options.key.split('/'); - this.currentFormGroup = name ? (this.form.controls[name] as FormGroup) : this.form; - } - - getTestName() { - return `${this.options.name}${this.options.subname ? '/' + this.options.subname : ''}`; - } - - outputValue(v: string, isPart = false) { - if (this.options.type === 'password') v = v.replace(/\w/gi, '*'); - if (['secrettext', 'secretfile'].includes(this.options.type)) v = '****'; - - return v.length > 80 ? (isPart ? v : `${v.substr(0, 80)}...`) : v; - } - - isAdvanced() { - return this.options.ui_options && this.options.ui_options.advanced; - } - - /** - * TODO: should be own restore() for each fieldComponent * - * @member FieldComponent - */ - restore() { - if (this.disabled) return; - - const field = this.currentFormGroup.controls[this.options.name]; - const defaultValue = this.options.default; - const type = this.options.type; - - if (field) { - if (type === 'json') { - field.setValue(defaultValue === null ? '' : JSON.stringify(defaultValue, undefined, 4)); - } else if (type === 'boolean') { - const allow = String(defaultValue) === 'true' || String(defaultValue) === 'false' || String(defaultValue) === 'null'; - field.setValue(allow ? defaultValue : null); - } else if (type === 'password') { - field.setValue(defaultValue); - field.updateValueAndValidity(); - - const confirm = this.currentFormGroup.controls[`confirm_${this.options.name}`]; - if (confirm) { - confirm.setValue(defaultValue); - confirm.updateValueAndValidity(); - } - } else if (type === 'map' || type === 'list') { - this.options.value = defaultValue; - (this.inputControl as BaseMapListDirective).reload(); - } else if (type === 'structure') { - this.options.value = defaultValue; - (this.inputControl as SchemeComponent).reload(); - } else { - field.setValue(defaultValue); - } - - this.options.value = field.value; - this.form.updateValueAndValidity(); - } - } - - reset() { - const type = this.options.type; - - if (this.disabled) return; - if (!this.noRefreshButtonFields.includes(type)) return; - - const field = this.currentFormGroup.controls[this.options.name]; - - switch (type) { - case('password'): - field.setValue(null); - field.updateValueAndValidity(); - - const confirm = this.currentFormGroup.controls[`confirm_${this.options.name}`]; - if (confirm) { - confirm.setValue(null); - confirm.updateValueAndValidity(); - } - (this.passControl as PasswordComponent).isHideDummy = true; - this.passControl['dummy'] = ''; - break; - case('secretfile'): - field.setValue(null); - field.updateValueAndValidity(); - (this.secretFileControl as SecretFileComponent).clear(); - break; - case('secrettext'): - field.setValue(null); - field.updateValueAndValidity(); - (this.secretTextControl as SecretTextComponent).clear(); - break; - case('secretmap'): - field.setValue(null); - field.updateValueAndValidity(); - break; - } - - this.options.value = field.value; - this.form.updateValueAndValidity(); - } -} diff --git a/web/src/app/shared/configuration/fields/fields.component.ts b/web/src/app/shared/configuration/fields/fields.component.ts deleted file mode 100644 index 8ecf83420f..0000000000 --- a/web/src/app/shared/configuration/fields/fields.component.ts +++ /dev/null @@ -1,110 +0,0 @@ -// Licensed 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 { Component, EventEmitter, Input, Output, QueryList, ViewChildren } from '@angular/core'; - -import { ChannelService, FullyRenderedService, keyChannelStrim } from '@app/core/services'; -import { FieldService, TFormOptions } from '../services/field.service'; -import { FieldComponent } from '../field/field.component'; -import { GroupFieldsComponent } from '../group-fields/group-fields.component'; -import { IConfig, IPanelOptions } from '../types'; -import { BaseDirective } from '@app/adwp'; -import { FormGroup } from "@angular/forms"; - -@Component({ - selector: 'app-config-fields', - template: ` - - - - - - - - - - - ` -}) -export class ConfigFieldsComponent extends BaseDirective { - - @Input() dataOptions: TFormOptions[] = []; - @Input() form: FormGroup; - @Input() uniqId: string; - @Output() - event = new EventEmitter<{ name: string; data?: any }>(); - - rawConfig: IConfig; - shapshot: any; - isAdvanced = false; - isCustomGroup = false; - - @Input() - set model(data: IConfig) { - if (!data) return; - this.rawConfig = data; - this.dataOptions = this.service.getPanels(data); - this.service.getAttrs(data, this.dataOptions.map(a => a.name), this.dataOptions); - this.form = this.service.toFormGroup(this.dataOptions); - this.isCustomGroup = this.checkCustomGroup(); - this.isAdvanced = data.config.some((a) => a.ui_options && a.ui_options.advanced); - this.shapshot = { ...this.form.value }; - this.event.emit({ name: 'load', data: { form: this.form } }); - this.stableView(); - } - - @ViewChildren(FieldComponent) - fields: QueryList; - - @ViewChildren(GroupFieldsComponent) - groups: QueryList; - - constructor(private service: FieldService, - private fr: FullyRenderedService, - private radio: ChannelService) {super();} - - get attr() { - return this.dataOptions.filter((a) => a.type === 'group' && (a as IPanelOptions).activatable).reduce((p, c: IPanelOptions) => ({ - ...p, - [c.name]: { active: c.active } - }), {}); - } - - isPanel(item: TFormOptions) { - return 'options' in item && !item.hidden; - } - - trackBy(index: number, item: IPanelOptions): string { - return item.name; - } - - checkCustomGroup() { - const check = (value) => { - if (!value.hasOwnProperty('custom_group')) { - return true; - } - - return value.custom_group === true; - } - - return this.dataOptions.some((config) => check(config)); - } - - /** - * This method detects the moment rendering final of all fields and groups (with internal fields) on the page - * it's need for test - * - * @member ConfigFieldsComponent - */ - stableView() { - this.fr.stableView(() => this.radio.next(keyChannelStrim.load_complete, 'Config has been loaded')); - } -} diff --git a/web/src/app/shared/configuration/group-fields/group-fields.component.html b/web/src/app/shared/configuration/group-fields/group-fields.component.html deleted file mode 100644 index ba4b505cfb..0000000000 --- a/web/src/app/shared/configuration/group-fields/group-fields.component.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - {{ panel.display_name }} - - - - - info_outline - - - - diff --git a/web/src/app/shared/configuration/group-fields/group-fields.component.ts b/web/src/app/shared/configuration/group-fields/group-fields.component.ts deleted file mode 100644 index 21fcc43d7f..0000000000 --- a/web/src/app/shared/configuration/group-fields/group-fields.component.ts +++ /dev/null @@ -1,93 +0,0 @@ -// Licensed 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 { Component, Input, OnInit, ViewChild } from '@angular/core'; -import { AbstractControl, FormGroup } from '@angular/forms'; -import { MatExpansionPanel } from '@angular/material/expansion'; -import { MatSlideToggleChange } from '@angular/material/slide-toggle'; -import { FieldService } from '@app/shared/configuration/services/field.service'; -import { IFieldOptions, IPanelOptions } from '../types'; -import { AttributeService } from "@app/shared/configuration/attributes/attribute.service"; - -@Component({ - selector: 'app-group-fields', - templateUrl: './group-fields.component.html', - styles: [ - '.title {font-size: 22px;}', - '.title > mat-slide-toggle {margin-left: 20px;}', - '.advanced {border: dotted 1px #00e676;}', - 'mat-panel-description {justify-content: flex-end;}', - 'mat-checkbox {margin-right: 10px;}', - ], -}) -export class GroupFieldsComponent implements OnInit { - active = true; - group_config: { [key: string]: boolean }; - @Input() panel: IPanelOptions; - @Input() form: FormGroup; - @Input() uniqId: string; - @ViewChild('ep') expanel: MatExpansionPanel; - - constructor(private service: FieldService, private attributesSrv: AttributeService) {} - - ngOnInit(): void { - if (this.panel.activatable) this.activatable(this.panel.active); - this.group_config = this.panel?.group_config; - } - - get isAdvanced() { - return this.panel.ui_options && this.panel.ui_options.advanced; - } - - activeToggle(e: MatSlideToggleChange): void { - this.panel.active = e.checked; - this.activatable(e.checked); - } - - activatable(flag: boolean): void { - this.active = flag; - this.checkFields(this.active); - } - - checkFields(flag: boolean): void { - this.panel.options - .filter((a) => !('options' in a)) - .forEach((a: IFieldOptions) => { - const split = a.key.split('/'); - const [name, ...other] = split; - const currentFormGroup = (other.reverse().reduce((p, c) => p.get(c), this.form)) as FormGroup; - const formControl = currentFormGroup.controls[name]; - this.updateValidator(formControl, flag, a); - if (a.type === 'password') this.updateValidator(currentFormGroup.controls['confirm_' + name], flag, a, formControl); - }); - } - - updateValidator(formControl: AbstractControl, flag: boolean, a: IFieldOptions, currentFormControl?: AbstractControl): void { - if (formControl) { - if (!flag) formControl.clearValidators(); - else formControl.setValidators(this.service.setValidator(a, currentFormControl)); - formControl.updateValueAndValidity(); - formControl.markAsTouched(); - this.form.updateValueAndValidity(); - } - } - - groupCheckboxExist() { - return this.panel?.type==='group' && this.panel.activatable && this.panel?.group_config?.exist; - } - - clickGroupCheckbox(event): void { - this.attributesSrv.groupCheckboxToggle(this.panel.name, !this.group_config.checkboxValue, this.uniqId); - this.panel.value = this.group_config.checkboxValue = !this.group_config.checkboxValue; - event.preventDefault(); - event.stopPropagation(); - } -} diff --git a/web/src/app/shared/configuration/main/config.component.html b/web/src/app/shared/configuration/main/config.component.html deleted file mode 100644 index e2fdea9d48..0000000000 --- a/web/src/app/shared/configuration/main/config.component.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - -
- -
- -
- {{ loadingStatus }} -
- -
- -
- diff --git a/web/src/app/shared/configuration/main/config.component.scss b/web/src/app/shared/configuration/main/config.component.scss deleted file mode 100644 index dcaca131a5..0000000000 --- a/web/src/app/shared/configuration/main/config.component.scss +++ /dev/null @@ -1,33 +0,0 @@ -:host { - flex: 1; - position: relative; - - ::ng-deep { - .mat-form-field-infix { - display: flex; - } - } -} - -.na-hu { - position: absolute; - top: -80000px; -} - -.fields { - position: absolute; - top: 70px; - bottom: 0; - left: 0; - right: 0; - overflow: auto; - z-index: 2; - padding: 0 10px; -} - -.pre-load { - position: absolute; - top: 60px; - width: 100%; - text-align: center; -} diff --git a/web/src/app/shared/configuration/main/config.component.spec.ts b/web/src/app/shared/configuration/main/config.component.spec.ts deleted file mode 100644 index f4035ecc81..0000000000 --- a/web/src/app/shared/configuration/main/config.component.spec.ts +++ /dev/null @@ -1,182 +0,0 @@ -// Licensed 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 { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormBuilder } from '@angular/forms'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { FullyRenderedService } from '@app/core/services'; -import { TextBoxComponent } from '@app/shared/form-elements/text-box.component'; -import { SharedModule } from '@app/shared/shared.module'; -import { provideMockStore } from '@ngrx/store/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { EMPTY } from 'rxjs'; - -import { FieldService } from '../services/field.service'; -import { FieldComponent } from '../field/field.component'; -import { ConfigFieldsComponent } from '../fields/fields.component'; -import { GroupFieldsComponent } from '../group-fields/group-fields.component'; -import { ToolsComponent } from '../tools/tools.component'; -import { IConfig } from '../types'; -import { ConfigComponent } from './config.component'; -import { MainService } from './main.service'; -import { ApiService } from '@app/core/api'; -import { ActivatedRoute } from '@angular/router'; - -const rawConfig: IConfig = { - attr: {}, - config: [ - { - name: 'field_string', - display_name: 'display_name', - subname: '', - type: 'string', - activatable: false, - read_only: false, - default: null, - value: 'some string', - description: '', - required: false, - group_config: null, - custom_group: true, - }, - { - name: 'group', - display_name: 'group_display_name', - subname: '', - type: 'group', - activatable: false, - read_only: false, - default: null, - value: null, - description: '', - required: false, - group_config: null, - custom_group: false, - }, - { - name: 'group', - display_name: 'field_in_group_display_name', - subname: 'field_in_group', - type: 'integer', - activatable: false, - read_only: false, - default: 10, - value: 10, - description: '', - required: true, - group_config: null, - custom_group: false, - }, - ], -}; - -describe('Configuration : ConfigComponent >> ', () => { - let component: ConfigComponent; - let fixture: ComponentFixture; - let FieldServiceStub: Partial; - const initialState = { socket: {} }; - - class MockMainService { - getConfig = () => EMPTY; - filterApply = () => { }; - getHistoryList = () => EMPTY; - parseValue = () => { }; - send = () => EMPTY; - worker$ = EMPTY - } - - beforeEach(async () => { - FieldServiceStub = new FieldService(new FormBuilder()); - await TestBed.configureTestingModule({ - imports: [ - NoopAnimationsModule, - SharedModule, - HttpClientTestingModule, - ], - declarations: [ConfigComponent, ToolsComponent, ConfigFieldsComponent, GroupFieldsComponent, FieldComponent, TextBoxComponent], - providers: [ - provideMockStore({ initialState }), - { provide: FieldService, useValue: FieldServiceStub }, - { - provide: FullyRenderedService, - useValue: { stableView: () => { } } - }, - ApiService, - - ], - schemas: [NO_ERRORS_SCHEMA], - }) - .overrideComponent(ConfigComponent, { - set: { - providers: [ - { provide: MainService, useClass: MockMainService }, - { provide: ActivatedRoute, useValue: { snapshot: { data: {} } } }, - ], - }, - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ConfigComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should exist ToolsComponent, HistoryComponent, FieldsComponent', () => { - fixture.detectChanges(); - const de = fixture.debugElement.nativeElement; - const tools = de.querySelector('app-tools'); - const history = de.querySelector('app-history'); - const fields = de.querySelector('app-config-fields'); - expect(tools).toBeTruthy(); - expect(history).toBeTruthy(); - expect(fields).toBeTruthy(); - }); - - it('should be Save button and it must be disabled', () => { - fixture.detectChanges(); - const de = fixture.debugElement.nativeElement; - const saveBtn = de.querySelector('app-tools div.control-buttons button.form_config_button_save'); - - component.isLock = true; - component.cd.detectChanges(); - - expect(saveBtn).toBeTruthy(); - expect(saveBtn.disabled).toBeTrue(); - }); - - it('the save button click should initialize form again', () => { - fixture.detectChanges(); - component.rawConfig.next(rawConfig); - component.cd.detectChanges(); - component.tools.disabledSave = !component.fields.form.invalid; - component.cd.detectChanges(); - const saveBtn = fixture.nativeElement.querySelector('app-tools div.control-buttons button.form_config_button_save'); - expect(saveBtn.disabled).toBeTruthy(); - - saveBtn.click(); - component.cd.detectChanges(); - - component.fields.form.get('group').get('field_in_group').setValue('string_not_valid'); - component.fields.form.markAsTouched(); - component.fields.form.get('group').markAsTouched(); - component.fields.form.get('group').get('field_in_group').markAsTouched(); - component.tools.disabledSave = !component.fields.form.invalid; - component.cd.detectChanges(); - - expect(saveBtn.disabled).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/configuration/main/config.component.ts b/web/src/app/shared/configuration/main/config.component.ts deleted file mode 100644 index 6b6181355f..0000000000 --- a/web/src/app/shared/configuration/main/config.component.ts +++ /dev/null @@ -1,255 +0,0 @@ -// Licensed 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 { - AfterViewInit, - ChangeDetectorRef, - Component, - EventEmitter, - Input, - OnChanges, OnDestroy, - OnInit, - Output, - SimpleChanges, - ViewChild -} from '@angular/core'; -import { EventMessage, SocketState } from '@app/core/store'; -import { SocketListenerDirective } from '@app/shared/directives'; -import { Store } from '@ngrx/store'; -import { BehaviorSubject, Observable, of, Subscription } from 'rxjs'; -import { catchError, finalize, tap, distinctUntilChanged } from 'rxjs/operators'; - -import { ConfigFieldsComponent } from '../fields/fields.component'; -import { HistoryComponent } from '../tools/history.component'; -import { ToolsComponent } from '../tools/tools.component'; -import { IConfig, IConfigAttr } from '../types'; -import { historyAnime, ISearchParam, MainService } from './main.service'; -import { WorkerInstance } from '@app/core/services/cluster.service'; -import { ActivatedRoute } from '@angular/router'; -import { AttributeService } from '@app/shared/configuration/attributes/attribute.service'; -import * as deepmerge from 'deepmerge'; - -@Component({ - selector: 'app-config-form', - templateUrl: './config.component.html', - styleUrls: ['./config.component.scss'], - animations: historyAnime, - providers: [MainService] -}) -export class ConfigComponent extends SocketListenerDirective implements OnChanges, OnInit, OnDestroy, AfterViewInit { - loadingStatus = 'Loading...'; - rawConfig = new BehaviorSubject(null); - saveFlag = false; - historyShow = false; - isLock = false; - isLoading = false; - isLoadingHistory = false; - attributeUniqId: string = null; - - worker$: Observable; - - @ViewChild('fls') fields: ConfigFieldsComponent; - @ViewChild('history') historyComponent: HistoryComponent; - @ViewChild('tools') tools: ToolsComponent; - - @Input() - configUrl: string; - - @Input() - isGroupConfig: boolean; - - @Output() - event = new EventEmitter<{ name: string; data?: any }>(); - private _workerSubscription: Subscription = Subscription.EMPTY; - - constructor( - private service: MainService, - private attributesSrv: AttributeService, - public cd: ChangeDetectorRef, - socket: Store, - route: ActivatedRoute, - ) { - super(socket); - this.isGroupConfig = route.snapshot.data['isGroupConfig']; - this.worker$ = service.worker$.pipe(distinctUntilChanged()); - - service.worker$.subscribe((data) => { - this.service.changeService(data.current.typeName); - this.getConfigUrlFromWorker(); - this._getConfig(data.current.config).subscribe(); - }); - } - - ngAfterViewInit(): void {} - - ngOnChanges(changes: SimpleChanges): void { - const url = changes['configUrl']; - const firstChange = url?.firstChange; - if (!firstChange || !url) this._getConfig(changes['configUrl'].currentValue).subscribe(); - } - - ngOnInit(): void { - if (!this.configUrl) this.getConfigUrlFromWorker(); - this._getConfig(this.configUrl).subscribe(); - - super.startListenSocket(); - } - - ngOnDestroy() { - super.ngOnDestroy(); - this._workerSubscription.unsubscribe(); - } - - onReady(): void { - this.tools.isAdvanced = this.fields.isAdvanced; - this.tools.description.setValue(this.rawConfig.value.description); - this.filter(this.tools.filterParams); - this.cd.detectChanges(); - - if (!this.isGroupConfig && !this.isLoadingHistory) { - this.isLoadingHistory = true; - this.service.getHistoryList(this.configUrl).subscribe((h) => { - this.historyComponent.compareConfig = h; - this.historyComponent.currentVersion = this.rawConfig.value.id; - this.tools.disabledHistory = !h.length || h.length === 1; - this.isLoadingHistory = false; - this.cd.detectChanges(); - }); - } - - this._scrollConfigListOnTop() - }; - - filter(c: ISearchParam): void { - this.service.filterApply(this.fields.dataOptions, c); - this.cd.detectChanges(); - } - - socketListener(m: EventMessage): void { - if ( - m.object.type === this.service.Current?.typeName && - m.object.id === this.service.Current.id && - !this.saveFlag && - (m.event === 'change_config' || m.event === 'change_state') - ) { - this.isLock = m.object.details.value === 'locked'; - this.reset(); - this._getConfig(this.configUrl).subscribe(); - } - } - - getConfigUrlFromWorker(): void { - this._workerSubscription.unsubscribe(); - this._workerSubscription = this.worker$ - .subscribe(_ => this.configUrl = this.service.Current?.config); - } - - save(url: string): void { - const form = this.fields.form; - - if (this._isValid()) { - this.saveFlag = true; - this.historyComponent.reset(); - const config = this.service.parseValue(this.fields.form.getRawValue(), this.rawConfig.value.config); - const send = { - config, - attr: deepmerge(this.mergeAttrsWithField(), this.fields.attr), - description: this.tools.description.value, - obj_ref: this.rawConfig.value.obj_ref - }; - - if (this.tools.description.value === this.rawConfig.value.description) { - delete send.description; - } - - this.isLoading = true; - - this.service.send(url, send).pipe( - tap((c) => { - this.saveFlag = false; - this.rawConfig.next(c); - this.cd.detectChanges(); - this.event.emit({ name: 'send', data: this.fields }); - }), - finalize(() => this.isLoading = false), - ).subscribe(); - } else { - Object.keys(form.controls).forEach((controlName) => form.controls[controlName].markAsTouched()); - } - } - - changeVersion(url: string, id: number): void { - this.isLoading = true; - this.reset(); - this.service.changeVersion(url, id).pipe( - tap((c) => this.rawConfig.next(c)), - finalize(() => this.isLoading = false), - catchError(() => { - this.loadingStatus = 'There is no config for this object.'; - return of(null); - }) - ).subscribe(); - } - - compareVersion(ids: number[]): void { - if (ids) this.service.compareConfig(ids, this.fields.dataOptions, this.historyComponent.compareConfig, this.configUrl); - } - - reset(): void { - this.fields.form.reset(); - this.fields.dataOptions = []; - this.historyComponent.reset(); - } - - mergeAttrsWithField(): IConfigAttr { - const attr = this.rawConfig.getValue().attr; - const attrSrv = this.attributesSrv.rawAttributes(this.attributeUniqId); - - Object.keys(attr).forEach(a => { - Object.keys(attr[a]).forEach((key) => { - // we use here hasOwnProperty because field has boolean value and ruin condition check - if (attrSrv[a] && attrSrv[a].hasOwnProperty(key)) { - attr[a][key] = attrSrv[a][key]; - } - }); - }) - - return attr; - } - - - private _getConfig(url: string): Observable { - this.isLoading = true; - return this.service.getConfig(url).pipe( - tap((config) => { - if (!this.attributeUniqId) { - this.attributeUniqId = this.attributesSrv.init(config.attr); - } - }), - tap((c) => this.rawConfig.next(c)), - finalize(() => this.isLoading = false), - catchError(() => { - this.loadingStatus = 'There is no config for this object.'; - return of(null); - }) - ); - } - - _isValid() { - const f = this.fields.form; - return f.status !== 'INVALID'; - } - - _scrollConfigListOnTop() { - const fiedsContainer: any = document.getElementsByClassName('fields')[0]; - fiedsContainer.scrollTop = 0; - } -} diff --git a/web/src/app/shared/configuration/main/main.service.spec.ts b/web/src/app/shared/configuration/main/main.service.spec.ts deleted file mode 100644 index 04bc7ce103..0000000000 --- a/web/src/app/shared/configuration/main/main.service.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed 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 { TestBed } from '@angular/core/testing'; - -import { MainService } from './main.service'; -import { FieldService } from '../services/field.service'; -import { ApiService } from '@app/core/api'; -import { Store } from '@ngrx/store'; - -describe('MainService', () => { - let service: MainService; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - MainService, - { provide: ApiService, useValue: {} }, - { provide: FieldService, useValue: {} }, - { provide: Store, useValue: {} }, - ], - }); - service = TestBed.inject(MainService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/configuration/main/main.service.ts b/web/src/app/shared/configuration/main/main.service.ts deleted file mode 100644 index a5f0cdaa3c..0000000000 --- a/web/src/app/shared/configuration/main/main.service.ts +++ /dev/null @@ -1,162 +0,0 @@ -// Licensed 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 { animate, state, style, transition, trigger } from '@angular/animations'; -import { Injectable, Injector } from '@angular/core'; -import { isObject, TypeName } from '@app/core/types'; -import { FieldService, IOutput, TFormOptions } from '../services/field.service'; -import { CompareConfig, IFieldOptions, IFieldStack } from '../types'; -import { ConfigService, IConfigService } from '@app/shared/configuration/services/config.service'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { ConfigGroupService } from '@app/config-groups/service/config-group.service'; - -/** - *``` - advanced: boolean; - search: string; - ``` - */ -export interface ISearchParam { - advanced: boolean; - search: string; -} - -export const historyAnime = [ - trigger('history', [ - state('hide', style({ top: '70px' })), - state('show', style({ top: '134px' })), - state('hideTools', style({ opacity: 0 })), - state('showTools', style({ opacity: 0.8 })), - transition('hideTools => showTools', animate('.5s .3s ease-in')), - transition('showTools => hideTools', animate('.2s ease-out')), - transition('hide <=> show', animate('.3s')), - ]), -]; - -@Injectable({ - providedIn: 'root' -}) -export class MainService { - configService: IConfigService; - - constructor(private fields: FieldService, - public cluster: ClusterService, - private injector: Injector) { - const current: TypeName | undefined = cluster.Current?.typeName; - this.changeService(current); - } - - get worker$() { - return this.cluster.worker$; - } - - get Current() { - return this.cluster.Current; - } - - getConfig(url: string) { - return this.configService.getConfig(url); - } - - changeVersion(url: string, id: number) { - return this.configService.changeVersion(id, url); - } - - changeService(type) { - if (type === 'group_config') { - this.configService = this.injector.get(ConfigGroupService); - } else { - this.configService = this.injector.get(ConfigService); - } - } - - filterApply(options: TFormOptions[], search: ISearchParam) { - this.fields.filterApply(options, search); - } - - parseValue(output: IOutput, source: IFieldStack[]) { - return this.fields.parseValue(output, source); - } - - send(url: string, data: any) { - return this.configService.send(url, data); - } - - getHistoryList(url: string) { - return this.configService.getHistoryList(url); - } - - compareConfig(ids: number[], dataOptions: TFormOptions[], compareConfig: CompareConfig[], configUrl: string) { - dataOptions.map((a) => this.runClear(a, ids)); - const cc = ids.map((id) => compareConfig.find((a) => a.id === id)); - - this.changeVersion(configUrl, ids[0]).subscribe((resp) => { - const mockConfig = this.fields.toFormGroup(this.fields.getPanels(resp)); - dataOptions.map((a) => this.runCheck(a, cc, mockConfig.value)); - }); - } - - runClear(a: TFormOptions, ids: number[]) { - if ('options' in a) a.options.map((b) => this.runClear(b, ids)); - else if (a.compare.length) a.compare = a.compare.filter((b) => ids.includes(b.id)); - return a; - } - - runCheck(a: TFormOptions, configs: CompareConfig[], mockConfig: IFieldStack[]) { - if ('options' in a) a.options.map((b) => this.runCheck(b, configs, mockConfig)); - else this.checkField(a, configs, mockConfig); - return a; - } - - checkField(a: IFieldOptions, configs: CompareConfig[], mockConfig: IFieldStack[]) { - configs - .filter((b) => a.compare.every((e) => e.id !== b.id)) - .map((c) => { - const co = this.findFieldCompare(a.key, { ...c, config: mockConfig }); - console.log(co) - if (!co) { - if (String(a.value) && String(a.value) !== 'null') a.compare.push({ - id: c.id, - date: c.date, - color: c.color, - value: 'null' - }); - } else { - if (isObject(co.value)) { - if (isObject(a.value)) { - if (JSON.stringify(a.value) !== JSON.stringify(co.value)) a.compare.push({ - ...co, - value: JSON.stringify(co.value) - }); - } else if (typeof a.value === 'string') { - if (JSON.stringify(JSON.parse(a.value)) !== JSON.stringify(co.value)) a.compare.push({ - ...co, - value: JSON.stringify(co.value) - }); - } - } else if (String(co.value) !== String(a.value)) a.compare.push(co); - } - }); - return a; - } - - findFieldCompare(key: string, cc: CompareConfig) { - const value = key - .split('/') - .reverse() - .reduce((p, c) => p[c], cc.config); - if (value !== null && value !== undefined && String(value)) { - const { id, date, color } = { ...cc }; - return { id, date, color, value }; - } - } - -} diff --git a/web/src/app/shared/configuration/scheme/item.component.spec.ts b/web/src/app/shared/configuration/scheme/item.component.spec.ts deleted file mode 100644 index 7547353549..0000000000 --- a/web/src/app/shared/configuration/scheme/item.component.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed 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 { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormControl, FormGroup } from '@angular/forms'; - -import { ItemComponent } from './item.component'; -import { IControl } from './scheme.service'; - -describe('ItemComponent', () => { - let component: ItemComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - TestBed.configureTestingModule({ - declarations: [ItemComponent], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ItemComponent); - component = fixture.componentInstance; - const item: IControl = { - name: 'test', - type: 'string', - rules: { name: 'test', type: 'string', path: ['test'], validator: {}, controlType: 'textbox', isInvisible: false }, - form: new FormGroup({ test: new FormControl() }), - parent: 'dict', - value: {}, - }; - component.item = item; - component.invisibleItems = ['field']; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/configuration/scheme/item.component.ts b/web/src/app/shared/configuration/scheme/item.component.ts deleted file mode 100644 index 316929b2ff..0000000000 --- a/web/src/app/shared/configuration/scheme/item.component.ts +++ /dev/null @@ -1,92 +0,0 @@ -// Licensed 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 { Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; - -import { controlType, IValidator } from '../types'; -import { IYField } from '../yspec/yspec.service'; -import { IControl } from './scheme.service'; - -@Component({ - selector: 'app-item-scheme', - template: ` - - - - - - - - - -
- {{ item.name }} - - Field [{{ item.name }}] is required! - -
- - {{ item.name }} - - - Field [{{ item.name }}] is required! - Field [{{ item.name }}] is invalid! - Field [{{ item.name }}] value cannot be less than {{ validator.min }}! - Field [{{ item.name }}] value cannot be greater than {{ validator.max }}! - - -
-
- `, - styles: [':host {flex: 1}', 'mat-form-field {margin: 6px 0 0; width: 100%}', '.chbox-field {margin:6px 0;}'], -}) -export class ItemComponent implements OnInit { - @Input() item: IControl; - @Input() invisibleItems: string[]; - @Input() index: number; - @Input() isReadOnly = false; - @Output() remove = new EventEmitter(); - - @HostListener('keyup') changes() { - this.control.markAsTouched(); - } - - controlType: controlType; - validator: IValidator; - - ngOnInit() { - const rules = this.item.rules as IYField; - this.controlType = rules.controlType; - this.validator = rules.validator; - if (this.controlType === 'boolean' && this.isReadOnly) this.control.disable(); - this.item.form.markAllAsTouched(); - } - - emmit() { - this.remove.emit(this.item.name); - } - - get control() { - return this.item.form.controls[this.item.name] as AbstractControl; - } - - get isValid() { - const f = this.control; - return f.status !== 'INVALID' && (f.dirty || f.touched); - } - - hasError(title: string) { - return this.control.hasError(title); - } -} diff --git a/web/src/app/shared/configuration/scheme/root.component.html b/web/src/app/shared/configuration/scheme/root.component.html deleted file mode 100644 index 9bf48492f0..0000000000 --- a/web/src/app/shared/configuration/scheme/root.component.html +++ /dev/null @@ -1,27 +0,0 @@ -
- - -
-
- -
- - - - - - - - - - -
-
-
diff --git a/web/src/app/shared/configuration/scheme/root.component.scss b/web/src/app/shared/configuration/scheme/root.component.scss deleted file mode 100644 index 2571de482f..0000000000 --- a/web/src/app/shared/configuration/scheme/root.component.scss +++ /dev/null @@ -1,32 +0,0 @@ -:host { - display: block; - width: 100%; - margin-bottom: 20px; - - & div.label { - display: flex; - align-items: center; - justify-content: space-between - } - - & div.content { - margin-left: 10px; - - & .item-iteration.dif:nth-child(even) { - background-color: #545454; - } - - & .item-iteration { - display: flex; - - &>div { - flex: 1; - } - } - - & .remote-btn { - align-self: center; - margin-left: 10px; - } - } -} diff --git a/web/src/app/shared/configuration/scheme/root.component.spec.ts b/web/src/app/shared/configuration/scheme/root.component.spec.ts deleted file mode 100644 index aa0e7654d7..0000000000 --- a/web/src/app/shared/configuration/scheme/root.component.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -// Licensed 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 { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { FieldService } from '../services/field.service'; -import { IYField } from '../yspec/yspec.service'; -import { RootComponent } from './root.component'; -import { SchemeService } from './scheme.service'; - -const item: IYField = { - name: 'test', - type: 'string', - path: ['test'], - controlType: 'textbox', - validator: {}, - isInvisible: false -}; - -describe('RootComponent', () => { - let component: RootComponent; - let fixture: ComponentFixture; - let service: SchemeService; - - beforeEach(async () => { - TestBed.configureTestingModule({ - imports: [FormsModule, ReactiveFormsModule], - declarations: [RootComponent], - providers: [FieldService, FormBuilder, SchemeService], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(RootComponent); - component = fixture.componentInstance; - service = TestBed.inject(SchemeService); - - component.options = item; - component.form = new FormGroup({ field: new FormControl() }); - component.value = {}; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should has form as FormGroup | FormArray | FormControl, options as IYContainer | IYField, value as TValue', () => { - expect(component.value).toBeDefined(); - expect(component.options).toBeDefined(); - expect(component.form).toBeDefined(); - }); - - xit('options type as list should displaying as list', () => { - - }); -}); diff --git a/web/src/app/shared/configuration/scheme/root.component.ts b/web/src/app/shared/configuration/scheme/root.component.ts deleted file mode 100644 index be5d051e2d..0000000000 --- a/web/src/app/shared/configuration/scheme/root.component.ts +++ /dev/null @@ -1,111 +0,0 @@ -// Licensed 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 { Component, Input, OnInit } from '@angular/core'; -import { FormArray, FormGroup } from '@angular/forms'; - -import { TNReq, TValue } from '../types'; -import { IYContainer, IYField } from '../yspec/yspec.service'; -import { IControl, IValue, SchemeService } from './scheme.service'; - -@Component({ - selector: 'app-root-scheme', - templateUrl: './root.component.html', - styleUrls: ['./root.component.scss'], -}) -export class RootComponent implements OnInit { - @Input() form: FormGroup | FormArray; - @Input() options: IYContainer | IYField; - @Input() value: TValue; - @Input() isReadOnly = false; - @Input() invisibleItems: string[]; - - controls: IControl[] = []; - - constructor(private scheme: SchemeService) {} - - init() { - if (this.value) { - if (Array.isArray(this.value)) { - this.value.forEach((value, index) => { - this.itemRules?.forEach((key) => { - if (!value[key.name]) { - value[key.name] = key.type === 'string' ? '' : key.type === 'integer' ? 0 : null; - } - }) - }) - } - - if (this.options.type === 'list' && Array.isArray(this.value)) { - (this.value as IValue[]).forEach((x, i) => this.add(['', x])); - } else if (typeof this.value === 'object') { - Object.keys(this.value).forEach((x) => this.add([x, this.value[x]])); - } - } else if (this.options.type === 'dict' && Array.isArray(this.options.options)) { - this.options.options.forEach((x) => this.add([x.name, ''])); - } - } - - ngOnInit(): void { - this.init(); - } - - reload(value: TValue) { - this.value = value; - this.controls.length = 0; - - if (Array.isArray(this.form.controls)) { - while (this.form.controls.length > 0) { - (this.form as FormArray).removeAt(0); - } - } else if (this.form.controls && typeof this.form.controls === 'object') { - Object.keys(this.form.controls).forEach((key) => { - while (this.form.controls[key]?.controls.length > 0) { - (this.form.controls[key] as FormArray).removeAt(0); - } - (this.form as FormGroup).removeControl(key); - }) - } - - this.init(); - } - - add(v: [string, IValue | TValue] = ['', '']) { - const [name, value] = v; - const flag = (this.rules as IYContainer).type === 'dict'; - const item = flag - ? this.scheme.addControlsDict(name, value, this.form as FormArray, this.itemRules as IYContainer[]) - : this.scheme.addControls(name, value, this.form, this.rules, this.options.type as TNReq); - this.controls = [...this.controls, item]; - this.form.updateValueAndValidity(); - } - - showControls() { - return !this.isReadOnly && (this.options.type === 'list' || this.options.type === 'dict'); - } - - remove(name: string | number) { - if (Array.isArray(this.form.controls)) { - (this.form as FormArray).removeAt(+name); - this.controls = this.controls.filter((a, i) => (a.name ? a.name !== name : i !== +name)); - this.form.updateValueAndValidity(); - } - } - - get rules(): IYField | IYContainer | (IYField | IYContainer)[] { - if ('options' in this.options) return this.options.options; - else return this.options; - } - - get itemRules(): (IYField | IYContainer)[] { - return (this.rules as IYContainer).options as (IYField | IYContainer)[]; - } -} diff --git a/web/src/app/shared/configuration/scheme/scheme.component.spec.ts b/web/src/app/shared/configuration/scheme/scheme.component.spec.ts deleted file mode 100644 index bfb786ac93..0000000000 --- a/web/src/app/shared/configuration/scheme/scheme.component.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed 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 { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MaterialModule } from '@app/shared/material.module'; - -import { FieldService } from '../services/field.service'; -import { IFieldOptions, TNForm } from '../types'; -import { YspecService } from '../yspec/yspec.service'; -import { RootComponent } from './root.component'; -import { SchemeComponent } from './scheme.component'; -import { SchemeService } from './scheme.service'; - -describe('SchemeComponent', () => { - let component: SchemeComponent; - let fixture: ComponentFixture; - let service: SchemeService; - let fieldService: FieldService; - - beforeEach(async () => { - TestBed.configureTestingModule({ - imports: [MaterialModule, FormsModule, ReactiveFormsModule], - declarations: [SchemeComponent, RootComponent], - providers: [YspecService, FieldService, FormBuilder, SchemeService], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(SchemeComponent); - service = TestBed.inject(SchemeService); - component = fixture.componentInstance; - component.form = new FormGroup({ field: new FormControl() }); - const yspec = { root: { match: 'list' as TNForm, item: 'string' }, string: { match: 'string' as TNForm } }; - component.field = ({ display_name: 'field_display_name', name: 'field', limits: { yspec }, required: true, value: null, default: null }) as IFieldOptions; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should has formGroup and fieldOptions.limits.yspec', () => { - expect(component.field?.limits?.yspec).toBeTruthy(); - expect(component.form).toBeTruthy(); - }); - - it('after init should be current form for children component', () => { - expect(component.current).toBeTruthy(); - }); - - it('if field is required and value of default is null should shown error notification', () => { - const error = fixture.nativeElement.querySelector('mat-error'); - expect(error).toBeTruthy(); - expect(error.innerText).toBe('Field [field_display_name] is required!'); - }); - - -}); diff --git a/web/src/app/shared/configuration/scheme/scheme.component.ts b/web/src/app/shared/configuration/scheme/scheme.component.ts deleted file mode 100644 index 82db7c2448..0000000000 --- a/web/src/app/shared/configuration/scheme/scheme.component.ts +++ /dev/null @@ -1,74 +0,0 @@ -// Licensed 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 { Component, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; -import { FieldDirective } from '@app/shared/form-elements/field.directive'; - -import { TNReq } from '../types'; -import { IYContainer, IYField, YspecService } from '../yspec/yspec.service'; -import { RootComponent } from './root.component'; -import { SchemeService } from './scheme.service'; - -@Component({ - selector: 'app-scheme', - styles: [ - ` - div.main { - flex: 1; - } - .error { - display: block; - margin: -20px 0 6px 10px; - } - `, - ], - template: `
- - Field [{{ field.display_name }}] is required! -
`, -}) -export class SchemeComponent extends FieldDirective implements OnInit, OnChanges { - rules: IYField | IYContainer; - current: AbstractControl; - invisibleItems: string[]; - - @ViewChild('root') root: RootComponent; - - constructor(private yspec: YspecService, private scheme: SchemeService) { - super(); - } - - /** - * after saving, the link between the form and the current (form) is lost - * TODO: eliminate - */ - ngOnChanges(changes: SimpleChanges): void { - if (!changes.form.firstChange) { - this.field.limits.rules = this.rules; - this.form.setControl(this.field.name, this.current); - } - } - - ngOnInit() { - this.yspec.Root = this.field.limits.yspec; - this.invisibleItems = this.yspec.getInvisibleItems(); - this.rules = this.yspec.build(); - this.field.limits.rules = this.rules; - this.rules.name = ''; - this.current = this.scheme.setCurrentForm(this.rules.type as TNReq, this.form, this.field); - } - - /** this is using for restore default value */ - reload() { - this.root.reload(this.field.default); - } -} diff --git a/web/src/app/shared/configuration/scheme/scheme.service.spec.ts b/web/src/app/shared/configuration/scheme/scheme.service.spec.ts deleted file mode 100644 index 881199f779..0000000000 --- a/web/src/app/shared/configuration/scheme/scheme.service.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -// Licensed 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 { TestBed } from '@angular/core/testing'; - -import { SchemeService } from './scheme.service'; -import { FieldService } from '../services/field.service'; -import { FormGroup, FormControl, FormArray } from '@angular/forms'; -import { IFieldOptions } from '../types'; - -const form = new FormGroup({ field: new FormControl() }); -const field = ({ display_name: 'field_display_name', name: 'field', limits: {}, required: true, value: null, default: null }) as IFieldOptions; - -describe('SchemeService', () => { - let service: SchemeService; - - beforeEach(() => { - TestBed.configureTestingModule({ providers: [SchemeService, { provide: FieldService, useValue: {} }] }); - service = TestBed.inject(SchemeService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - it('setCurrentForm with type as dict should return FormGroup', () => { - const b = service.setCurrentForm('dict', form, field) as FormGroup; - expect(b.controls).toEqual(jasmine.any(Object)); - expect(b instanceof FormGroup).toBeTrue(); - }); - - it('setCurrentForm with type as list should return FormArray', () => { - const b = service.setCurrentForm('list', form, field) as FormArray; - expect(b.controls).toEqual([]); - expect(b instanceof FormArray).toBeTrue(); - }); - - it('setCurrentForm with type not list or dict should return FormControl', () => { - const b = service.setCurrentForm('string', form, field) as any; - expect(b.controls).toBeUndefined(); - expect(b instanceof FormControl).toBeTrue(); - }); - - it('setCurrentForm with field is required should has errors {isEmpty: true}', () => { - const b = service.setCurrentForm('string', form, field) as any; - expect(b.errors).toEqual({isEmpty: true}); - }); -}); diff --git a/web/src/app/shared/configuration/scheme/scheme.service.ts b/web/src/app/shared/configuration/scheme/scheme.service.ts deleted file mode 100644 index eaea0a5462..0000000000 --- a/web/src/app/shared/configuration/scheme/scheme.service.ts +++ /dev/null @@ -1,88 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { AbstractControl, FormArray, FormControl, FormGroup, ValidatorFn } from '@angular/forms'; -import { isObject } from '@app/core/types/func'; - -import { FieldService } from '../services/field.service'; -import { IFieldOptions, TNForm, TNReq, TValue } from '../types'; -import { IYContainer, IYField } from '../yspec/yspec.service'; - -export interface IValue { - [key: string]: TValue; -} - -export interface IControl { - name: string; - type: TNForm; - rules: IYField | IYContainer | (IYField | IYContainer)[]; - form: FormGroup | FormArray; - value: IValue | TValue; - parent: TNReq; -} - -@Injectable() -export class SchemeService { - constructor(private service: FieldService) {} - - emptyValidator() { - // const isEmptyArray = (v: any) => (Array.isArray(v) && v.length ? v.some((a) => isEmptyValue(a)) : false); - // const isEmptyObj = (v: any) => (isObject(v) && Object.keys(v).length ? Object.keys(v).some((a) => isEmptyValue(v[a])) : false); - const isEmptyValue = (v: any) => !v || (Array.isArray(v) && !v.length) || (isObject(v) && !Object.keys(v).length); - return (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => (isEmptyValue(control.value) ? { isEmpty: true } : null); - } - - setCurrentForm(type: TNForm, parent: FormGroup, field: IFieldOptions) { - const v = field.required ? this.emptyValidator()() : null; - const current = type === 'list' || type === 'dict' ? (type === 'list' ? new FormArray([], v) : new FormGroup({}, v)) : new FormControl('', v); - parent.setControl(field.name, current); - return current; - } - - addControlsDict(name: string, source: TValue | IValue, currentForm: FormArray, rules: IYContainer[]): IControl { - const value = !source ? rules.reduce((p, c) => ({ ...p, [c.name]: '' }), {}) : source; - - const checkValue = () => { - if (Array.isArray(rules)) { - if (Array.isArray(value)) { - return rules.some((a) => a.name === value[0]); - } else if (typeof value === 'object') { - return Object.keys(value).every((x) => rules.some((a) => a.name === x)); - } - } - }; - - if (checkValue()) { - const form = new FormGroup({}); - currentForm.push(form); - return { name, value, type: 'dict', rules, form, parent: 'list' }; - } - } - - addControls(name: string, value: TValue | IValue, currentForm: FormGroup | FormArray, opt: IYContainer | IYField | (IYContainer | IYField)[], type: TNReq): IControl { - const rules = Array.isArray(opt) ? opt.find((a) => a.name === name) : opt; - if (!rules) return; - let form = currentForm; - if (rules.type !== 'list' && rules.type !== 'dict') { - const { validator, controlType } = rules as IYField; - if (Array.isArray(currentForm.controls)) { - name = currentForm.controls.length.toString(); - (currentForm as FormArray).push(new FormControl(value || '', this.service.setValidator({ validator, controlType }))); - } else (currentForm as FormGroup).addControl(rules.name, new FormControl(rules.type !== 'bool' ? value || '' : value, this.service.setValidator({ validator, controlType }))); - } else { - form = rules.type === 'list' ? new FormArray([]) : new FormGroup({}); - (currentForm as FormGroup).addControl(rules.name, form); - } - - return { name, value, type: rules.type, rules, form, parent: type }; - } -} diff --git a/web/src/app/shared/configuration/services/config.service.ts b/web/src/app/shared/configuration/services/config.service.ts deleted file mode 100644 index da18201fe4..0000000000 --- a/web/src/app/shared/configuration/services/config.service.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { CompareConfig, IConfig } from '../types'; -import { map, switchMap } from 'rxjs/operators'; -import { getRandomColor } from '@app/core/types'; -import { ApiService } from '@app/core/api'; - -export interface IConfigResponse { - current: string; - history: string; - previous: string; -} - -export interface IConfigListResponse { - count: 1; - next: null; - previous: null; - results: IConfig[]; -} - - -export interface IConfigService { - getConfig(url: string): Observable; - - getHistoryList(url: string): Observable; - - send(url: string, data: any): Observable; - - changeVersion(id: number, url?: string): Observable; -} - -@Injectable({ - providedIn: 'root' -}) -export class ConfigService implements IConfigService { - constructor(private api: ApiService) { } - - changeVersion(id: number, url: string): Observable { - return this.api.get(`${url}history/${id}/`); - } - - getConfig(url: string): Observable { - return this.api.get(`${url}current/`); - } - - getHistoryList(url: string): Observable { - return this.api.get(url).pipe( - switchMap((config) => this.api.get(config.history + '?fields=id,date,description')), - // ToDo remove it when API will be consistent - map((value) => Array.isArray(value) ? value as IConfig[] : value.results), - map((h) => h.map((b) => ({ - ...b, - color: getRandomColor() - })))); - } - - send(url: string, data: any): Observable { - return this.api.post(`${url}history/`, data); - } -} diff --git a/web/src/app/shared/configuration/services/field.service.spec.ts b/web/src/app/shared/configuration/services/field.service.spec.ts deleted file mode 100644 index a01c18dc03..0000000000 --- a/web/src/app/shared/configuration/services/field.service.spec.ts +++ /dev/null @@ -1,439 +0,0 @@ -// Licensed 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 { TestBed } from '@angular/core/testing'; -import { FormBuilder, Validators } from '@angular/forms'; - -import { FieldService, getValue, IOutput, ISource } from './field.service'; -import { Configuration, FieldFactory, setValue, toFormOptions } from '../tests/configuration'; -import { IFieldStack, resultTypes, TNForm } from '../types'; -import { IYContainer, IYField, IYspec } from '../yspec/yspec.service'; - -/** - * inputData - data from backend for configuration IConfig.config : FieldStack[] - * formData : itemOptions[] - we can render the form based on inputData - * - * FormControl.value - user input - * outputData - this is that we send to backend after parsing FormControl.value - IOutput - * - */ - -describe('Configuration fields service', () => { - let service: FieldService; - let checkValue: (value: resultTypes, type: TNForm) => resultTypes; - // let parseValue: (value: IOutput, source: Partial[]) => IOutput; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [FormBuilder, FieldService], - }); - - service = TestBed.inject(FieldService); - checkValue = service.checkValue; - }); - - it('service should be created', () => { - expect(service).toBeTruthy(); - }); - - it('getPanels(undefined) should return undefined', () => { - expect(service.getPanels(undefined)).toEqual(undefined); - }); - - it('getPanels({}) should return undefined', () => { - expect(service.getPanels({} as any)).toEqual(undefined); - }); - - it('getPanels({config: []}) should return []', () => { - expect(service.getPanels({ config: [] })).toEqual([]); - }); - - it('getPanels should transform FieldStack[] to itemOptions[]', () => { - const inputData = new Configuration(FieldFactory.add(['string', ['integer']])); - const formData = toFormOptions(inputData); - const output = service.getPanels(inputData); - expect(output).toEqual(formData); - }); - - it('toFormGroup should generate FormGroup and check value', () => { - const inputData = new Configuration(FieldFactory.add(['string', ['integer']])); - const formData = toFormOptions(inputData); - const fg = service.fb.group( - { - field_string_0: service.fb.control(''), - field_group_1: service.fb.group({ - subname_integer_0: ['', [Validators.required, Validators.pattern(/^[-]?\d+$/)]], - }), - }, - { validator: () => null } - ); - const form = service.toFormGroup(formData); - expect(form.value).toEqual(fg.value); - }); - - it('filterApply with search by display_name and value should change the fields satisfy search condition on as hidden', () => { - const source = new Configuration(FieldFactory.add(['string', 'json', 'integer', 'text'])); - source.config[1].value = { key: 'string_0' }; - source.config[3].value = 'other text'; - const formOpt = toFormOptions(source); - expect(service.filterApply(formOpt, { search: 'string_0', advanced: false }).filter((a) => !a.hidden)).toEqual([ - { - type: 'string', - name: 'field_string_0', - value: '', - required: true, - read_only: false, - activatable: false, - default: null, - subname: '', - display_name: 'display_field_string_0_', - controlType: 'textbox', - validator: { required: true, min: undefined, max: undefined, pattern: null }, - compare: [], - key: 'field_string_0', - hidden: false, - }, - { - type: 'json', - name: 'field_json_1', - value: getValue('json')({ key: 'string_0' }), - required: true, - read_only: false, - activatable: false, - default: null, - subname: '', - display_name: 'display_field_json_1_', - controlType: 'json', - validator: { required: true, min: undefined, max: undefined, pattern: null }, - compare: [], - key: 'field_json_1', - hidden: false, - }, - ]); - }); - - it('filterApply with search by display_name and value should change the fields satisfy search condition on as hidden, in case when config have group', () => { - const source = new Configuration(FieldFactory.add(['string', ['text']])); - source.config[2].value = 'other text'; - const formOpt = toFormOptions(source); - expect(service.filterApply(formOpt, { search: 'string_0', advanced: false }) as any).toEqual([ - { - type: 'string', - name: 'field_string_0', - value: '', - required: true, - read_only: false, - activatable: false, - default: null, - subname: '', - display_name: 'display_field_string_0_', - controlType: 'textbox', - validator: { required: true, min: undefined, max: undefined, pattern: null }, - compare: [], - key: 'field_string_0', - hidden: false, - }, - { - activatable: false, - active: true, - default: null, - display_name: 'display_field_group_1_', - hidden: true, - name: 'field_group_1', - read_only: false, - required: true, - subname: '', - type: 'group', - value: '', - options: [ - { - type: 'text', - name: 'subname_text_0', - value: 'other text', - required: true, - read_only: false, - activatable: false, - default: null, - subname: 'subname_text_0', - display_name: 'display_field_group_1_subname_text_0', - key: 'subname_text_0/field_group_1', - validator: { required: true, min: undefined, max: undefined, pattern: null }, - controlType: 'textarea', - hidden: true, - compare: [], - }, - ], - }, - ]); - }); - - it('parseValue(empty, empty) should return {}', () => { - const source: IFieldStack[] = []; - const value: IOutput = {}; - expect(service.parseValue(value, source)).toEqual({}); - }); - - it('parseValue should cast the string from the form to its original type', () => { - const source = new Configuration( - FieldFactory.add(['string', 'integer', 'integer', 'integer', 'boolean', 'boolean', 'boolean', 'float', 'float', 'map', 'map', 'list', 'list', 'option', 'option']) - ); - const value = setValue(source.config, ['a', 1, 0, '123', true, undefined, null, 1.2, '1.23', { key: 'value' }, 'string', ['a', 1], 'string', 'option string', 0]); - expect(service.parseValue(value, source.config)).toEqual({ - field_string_0: 'a', - field_integer_1: 1, - field_integer_2: 0, - field_integer_3: 123, - field_boolean_4: true, - field_boolean_5: undefined, - field_boolean_6: null, - field_float_7: 1.2, - field_float_8: 1.23, - field_map_9: Object({ key: 'value' }), - field_map_10: 'string', - field_list_11: ['a', 1], - field_list_12: 'string', - field_option_13: 'option string', - field_option_14: 0, - }); - }); - - it('parseValue should cast the string from the form to its original type, in case when config have group', () => { - const source = new Configuration(FieldFactory.add(['string', ['integer', 'float', 'float', 'string'], ['map', 'list', 'map', 'list', 'option'], []])); - const value = setValue(source.config, ['a', ['12', '1.0', '1.2', ''], [null, null, 'str', 'str', 0]]); - - expect(service.parseValue(value, source.config)).toEqual({ - field_string_0: 'a', - field_group_1: { subname_integer_0: 12, subname_float_1: 1, subname_float_2: 1.2, subname_string_3: null }, - field_group_2: { - subname_map_0: null, - subname_list_1: [], - subname_map_2: 'str', - subname_list_3: 'str', - subname_option_4: 0 - }, - }); - }); - - it('checkValue("", "string") should return null', () => { - expect(checkValue('', 'string')).toBeNull(); - }); - - it('checkValue("2.0", "float") should return 2', () => { - expect(checkValue('2.0', 'float')).toBe(2); - }); - - it('checkValue("2.2", "float") should return 2.2', () => { - expect(checkValue('2.2', 'float')).toBe(2.2); - }); - - it('checkValue("0", "float") should return 0', () => { - expect(checkValue('0', 'float')).toBe(0); - }); - - it('checkValue("", "float") should return null', () => { - expect(checkValue('', 'float')).toBeNull(); - }); - - it('checkValue("23456778", "integer") should return 23456778', () => { - expect(checkValue('23456778', 'integer')).toBe(23456778); - }); - - it('checkValue("0", "integer") should return 0', () => { - expect(checkValue('0', 'integer')).toBe(0); - }); - - it('checkValue("", "integer") should return null', () => { - expect(checkValue('', 'integer')).toBeNull(); - }); - - it('checkValue(12345678, "option") should return 12345678', () => { - expect(checkValue(12345678, 'option')).toBe(12345678); - }); - - it('checkValue("default", "option") should return "default"', () => { - expect(checkValue('default', 'option')).toBe('default'); - }); - - it('checkValue("0 one two", "option") should return "0 one two"', () => { - expect(checkValue('0 one two', 'option')).toBe('0 one two'); - }); - - it('checkValue(0, "option") should return 0', () => { - expect(checkValue(0, 'option')).toBe(0); - }); - - it('checkValue("", "option") should return null', () => { - expect(checkValue('', 'option')).toBeNull(); - }); - - it('checkValue(true, "boolean") should return true', () => { - expect(checkValue(true, 'boolean')).toBeTrue(); - }); - - it('checkValue(false, "boolean") should return false', () => { - expect(checkValue(false, 'boolean')).toBeFalse(); - }); - - it('checkValue(null, "boolean") should return null', () => { - expect(checkValue(null, 'boolean')).toBeNull(); - }); - - it('checkValue("", "boolean") should return null', () => { - expect(checkValue('', 'boolean')).toBeNull(); - }); - - it('checkValue("{}", "json") should return {}', () => { - expect(checkValue('{}', 'json')).toEqual({}); - }); - - it('checkValue("", "json") should return null', () => { - expect(checkValue('', 'json')).toBeNull(); - }); - - it('checkValue(null, "json") should return null', () => { - expect(checkValue(null, 'json')).toBeNull(); - }); - - it('checkValue("{↵ "a": 23 ↵}", "json") should return { "a": 23 }', () => { - expect(checkValue('{"a": 23 }', 'json')).toEqual({ a: 23 }); - }); - - it('List fieldType :: checkValue("some string", "list") should return "some string"', () => { - expect(checkValue('some string', 'list')).toEqual('some string'); - }); - - it('List fieldType :: checkValue("[]", "list") should return null', () => { - expect(checkValue([], 'list')).toEqual([]); - }); - - it('List fieldType :: checkValue(["string1", "", "string2"], "list") should return ["string1", "string2"]', () => { - expect(checkValue(['string1', '', 'string2'], 'list')).toEqual(['string1', 'string2']); - }); - - it('Map fieldType :: checkValue({"string1": "value1", "string2": "value2"}, "map") should return {"string1": "value1", "string2": "value2"}', () => { - expect(checkValue({ string1: 'value1', string2: 'value2' }, 'map')).toEqual({ - string1: 'value1', - string2: 'value2' - }); - }); - - it('Map fieldType :: checkValue({"string1": "", "string2": "value2"}, "map") should return { "string1": "","string2": "value2"}', () => { - expect(checkValue({ string1: '', string2: 'value2' }, 'map')).toEqual({ string1: '', string2: 'value2' }); - }); - - it('Map fieldType :: checkValue({"": "value1", "string2": "value2"}, "map") should return {"string2": "value2"}', () => { - expect(checkValue({ '': 'value1', string2: 'value2' }, 'map')).toEqual({ string2: 'value2' }); - }); - - it('Map fieldType :: checkValue(["string1", "string2"], "map") should return { 0: "string1", 1: "string2" }', () => { - expect(checkValue(['string1', 'string2'], 'map')).toEqual({ 0: 'string1', 1: 'string2' }); - }); - - it('Map fieldType :: checkValue("some string", "map") should return "some string"', () => { - expect(checkValue('some string', 'map')).toEqual('some string'); - }); - - it('Map fieldType :: checkValue("{}", "map") should return null', () => { - expect(checkValue({}, 'map')).toEqual(null); - }); - - /** - * - * check value - mocking the click save button - * - */ - it('parseValue - for structure: after init with empty field and not required', () => { - const source: ISource[] = [{ - type: 'structure', - name: 'field', - subname: '', - read_only: false, - value: null, - limits: { rules: {} } - }]; - const output: IOutput = { field: {} }; - - const result = service.parseValue(output, source); - expect(result).toEqual({ field: null }); - - const output2: IOutput = { field: [] }; - - const result2 = service.parseValue(output2, source); - expect(result2).toEqual({ field: null }); - - const output3: IOutput = { field: { field1: [] } }; - - const result3 = service.parseValue(output3, source); - expect(result3).toEqual({ field: null }); - }); - - it('parseValue for structure should return list', () => { - const rules: IYContainer | IYField = { - name: 'root', - type: 'list', - options: { - name: 'listener', - type: 'dict', - options: [ - { - controlType: 'textbox', - name: 'name', - path: ['name', 'listener'], - type: 'string', - validator: { - pattern: null, - required: true, - }, - isInvisible: false - }, - { - controlType: 'textbox', - name: 'port', - path: ['port', 'listener'], - type: 'int', - validator: { required: true, pattern: /^[-]?\d+$/ }, - isInvisible: false - }, - { name: 'ssl enable', type: 'bool', path: [], controlType: 'boolean', validator: {}, isInvisible: false }, - { name: 'sasl protocol', type: 'string', path: [], controlType: 'textbox', validator: {}, isInvisible: false }, - ], - }, - }; - - const yspec: IYspec = { - boolean: { match: 'bool' }, - integer: { match: 'int' }, - string: { match: 'string' }, - root: { - match: 'list', - item: 'listener', - }, - listener: { - items: { - name: 'string', - port: 'integer', - 'sasl protocol': 'string', - 'ssl enable': 'boolean', - }, - match: 'dict', - required_items: ['name', 'port'], - }, - }; - - const source = new Configuration(FieldFactory.add(['structure'])); - source.config[0].value = [{ name: 'DEFAULT', port: 9092 }]; - source.config[0].limits = { rules, yspec }; - const output = { field_structure_0: [{ name: 'DEFAULT', port: '9092' }] }; - const result = service.parseValue(output, source.config); - - expect(result).toEqual({ field_structure_0: [Object({ name: 'DEFAULT', port: 9092 })] }); - }); -}); diff --git a/web/src/app/shared/configuration/services/field.service.ts b/web/src/app/shared/configuration/services/field.service.ts deleted file mode 100644 index a49b61ec5f..0000000000 --- a/web/src/app/shared/configuration/services/field.service.ts +++ /dev/null @@ -1,427 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { AbstractControl, AbstractControlOptions, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; -import { isEmptyObject } from '@app/core/types'; - -import { ISearchParam } from '../main/main.service'; -import { - controlType, - IConfig, - IConfigAttr, - IFieldOptions, - IFieldStack, - ILimits, - IPanelOptions, - IValidator, - resultTypes, - TNBase, - TNForm -} from '../types'; -import { AttributeService } from '@app/shared/configuration/attributes/attribute.service'; - -export type TFormOptions = IFieldOptions | IPanelOptions; - -export interface IOutput { - [key: string]: resultTypes; -} - -export interface ISource { - name: string; - subname: string; - type: TNForm; - read_only: boolean; - limits?: ILimits; - value: any; -} - -export interface IToolsEvent { - name: string; - conditions?: { advanced: boolean; search: string } | boolean; -} - -const isVisibleField = (a: TFormOptions) => !a.ui_options?.invisible; -const isAdvancedField = (a: TFormOptions) => isVisibleField(a) && a.ui_options?.advanced; -const isHidden = (a: IFieldStack) => !!(a.ui_options?.invisible || a.ui_options?.advanced); - -const typeToControl: Partial<{ [key in TNForm | controlType]: controlType }> = { - bool: 'boolean', - int: 'textbox', - integer: 'textbox', - float: 'textbox', - string: 'textbox', - file: 'textarea', - text: 'textarea', -}; - -export const getControlType = (t: TNForm): controlType => typeToControl[t] || (t as controlType); - -const intPattern = () => new RegExp(/^[-]?\d+$/); -const patternFn = { - integer: intPattern, - int: intPattern, - float: () => new RegExp(/^[-]?[0-9]+(\.[0-9]+)?$/), -}; - -export const getPattern = (t: TNForm): RegExp => (patternFn[t] ? patternFn[t]() : null); - -const fn = { - boolean: (v: boolean | null, d: boolean | null, r: boolean): boolean | null => (String(v) === 'true' || String(v) === 'false' || String(v) === 'null' ? v : r ? d : null), - json: (v: string): string => (v === null ? '' : JSON.stringify(v, undefined, 4)), - map: (v: object, d: object): object => (!v ? d : v), - secretmap: (v: object, d: object): object => (!v ? d : v), - list: (v: string[], d: string[]): string[] => (!v ? d : v), - structure: (v: any): any => v, -}; - -export const getValue = (t: TNForm) => { - const def = (value: number | string) => (value === null || value === undefined ? '' : String(value)); - return fn[t] ? fn[t] : def; -}; - -export const getKey = (name: string, subname: string): string => (subname ? `${subname}/${name}` : name); - -export const getValidator = (required: boolean, min: number, max: number, type: TNForm) => ({ - required, - min, - max, - pattern: getPattern(type), -}); - -const getField = (item: IFieldStack): IFieldOptions => { - return { - ...item, - key: getKey(item.name, item.subname), - value: getValue(item.type)(item.value, item.default, item.required), - validator: getValidator(item.required, item.limits?.min, item.limits?.max, item.type), - controlType: getControlType(item.type), - hidden: item.name === '__main_info' || isHidden(item), - compare: [] - }; -}; - -const fo = (n: string) => (b: IFieldStack) => b.type !== 'group' && b.subname && b.name === n; -const isActive = (a: IConfigAttr, n: string) => a[n]?.active; -export const getOptions = (a: IFieldStack, d: IConfig) => - d.config - .filter(fo(a.name)) - .map((f) => getField(f)) - // switch off validation for field if !(activatable: true && active: false) - line: 146 - .map((c) => ({ ...c, name: c.subname, activatable: a.activatable && !isActive(d.attr, a.name) })); - -const getPanel = (a: IFieldStack, d: IConfig): IPanelOptions => ({ - ...a, - hidden: isHidden(a), - active: a.activatable ? isActive(d.attr, a.name) : true, - options: getOptions(a, d), -}); - -const handleTree = (c: ISearchParam): ((a: TFormOptions) => TFormOptions) => (a: TFormOptions): TFormOptions => { - if ('options' in a) { - a.options = a.options.map(handleTree(c)); - if (c.search) a.hidden = a.options.filter((b) => !b.hidden).length === 0; - else a.hidden = isAdvancedField(a) ? !c.advanced : false; - } else if (isVisibleField(a)) { - a.hidden = !(a.display_name.toLowerCase().includes(c.search.toLowerCase()) || String(a.value).toLocaleLowerCase().includes(c.search.toLocaleLowerCase())); - if (!a.hidden && isAdvancedField(a)) a.hidden = !c.advanced; - } - return a; -}; - -const findAttrValue = (obj: T, key: string): boolean => { - let value; - for (let i in obj) { - if (!obj.hasOwnProperty(i)) continue; - if (typeof obj[i] === 'object') { - value = findAttrValue(obj[i], key); - } else if (i === key) { - value = obj[i]; - } - } - return value; -}; - -@Injectable() -export class FieldService { - attributesService: AttributeService | undefined; - - constructor(public fb: FormBuilder) {} - - /** - * Parse and prepare source data from backend - */ - public getPanels(data: IConfig): TFormOptions[] { - return data?.config - ?.filter((a) => a.name !== '__main_info') - .reduce((p, c) => { - if (c.subname) return p; - if (c.type !== 'group') return [...p, getField(c)]; - else return [...p, getPanel(c, data)]; - }, []); - } - - /** - * Parse and prepare attrs data for group config from backend - */ - public getAttrs(data: IConfig, groups: string[], dataOptions: TFormOptions[]): void { - if (!data?.attr || !groups) return; - - groups.forEach((group) => { - let disabled: boolean; - const i = dataOptions.findIndex(item => item.name === group); - const config = data.config.filter(c => c.name === group && c.type === 'group'); - - if (config.length === 0) return; - - if (!data.attr?.custom_group_keys || !data.attr?.group_keys) { - dataOptions[i].group_config = { - 'exist': false, - } - - return; - } - - if (config[0]?.read_only || !data.attr?.custom_group_keys[group].value) { - disabled = true; - } else if (data.attr?.custom_group_keys[group].value && data.attr?.group_keys[group].value) { - disabled = false; - } - - dataOptions[i] = { - ...dataOptions[i], - active: dataOptions[i]['active'], - group_config: { - 'exist': true, - 'checkboxValue': data.attr?.custom_group_keys[group].value && data.attr?.group_keys[group].value, - 'disabled': disabled - } - } - }) - } - - /** - * Generate FormGroup - * @param options - */ - public toFormGroup(options: TFormOptions[] = []): FormGroup { - const check = (a: TFormOptions): boolean => - 'options' in a - ? a.activatable - ? isVisibleField(a) // if group.activatable - only visible - : isVisibleField(a) && !a.read_only // else visible an not read_only - ? a.options.some((b) => check(b)) // check inner fields - : false - : isVisibleField(a) && !a.read_only; // for fields in group - - return this.fb.group( - options.reduce((p, c) => this.runByTree(c, p), {}), - { - validator: () => (options.filter(check).length === 0 ? { error: 'Form is empty' } : null), - } as AbstractControlOptions - ); - } - - // TODO: - private runByTree(field: TFormOptions, controls: { [key: string]: {} }): { [key: string]: {} } { - if ('options' in field) { - controls[field.name] = this.fb.group( - field.options.reduce((p, a) => { - if ('options' in a) this.fb.group(this.runByTree(a, p)); - else this.fillForm(a, p); - return p; - }, {}) - ); - return controls; - } else { - return this.fillForm(field, controls); - } - } - - private fillForm(field: IFieldOptions, controls: {}) { - const name = field.subname || field.name; - controls[name] = this.fb.control(field.value, field.activatable ? [] : this.setValidator(field)); - return controls; - } - - /** - * External use (scheme.service) to set validator for FormControl by type - * @param field Partial{ ValidatorInfo, controlType } - * @param controlToCompare - */ - public setValidator(field: { validator: IValidator; controlType: controlType }, controlToCompare?: AbstractControl) { - const v: ValidatorFn[] = []; - - if (field.validator.required) v.push(Validators.required); - if (field.validator.pattern) v.push(Validators.pattern(field.validator.pattern)); - //if (field.validator.max !== null) - v.push(Validators.max(field.validator.max)); - //if (field.validator.min !== null) - v.push(Validators.min(field.validator.min)); - - if (field.controlType === 'password') { - const passwordConfirm = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => { - if (controlToCompare && controlToCompare.value !== control.value) return { notEqual: true }; - return null; - }; - v.push(passwordConfirm()); - } - - if (field.controlType === 'json') { - const jsonParse = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => { - if (control.value) { - try { - JSON.parse(control.value); - return null; - } catch (e) { - return { jsonParseError: { value: control.value } }; - } - } else return null; - }; - - v.push(jsonParse()); - } - - if (field.controlType === 'map' || field.controlType === 'secretmap') { - const parseKey = (): ValidatorFn => (control: AbstractControl): { [key: string]: any } | null => - control.value && Object.keys(control.value).length && Object.keys(control.value).some((a) => !a) ? { parseKey: true } : null; - v.push(parseKey()); - } - - return v; - } - - /** - * Filter by group and all fields - */ - public filterApply(options: TFormOptions[], c: ISearchParam): TFormOptions[] { - return options.filter((a) => isVisibleField(a)).map(handleTree(c)); - } - - /** - * Output form, cast to source type - */ - public parseValue(formValue: IOutput, configData: ISource[]): IOutput { - const findField = (name: string, parentName?: string): Partial => configData.find((a) => (parentName ? a.name === parentName && a.subname === name : a.name === name && !a.subname)); - - const runYspecParse = (formData: any, fieldProperties: Partial) => ((!formData || !Object.keys(formData).length) && !fieldProperties.value ? fieldProperties.value : this.runYspec(formData, fieldProperties.limits.rules)); - - const replaceEmptyObjectWithNull = (value: any): string => ((Array.isArray(value) && value?.length === 0) || JSON.stringify(value) === '{}' || this.emptyArrayInside(value)) ? null : value - - const runParse = (configElements: IOutput, parentName?: string): IOutput => { - - const runByValue = (siblingConfigElements: IOutput, name: string) => { - - const checkType = (formData: resultTypes | IOutput, elementProperties: Partial): resultTypes => { - const { type } = elementProperties; - if (type === 'structure') { - return replaceEmptyObjectWithNull(runYspecParse(formData, elementProperties)); - } else if (type === 'group') { - return this.checkValue(runParse(formData as IOutput, elementProperties.name), type); - } else if (type === 'option') { - const optionValueType = elementProperties?.limits?.option ? typeof Object.values(elementProperties?.limits?.option)[0] : typeof elementProperties?.default; - let optionTypeParam: TNForm; - - if (optionValueType === 'number') { - optionTypeParam = Number.isInteger(formData) ? 'integer' : 'float'; - } else { - optionTypeParam = optionValueType as TNForm; - } - - return this.checkValue(formData, optionTypeParam); - } - else { - return this.checkValue(formData, type); - } - }; - - const configElement = findField(name, parentName); - if (configElement) { - const result = checkType(configElements[name], configElement); - return configElement.type !== 'group' || result ? { ...siblingConfigElements, [name]: result } : siblingConfigElements; - } - return siblingConfigElements; - }; - - return Object.keys(configElements).reduce(runByValue, {}); - }; - - const __main_info = findField('__main_info'); - - return runParse(!!__main_info ? { ...formValue, __main_info: __main_info.value } : { ...formValue }); - } - - private runYspec(value: resultTypes, rules: any) { - switch (rules?.type) { - case 'list': { - return (value as Array).filter((a) => !!a).map((a) => this.runYspec(a, rules.options)); - } - case 'dict': { - return Object.keys(value).reduce((p, c) => { - const r = rules.options.find((b: any) => b.name === c); - const v = r ? this.runYspec(value[c], r) : null; - - if (r.isInvisible) { - if (v === null) return { ...p, [c]: '' }; - - return { ...p, [c]: v }; - } - - return v !== null ? { ...p, [c]: v } : { ...p }; - }, {}); - } - default: { - return this.checkValue(value, rules?.type); - } - } - } - - checkValue(value: resultTypes, type: TNForm): resultTypes { - if (value === '' || value === null || isEmptyObject(value)) { - if (type === 'list') return []; - return null; - } - - if (typeof value === 'boolean') return value; - else if (typeof value === 'string' && type === 'boolean') return value === 'true'; - else if (typeof value === 'string') - switch (type) { - case 'integer': - case 'int': - return parseInt(value, 10); - case 'float': - return parseFloat(value); - case 'json': - return JSON.parse(value); - } - else - switch (type) { - case 'map': - case 'secretmap': - return Object.keys(value) - .filter((a) => !!a) - .reduce((p, c) => ({ ...p, [c]: value[c] }), {}); - - case 'list': - return Array.isArray(value) ? (value as Array).filter((a) => !!a) : null; - } - - return value; - } - - emptyArrayInside(object: Object): boolean { - if (object) { - const keys = Object.keys(object); - return keys?.length === 1 && Array.isArray(object[keys[0]]) && object[keys[0]]?.length === 0; - } - } -} diff --git a/web/src/app/shared/configuration/tests/configuration.ts b/web/src/app/shared/configuration/tests/configuration.ts deleted file mode 100644 index 3a84c23bce..0000000000 --- a/web/src/app/shared/configuration/tests/configuration.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { IFieldOptions } from './../types'; -// Licensed 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 { getControlType, getKey, getOptions, getValidator, getValue, TFormOptions, IOutput } from '../services/field.service'; - -import { IConfig, IConfigAttr, IFieldStack, ILimits, IPanelOptions, IUIoptions, stateType, TNForm, TValue } from '../types'; -import { IYContainer, IYField, IYspec } from '../yspec/yspec.service'; - -export class YContainer {} - -export class YField {} - -export class Yspec { - constructor() {} -} - -export class UIOptions implements IUIoptions {} - -export class Limits { - min: number; - max: number; - option: any; - read_only: stateType[]; - active: boolean; - rules: IYField | IYContainer; - constructor(public yspec: IYspec) {} - set Rules(rules: IYField | IYContainer) { - this.rules = rules; - } -} - -export class FieldStack implements IFieldStack { - subname: string; - display_name: string; - default: TValue = null; - description?: string; - limits: ILimits; - ui_options: IUIoptions; - group_config: { [key: string]: boolean }; - - constructor( - id: number, - public type: TNForm, - public name: string = null, - public value = null, - public required = true, - public read_only = false, - public activatable = false - ) { - const dn = `field_${type}_${id}`; - this.name = !this.name ? dn : this.name; - this.subname = this.name === dn ? '' : `subname_${type}_${id}`; - this.display_name = `display_${this.name}_${this.subname}`; - this.value = getValue(this.type)(this.value, this.default, this.required); - } - - set Limits(limits: ILimits) { - this.limits = limits; - } - set UIOptions(options: IUIoptions) { - this.ui_options = options; - } -} - -export class Configuration implements IConfig { - id?: number; - date?: string; - description?: string; - attr?: IConfigAttr; - constructor(public config: IFieldStack[]) {} -} - -export class FieldFactory { - public static addGroup(id: number, params: TNForm[]): IFieldStack[] { - const group = new FieldStack(id, 'group'); - return params.reduce((p, c, i) => [...p, new FieldStack(i, c, group.name)], [group]); - } - - /** - * return group if params as array - */ - public static add(params: (TNForm | TNForm[])[]) { - return params.reduce( - (p, c, i) => [...p, ...(Array.isArray(c) ? this.addGroup(i, c) : [new FieldStack(i, c)])], - [] - ); - } -} - -const toPanel = (a: IFieldStack, data: IConfig): IPanelOptions => ({ - ...a, - options: getOptions(a, data), - active: true, - hidden: false, -}); - -const toField = (a: IFieldStack): IFieldOptions => ({ - ...a, - controlType: getControlType(a.type), - validator: getValidator(a.required, a.limits?.min, a.limits?.max, a.type), - compare: [], - key: getKey(a.name, a.subname), - hidden: false, - value: getValue(a.type)(a.value, a.default, a.required), -}); - -export const toFormOptions = (data: IConfig): TFormOptions[] => { - return data.config.reduce((p, c) => { - if (c.subname) return p; - if (c.type !== 'group') return [...p, toField(c)]; - else return [...p, toPanel(c, data)]; - }, []); -}; - -export const setValue = (data: IFieldStack[], v: TValue): IOutput => - data - .filter((a) => !a.subname) - .reduce( - (p, c, i) => ({ - ...p, - [c.name]: - c.type === 'group' - ? data - .filter((a) => a.name === c.name && a.type !== 'group') - .reduce((a, b, k) => ({ ...a, [b.subname]: v[i][k] }), {}) - : v - ? v[i] - : null, - }), - {} - ); diff --git a/web/src/app/shared/configuration/tools/color-option.directive.ts b/web/src/app/shared/configuration/tools/color-option.directive.ts deleted file mode 100644 index 4f63e2a4b8..0000000000 --- a/web/src/app/shared/configuration/tools/color-option.directive.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed 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 { Directive, ElementRef, Input, AfterViewInit, Renderer2 } from '@angular/core'; - -@Directive({ - selector: '[appColorOption]' -}) -export class ColorOptionDirective implements AfterViewInit { - - @Input('appColorOption') - colorOption: string; - - constructor(private el: ElementRef, private render: Renderer2) { } - - ngAfterViewInit(): void { - const pchb = this.el.nativeElement.firstElementChild; - this.render.setStyle(pchb, 'backgroundColor', this.colorOption); - } -} diff --git a/web/src/app/shared/configuration/tools/filter/filter-list/filter-list.component.scss b/web/src/app/shared/configuration/tools/filter/filter-list/filter-list.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/shared/configuration/tools/filter/filter-list/filter-list.component.ts b/web/src/app/shared/configuration/tools/filter/filter-list/filter-list.component.ts deleted file mode 100644 index aa206ff986..0000000000 --- a/web/src/app/shared/configuration/tools/filter/filter-list/filter-list.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed 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 {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; -import { MatMenu } from "@angular/material/menu"; - -@Component({ - selector: 'filter-list', - template: ` - -
- No filters -
- - -
- -
-
-
-
`, - styleUrls: ['./filter-list.component.scss'] -}) -export class FilterListComponent { - @Input() filters: any[]; - @Input() activeFilters: number[]; - @Output() toggleFilter: EventEmitter = new EventEmitter(); - @ViewChild('menu', {static: true}) menu: MatMenu; - - constructor() {} - - onClick(filter) { - this.toggleFilter.emit(filter); - } -} diff --git a/web/src/app/shared/configuration/tools/filter/filter.component.html b/web/src/app/shared/configuration/tools/filter/filter.component.html deleted file mode 100644 index 4622f6fbf5..0000000000 --- a/web/src/app/shared/configuration/tools/filter/filter.component.html +++ /dev/null @@ -1,48 +0,0 @@ -
-
- filter_list - -
- -
- - - - - - - {{ p.display_name }} - - - - - - - - {{ filter.display_name }} - - - - - - - Invalid start date - Invalid end date - - - - - - - - -
-
diff --git a/web/src/app/shared/configuration/tools/filter/filter.component.scss b/web/src/app/shared/configuration/tools/filter/filter.component.scss deleted file mode 100644 index 7939689e01..0000000000 --- a/web/src/app/shared/configuration/tools/filter/filter.component.scss +++ /dev/null @@ -1,51 +0,0 @@ -:host { - display: flex; - position: relative; - padding: 0 8px; -} - -.filter-container { - display: flex; - align-items: center; -} - -.filter-toggle-button { - cursor: pointer; -} - -mat-form-field { - flex: auto; - margin: 0 10px; - font-size: 14px; -} - -::ng-deep .filter-field.datepicker { - & > .mat-form-field-wrapper { - & > .mat-form-field-underline { - display: none !important; - } - } - - .datepicker-form { - .mat-form-field-suffix { - left: -20px; - } - - .mat-form-field-infix { - width: 170px; - margin-right: 16px; - } - } -} - -::ng-deep .mat-calendar-body-in-range { - &:before { - background: #00e676 !important; - opacity: 0.3; - } -} - -::ng-deep .mat-calendar-body-selected { - color: #333 !important; - background: #00e676 !important; -} diff --git a/web/src/app/shared/configuration/tools/filter/filter.component.ts b/web/src/app/shared/configuration/tools/filter/filter.component.ts deleted file mode 100644 index 61f1bc47e4..0000000000 --- a/web/src/app/shared/configuration/tools/filter/filter.component.ts +++ /dev/null @@ -1,208 +0,0 @@ -// Licensed 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. -/** - * INSTRUCTIONS - * For the filter to work correctly, you need to create a filter rules with IFilter stucture in filter parent component - * "copy" of the BehaviourSubject with data for the table and pass it to the table. You must pass both the original - * and the "copy" to the filter component - */ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { BaseDirective } from "../../../directives"; -import { BehaviorSubject } from "rxjs"; - -export interface IFilter { - id: number, - name: string, - display_name: string, - filter_field: string, - filter_type: FilterType, - options?: IFilterOption[], - active?: boolean, -} - -export interface IFilterOption { - id: number, - name: string, - display_name: string, - value: any, -} - -type FilterType = 'list' | 'input' | 'datepicker'; - -@Component({ - selector: 'app-filter', - templateUrl: './filter.component.html', - styleUrls: ['./filter.component.scss'], -}) -export class FilterComponent extends BaseDirective implements OnInit, OnDestroy { - filterForm = new FormGroup({}); - availableFilters: any[]; - activeFilters: number[] = []; - filtersByType = {}; - backupData: any; - freezeBackupData: boolean = false; - externalChanges: boolean = false; - @Input() filterList: IFilter[] = []; - @Input() externalData: BehaviorSubject; - @Input() innerData: BehaviorSubject; - - get filters() { - return this.filterList.filter((filter) => (this.activeFilters?.includes(filter.id))); - } - - constructor() { - super(); - } - - ngOnInit() { - this.availableFilters = this.filterList.map((filter: IFilter) => ({ - id: filter.id, - name: filter.name, - display_name: filter.display_name, - filter_field: filter.filter_field, - filter_type: filter.filter_type - })); - - this.availableFilters.forEach((i: IFilter) => { - this.filtersByType[i.filter_field] = i.filter_type; - }) - - this.externalData.subscribe((values: any) => { - this.externalChanges = true; - this.freezeBackupData = false; - - if (this.externalChanges && values) { - this.innerData.next(values); - - this.innerData.subscribe((values: any) => { - if (!this.backupData || !this.freezeBackupData) { - this.backupData = values; - this.freezeBackupData = false; - } - - if (this.externalChanges) { - this.externalChanges = false; - this.applyFilters(); - } - }) - } - }); - } - - clear(filter, event: any) { - if (this.filtersByType[filter] === 'datepicker') { - this.filterForm.get(filter).setValue({start: undefined, end: undefined}); - } else this.filterForm.get(filter).setValue(undefined); - this.innerData.next(this.backupData); - event.preventDefault(); - event.stopPropagation(); - } - - removeFilter(filter, event) { - this.toggleFilters(filter); - this.applyFilters(); - event.preventDefault(); - } - - setDate(event) { - if (event.value) { - event.value.setHours(23, 59, 59, 999); - this.applyFilters(); - } - } - - applyFilters() { - const filters = this.filterForm.value; - - if (Object.keys(filters).filter((f) => { - if (filters[f] === '' || filters[f] === undefined) { - delete filters[f]; - return false; - } else return true; - }).length === 0) { - this.innerData.next(this.backupData); - return; - } - - let data = this.backupData?.results?.filter((item) => { - for (let key in filters) { - if (this.filtersByType[key] === 'list') { - if (item[key] === undefined || item[key] !== filters[key]) { - return false; - } - } - } - - return true; - }); - - if (this.filters.some((f) => f.filter_type === 'input' && filters[f.filter_field])) { - data = data.filter((item) => { - return Object.keys(filters).filter((f) => this.filtersByType[f] === 'input').every((i) => { - if (i.includes('/')) { - let nestedKey = i.split('/'); - - if (item[nestedKey[0]][nestedKey[1]] !== undefined && - item[nestedKey[0]][nestedKey[1]] !== null && - item[nestedKey[0]][nestedKey[1]] !== '' && - item[nestedKey[0]][nestedKey[1]].toLowerCase().includes(filters[i].toLowerCase())) { - return true; - } - } else { - if (item[i] !== undefined && item[i] !== null && item[i] !== '' && item[i].toLowerCase().includes(filters[i].toLowerCase())) { - return true; - } - } - }) - }) - } - - if (this.filters.some((f) => f.filter_type === 'datepicker' && filters[f.filter_field].end)) { - data = data.filter((item) => { - return Object.keys(filters).filter((f) => this.filtersByType[f] === 'datepicker').every((i) => { - if (item[i] !== undefined && item[i] !== null && (filters[i].start < new Date(item[i]) && new Date(item[i]) < filters[i].end)) { - return true; - } - }) - }) - } - - let count = this.activeFilters.length === 0 ? this.backupData.count : data.count; - this.freezeBackupData = true; - this.innerData.next({...this.backupData, count, results: data}); - } - - clearButtonVisible(field) { - const value = this.filterForm?.getRawValue()[field]; - return this.filtersByType[field] !== 'datepicker' && (value || (typeof value === 'boolean' && !value)); - } - - toggleFilters(filter) { - if (this.activeFilters.includes(filter.id)) { - this.activeFilters = this.activeFilters.filter((f) => f !== filter.id); - this.filterForm.removeControl(filter.filter_field); - } else { - this.activeFilters.push(filter.id); - if (filter.filter_type === 'datepicker') { - this.filterForm.addControl(filter.filter_field, new FormGroup({ - start: new FormControl(new Date()), - end: new FormControl(new Date()), - })); - } else this.filterForm.addControl(filter.filter_field, new FormControl('')) - } - } - - datepickerGroup(controlName): FormGroup { - return this.filterForm.get(controlName) as FormGroup; - } -} diff --git a/web/src/app/shared/configuration/tools/history.component.ts b/web/src/app/shared/configuration/tools/history.component.ts deleted file mode 100644 index 8ff4476534..0000000000 --- a/web/src/app/shared/configuration/tools/history.component.ts +++ /dev/null @@ -1,68 +0,0 @@ -// Licensed 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 { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { FormControl } from '@angular/forms'; -import { BaseDirective } from '@app/shared/directives/base.directive'; - -import { CompareConfig } from '../types'; - -@Component({ - selector: 'app-history', - template: ` - - - - [#{{ item.id }}] - {{ item.date | date: 'short' }} {{ item.description }} - - -    - - - - [#{{ item.id }}] - {{ item.date | date: 'short' }} {{ item.description }} - - - - - `, - styles: [':host {height: 64px;}', 'mat-form-field {flex: auto; margin: 0 10px; font-size: 14px; }'], -}) -export class HistoryComponent extends BaseDirective implements OnInit { - @Input() compareConfig: CompareConfig[]; - @Input() currentVersion: number; - @Output() version = new EventEmitter(); - @Output() compare = new EventEmitter(); - - historyVersion = new FormControl(); - comparator = new FormControl(); - - get currentCompareConfig() { - return this.compareConfig ? this.compareConfig.filter((config) => config.id !== this.currentVersion) : []; - } - - ngOnInit() { - this.comparator.valueChanges.pipe(this.takeUntil()).subscribe((ids: number[]) => this.compare.emit(ids)); - this.historyVersion.valueChanges.pipe(this.takeUntil()).subscribe((id: number) => this.version.emit(id)); - } - - changeVersion(id: number) { - this.version.emit(id); - } - - trackById(item: CompareConfig): number { - return item.id; - } - - reset() { - this.comparator.reset(); - } -} diff --git a/web/src/app/shared/configuration/tools/search.component.ts b/web/src/app/shared/configuration/tools/search.component.ts deleted file mode 100644 index 4d9cde10b5..0000000000 --- a/web/src/app/shared/configuration/tools/search.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed 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 { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; -import { FormControl } from '@angular/forms'; -import { BaseDirective } from '@app/shared/directives/base.directive'; -import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; - -@Component({ - selector: 'app-search', - template: ` - - - - - - `, - styles: ['mat-form-field {flex: auto;margin: 0 10px;font-size: 14px;}'], -}) -export class SearchComponent extends BaseDirective implements OnInit, OnDestroy { - search = new FormControl(); - @Output() pattern = new EventEmitter(); - - constructor() { - super(); - } - - ngOnInit() { - this.search.valueChanges.pipe(this.takeUntil(), debounceTime(300), distinctUntilChanged()).subscribe((value) => this.pattern.emit(value)); - } -} diff --git a/web/src/app/shared/configuration/tools/server-filter/server-filter.component.scss b/web/src/app/shared/configuration/tools/server-filter/server-filter.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/shared/configuration/tools/server-filter/server-filter.component.ts b/web/src/app/shared/configuration/tools/server-filter/server-filter.component.ts deleted file mode 100644 index 63af44a703..0000000000 --- a/web/src/app/shared/configuration/tools/server-filter/server-filter.component.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { FilterComponent, IFilter } from "@app/shared/configuration/tools/filter/filter.component"; -import { BehaviorSubject } from "rxjs"; -import { FormControl, FormGroup } from "@angular/forms"; - -@Component({ - selector: 'app-server-filter', - templateUrl: '../filter/filter.component.html', - styleUrls: ['../filter/filter.component.scss'] -}) -export class ServerFilterComponent extends FilterComponent implements OnInit { - @Input() filterParams$: BehaviorSubject; - @Input() entity: string; - - filterArr: string[]; - - constructor() { - super(); - } - - ngOnInit() { - this.availableFilters = this.filterList.map((filter: IFilter) => ({ - id: filter.id, - name: filter.name, - display_name: filter.display_name, - filter_field: filter.filter_field, - filter_type: filter.filter_type - })); - - this.filterArr = this.filterList.map((filter: IFilter) => (filter.name)); - - this.availableFilters.forEach((i: IFilter) => { - this.filtersByType[i.filter_field] = i.filter_type; - }) - - const listParam = localStorage.getItem('list:param'); - - if (listParam) { - const json = JSON.parse(listParam); - - if (json[this.entity]) { - this.manageDatepickerValue(json); - Object.keys(json[this.entity]).forEach((name) => { - if (!this.filterArr.includes(name)) return; - - this.toggleFilters(this.availableFilters.find((f) => f.name === name)); - this.filterForm.get(name).setValue(json[this.entity][name]); - }); - } - - this.applyFilters(); - } - } - - applyFilters(): void { - const filters = Object.entries(this.filterForm.value).reduce((res, [filterKey, filterVal]) => { - if (filterVal === '' || filterVal === undefined) { - return res; - } - - if (this.filtersByType[filterKey] === 'datepicker' && filterVal['start'] && filterVal['end']) { - return { - ...res, - [`${filterKey}_after`]: filterVal['start'].toISOString(), - [`${filterKey}_before`]: filterVal['end'].toISOString() - } - } - - return { - ...res, - [filterKey]: filterVal - } - }, {}) - - this.localStorageUpdate(filters); - } - - toggleFilters(filter): void { - if (this.activeFilters.includes(filter?.id)) { - this.activeFilters = this.activeFilters.filter((f) => f !== filter?.id); - this.localStorageCleaning(filter); - this.filterForm.removeControl(filter?.filter_field); - } else if (filter) { - this.activeFilters.push(filter?.id); - if (filter?.filter_type === 'datepicker') { - this.filterForm.addControl(filter.filter_field, new FormGroup({ - start: new FormControl(new Date()), - end: new FormControl(new Date()), - })); - } else if (filter) this.filterForm.addControl(filter?.filter_field, new FormControl('')) - } - } - - clear(filter, event: any) { - if (this.filtersByType[filter] === 'datepicker') { - this.filterForm.get(filter).setValue({start: undefined, end: undefined}); - } else this.filterForm.get(filter).setValue(undefined); - - this.applyFilters(); - } - - removeFilter(filter, event) { - this.toggleFilters(filter); - this.applyFilters(); - } - - localStorageCleaning(filter): void { - const listParamStr = localStorage.getItem('list:param'); - - if (listParamStr) { - const json = JSON.parse(listParamStr); - - if (json[this.entity]) { - delete json[this.entity][filter.filter_field]; - - this.manageDatepickerValue(json, true); - - if (Object.keys(json[this.entity]).length === 0) { - delete json[this.entity]; - } - } - - if (Object.keys(json).length === 0) { - localStorage.removeItem('list:param'); - } else localStorage.setItem('list:param', JSON.stringify(json)); - } - } - - localStorageUpdate(filters) { - const listParamStr = localStorage.getItem('list:param'); - const json = listParamStr ? JSON.parse(listParamStr) : null; - - let listParam = { - ...json, - [this.entity]: { - limit: json?.[this.entity]?.limit || '', - filter: json?.[this.entity]?.filter || '', - ordering: json?.[this.entity]?.ordering || '', - ...filters, - } - } - - localStorage.setItem('list:param', JSON.stringify(listParam)); - this.filterParams$.next(listParam[this.entity]); - } - - manageDatepickerValue(json: Object, deleteMode?: boolean) { - Object.keys(json[this.entity]).filter((name) => name.includes('_after') || name.includes('_before')).forEach((date) => { - const dateProp = date.replace(/_after|_before/gi, ''); - const period = date.includes('_after') ? 'start' : 'end'; - - if (!deleteMode) { - json[this.entity][dateProp] = {...json[this.entity][dateProp], [period]: new Date(json[this.entity][date])}; - } - - delete json[this.entity][date]; - }) - } -} diff --git a/web/src/app/shared/configuration/tools/tools.component.ts b/web/src/app/shared/configuration/tools/tools.component.ts deleted file mode 100644 index 0c8789cfc2..0000000000 --- a/web/src/app/shared/configuration/tools/tools.component.ts +++ /dev/null @@ -1,75 +0,0 @@ -// Licensed 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 { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { FormControl } from '@angular/forms'; -import { BaseDirective } from '@app/shared/directives'; -import { Subject } from 'rxjs'; - -import { ISearchParam } from '../main/main.service'; - -@Component({ - selector: 'app-tools', - template: ` - - - - - Advanced -
- - -
- `, - styles: [ - ':host {display: flex;justify-content: space-between;align-items: baseline; margin: 10px 20px 0;}', - '.form_config_button_save { margin: 0 16px 0 30px;}', - '.description {flex: 0}', - ], -}) -export class ToolsComponent extends BaseDirective implements OnInit { - private filter$ = new Subject(); - filterParams: ISearchParam = { advanced: false, search: '' }; - historyShow = false; - isAdvanced: boolean; - description = new FormControl(); - @Input() disabledSave = true; - @Input() disabledHistory = true; - - @Output() applyFilter = new EventEmitter(); - @Output() save = new EventEmitter(); - @Output() showHistory = new EventEmitter(); - - ngOnInit() { - this.filter$.pipe(this.takeUntil()).subscribe(() => this.applyFilter.emit(this.filterParams)); - } - - set advanced(advanced: boolean) { - this.filterParams.advanced = advanced; - this.filter$.next(); - } - - search(search: string) { - this.filterParams.search = search; - this.filter$.next(); - } - - toggleHistory() { - this.historyShow = !this.historyShow; - this.showHistory.emit(this.historyShow); - } - - onSave() { - this.save.emit(); - } -} diff --git a/web/src/app/shared/configuration/types.ts b/web/src/app/shared/configuration/types.ts deleted file mode 100644 index 0cb505a50f..0000000000 --- a/web/src/app/shared/configuration/types.ts +++ /dev/null @@ -1,193 +0,0 @@ -// Licensed 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 { IYspec } from './yspec/yspec.service'; -import { TFormOptions } from './services/field.service'; -import { BaseEntity } from '@app/core/types'; - -export type stateType = 'created' | 'locked'; - -export type TNBase = 'string' | 'integer' | 'int' | 'boolean' | 'bool' | 'float'; -export type TNReq = 'dict' | 'list'; -export type TNSpec = 'structure' | 'group' | 'option' | 'json' | 'map' | 'file' | 'text' | 'password' | 'secrettext' | 'secretmap' | 'secretfile' | 'variant'; -export type TNForm = TNBase | TNReq | TNSpec; -export type simpleTypes = string | number | boolean; -export type resultTypes = simpleTypes | simpleTypes[] | object; -export type TValue = string | number | boolean | object | any[]; - -/** - *``` - { - invisible?: boolean; - no_confirm?: boolean; - advanced?: boolean; - } - ``` - * - */ -export interface IUIoptions { - invisible?: boolean; - no_confirm?: boolean; - advanced?: boolean; -} - -/** - * ``` - { - min?: number; - max?: number; - option?: any; - read_only?: stateType[]; // created | locked - yspec?: IYspec; - rules?: any; - active?: boolean; -} - * ``` - */ -export interface IVariantSet { - name?: string; - strict: boolean; - type: 'config' | 'inline'; - value: string[]; -} - -export interface ILimits { - min?: number; - max?: number; - option?: any; - read_only?: stateType[]; - yspec?: IYspec; - rules?: any; - active?: boolean; - source?: IVariantSet; -} - -/** - * Property config object from backend - */ -export interface IFieldStack { - name: string; - subname: string; - display_name: string; - type: TNForm; - default: TValue; - value: TValue; - required: boolean; - activatable: boolean; - read_only: boolean; - description?: string; - custom_group?: boolean; - limits?: ILimits; - ui_options?: IUIoptions; - group_config?: { [key: string]: boolean }; -} - -/** - * The object for config for backend - */ -export interface IConfig { - id?: number; - date?: string; - description?: string; - config: IFieldStack[]; - attr?: IConfigAttr; - obj_ref?: number; -} - -/** - *``` - { - [group: string]: { active: boolean }; -} - ``` - */ -export interface IConfigAttr { - [group: string]: { active?: boolean }; - - group_keys?: { [key: string]: { [key: string]: boolean }}; - custom_group_keys?: { [key: string]: { [key: string]: boolean }}; -} - -//#region Modified data for ngForm build - -/** - * Mark for rendering required component - */ -export type controlType = - 'boolean' - | 'textbox' - | 'textarea' - | 'json' - | 'password' - | 'list' - | 'map' - | 'dropdown' - | 'file' - | 'text' - | 'structure' - | 'secrettext' - | 'secretfile' - | 'secretmap'; - -/** - *``` - pattern?: string | RegExp; - required?: boolean; - max?: number; - min?: number; - ``` - */ -export interface IValidator { - pattern?: string | RegExp; - required?: boolean; - max?: number; - min?: number; -} - -export interface CompareConfig extends IConfig { - color: string; -} - -export interface ICompare { - id: number; - date: string; - value: string; - color: string; -} - -export interface IFormOptions extends IFieldStack { - key?: string; - hidden: boolean; -} - -export interface IPanelOptions extends IFormOptions { - options: TFormOptions[]; - active: boolean; -} - -export interface ICanGroup { - group?: boolean; -} - -export interface IFieldOptions extends IFormOptions, ICanGroup { - controlType: controlType; - validator: IValidator; - compare: ICompare[]; -} - -export interface ISettingsListResponse { - count: 1; - next: null; - previous: null; - results: BaseEntity[]; -} - -//#endregion diff --git a/web/src/app/shared/configuration/yspec/yspec.service.spec.ts b/web/src/app/shared/configuration/yspec/yspec.service.spec.ts deleted file mode 100644 index a5ad050bb9..0000000000 --- a/web/src/app/shared/configuration/yspec/yspec.service.spec.ts +++ /dev/null @@ -1,368 +0,0 @@ -// Licensed 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 { IYContainer, IYField, IYspec, YspecService } from './yspec.service'; - -const simpleField: IYField = { - name: 'root', - type: 'string', - controlType: 'textbox', - path: ['root'], - validator: { - required: false, - pattern: null - }, - isInvisible: false -}; - -const simpleStr: IYspec = { - root: { match: 'list', item: 'simpl_str' }, - simpl_str: { - match: 'string' - } -}; - -const ex_policy: IYspec = { - volume: { - match: 'dict', - items: { - name: 'string', - disk: 'string', - max_data_part_size_bytes: 'int' - }, - required_items: ['name'] - }, - - volumes: { - match: 'list', - item: 'volume' - }, - - policy: { - match: 'dict', - items: { name: 'string', move_factor: 'float', volumes_list: 'volumes' }, - required_items: ['move_factor'] - }, - - root: { - match: 'list', - item: 'policy' - }, - boolean: { - match: 'bool' - }, - string: { - match: 'string' - }, - int: { - match: 'int' - }, - float: { - match: 'float' - } -}; - -describe('YspecService', () => { - let service: YspecService; - - beforeEach(() => { - service = new YspecService(); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - it('create Root element', () => { - service.Root = simpleStr; - expect(service.Root.root).toBeDefined(); - expect(service.Root.root.match).toBeDefined(); - }); - - it('create Field instance', () => { - service.Root = simpleStr; - expect(service.field({ path: ['root'], type: 'string' })).toEqual(simpleField); - }); - - it('Root as list of dict', () => { - service.Root = { - root: { match: 'list', item: 'country_code' }, - country_code: { - match: 'dict', - items: { - country: 'str', - code: 'int' - } - }, - str: { - match: 'string' - }, - int: { - match: 'integer' - } - }; - - const output: IYContainer = { - name: 'root', - type: 'list', - options: { - type: 'dict', - name: 'country_code', - options: [ - { - name: 'country', - type: 'string', - path: ['country', 'country_code'], - controlType: 'textbox', - validator: { required: false, pattern: null }, - isInvisible: false - }, - { - name: 'code', - type: 'integer', - path: ['code', 'country_code'], - controlType: 'textbox', - validator: { required: false, pattern: /^[-]?\d+$/ }, - isInvisible: false - } - ] - } - }; - - const _out = service.build(); - expect(_out).toEqual(output); - }); - - it('Funcion findRules check required_items param 2 level', () => { - service.Root = ex_policy; - const func1 = service.findRule(['move_factor', 'policy'], 'required_items'); - expect(func1).toBeTrue(); - }); - - it('Funcion findRules check required_items param 4 level', () => { - service.Root = ex_policy; - const func2 = service.findRule(['name', 'volume', 'volumes_list', 'policy'], 'required_items'); - expect(func2).toBeTrue(); - }); - - it('Test required items', () => { - service.Root = ex_policy; - - const output: IYContainer = { - type: 'list', - name: 'root', - options: { - type: 'dict', - name: 'policy', - options: [ - { - name: 'name', - type: 'string', - path: ['name', 'policy'], - controlType: 'textbox', - validator: { required: false, pattern: null }, - isInvisible: false - }, - { - name: 'move_factor', - type: 'float', - path: ['move_factor', 'policy'], - controlType: 'textbox', - validator: { required: true, pattern: /^[-]?[0-9]+(\.[0-9]+)?$/ }, - isInvisible: false - }, - { - type: 'list', - name: 'volumes_list', - options: { - type: 'dict', - name: 'volume', - options: [ - { - name: 'name', - type: 'string', - path: ['name', 'volume', 'volumes_list', 'policy'], - controlType: 'textbox', - validator: { required: true, pattern: null }, - isInvisible: false - }, - { - name: 'disk', - type: 'string', - path: ['disk', 'volume', 'volumes_list', 'policy'], - controlType: 'textbox', - validator: { required: false, pattern: null }, - isInvisible: false - }, - { - name: 'max_data_part_size_bytes', - type: 'int', - path: ['max_data_part_size_bytes', 'volume', 'volumes_list', 'policy'], - controlType: 'textbox', - validator: { required: false, pattern: /^[-]?\d+$/ }, - isInvisible: false - } - ] - } - } - ] - } - }; - - expect(service.build()).toEqual(output); - }); - - it('Scheme as tree :: dictionary with inner elements', () => { - service.Root = { - boolean: { match: 'bool' }, - string: { match: 'string' }, - integer: { match: 'int' }, - float: { match: 'float' }, - list: { match: 'list', item: 'string' }, - onemoredict: { match: 'dict', items: { key1: 'list', key2: 'the_dict' } }, - the_dict: { match: 'dict', items: { key1: 'boolean', key2: 'string', key3: 'integer', key4: 'float', key5: 'list' } }, - root: { - match: 'dict', - items: { key1: 'boolean', key2: 'string', key3: 'integer', key4: 'float', key5: 'list', key6: 'onemoredict' } - } - }; - - const output: IYContainer = { - name: 'root', - type: 'dict', - options: [ - { - name: 'key1', - type: 'bool', - path: ['key1'], - controlType: 'boolean', - validator: { required: false, pattern: null }, - isInvisible: false - }, - { - name: 'key2', - type: 'string', - path: ['key2'], - controlType: 'textbox', - validator: { required: false, pattern: null }, - isInvisible: false - }, - { - name: 'key3', - type: 'int', - path: ['key3'], - controlType: 'textbox', - validator: { required: false, pattern: /^[-]?\d+$/ }, - isInvisible: false - }, - { - name: 'key4', - type: 'float', - path: ['key4'], - controlType: 'textbox', - validator: { required: false, pattern: /^[-]?[0-9]+(\.[0-9]+)?$/ }, - isInvisible: false - }, - { - type: 'list', - name: 'key5', - options: { - name: 'string', - type: 'string', - path: ['string', 'key5'], - controlType: 'textbox', - validator: { - required: false, - pattern: null - }, - isInvisible: false - } - }, - { - type: 'dict', - name: 'key6', - options: [ - { - type: 'list', - name: 'key1', - options: { - name: 'string', - type: 'string', - path: ['string', 'key1', 'key6'], - controlType: 'textbox', - validator: { - required: false, - pattern: null - }, - isInvisible: false - } - }, - { - type: 'dict', - name: 'key2', - options: [ - { - name: 'key1', - type: 'bool', - path: ['key1', 'key2', 'key6'], - controlType: 'boolean', - validator: { required: false, pattern: null }, - isInvisible: false - }, - { - name: 'key2', - type: 'string', - path: ['key2', 'key2', 'key6'], - controlType: 'textbox', - validator: { required: false, pattern: null }, - isInvisible: false - }, - { - name: 'key3', - type: 'int', - path: ['key3', 'key2', 'key6'], - controlType: 'textbox', - validator: { required: false, pattern: /^[-]?\d+$/ }, - isInvisible: false - }, - { - name: 'key4', - type: 'float', - path: ['key4', 'key2', 'key6'], - controlType: 'textbox', - validator: { required: false, pattern: /^[-]?[0-9]+(\.[0-9]+)?$/ }, - isInvisible: false - }, - { - type: 'list', - name: 'key5', - options: { - name: 'string', - type: 'string', - path: ['string', 'key5', 'key2', 'key6'], - controlType: 'textbox', - validator: { - required: false, - pattern: null - }, - isInvisible: false - } - } - ] - } - ] - } - ] - }; - - expect(service.build()).toEqual(output); - }); -}); diff --git a/web/src/app/shared/configuration/yspec/yspec.service.ts b/web/src/app/shared/configuration/yspec/yspec.service.ts deleted file mode 100644 index 8437d51f8a..0000000000 --- a/web/src/app/shared/configuration/yspec/yspec.service.ts +++ /dev/null @@ -1,175 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { IRoot } from '@app/core/types'; - -import { IFieldOptions, controlType, IValidator, TNBase, TNReq } from '../types'; -import { getControlType, getPattern } from '../services/field.service'; - -export type TMatch = TNBase | TNReq; - -/** - *``` - { - match: matchType; - selector?: string; - variants?: { [key: string]: string }; - item?: string; - items?: IRoot; // { [key: string]: string; } - required_items?: string[]; - default_item?: string; - } - ``` - */ -interface IYRoot { - match: TMatch; - selector?: string; - variants?: { [key: string]: string }; - item?: string; - items?: IRoot; - required_items?: string[]; - invisible_items?: string[]; - default_item?: string; -} - -/** - *``` - { - [key: string]: IYRoot; - } - ``` - */ -export interface IYspec { - [key: string]: IYRoot; -} - -/** - *``` -{ - name: string; - path: string[]; - type: simpleType; - controlType: controlType; - validator: ValidatorInfo; -} - *``` - */ -export interface IYField { - name: string; - path: string[]; - type: TNBase; - controlType: controlType; - validator: IValidator; - isInvisible: boolean; -} - -/** - * ``` - * { - * name: string; - * type: reqursionType; // 'list' | 'dict' - * options: IYContainer | IYField | (IYContainer | IYField)[]; - * } - *``` - */ -export interface IYContainer { - name: string; - type: TNReq; - options: IYContainer | IYField | (IYContainer | IYField)[]; -} - -export interface IStructure extends IFieldOptions { - rules: { options: any; type: string; name: string }; -} - -@Injectable() -export class YspecService { - private root: IYspec; - - set Root(yspec: IYspec) { - this.root = yspec; - } - - get Root() { - return this.root; - } - - getInvisibleItems() { - const invisibleItems = []; - for (const item in this.Root) { - const { invisible_items } = this.Root[item]; - - if (invisible_items !== undefined) { - invisibleItems.push(...invisible_items); - } - } - return invisibleItems; - } - - build(rule = 'root', path: string[] = []): IYContainer | IYField { - const { match, item, items } = this.Root[rule]; - - switch (match) { - case 'list': - return this.list(item, path); - case 'dict': - return this.dict(items, path); - // case 'one_of': - // return this.one_of(); - // case 'dict_key_selection': - // return this.dict_key_selection(); - default: - return this.field({ type: match, path }); - } - } - - field(field: { type: TNBase; path: string[] }): IYField { - const invisibleItems = this.getInvisibleItems(); - const name = field.path.reverse()[0]; - const isInvisible = invisibleItems.includes(name); - return { - name, - type: field.type, - path: field.path, - controlType: getControlType(field.type), - validator: { - required: this.findRule(field.path, 'required_items'), - pattern: getPattern(field.type), - }, - isInvisible, - }; - } - - findRule(path: string[], name: string): boolean { - const [field, parent] = path; - const rule = this.Root[parent]; - return !!(rule && rule[name] && Array.isArray(rule[name]) && rule[name].includes(field)); - } - - list(item: string, path: string[]): IYContainer { - const name = [...path].reverse()[0] || 'root'; - return { type: 'list', name, options: this.build(item, [...path, item]) }; - } - - dict(items: IRoot, path: string[]): IYContainer { - const name = [...path].reverse()[0] || 'root'; - return { - type: 'dict', - name, - options: Object.keys(items).map((item_name: string) => this.build(items[item_name], [...path, item_name])), - }; - } - - one_of() {} - - dict_key_selection() {} -} diff --git a/web/src/app/shared/details/details.module.ts b/web/src/app/shared/details/details.module.ts deleted file mode 100644 index fc2a6c1a57..0000000000 --- a/web/src/app/shared/details/details.module.ts +++ /dev/null @@ -1,103 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatCardModule } from '@angular/material/card'; -import { MatIconModule } from '@angular/material/icon'; -import { MatListModule } from '@angular/material/list'; -import { MatSidenavModule } from '@angular/material/sidenav'; -import { MatToolbarModule } from '@angular/material/toolbar'; -import { RouterModule } from '@angular/router'; -import { AdwpListModule } from '@app/adwp'; -import { StuffModule } from '../stuff.module'; -import { SubtitleComponent } from './subtitle.component'; -import { NavigationComponent } from '@app/components/navigation/navigation.component'; -import { NavItemPipe } from '@app/pipes/nav-item.pipe'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { ObjectLinkColumnPipe } from '@app/pipes/object-link-column.pipe'; -import { SortObjectsPipe } from '@app/pipes/sort-objects.pipe'; -import { TaskObjectsComponent } from '@app/components/columns/task-objects/task-objects.component'; -import { HostDetailsComponent } from '@app/components/host/host-details/host-details.component'; -import { LeftMenuComponent } from './left-menu/left-menu.component'; -import { LabelMenuItemComponent } from './left-menu-items/label-menu-item/label-menu-item.component'; -import { StatusMenuItemComponent } from './left-menu-items/status-menu-item/status-menu-item.component'; -import { ProviderDetailsComponent } from '@app/components/hostprovider/provider-details/provider-details.component'; -import { GroupConfigDetailsComponent } from '@app/components/hostprovider/group-config-details/group-config-details.component'; -import { BundleDetailsComponent } from '@app/components/bundle/bundle-details/bundle-details.component'; -import { ServiceDetailsComponent } from '@app/components/service/service-details/service-details.component'; -import { ServiceComponentDetailsComponent } from '@app/components/service-component/service-component-details/service-component-details.component'; -import { JobDetailsComponent } from '@app/components/job/job-details/job-details.component'; -import { ClusterDetailsComponent } from '@app/components/cluster/cluster-details/cluster-details.component'; -import { LogMenuItemComponent } from './left-menu-items/log-menu-item/log-menu-item.component'; -import { ConcernMenuItemComponent } from '@app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.component'; -import { ConcernMenuItemPipe } from './left-menu-items/concern-menu-item/concern-menu-item.pipe'; -import { - MaintenanceModeButtonComponent -} from "@app/components/maintenance-mode-button/maintenance-mode-button.component"; - -@NgModule({ - imports: [ - CommonModule, - RouterModule, - StuffModule, - MatCardModule, - MatToolbarModule, - MatSidenavModule, - MatListModule, - MatIconModule, - MatButtonModule, - MatTooltipModule, - AdwpListModule.forRoot({ - itemsPerPage: [10, 25, 50, 100], - }), - ], - exports: [ - ServiceDetailsComponent, - HostDetailsComponent, - ProviderDetailsComponent, - GroupConfigDetailsComponent, - ServiceComponentDetailsComponent, - ClusterDetailsComponent, - BundleDetailsComponent, - JobDetailsComponent, - MaintenanceModeButtonComponent, - ObjectLinkColumnPipe, - SortObjectsPipe, - AdwpListModule, - TaskObjectsComponent, - ], - declarations: [ - ServiceDetailsComponent, - HostDetailsComponent, - ProviderDetailsComponent, - GroupConfigDetailsComponent, - ServiceComponentDetailsComponent, - ClusterDetailsComponent, - BundleDetailsComponent, - JobDetailsComponent, - SubtitleComponent, - NavigationComponent, - MaintenanceModeButtonComponent, - NavItemPipe, - ObjectLinkColumnPipe, - SortObjectsPipe, - TaskObjectsComponent, - LeftMenuComponent, - LabelMenuItemComponent, - StatusMenuItemComponent, - LogMenuItemComponent, - ConcernMenuItemComponent, - ConcernMenuItemPipe, - ], -}) -export class DetailsModule {} diff --git a/web/src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.component.ts b/web/src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.component.ts deleted file mode 100644 index 06d5f6b606..0000000000 --- a/web/src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.component.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive'; -import { BaseEntity } from '@app/core/types'; -import { ApiService } from '@app/core/api'; -import { ConcernService } from '@app/services/concern.service'; -import { environment } from '@env/environment'; - -@Component({ - selector: 'app-concern-menu-item', - template: ` - - {{ label }}  - - - - - `, - styles: ['a span { white-space: nowrap; }'], -}) -export class ConcernMenuItemComponent extends MenuItemAbstractDirective implements OnInit { - - concernsPresent = false; - concerns = null; - - @Input() set entity(entity: BaseEntity) { - this._entity = entity; - this.getConcernStatus(); - } - - get entity(): BaseEntity { - return this._entity; - } - - constructor( - private api: ApiService, - private concernService: ConcernService - ) { - super(); - } - - ngOnInit(): void { - this.concernService.events({ types: [this.data.type] }) - .pipe(this.takeUntil()) - .subscribe(_ => this.getConcernStatus()); - } - - private getConcernStatus(): void { - const params = { - owner_type: this.data.owner_type, - owner_id: this.entity.id + '', - cause: this.data.cause - }; - - this.api.get(`${environment.apiRoot}/concern`, params) - .subscribe((concerns: any[]) => { - this.concerns = concerns; - this.concernsPresent = !!concerns?.length - }); - } -} diff --git a/web/src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.pipe.ts b/web/src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.pipe.ts deleted file mode 100644 index d3420cf738..0000000000 --- a/web/src/app/shared/details/left-menu-items/concern-menu-item/concern-menu-item.pipe.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { BaseEntity } from '@app/core/types'; - -@Pipe({ - name: 'concernMenuItem' -}) -export class ConcernMenuItemPipe implements PipeTransform { - - transform(value: BaseEntity, cause: string): boolean { - const concerns = value && value.concerns; - if (!(concerns && concerns.length)) return false; - - return !!concerns.filter((c) => c.cause === cause).length; - } - -} diff --git a/web/src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.spec.ts b/web/src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.spec.ts deleted file mode 100644 index 178e26442e..0000000000 --- a/web/src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { LabelMenuItemComponent } from './label-menu-item.component'; - -describe('LabelMenuItemComponent', () => { - let component: LabelMenuItemComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ LabelMenuItemComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(LabelMenuItemComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.ts b/web/src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.ts deleted file mode 100644 index fc6d64d209..0000000000 --- a/web/src/app/shared/details/left-menu-items/label-menu-item/label-menu-item.component.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Component } from '@angular/core'; - -import { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive'; - -@Component({ - selector: 'app-label-menu-item', - template: ` - - {{ label }} - - `, - styles: ['a span { white-space: nowrap; }'], -}) -export class LabelMenuItemComponent extends MenuItemAbstractDirective {} diff --git a/web/src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.spec.ts b/web/src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.spec.ts deleted file mode 100644 index 830902601d..0000000000 --- a/web/src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { LogMenuItemComponent } from './log-menu-item.component'; -import { AuthService } from "@app/core/auth/auth.service"; -import { ApiService } from "@app/core/api"; -import { HttpClient, HttpHandler } from "@angular/common/http"; -import { Store, StoreModule } from "@ngrx/store"; - -describe('LogMenuItemComponent', () => { - let component: LogMenuItemComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ LogMenuItemComponent ], - imports: [ StoreModule.forRoot({}) ], - providers: [ AuthService, ApiService, HttpClient, HttpHandler, Store ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(LogMenuItemComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.ts b/web/src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.ts deleted file mode 100644 index 465182a2f6..0000000000 --- a/web/src/app/shared/details/left-menu-items/log-menu-item/log-menu-item.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Component } from '@angular/core'; - -import { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive'; -import { BaseEntity, Job } from '@app/core/types'; -import { AuthService } from "@app/core/auth/auth.service"; - -@Component({ - selector: 'app-log-menu-item', - template: ` - - {{ label }}  - - - - `, - styles: ['a span { white-space: nowrap; }'], -}) -export class LogMenuItemComponent extends MenuItemAbstractDirective { - - constructor(private auth: AuthService) { - super(); - } - - download() { - if (this.data?.logId) { - const file = (this.entity as Job).log_files.find(job => job.id === this.data.logId); - if (file) { - location.href = file.download_url; - } else { - throw new Error('Log file not found!'); - } - } else { - throw new Error('Log id isn\'t provided!'); - } - } - -} diff --git a/web/src/app/shared/details/left-menu-items/status-menu-item/status-menu-item.component.ts b/web/src/app/shared/details/left-menu-items/status-menu-item/status-menu-item.component.ts deleted file mode 100644 index 2f97a2b6ce..0000000000 --- a/web/src/app/shared/details/left-menu-items/status-menu-item/status-menu-item.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { filter } from 'rxjs/operators'; -import { Store } from '@ngrx/store'; - -import { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive'; -import { BaseEntity } from '@app/core/types'; -import { selectMessage, SocketState } from '@app/core/store'; - -@Component({ - selector: 'app-status-menu-item', - template: ` - - {{ label }}  - - - {{ entity.status === 0 ? 'check_circle_outline' : 'error_outline' }} - - - - `, - styles: ['a span { white-space: nowrap; }'], -}) -export class StatusMenuItemComponent extends MenuItemAbstractDirective { - - @Input() set entity(entity: BaseEntity) { - this._entity = entity; - this.listenToStatusChanges(); - } - get entity(): BaseEntity { - return this._entity; - } - - constructor( - private store: Store, - ) { - super(); - } - - listenToStatusChanges() { - this.store.pipe( - selectMessage, - filter(event => event?.object?.id && this.entity?.id && event.object.id === this.entity.id), - filter(event => event?.event === 'change_status'), - filter(event => event?.object?.type === this.data.entityType), - this.takeUntil(), - ).subscribe((event) => this.entity.status = +event.object.details.value); - } - -} diff --git a/web/src/app/shared/details/left-menu/left-menu.component.scss b/web/src/app/shared/details/left-menu/left-menu.component.scss deleted file mode 100644 index 8367bc4bcb..0000000000 --- a/web/src/app/shared/details/left-menu/left-menu.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -mat-nav-list { - padding-top: 20px; -} diff --git a/web/src/app/shared/details/left-menu/left-menu.component.spec.ts b/web/src/app/shared/details/left-menu/left-menu.component.spec.ts deleted file mode 100644 index 31b97067d6..0000000000 --- a/web/src/app/shared/details/left-menu/left-menu.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { LeftMenuComponent } from './left-menu.component'; - -describe('LeftMenuComponent', () => { - let component: LeftMenuComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ LeftMenuComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(LeftMenuComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/details/left-menu/left-menu.component.ts b/web/src/app/shared/details/left-menu/left-menu.component.ts deleted file mode 100644 index f7e6a938f2..0000000000 --- a/web/src/app/shared/details/left-menu/left-menu.component.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Component, ComponentFactoryResolver, ComponentRef, Input, Type, ViewChild, ViewContainerRef } from '@angular/core'; - -import { AdcmEntity } from '@app/models/entity'; -import { MenuItemAbstractDirective } from '@app/abstract-directives/menu-item.abstract.directive'; - -export interface LeftMenuItem { - link: string; - label: string; - data?: any; - component: Type; -} - -@Component({ - selector: 'app-left-menu', - template: ` - - - - `, - styleUrls: ['./left-menu.component.scss'] -}) -export class LeftMenuComponent { - - @ViewChild('menu', { read: ViewContainerRef }) menuRef: ViewContainerRef; - - private _leftMenu: LeftMenuItem[] = []; - @Input() set leftMenu(leftMenu: LeftMenuItem[]) { - this._leftMenu = leftMenu; - this.rebuildComponents(); - } - get leftMenu(): LeftMenuItem[] { - return this._leftMenu; - } - - @Input() set entity(entity: AdcmEntity) { - this._entity = entity; - this.componentsRef.forEach((componentRef) => componentRef.instance.entity = entity); - } - get entity(): AdcmEntity { - return this._entity; - } - - private componentsRef: Array> = []; - private _entity: AdcmEntity; - - constructor( - protected componentFactoryResolver: ComponentFactoryResolver, - ) {} - - rebuildComponents() { - setTimeout(() => { - this.componentsRef = []; - this.menuRef.clear(); - this.leftMenu.forEach((item) => { - const componentFactory = - this.componentFactoryResolver.resolveComponentFactory(item.component); - const componentRef = this.menuRef.createComponent(componentFactory); - componentRef.instance.label = item.label; - componentRef.instance.link = item.link; - if (item.data) { - componentRef.instance.data = item.data; - } - if (this.entity !== undefined) { - componentRef.instance.entity = this.entity; - } - this.componentsRef.push(componentRef); - }); - }); - } - -} diff --git a/web/src/app/shared/details/subtitle.component.ts b/web/src/app/shared/details/subtitle.component.ts deleted file mode 100644 index 66f4fb4cad..0000000000 --- a/web/src/app/shared/details/subtitle.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed 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 { Component, Input } from '@angular/core'; -import { IDetails } from '@app/models/details'; - -@Component({ - selector: 'app-details-subtitle', - template: ` - - - - - - - {{ currentObject.provider_name || '' }} - {{ currentObject.typeName === 'host' ? '' : currentObject.prototype_display_name || currentObject.prototype_name }} - {{ currentObject.typeName === 'host' ? '' : currentObject.prototype_version }} - - - - `, -}) -export class SubtitleComponent { - currentObject: IDetails; - - @Input() set current(currentInput: IDetails) { - if (currentInput) { - this.currentObject = currentInput; - } - } - -} diff --git a/web/src/app/shared/directives/base.directive.ts b/web/src/app/shared/directives/base.directive.ts deleted file mode 100644 index 54b1a40de0..0000000000 --- a/web/src/app/shared/directives/base.directive.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed 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 { Directive, OnDestroy } from '@angular/core'; -import { EventMessage } from '@app/core/store'; -import { MonoTypeOperatorFunction, Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; - -@Directive({ - selector: '[appBase]' -}) -export class BaseDirective implements OnDestroy { - destroy$ = new Subject(); - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - takeUntil(): MonoTypeOperatorFunction { - return takeUntil(this.destroy$); - } -} -export interface ISocketListener { - socketListener: (m: EventMessage) => void; -} diff --git a/web/src/app/shared/directives/dynamic/dynamic.directive.ts b/web/src/app/shared/directives/dynamic/dynamic.directive.ts deleted file mode 100644 index cd0d9510a6..0000000000 --- a/web/src/app/shared/directives/dynamic/dynamic.directive.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed 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 { Directive, ViewContainerRef, EventEmitter } from '@angular/core'; - -/** - * @param name string required name action - * @param data any - */ -export interface DynamicEvent { - name: string; - data?: any; -} - -export interface DynamicComponent { - event?: EventEmitter; - model?: any; - onEnterKey?: () => void; -} - -@Directive({ - selector: '[appDynamic]', -}) -export class DynamicDirective { - constructor(public viewContainerRef: ViewContainerRef) {} -} diff --git a/web/src/app/shared/directives/dynamic/dynamic.module.ts b/web/src/app/shared/directives/dynamic/dynamic.module.ts deleted file mode 100644 index 3b8f91d915..0000000000 --- a/web/src/app/shared/directives/dynamic/dynamic.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { DynamicDirective } from './dynamic.directive'; - - -@NgModule({ - declarations: [DynamicDirective], - imports: [ - CommonModule - ], - exports: [DynamicDirective] -}) -export class DynamicModule { -} diff --git a/web/src/app/shared/directives/for-test.directive.ts b/web/src/app/shared/directives/for-test.directive.ts deleted file mode 100644 index 2db9a800f7..0000000000 --- a/web/src/app/shared/directives/for-test.directive.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed 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 { Directive, Input, OnInit, ElementRef } from '@angular/core'; - -@Directive({ - selector: '[appForTest]', -}) -export class ForTestDirective implements OnInit { - @Input('appForTest') attr: string; - constructor(private el: ElementRef) {} - - ngOnInit() { - // old attrname = test - this.el.nativeElement.setAttribute('adcm_test', this.attr); - } -} diff --git a/web/src/app/shared/directives/hover.directive.ts b/web/src/app/shared/directives/hover.directive.ts deleted file mode 100644 index 3ab5cb6504..0000000000 --- a/web/src/app/shared/directives/hover.directive.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed 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 { Directive, HostListener, ElementRef } from '@angular/core'; - -@Directive({ - selector: '[appHover]', -}) -export class HoverDirective { - constructor(private el: ElementRef) {} - - @HostListener('mouseenter') - onmouseenter() { - this.el.nativeElement.style.backgroundColor = 'rgba(255, 255, 255, 0.12)'; - this.el.nativeElement.style.cursor = 'pointer'; - } - - @HostListener('mouseleave') - onmouseleave() { - this.el.nativeElement.style.backgroundColor = 'transparent'; - this.el.nativeElement.style.cursor = 'defautl'; - } -} diff --git a/web/src/app/shared/directives/index.ts b/web/src/app/shared/directives/index.ts deleted file mode 100644 index fdb3f22361..0000000000 --- a/web/src/app/shared/directives/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed 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 * from './dynamic/dynamic.directive'; -export * from './for-test.directive'; -export * from './hover.directive'; -export * from './m-textarea.directive'; -export * from './base.directive'; -export * from './scroll.directive'; -export * from './infinity-scroll.directive'; -export * from './socketListener.directive'; diff --git a/web/src/app/shared/directives/infinity-scroll.directive.ts b/web/src/app/shared/directives/infinity-scroll.directive.ts deleted file mode 100644 index 6573dbff24..0000000000 --- a/web/src/app/shared/directives/infinity-scroll.directive.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed 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 { Directive, Renderer2, Host, OnInit, Output, EventEmitter } from '@angular/core'; -import { MatSelect } from '@angular/material/select'; - -const POINT_WHEN_EMMIT = 100; - -@Directive({ - selector: '[appInfinityScroll]', -}) -export class InfinityScrollDirective implements OnInit { - @Output() topScrollPoint = new EventEmitter(); - - constructor(private renderer: Renderer2, @Host() private el: MatSelect) {} - - ngOnInit(): void { - if ('openedChange' in this.el) this.el.openedChange.subscribe((open: boolean) => this.registerPanel(open)); - else this.renderer.listen(this.el, 'scroll', this.onScrollPanel.bind(this)); - } - - registerPanel(open: boolean) { - if (open) { - const panel = (this.el as MatSelect).panel.nativeElement; - this.renderer.listen(panel, 'scroll', this.onScrollPanel.bind(this)); - } - } - - onScrollPanel(event: any) { - const target = event.target; - - const height = Array.from(target.children).reduce((p, c) => p + c.clientHeight, 0) - target.clientHeight; - if (target.scrollTop > height - POINT_WHEN_EMMIT) this.topScrollPoint.emit(); - } -} diff --git a/web/src/app/shared/directives/m-textarea.directive.ts b/web/src/app/shared/directives/m-textarea.directive.ts deleted file mode 100644 index 1aa578f896..0000000000 --- a/web/src/app/shared/directives/m-textarea.directive.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Licensed 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 { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit } from '@angular/core'; -import { getProfile, ProfileService, ProfileState, setTextareaHeight } from '@app/core/store'; -import { Store } from '@ngrx/store'; - -import { BaseDirective } from './base.directive'; - -// textarea Material -const PADDING_TOP_BOTTOM = 16; - -@Directive({ - selector: '[appMTextarea]', - providers: [ProfileService], -}) -export class MTextareaDirective extends BaseDirective implements OnInit, OnDestroy { - flag = false; - @Input('appMTextarea') - key: string; - - constructor(private el: ElementRef, private profile: Store) { - super(); - } - - @HostListener('mousedown') - mouseDown() { - this.flag = true; - } - - ngOnInit(): void { - window.addEventListener('mouseup', () => { - this.profile - .select(getProfile) - .pipe(this.takeUntil()) - .subscribe(p => { - const data = p.textarea; - const old = data[this.key]; - const value = +this.el.nativeElement.offsetHeight - PADDING_TOP_BOTTOM; - if (this.flag && old !== value) this.profile.dispatch(setTextareaHeight({ key: this.key, value })); - this.flag = false; - }); - }); - - this.profile - .select(getProfile) - .pipe(this.takeUntil()) - .subscribe(p => { - const k = Object.keys(p.textarea).find(key => key === this.key); - if (k) (this.el.nativeElement as HTMLTextAreaElement).style.height = p.textarea[k] + 'px'; - }); - } -} diff --git a/web/src/app/shared/directives/scroll.directive.spec.ts b/web/src/app/shared/directives/scroll.directive.spec.ts deleted file mode 100644 index beed2251d5..0000000000 --- a/web/src/app/shared/directives/scroll.directive.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed 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 { ScrollDirective } from './scroll.directive'; - -describe('ScrollDirective', () => { - it('should create an instance', () => { - const directive = new ScrollDirective(); - expect(directive).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/directives/scroll.directive.ts b/web/src/app/shared/directives/scroll.directive.ts deleted file mode 100644 index b1890374dd..0000000000 --- a/web/src/app/shared/directives/scroll.directive.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed 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 { Directive, Output, HostListener, EventEmitter } from '@angular/core'; - -@Directive({ - selector: '[appScroll]', -}) -export class ScrollDirective { - private scrollTop = 0; - - @Output() read = new EventEmitter<{ direct: -1 | 1 | 0; scrollTop: number }>(); - - @HostListener('scroll', ['$event.target']) onscroll(e: Element) { - - const { scrollHeight, scrollTop, clientHeight } = e; - - if (scrollTop < this.scrollTop) this.read.emit({ direct: -1, scrollTop }); - else this.read.emit( { direct: 1, scrollTop }); - - if (scrollHeight <= scrollTop + clientHeight) this.read.emit({ direct: 0, scrollTop }); - - this.scrollTop = scrollTop; - - } -} diff --git a/web/src/app/shared/directives/socketListener.directive.ts b/web/src/app/shared/directives/socketListener.directive.ts deleted file mode 100644 index 21bceafe9d..0000000000 --- a/web/src/app/shared/directives/socketListener.directive.ts +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed 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 { Directive, Injectable, OnDestroy } from '@angular/core'; -import { select, Store } from '@ngrx/store'; -import { filter, tap } from 'rxjs/operators'; -import { BaseDirective } from '@app/adwp'; - -import { EventMessage, getMessage, SocketState, clearMessages } from '@app/core/store'; - -@Directive({ - selector: '[appBase]', -}) -@Injectable() -export class SocketListenerDirective extends BaseDirective implements OnDestroy { - socket$ = this.socket.pipe(this.takeUntil(), select(getMessage), filter(m => !!m && !!m.object)); - - constructor(private socket: Store) { - super(); - } - - ngOnDestroy() { - super.ngOnDestroy(); - this.socket.dispatch(clearMessages()); - } - - startListenSocket(): void { - this.socket$.pipe( - tap(m => this.socketListener(m)) - ).subscribe(); - } - - socketListener(m: EventMessage) { - console.warn('No implemented socketListener method', m); - } -} diff --git a/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.html b/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.html deleted file mode 100644 index b280ace82f..0000000000 --- a/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.html +++ /dev/null @@ -1,60 +0,0 @@ -
-
- - - - {{ label }} - - - -
- - - -
- - - - Nothing found - - - - {{ item | adwpMapper:nameHandler }} - - - - - - -
-
- -
-
-
- -
-
-
- diff --git a/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.scss b/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.scss deleted file mode 100644 index ded62eb19b..0000000000 --- a/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.scss +++ /dev/null @@ -1,84 +0,0 @@ -.adcm-input-rbac-permissions { - - .row { - margin-bottom: 0; - } - - &__selected-field { - width: 100%; - } - - &__selected-control { - ::ng-deep { - .mat-chip-list-wrapper { - height: 110px; - overflow-y: auto; - align-items: start; - align-content: flex-start; - } - } - } - - &__selected-filter { - display: flex; - width: 100%; - flex-wrap: nowrap; - align-items: stretch; - - ::ng-deep { - input.mat-chip-input { - width: 100%; - margin: 0; - flex: 1; - } - } - } - - &__selected-clear { - margin-left: auto; - } - - &__selected-filter-clear { - - } - - &__selected-permission { - min-height: 28px; - font-size: 12px; - border-radius: 4px; - padding: 4px 8px; - - &:after { - background-color: red; - } - } - - &__selected-permission-remove.mat-chip-remove { - width: 20px; - height: 20px; - line-height: 20px; - - ::ng-deep { - mat-icon { - line-height: 20px; - } - } - } - - &__permission-form-wrapper { - display: flex; - width: 100%; - height: 100%; - flex: 1; - overflow: hidden; - - ::ng-deep > * { - display: flex; - width: 100%; - flex: 1; - overflow: hidden; - height: 270px; - } - } - -} diff --git a/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.ts b/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.ts deleted file mode 100644 index 7e5afd4d4a..0000000000 --- a/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.component.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Component, ContentChild, Input } from '@angular/core'; -import { AbstractControl, FormGroup } from '@angular/forms'; -import { ADWP_DEFAULT_MATCHER, AdwpMatcher, AdwpStringHandler } from '@app/adwp'; -import { RbacRoleModel } from '../../../models/rbac/rbac-role.model'; -import { RbacPermissionFormComponent } from '../../../components/rbac/permission-form/rbac-permission-form.component'; - -@Component({ - selector: 'adcm-input-rbac-permission', - templateUrl: './adcm-input-rbac-permission.component.html', - styleUrls: ['./adcm-input-rbac-permission.component.scss'] -}) -export class AdcmInputRbacPermissionComponent { - @Input() form: FormGroup; - - @Input() controlName: string; - - @Input() multiple: boolean; - - @Input() label: string; - - @Input() nameHandler: AdwpStringHandler; - - @Input() categoryHandler: AdwpStringHandler; - - @Input() isRequired = false; - - @Input() readonly = false; - - @ContentChild(RbacPermissionFormComponent) permissionForm: RbacPermissionFormComponent; - - get permissionsControl(): AbstractControl { - return this.form.controls[this.controlName]; - } - - get selectedPermissions(): RbacRoleModel[] { - return this.permissionsControl.value || []; - } - - removeSelectedPermission(item: RbacRoleModel): void { - const selected = this.permissionsControl.value; - this.permissionsControl.setValue(selected.filter((i) => i.id !== item.id)); - this.form.markAsDirty(); - } - - open = false; - - matcher: AdwpMatcher = ADWP_DEFAULT_MATCHER; - - isError(name: string): boolean { - const f = this.form.get(name); - return f.invalid && (f.dirty || f.touched); - } - - hasError(name: string, error: string): boolean { - return this.form.controls[name].hasError(error); - } - - onBackspaceKeydown(e: KeyboardEvent, chipListInput: HTMLInputElement): void { - e.stopImmediatePropagation(); - if (!chipListInput.value) { - e.preventDefault(); - chipListInput.focus(); - } - } - - reset(control: AbstractControl, chipListInput: HTMLInputElement): void { - control.reset([]); - chipListInput.value = ''; - this.permissionForm.value = [] as any; - } -} diff --git a/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.module.ts b/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.module.ts deleted file mode 100644 index 143b0506e2..0000000000 --- a/web/src/app/shared/form-elements/adcm-input-rbac-permission/adcm-input-rbac-permission.module.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { AdcmInputRbacPermissionComponent } from './adcm-input-rbac-permission.component'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatChipsModule } from '@angular/material/chips'; -import { - AdwpClickOutsideModule, - AdwpDropdownModule, - AdwpMapperPipeModule, - AdwpFilterPipeModule -} from '@app/adwp'; -import { MatIconModule } from '@angular/material/icon'; -import { ReactiveFormsModule } from '@angular/forms'; -import { MatButtonModule } from '@angular/material/button'; -import { MatInputModule } from '@angular/material/input'; -import { TooltipModule } from '../../components/tooltip/tooltip.module'; -import { FalseAsEmptyArrayModule } from '../../pipes/false-as-empty-array/false-as-empty-array.module'; - - -@NgModule({ - declarations: [ - AdcmInputRbacPermissionComponent - ], - exports: [ - AdcmInputRbacPermissionComponent - ], - imports: [ - CommonModule, - MatFormFieldModule, - MatChipsModule, - AdwpDropdownModule, - MatIconModule, - ReactiveFormsModule, - AdwpClickOutsideModule, - AdwpMapperPipeModule, - MatButtonModule, - AdwpFilterPipeModule, - MatInputModule, - TooltipModule, - FalseAsEmptyArrayModule - ] -}) -export class AdcmInputRbacPermissionModule { -} diff --git a/web/src/app/shared/form-elements/boolean.component.ts b/web/src/app/shared/form-elements/boolean.component.ts deleted file mode 100644 index eb53487e3b..0000000000 --- a/web/src/app/shared/form-elements/boolean.component.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed 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 { Component } from '@angular/core'; -import { MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox'; - -import { FieldDirective } from './field.directive'; - -const options = { clickAction: 'noop', color: 'accent' }; - -@Component({ - selector: 'app-fields-boolean', - template: ` - - - - - - - `, - styles: [':host {height: 58px;} mat-error { font-size: 0.75em; margin-left: 14px; }'], - providers: [{ provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: options }] -}) -export class BooleanComponent extends FieldDirective { - cbChange() { - if (this.field.read_only || this.control.disabled) return; - const tape = this.field.validator.required ? [true, false] : [null, true, false]; - this.field.value = tape[(tape.indexOf(this.field.value as boolean) + 1) % tape.length]; - this.control.markAsDirty({ - onlySelf: true - }); - this.control.setValue(this.field.value); - } -} diff --git a/web/src/app/shared/form-elements/bundle.component.spec.ts b/web/src/app/shared/form-elements/bundle.component.spec.ts deleted file mode 100644 index c186fd091b..0000000000 --- a/web/src/app/shared/form-elements/bundle.component.spec.ts +++ /dev/null @@ -1,116 +0,0 @@ -// Licensed 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 { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { FormGroup, FormControl } from '@angular/forms'; -import { MatSelectModule } from '@angular/material/select'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { Bundle } from '@app/core/types'; -import { of } from 'rxjs'; - -import { AddService } from '../add-component/add.service'; -import { BundlesComponent } from './bundles.component'; - -let COUNT_DATA = 1; -const uploadBundle: Partial = { id: 9, display_name: 'bundle_9', version: '0.09', bundle_edition: 'community' }; -const getProto = () => - Array(COUNT_DATA) - .fill(0) - .map((_, i) => ({ bundle_id: i, display_name: `bundle_${i}`, version: `0.0${i}`, bundle_edition: 'community' })); - -const getProtoList = () => - Array(COUNT_DATA) - .fill(0) - .map((_, i) => ({ display_name: `bundle_${i}`, versions: [{ prototype_id: Number(`0.${i}`), version: `0.0${i}`}] })); - -describe('Form control :: bundle component', () => { - let component: BundlesComponent; - let fixture: ComponentFixture; - let aService = { - getPrototype: () => of(getProto()), - getPrototypeList: () => of(getProtoList()), - upload: () => of([uploadBundle]), - }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [MatSelectModule, NoopAnimationsModule, MatTooltipModule], - providers: [{ provide: AddService, useValue: aService }], - }).compileComponents(); - }); - - beforeEach(async () => { - fixture = await TestBed.createComponent(BundlesComponent); - component = fixture.componentInstance; - component.form = new FormGroup({ prototype_id: new FormControl() }); - component.limit = 10; - component.page = 1 - }); - - it('Bundle component should created', () => { - expect(component).toBeTruthy(); - }); - - it('list bundle with one element should contains first display_name', async () => { - COUNT_DATA = 1; - fixture.detectChanges(); - await fixture.whenStable().then((_) => { - fixture.detectChanges(); - const displayNameSelect = fixture.debugElement.nativeElement.querySelector('mat-select[formcontrolname=display_name]'); - const firstDisplyaName = component.bundles[0].display_name; - expect(displayNameSelect.querySelector('div>div>span>span').innerText).toBe(firstDisplyaName); - }); - }); - - it('check paging', fakeAsync(() => { - COUNT_DATA = 10; - fixture.detectChanges(); - fixture.whenStable().then((_) => { - fixture.detectChanges(); - expect(component.bundles.length).toBe(component.page * component.limit); - expect(component.bundles.length).toBe(10); - - COUNT_DATA = 20; - component.getNextPage(); - fixture.detectChanges(); - expect(component.bundles.length).toBe(component.page * component.limit); - expect(component.bundles.length).toBe(20); - - const displayNameSelect = fixture.debugElement.nativeElement.querySelector('mat-select[formcontrolname=display_name]'); - const select_id = displayNameSelect.getAttribute('id'); - - displayNameSelect.click(); - tick(); - fixture.detectChanges(); - - const options = document.querySelector(`div#${select_id}-panel`).getElementsByTagName('mat-option'); - expect(options.length).toBe(21); - }); - })); - - it('when loading a new package, display_name should be displayed in the drop-down list', async () => { - COUNT_DATA = 10; - fixture.detectChanges(); - // upload bundle #9 for example - component.upload([]); - fixture.detectChanges(); - - await fixture.whenStable().then((_) => { - fixture.detectChanges(); - const displayNameSelect = fixture.debugElement.nativeElement.querySelector('mat-select[formcontrolname=display_name]'); - expect(displayNameSelect.querySelector('div>div>span>span').innerText).toBe(uploadBundle.display_name); - - const versionSelect = fixture.debugElement.nativeElement.querySelector('mat-select[formcontrolname=bundle_id]'); - expect(versionSelect.querySelector('div>div>span>span').innerText).toBe(`${uploadBundle.version} ${uploadBundle.bundle_edition}`); - }); - }); -}); diff --git a/web/src/app/shared/form-elements/bundles.component.ts b/web/src/app/shared/form-elements/bundles.component.ts deleted file mode 100644 index 74b7cc0ea4..0000000000 --- a/web/src/app/shared/form-elements/bundles.component.ts +++ /dev/null @@ -1,145 +0,0 @@ -// Licensed 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 { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { FormControl } from '@angular/forms'; -import { Prototype, PrototypeList, StackBase } from '@app/core/types'; -import { of } from 'rxjs'; -import {filter, map, switchMap, tap} from 'rxjs/operators'; -import { EventHelper } from '@app/adwp'; - -import { AddService } from '../add-component/add.service'; -import { ButtonUploaderComponent } from './button-uploader.component'; -import { InputComponent } from './input.component'; - -@Component({ - selector: 'app-bundles', - template: ` -
- - - ... - {{ bundle.display_name }} - - -    - - - {{ bundle.version }} {{ bundle.bundle_edition }} - - - - -
- `, - styles: ['.row { align-items: center;display:flex; }', 'mat-form-field {flex: 1}'], -}) -export class BundlesComponent extends InputComponent implements OnInit { - EventHelper = EventHelper; - - @Input() typeName: 'cluster' | 'provider'; - @ViewChild('uploadBtn', { static: true }) uploadBtn: ButtonUploaderComponent; - loadedBundle: { bundle_id: number; display_name: string }; - bundles: StackBase[] = []; - versions: StackBase[]; - page = 1; - limit = 50; - disabledVersion = true; - elementName = null; - - @Output() prototypeChanged = new EventEmitter(); - - constructor(private service: AddService) { - super(); - } - - ngOnInit(): void { - this.form.addControl('display_name', new FormControl()); - this.form.addControl('bundle_id', new FormControl()); - - this.getBundles(); - - this.form - .get('display_name') - .valueChanges.pipe( - this.takeUntil(), - tap((elementName) => this.elementName = elementName), - switchMap(() => (this.service.getPrototype(this.typeName, { page: 0, limit: 500, ordering: '-version' }) || of([]))) - ) - .subscribe((elements) => { - this.versions = elements - .filter((element) => element.display_name === this.elementName) - .sort((a, b) => - b.version.localeCompare(a.version, undefined, { numeric: true }) - ); - this.selectOne(this.versions, "bundle_id"); - this.loadedBundle = null; - }); - - // for check license agreement - this.form - .get('bundle_id') - .valueChanges.pipe( - this.takeUntil(), - filter((a) => a) - ) - .subscribe((id) => { - const prototype = this.versions.find((b) => b.bundle_id === +id); - this.service.currentPrototype = prototype; - this.prototypeChanged.emit(prototype); - this.form.get('prototype_id').setValue(this.service.currentPrototype.id); - }); - } - - getNextPage() { - const count = this.bundles.length; - if (count === this.page * this.limit) { - this.page++; - this.getBundles(); - } - } - - getBundles() { - this.service.getPrototypeList(this.typeName).subscribe((response: any) => { - this.bundles = response.map((item: PrototypeList) => ({ - display_name: item.display_name - })).sort((a, b) => a.display_name.localeCompare(b.display_name, undefined, { numeric: true })); - this.selectOne(this.bundles, 'display_name'); - }); - } - - selectOne(a: Partial[] = [], formName: string) { - const el = this.loadedBundle ? a.find((e) => e[formName] === this.loadedBundle[formName]) : null; - const id = el ? el[formName] : a.length ? (formName === 'bundle_id' || a.length === 1 ? a[0][formName] : '') : ''; - this.form.get(formName).setValue(id); - } - - upload(data: FormData[]) { - this.service - .upload(data) - .pipe(map((a) => a.map((e) => ({ bundle_id: e.id, display_name: e.display_name, version: e.version })))) - .subscribe((a) => { - this.loadedBundle = a[0]; - this.uploadBtn.fileUploadInput.nativeElement.value = ''; - this.page = 0; - this.bundles = []; - this.getBundles(); - }); - } -} diff --git a/web/src/app/shared/form-elements/button-uploader.component.ts b/web/src/app/shared/form-elements/button-uploader.component.ts deleted file mode 100644 index b4add1598b..0000000000 --- a/web/src/app/shared/form-elements/button-uploader.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Licensed 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 { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; -import { CanColor } from '@angular/material/core'; - -@Component({ - selector: 'app-button-uploader', - template: ` - - - - ` -}) -export class ButtonUploaderComponent { - @Input() color: CanColor; - @Input() label: string; - @Input() asIcon = false; - - @ViewChild('fileUploadInput', { static: true }) fileUploadInput: ElementRef; - - @Output() output = new EventEmitter(); - - show() { - this.fileUploadInput.nativeElement.click(); - } - - fileUploadHandler(fu: HTMLInputElement) { - let output: FormData[] = []; - for (let i = 0; i < fu.files.length; i++) { - const file = fu.files.item(i); - const form = new FormData(); - form.append('file', file, file.name); - output.push(form); - } - this.output.emit(output); - this.fileUploadInput.nativeElement.value = ''; - } -} diff --git a/web/src/app/shared/form-elements/confirm-equal-validator.directive.ts b/web/src/app/shared/form-elements/confirm-equal-validator.directive.ts deleted file mode 100644 index 8bbe817a15..0000000000 --- a/web/src/app/shared/form-elements/confirm-equal-validator.directive.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed 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 { Directive, Input } from '@angular/core'; -import { AbstractControl, NG_VALIDATORS, Validator } from '@angular/forms'; - -@Directive({ - selector: '[appConfirmEqualValidator]', - providers: [ - { - provide: NG_VALIDATORS, - useExisting: ConfirmEqualValidatorDirective, - multi: true, - }, - ], -}) -export class ConfirmEqualValidatorDirective implements Validator { - @Input() appConfirmEqualValidator: string; - - validate(control: AbstractControl): { [key: string]: any } | null { - const controlToCompare = control.parent.controls[this.appConfirmEqualValidator]; - if (controlToCompare && controlToCompare.value !== control.value) return { notEqual: true }; - return null; - } -} diff --git a/web/src/app/shared/form-elements/dropdown.component.ts b/web/src/app/shared/form-elements/dropdown.component.ts deleted file mode 100644 index 190841cc04..0000000000 --- a/web/src/app/shared/form-elements/dropdown.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed 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 { AfterViewInit, Component, OnInit } from '@angular/core'; -import { Observable, of } from 'rxjs'; - -import { FieldDirective } from './field.directive'; - -@Component({ - selector: 'app-fields-dropdown', - template: ` - - - - - - - - {{ option.name }} - - - - - `, -}) -export class DropdownComponent extends FieldDirective implements OnInit, AfterViewInit { - options$: Observable<{ id: number | string; name: string }[]>; - - ngAfterViewInit() { - setTimeout(() => { - this.form.get(this.field.name)?.markAsTouched(); - }, 100) - } - - ngOnInit() { - super.ngOnInit(); - if (this.field.limits) { - const o = Object.entries(this.field.limits.option).map((e) => ({ - id: String(e[1]), - name: e[0], - })); - this.options$ = of(o); - } - } -} diff --git a/web/src/app/shared/form-elements/error-info.component.ts b/web/src/app/shared/form-elements/error-info.component.ts deleted file mode 100644 index ef746cc5df..0000000000 --- a/web/src/app/shared/form-elements/error-info.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed 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 { Component, Input } from '@angular/core'; -import { FormControl } from '@angular/forms'; - -import { IFieldOptions } from '../configuration/types'; - -@Component({ - selector: 'app-error-info', - template: ` - Field [{{ field.display_name }}] is required! - Field [{{ field.display_name }}] is invalid! - Field [{{ field.display_name }}] value cannot be less than {{ field.validator.min }}! - Field [{{ field.display_name }}] value cannot be greater than {{ field.validator.max }}! - Json parsing error! - ` -}) -export class ErrorInfoComponent { - @Input() control: FormControl; - @Input() field: IFieldOptions; - - hasError(name: string) { - return this.control.hasError(name); - } -} diff --git a/web/src/app/shared/form-elements/field.directive.ts b/web/src/app/shared/form-elements/field.directive.ts deleted file mode 100644 index 279c880283..0000000000 --- a/web/src/app/shared/form-elements/field.directive.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed 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 { Directive, HostListener, Input, OnInit } from '@angular/core'; -import { FormGroup} from '@angular/forms'; - -import { IFieldOptions } from '../configuration/types'; -import { BaseDirective } from '../directives'; - -@Directive({ - selector: '[appField]' -}) -export class FieldDirective extends BaseDirective implements OnInit { - @Input() form: FormGroup; - @Input() field: IFieldOptions; - @Input() disabled: boolean; - - @HostListener('keyup') changes() { - this.control.markAsTouched(); - } - - ngOnInit() { - this.control.markAllAsTouched(); - } - - get control() { - return this.form.controls[this.field.name]; - } - - get isValid() { - if (this.field.read_only) return true; - this.control.markAsTouched(); - const control = this.control; - return control.valid && (control.dirty || control.touched); - } - - hasError(name: string) { - this.control.markAsTouched(); - return this.control.hasError(name); - } -} diff --git a/web/src/app/shared/form-elements/form-elements.module.ts b/web/src/app/shared/form-elements/form-elements.module.ts deleted file mode 100644 index 8792b3739a..0000000000 --- a/web/src/app/shared/form-elements/form-elements.module.ts +++ /dev/null @@ -1,78 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { MaterialModule } from '../material.module'; -import { StuffModule } from '../stuff.module'; -import { BooleanComponent } from './boolean.component'; -import { BundlesComponent } from './bundles.component'; -import { ButtonUploaderComponent } from './button-uploader.component'; -import { ConfirmEqualValidatorDirective } from './confirm-equal-validator.directive'; -import { DropdownComponent } from './dropdown.component'; -import { ErrorInfoComponent } from './error-info.component'; -import { FieldDirective } from './field.directive'; -import { InputComponent } from './input.component'; -import { JsonComponent } from './json.component'; -import { BaseMapListDirective, FieldListComponent, FieldMapComponent } from './map.component'; -import { PasswordComponent } from './password/password.component'; -import { TextBoxComponent } from './text-box.component'; -import { TextareaComponent } from './textarea.component'; -import { VariantComponent } from './variant.component'; -import { SecretTextComponent } from './secret-text/secret-text.component'; -import { SecretFileComponent } from './secret-file/secret-file.component'; -import { SecretMapComponent } from './secret-map/secret-map.component'; - -@NgModule({ - declarations: [ - PasswordComponent, - BooleanComponent, - TextBoxComponent, - TextareaComponent, - JsonComponent, - DropdownComponent, - BundlesComponent, - ButtonUploaderComponent, - FieldListComponent, - FieldMapComponent, - InputComponent, - BaseMapListDirective, - ConfirmEqualValidatorDirective, - FieldDirective, - ErrorInfoComponent, - VariantComponent, - SecretTextComponent, - SecretFileComponent, - SecretMapComponent - ], - imports: [CommonModule, FormsModule, ReactiveFormsModule, MaterialModule, StuffModule], - exports: [ - FieldListComponent, - FieldMapComponent, - PasswordComponent, - BooleanComponent, - TextBoxComponent, - TextareaComponent, - JsonComponent, - DropdownComponent, - BundlesComponent, - InputComponent, - ButtonUploaderComponent, - VariantComponent, - ConfirmEqualValidatorDirective, - SecretTextComponent, - SecretFileComponent, - SecretMapComponent - ], -}) -export class FormElementsModule {} diff --git a/web/src/app/shared/form-elements/input.component.ts b/web/src/app/shared/form-elements/input.component.ts deleted file mode 100644 index cba2aa51e5..0000000000 --- a/web/src/app/shared/form-elements/input.component.ts +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed 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 { Component, Input } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { BaseDirective } from '../directives'; - -@Component({ - selector: 'app-input', - template: ` -
- - - - Ensure this field has no more than 30 characters. - - {{ label }} is required. - {{ label }} is not correct. - - -
- `, - styles: ['.row {display:flex;}'], -}) -export class InputComponent extends BaseDirective { - @Input() form: FormGroup; - @Input() controlName: string; - @Input() label: string; - @Input() isRequired = false; - - isError(name: string) { - const f = this.form.get(name); - return f.invalid && (f.dirty || f.touched); - } - - hasError(name: string, error: string) { - return this.form.controls[name].hasError(error); - } -} diff --git a/web/src/app/shared/form-elements/json.component.ts b/web/src/app/shared/form-elements/json.component.ts deleted file mode 100644 index c0980be506..0000000000 --- a/web/src/app/shared/form-elements/json.component.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed 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 { Component, OnInit } from '@angular/core'; - -import { FieldDirective } from './field.directive'; -import { debounceTime } from 'rxjs/operators'; - -@Component({ - selector: 'app-fields-json', - template: ` - - - - - - - - - `, -}) -export class JsonComponent extends FieldDirective implements OnInit { - ngOnInit() { - super.ngOnInit(); - const control = this.form.controls[this.field.name]; - control.valueChanges.pipe(debounceTime(500)).subscribe((value) => { - try { - const v = JSON.parse(value); - control.setValue(JSON.stringify(v, undefined, 4), { emitEvent: false }); - } catch (e) { - } - }); - } -} diff --git a/web/src/app/shared/form-elements/map-list.template.html b/web/src/app/shared/form-elements/map-list.template.html deleted file mode 100644 index 65f00d076d..0000000000 --- a/web/src/app/shared/form-elements/map-list.template.html +++ /dev/null @@ -1,20 +0,0 @@ -
- -
- -
- - : - - Map property name is required! - - - - - -
-Field [{{ field.display_name }}] is required! diff --git a/web/src/app/shared/form-elements/map.component.scss b/web/src/app/shared/form-elements/map.component.scss deleted file mode 100644 index 960b91d3ed..0000000000 --- a/web/src/app/shared/form-elements/map.component.scss +++ /dev/null @@ -1,27 +0,0 @@ -:host { - margin-bottom: 10px; - flex-direction: column; - - .tools { - align-self: flex-end; - } - - & div.item { - width: 100%; - display: flex; - align-items: baseline; - - & .key-field { - flex: 0 1 50%; - margin-right: 10px; - } - - & .value-field { - flex: 1 0 50%; - } - } - - .error { - font-size: 75%; - } -} diff --git a/web/src/app/shared/form-elements/map.component.ts b/web/src/app/shared/form-elements/map.component.ts deleted file mode 100644 index dd1636a719..0000000000 --- a/web/src/app/shared/form-elements/map.component.ts +++ /dev/null @@ -1,123 +0,0 @@ -// Licensed 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 { Component, Directive, OnChanges, OnInit, SimpleChanges } from '@angular/core'; -import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; - -import { FieldDirective } from './field.directive'; - -@Directive({ - selector: '[appBaseMapList]' -}) -export class BaseMapListDirective extends FieldDirective implements OnInit, OnChanges { - asList: boolean; - items = new FormArray([]); - - constructor(private fb: FormBuilder) { - super(); - } - - ngOnChanges(changes: SimpleChanges) { - this.control.statusChanges.pipe( - this.takeUntil() - ).subscribe((state) => { - if (state === 'DISABLED') { - this.items.controls.forEach((control) => { - control.disable({ emitEvent: false }); - control.markAsUntouched(); - }); - this.control.markAsUntouched(); - } else { - this.items.controls.forEach((control) => { - control.enable({ emitEvent: false }); - control.markAsTouched(); - }); - this.control.markAsTouched(); - } - }); - } - - ngOnInit() { - if (!Object.keys(this.field.value || {}).length) this.control.setValue(''); - - this.reload(); - this.items.valueChanges.pipe( - this.takeUntil() - ).subscribe((a: { key: string; value: string }[]) => { - this.prepare(a) - }); - } - - prepare(a: { key: string; value: string }[]) { - let value = this.asList ? - a.map(b => b.value).filter(c => c) : - a.length && a.length > 0 ? - a.reduce((p, c) => ({ - ...p, - [c.key]: c.value - }), {}) : - null; - - if (value && this.asList) value = (value as Array).length ? value : null; - this.control.setValue(value); - this.control.markAsTouched(); - } - - reload() { - const fieldValue = this.field.value ? { ...(this.field.value as Object) } : null; - - if (!fieldValue) { - this.items.clear(); - } else { - this.items.reset([]); - this.items.controls = []; - - Object.keys(fieldValue).forEach(a => this.items.push( - this.fb.group({ - key: [{ value: a, disabled: this.control.disabled }, Validators.required], - value: [{ value: fieldValue[a], disabled: this.control.disabled }], - }) - )); - } - } - - add() { - const group = this.fb.group({ key: ['', Validators.required], value: '' }); - this.items.push(group); - group.controls['key'].markAsTouched(); - } - - check(item: FormGroup) { - return item.controls['key'].hasError('required'); - } - - clear(i: number) { - this.items.removeAt(i); - } -} - -@Component({ - selector: 'app-fields-list', - templateUrl: './map-list.template.html', - styleUrls: ['./map.component.scss'] -}) -export class FieldListComponent extends BaseMapListDirective { - asList = true; -} - -@Component({ - selector: 'app-fields-map', - templateUrl: './map-list.template.html', - styleUrls: ['./map.component.scss'] -}) -export class FieldMapComponent extends BaseMapListDirective { - asList = false; -} diff --git a/web/src/app/shared/form-elements/password/password.component.html b/web/src/app/shared/form-elements/password/password.component.html deleted file mode 100644 index a24bef5236..0000000000 --- a/web/src/app/shared/form-elements/password/password.component.html +++ /dev/null @@ -1,35 +0,0 @@ -
- - - - - - -
- -
- - - Field [{{ field.display_name }}] is required! - - - - Confirm [{{ field.display_name }}] is required! - - Field [{{ field.display_name }}] and confirm [{{ field.display_name }}] does not match! - - -
diff --git a/web/src/app/shared/form-elements/password/password.component.scss b/web/src/app/shared/form-elements/password/password.component.scss deleted file mode 100644 index b3ddad770b..0000000000 --- a/web/src/app/shared/form-elements/password/password.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -div { - flex: 1; - - & mat-form-field { - flex-basis: 50%; - } - - & mat-form-field:first-child { - margin-right: 10px; - } -} diff --git a/web/src/app/shared/form-elements/password/password.component.ts b/web/src/app/shared/form-elements/password/password.component.ts deleted file mode 100644 index 0475728629..0000000000 --- a/web/src/app/shared/form-elements/password/password.component.ts +++ /dev/null @@ -1,180 +0,0 @@ -// Licensed 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 { - AfterViewInit, - ChangeDetectorRef, - Component, - ElementRef, - OnChanges, - OnInit, - SimpleChanges, - ViewChild, -} from '@angular/core'; -import { AbstractControl, FormControl } from '@angular/forms'; -import { fromEvent, merge } from 'rxjs'; -import { debounceTime, pluck, tap } from 'rxjs/operators'; - -import { FieldDirective } from '../field.directive'; -import { FieldService } from '../../configuration/services/field.service'; - -@Component({ - selector: 'app-fields-password', - templateUrl: './password.component.html', - styleUrls: ['./password.component.scss'], -}) -export class PasswordComponent extends FieldDirective implements OnInit, AfterViewInit, OnChanges { - dummy = '********'; - isHideDummy = false; - value: string; - - constructor(private service: FieldService, private cd: ChangeDetectorRef) { - super(); - } - - @ViewChild('input', { read: ElementRef }) input: ElementRef; - @ViewChild('conf', { read: ElementRef }) conf: ElementRef; - - ngOnChanges(changes: SimpleChanges) { - if (!changes.field.firstChange) { - this.initConfirm(); - } - } - - ngOnInit() { - this.initConfirm(); - super.ngOnInit(); - - if (!this.control.value) this.dummy = ''; - this.value = this.control.value; - } - - initConfirm(): void { - if (!this.field.ui_options?.no_confirm) { - this.form.addControl( - `confirm_${this.field.name}`, - new FormControl( - { value: this.field.value, disabled: this.control.disabled }, - this.field.activatable ? [] : this.service.setValidator(this.field, this.control) - ) - ); - - this.control.statusChanges.pipe( - this.takeUntil() - ).subscribe((state) => { - if (state === 'DISABLED') { - this.form.controls[`confirm_${this.field.name}`].disable(); - } else { - this.form.controls[`confirm_${this.field.name}`].enable(); - } - }); - } - - if (this.field.required && !this.field.value) { - this.isHideDummy = true; - } - - if (this.ConfirmPasswordField) this.ConfirmPasswordField.markAllAsTouched(); - } - - ngAfterViewInit(): void { - if (this.ConfirmPasswordField) { - const a = fromEvent(this.input.nativeElement, 'blur'); - const c = fromEvent(this.input.nativeElement, 'focus'); - const b = fromEvent(this.conf.nativeElement, 'blur'); - const d = fromEvent(this.conf.nativeElement, 'focus'); - - merge(a, b, c, d) - .pipe( - debounceTime(100), - pluck('type'), - tap((res: 'focus' | 'blur') => { - if (res === 'blur' && (this.isValidField() || this.isCleared())) { - if ((this.isValidField() && this.isCleared()) || this.isCleared()) { - this.control.setValue(this.value); - this.ConfirmPasswordField.setValue(this.value); - } - this.isHideDummy = false; - this.cd.detectChanges(); - } - }) - ) - .subscribe(); - } else { - fromEvent(this.input.nativeElement, 'blur') - .pipe( - tap(_ => { - if (this.control.valid || this.value !== '' && this.control.value === '') { - if ((this.control.valid && this.value !== '' && this.control.value === '') || this.value !== '' && this.control.value === '') { - this.control.setValue(this.value); - } - this.isHideDummy = false; - this.cd.detectChanges(); - } - }) - ).subscribe(); - } - } - - isValidField(): boolean { - return this.control.valid && this.ConfirmPasswordField.valid; - } - - isCleared(): boolean { - return this.value !== '' && this.control.value === '' && this.ConfirmPasswordField.value === ''; - } - - hideDummy(isConfirmField: boolean): void { - if (this.field.read_only) return null; - this.isHideDummy = true; - this.cd.detectChanges(); - - if (isConfirmField) { - this.conf.nativeElement.focus(); - } else { - this.input.nativeElement.focus(); - } - - this.control.setValue(''); - if (this.ConfirmPasswordField) this.ConfirmPasswordField.setValue(''); - } - - get ConfirmPasswordField(): AbstractControl { - return this.form.controls['confirm_' + this.field.name]; - } - - hasErrorConfirm(name: string) { - const c = this.ConfirmPasswordField; - return this.getConfirmPasswordFieldErrors(name) && (c.touched || c.dirty); - } - - confirmPasswordFieldUpdate() { - this.dummy = this.control.value; - this.value = this.control.value; - const confirm = this.ConfirmPasswordField; - return confirm ? confirm.updateValueAndValidity() : ''; - } - - getConfirmPasswordFieldErrors(error: string) { - const confirm = this.ConfirmPasswordField; - if (confirm && confirm.errors) { - return confirm.errors[error]; - } - return null; - } - - change(value: string) { - if (value === null) { - this.hideDummy(false); - this.cd.detectChanges(); - } - } -} diff --git a/web/src/app/shared/form-elements/secret-file/secret-file.component.html b/web/src/app/shared/form-elements/secret-file/secret-file.component.html deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/shared/form-elements/secret-file/secret-file.component.scss b/web/src/app/shared/form-elements/secret-file/secret-file.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/shared/form-elements/secret-file/secret-file.component.ts b/web/src/app/shared/form-elements/secret-file/secret-file.component.ts deleted file mode 100644 index 1399b8ac3e..0000000000 --- a/web/src/app/shared/form-elements/secret-file/secret-file.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { SecretTextComponent } from "@app/shared/form-elements/secret-text/secret-text.component"; - -@Component({ - selector: 'app-fields-secret-file', - templateUrl: '../secret-text/secret-text.component.html', -}) -export class SecretFileComponent extends SecretTextComponent implements OnInit { - - constructor() { - super(); - } - -} diff --git a/web/src/app/shared/form-elements/secret-map/secret-map.component.html b/web/src/app/shared/form-elements/secret-map/secret-map.component.html deleted file mode 100644 index 7969ac8091..0000000000 --- a/web/src/app/shared/form-elements/secret-map/secret-map.component.html +++ /dev/null @@ -1,20 +0,0 @@ -
- -
- -
- - : - - Map property name is required! - - - - - -
-Field [{{ field.display_name }}] is required! diff --git a/web/src/app/shared/form-elements/secret-map/secret-map.component.scss b/web/src/app/shared/form-elements/secret-map/secret-map.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/app/shared/form-elements/secret-map/secret-map.component.ts b/web/src/app/shared/form-elements/secret-map/secret-map.component.ts deleted file mode 100644 index 4602c7772d..0000000000 --- a/web/src/app/shared/form-elements/secret-map/secret-map.component.ts +++ /dev/null @@ -1,101 +0,0 @@ -import {Component, ElementRef, OnChanges, OnInit, QueryList, ViewChild, ViewChildren} from '@angular/core'; -import { BaseMapListDirective } from "@app/shared/form-elements/map.component"; -import {FormArray, FormControl, FormGroup, Validators} from "@angular/forms"; -import { TValue } from "@app/shared/configuration/types"; -import {ErrorStateMatcher} from "@angular/material/core"; - -@Component({ - selector: 'app-fields-secret-map', - templateUrl: './secret-map.component.html', - styleUrls: ['../map.component.scss', './secret-map.component.scss'] -}) -export class SecretMapComponent extends BaseMapListDirective implements OnInit, OnChanges { - @ViewChildren("secretInput") secretInput: QueryList; - - dummy = '********'; - dummyLength = this.dummy.length; - dummyControl = new FormArray([]); - value: TValue; - asList = false; - matcher = new MyErrorStateMatcher(); - - ngOnChanges(): void { - this.value = this.field?.value; - - this.control.valueChanges - .pipe(this.takeUntil()) - .subscribe((a) => { - this.dummyControl.clear(); - if (a === null) { - this.items.clear(); - } else { - this.items.controls.forEach((control, i) => { - const itemsValue = control.value.value === '' || control.value.value === null ? null : this.dummy - this.dummyControl.push(new FormGroup({ - key: new FormControl(control.value.key, Validators.required), - value: new FormControl(itemsValue) - })); - }); - } - }) - - this.control.statusChanges - .pipe(this.takeUntil()) - .subscribe((state) => { - if (state === 'DISABLED') { - this.dummyControl.controls.forEach((control) => { - control.disable({ emitEvent: false }); - control.markAsUntouched(); - }); - this.control.markAsUntouched(); - } else { - this.dummyControl.controls.forEach((control) => { - control.enable({ emitEvent: false }); - control.markAsTouched(); - }); - this.control.markAsTouched(); - } - }); - } - - ngOnInit() { - super.ngOnInit(); - - if (this.field?.value) { - Object.keys(this.field.value)?.forEach((key, i) => { - this.dummyControl.push(new FormGroup({ - key: new FormControl(key, Validators.required), - value: new FormControl(this.field.value[key]), - } - )); - - this.dummyControl.at(i).patchValue({ key: key, value: this.dummy }, { emitEvent: false }); - }) - } - } - - onBlur(index): void { - const controlValue = { - key: this.dummyControl.value[index].key, - value: this.dummyControl.value[index].value !== this.dummy ? this.dummyControl.value[index].value : this.control.value[this.dummyControl.value[index].key] - }; - this.items.at(index).setValue(controlValue); - } - - onFocus(index): void { - this.secretInput.get(index).nativeElement.value = ''; - } - - validate() { - const obj = {}; - this.dummyControl.value.forEach((i) => obj[i.key] = i.value); - this.control.patchValue(obj, { emitEvent: false }); - this.control.updateValueAndValidity({ emitEvent: false }) - } -} - -export class MyErrorStateMatcher implements ErrorStateMatcher { - isErrorState(control: FormControl | null): boolean { - return !(control?.value !== '' && control?.value !== null); - } -} diff --git a/web/src/app/shared/form-elements/secret-text/secret-text.component.html b/web/src/app/shared/form-elements/secret-text/secret-text.component.html deleted file mode 100644 index c21d7e9c51..0000000000 --- a/web/src/app/shared/form-elements/secret-text/secret-text.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/web/src/app/shared/form-elements/secret-text/secret-text.component.ts b/web/src/app/shared/form-elements/secret-text/secret-text.component.ts deleted file mode 100644 index 96eea7feb1..0000000000 --- a/web/src/app/shared/form-elements/secret-text/secret-text.component.ts +++ /dev/null @@ -1,75 +0,0 @@ -// Licensed 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 { Component, OnChanges, OnInit, } from '@angular/core'; - -import { FieldDirective } from '../field.directive'; -import { FormControl, Validators } from '@angular/forms'; - -@Component({ - selector: 'app-fields-secret-text', - templateUrl: './secret-text.component.html', -}) -export class SecretTextComponent extends FieldDirective implements OnInit, OnChanges { - dummy = '********'; - dummyControl: FormControl; - value: string; - - ngOnChanges(): void { - this.value = this.field.value as string; - - this.control.statusChanges.pipe(this.takeUntil()).subscribe((status) => { - if (status === 'DISABLED') { - this.dummyControl.disable(); - this.dummyControl.markAsUntouched(); - this.control.markAsUntouched(); - } else { - this.dummyControl.enable(); - this.dummyControl.markAsTouched(); - this.control.markAsTouched(); - } - }); - } - - ngOnInit(): void { - this._initDummyControl(); - } - - onBlur(): void { - this.control.setValue(this.dummyControl.value || this.value); - this.dummyControl.setValue(this.control.value ? this.dummy : null); - } - - onFocus(): void { - this.dummyControl.setValue(null); - if (this.field.required) this.control.setErrors({'required': this.field.required}); - } - - clear(): void { - this.dummyControl.setValue(null); - } - - get isValid() { - if (this.field.read_only) return true; - this.dummyControl.markAsTouched(); - const control = this.dummyControl; - return control.valid && (control.dirty || control.touched); - } - - private _initDummyControl(): void { - this.dummyControl = new FormControl( - { value: this.control.value ? this.dummy : null, disabled: this.control.disabled }, - Validators.compose(this.field.required ? [Validators.required] : []) - ); - this.dummyControl.markAllAsTouched(); - } - -} diff --git a/web/src/app/shared/form-elements/text-box.component.ts b/web/src/app/shared/form-elements/text-box.component.ts deleted file mode 100644 index d745e833d0..0000000000 --- a/web/src/app/shared/form-elements/text-box.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed 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 { Component } from '@angular/core'; - -import { FieldDirective } from './field.directive'; - -@Component({ - selector: 'app-fields-textbox', - template: ` - - - - - - - ` -}) -export class TextBoxComponent extends FieldDirective {} diff --git a/web/src/app/shared/form-elements/textarea.component.ts b/web/src/app/shared/form-elements/textarea.component.ts deleted file mode 100644 index f57f77b05c..0000000000 --- a/web/src/app/shared/form-elements/textarea.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed 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 { Component } from '@angular/core'; - -import { FieldDirective } from './field.directive'; - -@Component({ - selector: 'app-fields-textarea', - template: ` - - - - - - - `, -}) -export class TextareaComponent extends FieldDirective {} diff --git a/web/src/app/shared/form-elements/variant.component.spec.ts b/web/src/app/shared/form-elements/variant.component.spec.ts deleted file mode 100644 index 574aae9ffe..0000000000 --- a/web/src/app/shared/form-elements/variant.component.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed 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 { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormControl, FormGroup } from '@angular/forms'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; - -import { IFieldOptions } from '../configuration/types'; -import { SharedModule } from '../shared.module'; -import { VariantComponent } from './variant.component'; - -describe('VariantComponent', () => { - let component: VariantComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - TestBed.configureTestingModule({ - imports: [SharedModule, NoopAnimationsModule], - declarations: [VariantComponent], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(VariantComponent); - component = fixture.componentInstance; - component.form = new FormGroup({ name: new FormControl() }); - component.field = { name: 'name', limits: {} } as IFieldOptions; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/form-elements/variant.component.ts b/web/src/app/shared/form-elements/variant.component.ts deleted file mode 100644 index a8beea811b..0000000000 --- a/web/src/app/shared/form-elements/variant.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed 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 { Component, OnInit } from '@angular/core'; - -import { FieldDirective } from './field.directive'; - -@Component({ - selector: 'app-fields-variant', - template: ` - - - - - {{ option }} - - - - - - - {{ option }} - - - - - - - `, -}) -export class VariantComponent extends FieldDirective implements OnInit { - ngOnInit() { - if (this.field.read_only) { - this.control.disable(); - } - } -} diff --git a/web/src/app/shared/host-components-map/dependencies.component.spec.ts b/web/src/app/shared/host-components-map/dependencies.component.spec.ts deleted file mode 100644 index 72bbad4bf1..0000000000 --- a/web/src/app/shared/host-components-map/dependencies.component.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -// Licensed 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 { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DependenciesComponent } from './dependencies.component'; - -describe('DependenciesComponent', () => { - let component: DependenciesComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - TestBed.configureTestingModule({ - declarations: [DependenciesComponent], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DependenciesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('data when creating a dialog', () => { - component.model = [{ prototype_id: 1, display_name: 'display_name_test_1', name: 'test_name_1' }]; - component.ngOnInit(); - fixture.detectChanges(); - const li = fixture.nativeElement.querySelector('ul').getElementsByTagName('li'); - expect(li.length).toBe(1); - expect(li[0].innerText).toBe('display_name_test_1'); - }); - - it('data when input property [components]', () => { - component.components = [{ prototype_id: 1, display_name: 'display_name_test_1', name: 'test_name_1' }]; - component.ngOnInit(); - fixture.detectChanges(); - const li = fixture.nativeElement.querySelector('ul').getElementsByTagName('li'); - expect(li.length).toBe(1); - expect(li[0].innerText).toBe('display_name_test_1'); - }); - - it('data as tree', () => { - component.model = [{ prototype_id: 1, display_name: 'display_name_test_1', name: 'test_name_1', components: [{ prototype_id: 2, display_name: 'display_name_test_2', name: 'test_name_2' }] }]; - component.ngOnInit(); - fixture.detectChanges(); - const ul = fixture.nativeElement.querySelector('ul'); - const li = ul.getElementsByTagName('li'); - expect(ul.getElementsByTagName('app-dependencies').length).toBe(2); - expect(li.length).toBe(2); - expect(li[1].innerText).toBe('display_name_test_2'); - expect(ul.innerText).toContain('display_name_test_1'); - expect(ul.innerText).toContain('display_name_test_2'); - }); -}); diff --git a/web/src/app/shared/host-components-map/dependencies.component.ts b/web/src/app/shared/host-components-map/dependencies.component.ts deleted file mode 100644 index dedebaeb4c..0000000000 --- a/web/src/app/shared/host-components-map/dependencies.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed 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 { Component, Input, OnInit } from '@angular/core'; -import { IRequires } from '@app/core/types'; - -@Component({ - selector: 'app-dependencies', - template: ` -
    -
  • - {{ item?.display_name }} - -
  • -
- `, - styles: ['li {padding: 6px 0;}'], -}) -export class DependenciesComponent implements OnInit { - // by dialog window - model: IRequires[]; - items: IRequires[]; - - @Input() components: IRequires[]; - - ngOnInit(): void { - this.items = this.model || this.components; - } -} diff --git a/web/src/app/shared/host-components-map/holder.directive.spec.ts b/web/src/app/shared/host-components-map/holder.directive.spec.ts deleted file mode 100644 index cf7609c9e6..0000000000 --- a/web/src/app/shared/host-components-map/holder.directive.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed 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 { Component } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; - -import { HolderDirective } from './holder.directive'; - -@Component({ - template: `
-
-
-
`, -}) -class TestComponent { - scrollEventData: { direct: 1 | -1 | 0; scrollTop: number }; -} - -describe('HolderDirective', () => { - let component: TestComponent; - let fixture: ComponentFixture; - let dir: HolderDirective; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [TestComponent, HolderDirective], - }); - - fixture = TestBed.createComponent(TestComponent); - dir = fixture.debugElement.queryAll(By.directive(HolderDirective))[0].injector.get(HolderDirective); - fixture.detectChanges(); - component = fixture.componentInstance; - }); - - it('should create component', () => { - expect(component).toBeDefined(); - }); - - it('can inject `HolderDirective`', () => { - expect(dir).toBeTruthy(); - }); - - it('Host component should contains two el > .wrapper', () => { - const host = fixture.nativeElement.querySelector('.main'); - const children = host.children; - expect(children.length).toBe(2); - expect(children[0].querySelector('.wrapper')).toBeDefined(); - expect(children[1].querySelector('.wrapper')).toBeDefined(); - }); - - it('Host component should change margin-top after scroll', () => { - component.scrollEventData = { direct: 0, scrollTop: 10 }; - fixture.detectChanges(); - expect(dir.ps).toBeDefined(); - component.scrollEventData = { direct: 0, scrollTop: 11 }; - fixture.detectChanges(); - const debugs = fixture.debugElement.nativeElement.getElementsByClassName('wrapper'); - expect(dir.ps.short.style.cssText).toContain('margin-top: 11px'); - expect(debugs[1].style.cssText).toContain('margin-top: 11px'); - }); -}); diff --git a/web/src/app/shared/host-components-map/holder.directive.ts b/web/src/app/shared/host-components-map/holder.directive.ts deleted file mode 100644 index 12fcc8f3ce..0000000000 --- a/web/src/app/shared/host-components-map/holder.directive.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed 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 { Directive, ElementRef, Input } from '@angular/core'; - -@Directive({ - selector: '[appHolder]', -}) -export class HolderDirective { - ps: { short: HTMLElement; long: HTMLElement }; - - @Input('appHolder') set scroll(data: { direct: -1 | 1 | 0; scrollTop: number }) { - if (data) { - if (!this.ps) this.getPs(); - else if (this.ps.short.clientHeight + data.scrollTop < this.ps.long.clientHeight) this.ps.short.style.marginTop = `${Math.floor(data.scrollTop)}px`; - } - } - - constructor(private el: ElementRef) {} - - getPs() { - const els: HTMLElement[] = [...this.el.nativeElement.children]; - if (els.length) { - const a = els[0].querySelector('.wrapper'), - b = els[1].querySelector('.wrapper'); - this.ps = a.clientHeight < b.clientHeight ? { short: a, long: b } : { short: b, long: a }; - } - } -} diff --git a/web/src/app/shared/host-components-map/host-components-map.module.ts b/web/src/app/shared/host-components-map/host-components-map.module.ts deleted file mode 100644 index 27f2fb8b17..0000000000 --- a/web/src/app/shared/host-components-map/host-components-map.module.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; - -import { MaterialModule } from '../material.module'; -import { StuffModule } from '../stuff.module'; -import { HolderDirective } from './holder.directive'; -import { Much2ManyComponent } from './much-2-many/much-2-many.component'; -import { ServiceHostComponent } from './services2hosts/service-host.component'; -import { TakeService } from './take.service'; -import { AddingModule } from '../add-component/adding.module'; -import { DependenciesComponent } from './dependencies.component'; - -@NgModule({ - declarations: [HolderDirective, ServiceHostComponent, Much2ManyComponent, DependenciesComponent], - imports: [CommonModule, MaterialModule, RouterModule, StuffModule, AddingModule], - exports: [ServiceHostComponent], - providers: [TakeService] -}) -export class HostComponentsMapModule {} diff --git a/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.html b/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.html deleted file mode 100644 index af63450331..0000000000 --- a/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.html +++ /dev/null @@ -1,19 +0,0 @@ -
-
- - -
-
-
- {{ rel.name }} - -
-
-
diff --git a/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.scss b/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.scss deleted file mode 100644 index 64a6496268..0000000000 --- a/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.scss +++ /dev/null @@ -1,99 +0,0 @@ -div.m2m { - border: solid 1px rgb(238, 236, 236); - margin-bottom: 8px; - padding: 8px; - box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12); - - &.selected { - border-color: #76FF03; - - .title-container { - .title { - font-weight: bolder; - color: #76FF03; - } - } - } - - &.linked { - border-color: #18FFFF; - - .title-container { - .title { - font-weight: bolder; - color: #18FFFF; - } - } - - } - - & .title-container { - display: flex; - - &.disabled { - pointer-events: none; - color: #FFFFFF4D; - } - - & .title { - flex: 1; - line-height: 40px; - font-size: 18px; - width: 1px; - overflow: hidden; - text-overflow: ellipsis; - - mat-icon { - vertical-align: middle; - line-height: .9 - } - } - - & .relations-count { - box-shadow: none; - background-color: #e4f9ef; - margin-left: 8px; - } - } - - & .relations-list { - padding: 4px 40px; - display: none; - - &.disabled { - pointer-events: none; - } - - & div { - display: flex; - - & span { - font-size: 14px; - font-weight: 500; - flex: 1 0 auto; - line-height: 40px; - overflow: hidden; - text-overflow: ellipsis; - width: 1px; - } - - & button { - flex: 0 1 auto; - } - } - } - - & .notification { - display: none; - } - - & .show { - display: block; - } -} - - - -.mat-mini-fab[disabled][disabled] { - color: rgba(0, 0, 0, 0.4); -} diff --git a/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.ts b/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.ts deleted file mode 100644 index 23ad47e35b..0000000000 --- a/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.ts +++ /dev/null @@ -1,109 +0,0 @@ -// Licensed 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 { AfterViewChecked, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { IActionParameter, isNumber } from '@app/core/types'; -import { CompTile, HostTile, Tile } from '../types'; -import { StatusType } from "@app/components/maintenance-mode-button/maintenance-mode-button.component"; - -@Component({ - selector: 'app-much-2-many', - templateUrl: './much-2-many.component.html', - styleUrls: ['./much-2-many.component.scss'], -}) -export class Much2ManyComponent implements AfterViewChecked { - isShow = false; - statusType = StatusType; - - @Output() clickToTitleEvt: EventEmitter = new EventEmitter(); - @Output() clearRelationEvt: EventEmitter<{ relation: Tile; model: Tile }> = new EventEmitter(); - @Input() model: Tile; - @Input() form: FormGroup; - @Input() actionParameters: IActionParameter[]; - @Input() selectedComponent: CompTile; - - constructor(private cdRef : ChangeDetectorRef) {} - - ngAfterViewChecked() { - this.cdRef.detectChanges(); - } - - isDisabled() { - if (this.model?.actions) return !this.model.actions.length; - return this.model?.disabled; - } - - isHostDisabled() { - return this.model?.mm === this.statusType.On && !this.hasHcRelations(this.model) - } - - isError() { - if ('service_id' in this.model && Object.keys(this.form.controls).length) { - const sc = this.model as CompTile; - const control = this.form.controls[`${sc.service_id}/${sc.id}`]; - - if (!control || !control?.errors?.error) return true; - - sc.notification = control.errors.error || null; - return !control.invalid; - } - return true; - } - - isMandatory() { - if (this.model?.limit) { - return ['+', 'odd', 1].includes(this.model?.limit[0]) && this.model?.relations.length === 0; - } - - return false; - } - - clearDisabled(rel: Tile) { - if (this.model.actions) return this.model.actions.every((e) => e !== 'remove'); - return rel.disabled || this.model.disabled; - } - - clickToTitle() { - this.clickToTitleEvt.emit(this.model); - } - - toggleRelations() { - this.isShow = !this.isShow; - } - - clearRelation(relation: Tile) { - this.model.relations = this.model.relations.filter((a) => a !== relation); - this.clearRelationEvt.emit({ relation, model: this.model }); - } - - setNotify() { - const [a, b] = this.model.limit, - lim = isNumber(b) ? b : a === 'odd' ? 1 : a === 'depend' ? 0 : a; - return `${this.model.relations.length}${lim !== 0 ? ` / ${lim}` : ''}`; - } - - tooltip() { - if (this.isHostDisabled()) { - return 'Host is in "Maintenance mode"'; - } - - return null; - } - - hasHcRelations(host: HostTile): boolean { - if (!this.selectedComponent) return false; - if (host?.relations.length === 0 && this.selectedComponent?.actions && this.selectedComponent?.actions.includes('add')) return true; - if (host?.relations.length === 0) return false; - - return !!host?.relations.some((relation) => relation.id === this.selectedComponent.id && this.selectedComponent?.actions && this.selectedComponent?.actions.includes('remove')); - } -} diff --git a/web/src/app/shared/host-components-map/services2hosts/service-host.component.html b/web/src/app/shared/host-components-map/services2hosts/service-host.component.html deleted file mode 100644 index 2e50d0ce15..0000000000 --- a/web/src/app/shared/host-components-map/services2hosts/service-host.component.html +++ /dev/null @@ -1,31 +0,0 @@ -
- - -
- -
-
-

Components

-
-
- Add services on the services page. -
- - -
-
-
-

Hosts - -

-
-
- Add hosts on the hosts page. -
- - -
-
-
diff --git a/web/src/app/shared/host-components-map/services2hosts/service-host.component.scss b/web/src/app/shared/host-components-map/services2hosts/service-host.component.scss deleted file mode 100644 index 1408066dd1..0000000000 --- a/web/src/app/shared/host-components-map/services2hosts/service-host.component.scss +++ /dev/null @@ -1,53 +0,0 @@ -.holder { - display: flex; - justify-content: space-around; - margin: 10px 0; - - - h3 { - margin: 10px; - line-height: 40px; - display: flex; - - .slide-toggle { - margin-left: 20px; - } - } - - div { - padding: 6px; - flex: 1 0 auto; - margin: 0 10px; - } -} - -p { - padding-right: 40px; - text-align: right; -} - -.wrapper { - overflow: auto; - transition-property: margin-top; - transition-duration: .5s; - transition-timing-function: ease-out-cubic; - margin-top: 0px; -} - -.link { - font-size: 1em; -} - -.controls { - top: 130px; - right: 80px; - - .notify { - opacity: 0; - - &>span { - line-height: 24px; - vertical-align: text-bottom; - } - } -} diff --git a/web/src/app/shared/host-components-map/services2hosts/service-host.component.spec.ts b/web/src/app/shared/host-components-map/services2hosts/service-host.component.spec.ts deleted file mode 100644 index 393dfec113..0000000000 --- a/web/src/app/shared/host-components-map/services2hosts/service-host.component.spec.ts +++ /dev/null @@ -1,253 +0,0 @@ -// Licensed 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 { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatDialog } from '@angular/material/dialog'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterTestingModule } from '@angular/router/testing'; -import { ChannelService } from '@app/core/services'; -import { AddService } from '@app/shared/add-component/add.service'; -import { SharedModule } from '@app/shared/shared.module'; -import { provideMockStore } from '@ngrx/store/testing'; - -import { Much2ManyComponent } from '../much-2-many/much-2-many.component'; -import { TakeService } from '../take.service'; -import { ComponentFactory, HCFactory, HcmHost, HCmRequires } from '../test'; -import { IRawHosComponent } from '../types'; -import { ServiceHostComponent } from './service-host.component'; -import { ADD_SERVICE_PROVIDER } from '@app/shared/add-component/add-service-model'; -import { ApiService } from '@app/core/api'; - -function genData() { - const _c = ComponentFactory(4, 1); - const host = [new HcmHost('test', 1)]; - return { component: _c, host, hc: HCFactory(1, 1, 4) }; -} - -function domFirstElems( - n: HTMLElement -): { - components: NodeListOf; - hosts: NodeListOf; - host: Element; - comp: Element; - hostBtn: HTMLElement; - compBtn: HTMLElement; - addAllBtn: HTMLElement; -} { - const components = n.querySelectorAll('.wrapper').item(0).querySelectorAll('app-much-2-many'); - const hosts = n.querySelectorAll('.wrapper').item(1).querySelectorAll('app-much-2-many'); - const host = hosts.item(0); - const comp = components.item(0); - const hostBtn = host.querySelector('.m2m .title-container button.title') as HTMLElement; - const compBtn = comp.querySelector('.m2m .title-container button.title') as HTMLElement; - const addAllBtn = n.querySelector('app-dialog button.mat-accent') as HTMLElement; - return { components, hosts, host, comp, hostBtn, compBtn, addAllBtn }; -} - -describe('Service Host Map Component', () => { - let component: ServiceHostComponent; - let fixture: ComponentFixture; - - const initialState = { socket: {} }; - - const initDefault = (r: IRawHosComponent): void => { - component.init(r); - fixture.detectChanges(); - }; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [NoopAnimationsModule, SharedModule, RouterTestingModule], - declarations: [ServiceHostComponent, Much2ManyComponent], - providers: [ - MatDialog, - TakeService, - ChannelService, - provideMockStore({ initialState }), - { - provide: ApiService, - useValue: {} - }, - { - provide: ADD_SERVICE_PROVIDER, - useClass: AddService - }, - ], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(ServiceHostComponent); - - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeDefined(); - }); - - it('should display components and hosts as button', () => { - initDefault(genData()); - const dom = domFirstElems(fixture.nativeElement); - const components = dom.components; - const hosts = dom.hosts; - expect(hosts.length).toBe(1); - expect(components.length).toBe(4); - const host_relations = hosts.item(0).querySelector('.relations-list').children; - expect(host_relations.length).toBe(4); - components.forEach((a) => expect(a.querySelector('.relations-list').children.length).toBe(1)); - }); - - it('should mark host/component as selected and(or) as linked', () => { - initDefault(genData()); - const dom = domFirstElems(fixture.nativeElement); - const components = dom.components; - const host = dom.host; - (host.querySelector('.m2m .title-container button.title') as HTMLElement).click(); - fixture.detectChanges(); - expect(host.querySelector('.m2m').classList.contains('selected')).toBeTrue(); - components.forEach((a) => expect(a.querySelector('.m2m').classList.contains('linked')).toBeTrue()); - }); - - it('should add relative on click and check linked and selected property', () => { - const data = { component: ComponentFactory(4, 1), host: [new HcmHost('test', 1)], hc: [] }; - initDefault(data); - const dom = domFirstElems(fixture.nativeElement); - const host = dom.host; - const comp = dom.comp; - const host_btn = dom.hostBtn; - const comp_btn = dom.compBtn; - const host_relations = host.querySelector('.relations-list').children; - const comp_relations = comp.querySelector('.relations-list').children; - - const comp_isLinked = () => comp.querySelector('.m2m').classList.contains('linked'); - const comp_isSelect = () => comp.querySelector('.m2m').classList.contains('selected'); - const host_isSelect = () => host.querySelector('.m2m').classList.contains('selected'); - const host_isLinked = () => host.querySelector('.m2m').classList.contains('linked'); - - // start: host - select - host_btn.click(); // added class .selected - fixture.detectChanges(); - expect(host_isSelect()).toBeTrue(); - - comp_btn.click(); - fixture.detectChanges(); - expect(comp_isLinked()).toBeTrue(); - expect(host_relations.length).toBe(1); - expect(comp_relations.length).toBe(1); - - comp_btn.click(); - fixture.detectChanges(); - expect(comp_isLinked()).toBeFalse(); - expect(host_relations.length).toBe(0); - expect(comp_relations.length).toBe(0); - - host_btn.click(); - fixture.detectChanges(); - expect(host_isSelect()).toBeFalse(); - // end - - // start: component- select - comp_btn.click(); - fixture.detectChanges(); - expect(comp_isSelect()).toBeTrue(); - - host_btn.click(); - fixture.detectChanges(); - expect(host_isLinked()).toBeTrue(); - expect(host_relations.length).toBe(1); - expect(comp_relations.length).toBe(1); - - host_btn.click(); - fixture.detectChanges(); - expect(host_isLinked()).toBeFalse(); - expect(host_relations.length).toBe(0); - expect(comp_relations.length).toBe(0); - - comp_btn.click(); - fixture.detectChanges(); - expect(host_isSelect()).toBeFalse(); - // end - }); - - it('check dependencies and add validation rules for them', () => { - const data = { component: ComponentFactory(4, 1), host: [new HcmHost('test', 1)], hc: [] }; - data.component[1].constraint = [1, 2]; - data.component[2].constraint = [0, '+']; - data.component[3].constraint = [0, 1]; - initDefault(data); - const dom = domFirstElems(fixture.nativeElement); - const components = dom.components; - const host_btn = dom.hostBtn; - const comp_btn = dom.compBtn; - - comp_btn.click(); - fixture.detectChanges(); - - // check constraints - components.forEach((c, i) => { - const title = c.querySelector('.m2m .title-container button.title') as HTMLElement; - const star = title.querySelector('span.warn'); - const d = data.component[i]; - if (d.constraint?.length) { - expect(star).toBeDefined(); - // mouseover - //expect(last.attributes.getNamedItem('ng-reflect-message').value).toBe('Must be installed at least 1 components.'); - } else { - expect(star).toBeNull(); - } - }); - - host_btn.click(); - fixture.detectChanges(); - - // check dependencies - components.forEach((c, i) => { - const title = c.querySelector('.m2m .title-container button.title') as HTMLElement; - const star = title.querySelector('span.warn'); - if (i !== 0) { - expect(star).toBeDefined(); - //expect(last.attributes.getNamedItem('ng-reflect-message').value).toBe('Must be installed at least 1 components.'); - } else { - expect(star).toBeNull(); - } - }); - }); - - it('if component has `requires` should show dialog with `requires`', () => { - const data = { component: ComponentFactory(1, 1), host: [new HcmHost('test', 1)], hc: [] }; - const r = new HCmRequires(2); - r.components = [new HCmRequires(3)]; - data.component[0].requires = [r]; - initDefault(data); - - const dom = domFirstElems(fixture.nativeElement); - const host_btn = dom.hostBtn; - const comp_btn = dom.compBtn; - - host_btn.click(); - fixture.detectChanges(); - - comp_btn.click(); - fixture.detectChanges(); - - const dialog = document.querySelector('app-dependencies') as HTMLElement; - - if (dialog) { - expect(dialog).toBeTruthy(); - expect(dialog.innerText).toContain('component_display_name_2'); - expect(dialog.innerText).toContain('component_display_name_3'); - } else { - expect(dialog).toBeNull(); - } - }); -}); diff --git a/web/src/app/shared/host-components-map/services2hosts/service-host.component.ts b/web/src/app/shared/host-components-map/services2hosts/service-host.component.ts deleted file mode 100644 index c457c51d51..0000000000 --- a/web/src/app/shared/host-components-map/services2hosts/service-host.component.ts +++ /dev/null @@ -1,288 +0,0 @@ -// Licensed 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 { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { ChannelService } from '@app/core/services'; -import { keyChannelStrim } from '@app/core/services'; -import { EventMessage, IEMObject, SocketState } from '@app/core/store'; -import { IActionParameter } from '@app/core/types'; -import { Store } from '@ngrx/store'; -import { SocketListenerDirective } from '@app/shared/directives'; -import { getSelected, TakeService } from '../take.service'; -import { CompTile, HostTile, IRawHosComponent, Post, StatePost, Tile } from '../types'; -import { ApiService } from "@app/core/api"; -import { Observable } from "rxjs"; -import { ClusterService } from '@app/core/services/cluster.service'; - -@Component({ - selector: 'app-service-host', - templateUrl: './service-host.component.html', - styleUrls: ['./service-host.component.scss'], -}) -export class ServiceHostComponent extends SocketListenerDirective implements OnInit { - showSpinner = false; - - statePost = new StatePost(); - loadPost = new StatePost(); - sourceMap = new Map([ - ['host', []], - ['compo', []], - ]); - - addedServices: number[]; - - form = new FormGroup({}); - - @Input() - cluster: { id: number; hostcomponent: string | IRawHosComponent }; - - /** - * fixed position buttons for the scrolling - */ - @Input() - fixedButton = true; - - /** - * hide Save button - */ - @Input() - hideButton = false; - - @Input() - actionParameters: IActionParameter[]; - - @Output() saveResult = new EventEmitter(); - - saveFlag = false; - initFlag = false; - - scrollEventData: { direct: 1 | -1 | 0; scrollTop: number }; - - get Hosts(): HostTile[] { - return this.sourceMap.get('host'); - } - - set Hosts(v: HostTile[]) { - this.sourceMap.set('host', v); - } - - get Components(): CompTile[] { - return this.sourceMap.get('compo') as CompTile[]; - } - - set Components(v: CompTile[]) { - this.sourceMap.set('compo', v); - } - - get selectedComponent() { - return this.Components.find((component) => component.isSelected); - } - - constructor(public service: TakeService, private channel: ChannelService, socket: Store, private api: ApiService, private clusterService: ClusterService) { - super(socket); - } - - public get noValid() { - return /*!!this.service.countConstraint */ !this.form.valid || !this.statePost.data.length; - } - - ngOnInit() { - this.load(); - super.startListenSocket(); - - this.channel - .on(keyChannelStrim.scroll) - .pipe(this.takeUntil()) - .subscribe((e) => (this.scrollEventData = e)); - } - - getClusterInfo(): Observable { - return this.api.get(`api/v1/cluster/${this.cluster.id}/hostcomponent/`); - } - - getAddedServices(): Observable { - return this.api.get(`api/v1/cluster/${this.clusterService.Cluster.id}/service/`); - } - - socketListener(m: EventMessage) { - const isCurrent = (type: string, id: number) => type === 'cluster' && id === this.cluster?.id; - if ( - (m.event === 'change_hostcomponentmap' || m.event === 'change_state') && - isCurrent(m.object.type, m.object?.id) && - !this.saveFlag - ) { - this.reset().load(); - } - if ((m.event === 'add' || m.event === 'remove') && isCurrent(m.object.details.type, +m.object.details.value)) - this.update(m); - } - - reset() { - this.Hosts = []; - this.Components = []; - this.statePost.clear(); - this.loadPost.clear(); - this.form = new FormGroup({}); - return this; - } - - update(em: EventMessage) { - if (em.event === 'add') this.add(em.object); - if (em.event === 'remove') this.remove(em.object); - } - - add(io: IEMObject) { - const { id, type, details } = io; - if (details.type === 'cluster' && +details.value === this.cluster?.id && typeof this.cluster.hostcomponent === 'string') { - this.service - .load(this.cluster.hostcomponent as string) - .pipe(this.takeUntil()) - .subscribe((raw: IRawHosComponent) => { - if (type === 'host') - this.Hosts = [ - ...this.Hosts, - ...this.service.fillHost( - raw.host.map((h) => new HostTile(h)).filter((h) => h?.id === id), - this.actionParameters - ), - ]; - if (type === 'service') - this.Components = [ - ...this.Components, - ...this.service.fillComponent( - raw.component.filter((a) => a.service_id === id && this.Components.every((b) => b?.id !== a?.id)), - this.actionParameters - ), - ]; - }); - } else if (typeof this.cluster.hostcomponent !== 'string') { - this.getClusterInfo() - .pipe(this.takeUntil()) - .subscribe((res) => { - this.Hosts = [ - ...this.Hosts, - ...this.service.fillHost( - res.host.map((h) => new HostTile(h)).filter((h) => h?.id === id), - this.actionParameters - ), - ]; - }); - } - - this.getAddedServices() - .pipe(this.takeUntil()) - .subscribe((res) => this.addedServices = res.map((service) => service.prototype_id)); - } - - /** host only */ - remove(io: IEMObject) { - if (io.type === 'host') { - const { id } = io; - this.Hosts = this.Hosts.filter((a) => a?.id !== id); - } - } - - load() { - if (this.cluster) { - if (this.initFlag) return; - this.initFlag = true; - - if (typeof this.cluster.hostcomponent === 'string' ) { - this.service - .load(this.cluster.hostcomponent) - .pipe(this.takeUntil()) - .subscribe((raw: IRawHosComponent) => this.init(raw)); - } else { - this.init(this.cluster.hostcomponent); - } - } - } - - init(raw: IRawHosComponent) { - if (raw?.host) this.Hosts = raw.host.map((h) => new HostTile(h)); - - if (raw?.component) - this.Components = [...this.Components, ...this.service.fillComponent(raw.component, this.actionParameters)]; - - if (raw?.hc) { - this.initFlag = false; - this.statePost.update(raw.hc); - this.loadPost.update(raw.hc); - this.service.setRelations(raw.hc, this.Components, this.Hosts, this.actionParameters); - this.service.fillHost(this.Hosts, this.actionParameters); - } - - if (this.cluster?.id) { - this.getAddedServices() - .pipe(this.takeUntil()) - .subscribe((res) => this.addedServices = res.map((service) => service.prototype_id)); - } - - this.service.formFill(this.Components, this.Hosts, this.form); - } - - clearServiceFromHost(data: { relation: CompTile; model: HostTile }) { - this.service.divorce([data.relation, data.model], this.Components, this.Hosts, this.statePost, this.form); - } - - clearHostFromService(data: { relation: HostTile; model: CompTile }) { - this.service.divorce([data.model, data.relation], this.Components, this.Hosts, this.statePost, this.form); - } - - selectHost(host: HostTile) { - const stream = { - linkSource: this.Components, - link: getSelected(this.Components), - selected: getSelected(this.Hosts), - }; - this.service.next(host, stream, this.Components, this.Hosts, this.statePost, this.loadPost, this.form, this.addedServices); - } - - selectService(component: CompTile) { - const stream = { - linkSource: this.Hosts, - link: getSelected(this.Hosts), - selected: getSelected(this.Components), - }; - this.service.next(component, stream, this.Components, this.Hosts, this.statePost, this.loadPost, this.form, this.addedServices); - } - - save() { - this.saveFlag = true; - const { id, hostcomponent } = this.cluster; - this.service.save(id, hostcomponent, this.statePost.data).subscribe((data) => { - this.loadPost.update(data); - this.statePost.update(data); - this.saveResult.emit(data); - this.saveFlag = false; - this.channel.next(keyChannelStrim.notifying, 'Successfully saved.'); - }); - } - - restore() { - const ma = (a: Tile): void => { - a.isSelected = false; - a.isLink = false; - a.relations = []; - }; - - this.Hosts.forEach(ma); - this.Components.forEach(ma); - - this.statePost.clear(); - this.statePost.update(this.loadPost.data); - - this.service.setRelations(this.loadPost.data, this.Components, this.Hosts, this.actionParameters); - this.form = new FormGroup({}); - this.service.formFill(this.Components, this.Hosts, this.form); - } -} diff --git a/web/src/app/shared/host-components-map/take.service.spec.ts b/web/src/app/shared/host-components-map/take.service.spec.ts deleted file mode 100644 index 966fae5854..0000000000 --- a/web/src/app/shared/host-components-map/take.service.spec.ts +++ /dev/null @@ -1,159 +0,0 @@ -// Licensed 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 { TestBed } from '@angular/core/testing'; -import { MatDialog } from '@angular/material/dialog'; -import { IActionParameter, IComponent } from '@app/core/types'; - -import { ApiService } from '../../core/api'; -import { AddService } from '../add-component/add.service'; -import { disableHost, isExist, TakeService } from './take.service'; -import { ComponentFactory } from './test'; -import { CompTile, HostTile } from './types'; - -const ctData: IComponent = ComponentFactory(1, 1)[0]; - -describe('HostComponentsMap :: TakeService', () => { - let service: TakeService; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - { provide: ApiService, useValue: {} }, - { provide: AddService, useValue: {} }, - { provide: MatDialog, useValue: {} }, - TakeService, - ], - }); - service = TestBed.inject(TakeService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - it('fillHost should return Hostile[] with the disabled=false property, if action parameters is null', () => { - const hosts = [{ id: 1, name: 'host_1', relations: [], disabled: false }]; - expect(service.fillHost(hosts)).toEqual([{ id: 1, name: 'host_1', disabled: false, relations: [] }]); - }); - - /** - * the Expand operation - * host must be disabled if all components are installed on it - */ - it('if there is the component on the host then host needs to be disabled for expand', () => { - const ap: IActionParameter[] = [{ service: 'service_1', component: 'component_2', action: 'add' }]; - const relations: CompTile[] = ComponentFactory(2, 1).map(a => new CompTile(a)); - const host: HostTile = { id: 1, name: 'name', relations, disabled: false }; - expect(isExist(relations, ap)).toBeTrue(); - expect(disableHost(host, ap)).toBeTrue(); - }); - - /** - * the Srink operation - * host must be disabled if components aren't installed on it - */ - it('if there is not the component on the host then host needs to be disabled for shrink', () => { - const ap: IActionParameter[] = [{ service: 'service_1', component: 'component_3', action: 'remove' }]; - const relations: CompTile[] = ComponentFactory(2, 1).map(a => new CompTile(a)); - const host: HostTile = { id: 1, name: 'name', relations, disabled: false }; - expect(isExist(relations, ap)).toBeFalse(); - expect(disableHost(host, ap)).toBeTrue(); - }); - - it('validateConstraints fn should be null if argument is null', () => { - const mCompTile = new CompTile(ctData); - expect(service.validateConstraints(mCompTile, 0)()).toBeNull(); - }); - - it('validateConstraints fn for Component.constrant = [0, 1] to be null', () => { - const d = { ...ctData, constraint: [0, 1] }; - const mCompTile = new CompTile(d); - expect(service.validateConstraints(mCompTile, 0)()).toBeNull(); - }); - - it('validateConstraints fn for Component.constrant = [0, +] to be null', () => { - const d = { ...ctData, constraint: [0, '+'] }; - const mCompTile = new CompTile(d); - expect(service.validateConstraints(mCompTile, 0)()).toBeNull(); - }); - - it('validateConstraints fn for Component.constrant = [1]', () => { - const d = { ...ctData, constraint: [1] }; - const mCompTile = new CompTile(d); - expect(service.validateConstraints(mCompTile, 0)()).toEqual({ error: 'Exactly 1 component should be installed' }); - }); - - it('validateConstraints fn for Component.constrant = [1, 2]', () => { - const d = { ...ctData, constraint: [1, 2] }; - const mCompTile = new CompTile(d); - expect(service.validateConstraints(mCompTile, 0)()).toEqual({ error: 'Must be installed at least 1 components.' }); - }); - - it('validateConstraints fn for Component.constrant = [1, +]', () => { - const d = { ...ctData, constraint: [1, '+'] }; - const mCompTile = new CompTile(d); - expect(service.validateConstraints(mCompTile, 0)()).toEqual({ error: 'Must be installed at least 1 components.' }); - }); - - it('validateConstraints fn for Component.constrant = [odd]', () => { - const d = { ...ctData, constraint: ['odd'] }; - const mCompTile = new CompTile(d); - expect(service.validateConstraints(mCompTile, 0)()).toEqual({ - error: 'One or more component should be installed. Total amount should be odd.', - }); - }); - - it('validateConstraints fn for Component.constrant = [1, odd]', () => { - const d = { ...ctData, constraint: [1, 'odd'] }; - const mCompTile = new CompTile(d); - expect(service.validateConstraints(mCompTile, 0)()).toEqual({ - error: 'Must be installed at least 1 components. Total amount should be odd.', - }); - }); - - it('validateConstraints fn for Component { constrant: [3, odd], relations: [{}]} => Must be installed at least 3 components. Total amount should be odd.', () => { - const d = { ...ctData, constraint: [3, 'odd'] }; - const mCompTile = new CompTile(d); - mCompTile.relations = [{ id: 0, name: 'test', relations: [], color: 'none', disabled: false }]; - expect(service.validateConstraints(mCompTile, 0)()).toEqual({ - error: 'Must be installed at least 3 components. Total amount should be odd.', - }); - }); - - it('validateConstraints fn for Component { constrant: [0, odd], relations: [{}, {}]} => Must be installed at least 0 components. Total amount should be odd.', () => { - const d = { ...ctData, constraint: [0, 'odd'] }; - const mCompTile = new CompTile(d); - (mCompTile.relations = [ - { id: 0, name: 'test', relations: [], color: 'none', disabled: false }, - { id: 1, name: 'test', relations: [], color: 'none', disabled: false }, - ]), - expect(service.validateConstraints(mCompTile, 0)()).toEqual({ error: 'Must be installed at least 0 components. Total amount should be odd.' }); - }); - - it('validateConstraints fn for Component { constrant: [1, odd], relations: [{}]}] tobe null', () => { - const d = { ...ctData, constraint: [1, 'odd'] }; - const mCompTile = new CompTile(d); - mCompTile.relations = [{ id: 0, name: 'test', relations: [], color: 'none', disabled: false }]; - expect(service.validateConstraints(mCompTile, 0)()).toBeNull(); - }); - - it('validateConstraints fn for Component.constrant = [+]', () => { - const d = { ...ctData, constraint: ['+'] }; - const mCompTile = new CompTile(d); - //compone.Hosts = [{ id: 0, name: 'test', relations: [], color: 'none', disabled: false }]; - expect(service.validateConstraints(mCompTile, 1)()).toEqual({ - error: 'Component should be installed on all hosts of cluster.', - }); - }); -}); diff --git a/web/src/app/shared/host-components-map/take.service.ts b/web/src/app/shared/host-components-map/take.service.ts deleted file mode 100644 index b5b2c1cee0..0000000000 --- a/web/src/app/shared/host-components-map/take.service.ts +++ /dev/null @@ -1,346 +0,0 @@ -// Licensed 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 { Injectable } from '@angular/core'; -import { FormControl, FormGroup, ValidationErrors } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; -import { ApiService } from '@app/core/api'; -import { IComponent, IActionParameter, IRequires } from '@app/core/types'; -import { filter, map, switchMap, take } from 'rxjs/operators'; - -import { AddService } from '../add-component/add.service'; -import { DialogComponent } from '../components'; -import { DependenciesComponent } from './dependencies.component'; -import { - CompTile, - TConstraint, - HostTile, - IRawHosComponent, - IStream, - Post, - StatePost, - Tile, - PrototypePost -} from './types'; - -export const getSelected = (from: Tile[]): Tile => from.find((a) => a.isSelected); - -const isShrink = (ap: IActionParameter[]): boolean => ap.every((a) => a.action === 'remove'); - -const isExpand = (ap: IActionParameter[]): boolean => ap.every((a) => a.action === 'add'); - -const accord = (a: IActionParameter): ((b: CompTile) => boolean) => (b: CompTile): boolean => - b.component === `${a.service}/${a.component}`; - -export const isExist = (rel: CompTile[], ap: IActionParameter[]): boolean => - isShrink(ap) ? ap.some((a) => rel.some(accord(a))) : ap.every((a) => rel.some(accord(a))); - -export const disableHost = (h: HostTile, ap: IActionParameter[]): boolean => - ap ? (isExist(h.relations as CompTile[], ap) ? isExpand(ap) : isShrink(ap)) : false; - -//#region user click - -const checkConstraint = (c: TConstraint, r: number): boolean => { - if (!c?.length) return true; - const v = c[c.length - 1]; - return v === '+' || v === 'odd' || v > r || v === 'depend'; -}; - -const flag = (host_id: number, com: CompTile, load: StatePost): boolean => - load.data.some((a) => a.component_id === com.id && a.service_id === com.service_id && a.host_id === host_id); - -const checkActions = (host_id: number, com: CompTile, action: 'add' | 'remove', load: StatePost): boolean => { - if (com.actions?.length) { - if (action === 'remove') return flag(host_id, com, load) ? com.actions.some((a) => a === 'remove') : true; - if (action === 'add') return flag(host_id, com, load) ? true : com.actions.some((a) => a === 'add'); - } else return true; -}; - -const findDependencies = (c: CompTile, cs: CompTile[]): CompTile[] => { - const r = - c.requires?.reduce<{ prototype_id: number }[]>( - (p, a) => [...p, ...a.components.map((b) => ({ prototype_id: b.prototype_id }))], - [] - ) || []; - return cs.filter((a) => r.some((b) => b.prototype_id === a.prototype_id)); -}; - -const checkDependencies = (c: CompTile, cs: CompTile[]): void => - findDependencies(c, cs).forEach((a) => (a.limit = a.limit ? [...a.limit, 'depend'] : ['depend'])); - -const checkRequiredComponents = (chosenComponent: CompTile, availableComponents: CompTile[]): IRequires[] => - chosenComponent.requires.reduce((p, currentRequire) => - (currentRequire.components.every((requireComponent) => availableComponents.some((availableComponent) => availableComponent.prototype_id === requireComponent.prototype_id)) ? p : [...p, currentRequire]), [] - ); - -const checkRequiredServices = (chosenComponent: CompTile, addedServices: number[]): IRequires[] => - chosenComponent.requires.reduce((p, currentRequire) => (addedServices.includes(currentRequire.prototype_id) ? p : [...p, currentRequire]), []); - -//#endregion -@Injectable() -export class TakeService { - constructor(private api: ApiService, private dialog: MatDialog, private add: AddService) {} - - //#region ----- HttpClient ------ - load(url: string) { - return this.api.get(url); - } - - save(cluster_id: number, hostcomponent: string | IRawHosComponent, hc: Post[]) { - const send = { cluster_id, hc }; - return this.api.post(hostcomponent as string, send).pipe(take(1)); - } - //#endregion - - //#region after a successful download, run and fill in - - /** - * Mapping backend source hosts to detect `disabled` properties based on action parameters, if present - */ - fillHost(hosts: HostTile[], ap?: IActionParameter[]): HostTile[] { - return hosts.map((h) => ({ ...h, disabled: disableHost(h, ap) })); - } - - fillComponent(pc: IComponent[], ap: IActionParameter[]) { - return pc.map( - (c) => - new CompTile( - c, - ap ? ap.filter((a) => a?.service === c?.service_name && a?.component === c?.name).map((b) => b.action) : null - ) - ); - } - - setRelations(rel: Post[], cs: CompTile[], hs: HostTile[], ap: IActionParameter[]) { - rel.forEach((p) => { - const host = hs.find((h) => h.id === p.host_id), - component = cs.find((s) => s.id === p.component_id); - if (host && component) { - if (ap) { - component.relations = [...component.relations, host]; - const clone_component = { ...component }; - clone_component.disabled = component.actions.every((k) => k !== 'remove'); - host.relations = [...host.relations, clone_component]; - } else { - host.relations = [...host.relations, component]; - component.relations = [...component.relations, host]; - } - } - }); - } - //#endregion - - //#region FormGrop and validation for Components - formFill(components: CompTile[], hosts: HostTile[], form: FormGroup) { - components.map((a) => - form.addControl( - `${a.service_id}/${a.id}`, - new FormControl(a.relations.length, this.validateConstraints(a, hosts.length)) - ) - ); - } - - /** - * ``` - https://docs.arenadata.io/adcm/sdk/config.html#components - [1] – exactly once component shoud be installed; - [0,1] – one or zero component shoud be installed; - [1,2] – one or two component shoud be installed; - [0,+] – zero or any more component shoud be installed (default value); - [1,odd] – one or more component shoud be installed; total amount should be odd - [0,odd] – zero or more component shoud be installed; if more than zero, total amount should be odd - [odd] – the same as [1,odd] - [1,+] – one or any more component shoud be installed; - [+] – component shoud be installed on all hosts of cluster. - ``` - */ - validateConstraints(component: CompTile, hostLength: number) { - const getError = (constraint: TConstraint, relations: HostTile[]) => { - if (!constraint?.length) return null; - const [a1, a2, a3] = constraint; - const countRelations = relations.length; - const depend = () => - relations.some((a) => a.relations.some((b) => b.id === component.id)) - ? null - : 'Must be installed because it is a dependency of another component'; - if (a3 && a3 === 'depend') return depend(); - else if (a2) { - switch (a2) { - case 'depend': - return depend(); - case 'odd': - return ((a1 === 0 && countRelations === 0) || countRelations % 2) && (countRelations >= a1) - ? null - : `Must be installed at least ${a1} components. Total amount should be odd.`; - case '+': - default: - return countRelations < a1 ? `Must be installed at least ${a1} components.` : null; - } - } else { - switch (a1) { - case 0: - return null; - case 'depend': - return depend(); - case '+': - return countRelations < hostLength ? 'Component should be installed on all hosts of cluster.' : null; - case 'odd': - return countRelations % 2 ? null : 'One or more component should be installed. Total amount should be odd.'; - default: - return countRelations !== a1 ? `Exactly ${a1} component should be installed` : null; - } - } - }; - return (): ValidationErrors => { - const { limit, relations } = component; - if (limit) { - const error = getError(limit, relations); - return error ? { error } : null; - } - return null; - }; - } - - setFormValue(c: CompTile, form: FormGroup) { - form.controls[`${c.service_id}/${c.id}`].setValue(c.relations); - } - - //#endregion - - //#region Removing links and dependencies - - clearDependencies(comp: CompTile, state: StatePost, cs: CompTile[], hs: HostTile[], form: FormGroup) { - const getLimitsFromState = (prototype_id: number) => cs.find((b) => b.prototype_id === prototype_id).limit; - if (comp.requires?.length) { - findDependencies(comp, cs).forEach((a) => { - a.limit = getLimitsFromState(a.prototype_id); - a.notification = ''; - }); - - state.data.map((a) => - checkDependencies( - cs.find((b) => b.id === a.component_id), - cs - ) - ); - - form.reset(); - this.formFill(cs, hs, form); - } - } - - //#endregion - - //#region handler user events - divorce(both: [CompTile, HostTile], cs: CompTile[], hs: HostTile[], state: StatePost, form: FormGroup) { - const [component, host] = both; - - component.isLink = false; - component.relations = component.relations.filter((r) => r.id !== host.id); - host.isLink = false; - host.relations = host.relations.filter((r) => r.id !== component.id); - - state.delete(this.containsPrototype(component, host)); - this.clearDependencies(component, state, cs, hs, form); - this.setFormValue(component, form); - } - - next( - target: Tile, - stream: IStream, - cs: CompTile[], - hs: HostTile[], - state: StatePost, - load: StatePost, - form: FormGroup, - addedServices: number[] - ) { - stream.linkSource.forEach((s) => (s.isLink = false)); - if (stream.selected) stream.selected.isSelected = false; - - if (stream.link) this.handleLink(stream.link, target, state, cs, hs, load, form, addedServices); - else if (stream.selected !== target) { - target.isSelected = true; - target.relations.forEach( - (e) => (stream.linkSource.find((s) => s.name === e.name && s.id === e.id).isLink = true) - ); - } - } - - handleLink( - link: Tile, - target: Tile, - state: StatePost, - cs: CompTile[], - hs: HostTile[], - load: StatePost, - form: FormGroup, - addedServices: number[] - ) { - const isComp = target instanceof CompTile; - const component = (isComp ? target : link) as CompTile; - const host = isComp ? link : target; - - if (link.relations.find((e) => e.id === target.id)) { - if (checkActions(host.id, component, 'remove', load)) this.divorce([component, host], cs, hs, state, form); - return; - } else if (checkConstraint(component.limit, component.relations.length)) { - if (!checkActions(host.id, component, 'add', load)) return; - if (component.requires?.length) { - const requiredComponents = checkRequiredComponents(component, cs); - const requiredServices = checkRequiredServices(component, addedServices); - const requires = [...new Set(requiredServices.concat(requiredComponents))] - - if (requires.length) { - this.dialog4Requires(requires); - return; - } else { - checkDependencies(component, cs); - form.reset(); - this.formFill(cs, hs, form); - } - } - link.relations.push(target); - target.relations.push(link); - target.isLink = true; - state.add(this.containsPrototype(component, host)); - } - this.setFormValue(component, form); - } - - dialog4Requires(model: IRequires[]) { - this.dialog - .open(DialogComponent, { - data: { - title: 'This component cannot be installed without the following dependencies.', - component: DependenciesComponent, - model, - controls: ['Add All', 'Cancel'], - }, - }) - .beforeClosed() - .pipe( - filter((a) => a), - map((_) => model.map((a) => ({ prototype_id: a.prototype_id }))), - switchMap((result) => this.add.addService(result)) - ) - .subscribe(); - } - - containsPrototype(component, host) { - if (component?.is_prototype) { - return new PrototypePost(host.id, component.service_id, component.id); - } - - return new Post(host.id, component.service_id, component.id) - } - //#endregion -} diff --git a/web/src/app/shared/host-components-map/test/index.ts b/web/src/app/shared/host-components-map/test/index.ts deleted file mode 100644 index face4ed7ff..0000000000 --- a/web/src/app/shared/host-components-map/test/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed 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 { IComponent, IRequires } from '@app/core/types'; -import { newArray } from '@app/core/types/func'; - -import { Post, TConstraint } from '../types'; - -export class HCmRequires implements IRequires { - name: string; - display_name: string; - components?: IRequires[]; - constructor(public prototype_id: number) { - this.name = `name_${prototype_id}`; - this.display_name = `component_display_name_${prototype_id}`; - } -} - -export class HostComponent { - id: number; - host_id: number; - service_id: number; - component_id: number; -} - -export class HcmHost { - constructor(public fqdn: string, public id: number) {} -} - -export class HCmComponent { - name: string; - display_name: string; - service_name: string; - service_state = 'created'; - prototype_id: number; - constraint: TConstraint = null; - requires: HCmRequires[]; - constructor(public id: number, public service_id: number) { - this.prototype_id = id; - this.name = `component_${id}`; - this.display_name = `component_display_name_${id}`; - this.service_name = `service_${service_id}`; - } -} - -/** - * Array with specific service id and components with id by index [1, count] - * see: class HCmComponent -*/ -export const ComponentFactory = (count: number, service_id: number): IComponent[] => - newArray(count, (_, i) => new HCmComponent(i + 1, service_id) as IComponent); - -export const HCFactory = (host_id: number, service_id: number, components: number): Post[] => - newArray(components, (_, i) => new Post(host_id, service_id, i + 1, i + 1)); diff --git a/web/src/app/shared/host-components-map/types.ts b/web/src/app/shared/host-components-map/types.ts deleted file mode 100644 index ae7259310a..0000000000 --- a/web/src/app/shared/host-components-map/types.ts +++ /dev/null @@ -1,168 +0,0 @@ -// Licensed 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 { IComponent, Host, IRequires } from '@app/core/types'; - -export type ActionParam = 'add' | 'remove'; -export type TConstraintValue = number | '+' | 'odd' | 'depend'; -export type TConstraint = TConstraintValue[]; - -export interface IRawHosComponent { - component: IComponent[]; - host: Partial[]; - hc: Post[]; -} - -export interface Post { - id?: number; - host_id: number; - service_id: number; - component_id?: number; -} - -export interface PrototypePost extends Post { - component_prototype_id: number; -} - -export class Post implements Post { - constructor(public host_id: number, public service_id: number, public component_id?: number, public id?: number ) {} -} - -export class PrototypePost implements Post { - constructor(public host_id: number, public service_id: number, public component_prototype_id: number, public id?: number ) {} -} - -/** - *``` - { - id: number; - name: string; - relations: Tile[] = []; - isSelected?: boolean; - isLink?: boolean; - limit?: Constraint; - disabled: boolean; - actions?: ActionParam[]; - color?: 'none' | 'white' | 'gray' | 'yellow'; - notification?: string; - } - ``` - * @class Tile - */ -export class Tile { - id: number; - name: string; - relations: Tile[] = []; - isSelected?: boolean; - isLink?: boolean; - limit?: TConstraint; - disabled: boolean; - actions?: ActionParam[]; - color?: 'none' | 'white' | 'gray' | 'yellow'; - notification?: string; - mm?: string; - is_prototype?: boolean; -} - -export class HostTile extends Tile { - constructor(rawHost: Partial) { - super(); - this.id = rawHost.id; - this.name = rawHost.fqdn; - this.mm = rawHost.maintenance_mode; - } -} - -export class CompTile extends Tile { - prototype_id: number; - service_id: number; - component: string; - requires: IRequires[]; - constructor(rawComponent: IComponent, public actions?: ActionParam[]) { - super(); - if (rawComponent) { - this.id = rawComponent.id; - this.service_id = rawComponent.service_id; - this.component = `${rawComponent.service_name}/${rawComponent.name}`; - this.name = rawComponent.display_name; - this.disabled = rawComponent.service_state !== 'created'; - this.limit = rawComponent.constraint; - this.requires = rawComponent.requires; - this.prototype_id = rawComponent.prototype_id; - } - this.is_prototype = this.isPrototype(rawComponent); - } - - isPrototype(component): boolean { - return component?.url?.includes('prototype') - } -} - -/** - * State user selection - * - * @class StatePost - */ -export class StatePost { - private _data: Post[]; - - constructor() { - this._data = []; - } - - private _compare(a: Post, b: Post) { - return a.host_id === b.host_id && a.service_id === b.service_id && a.component_id === b.component_id; - } - - get data() { - return this._data; - } - - add(post: Post) { - const f = this._data.find((p) => this._compare(p, post)); - if (!f) this._data.push(post); - else if (!f.id) f.id = post.id; - } - - delete(post: Post) { - this._data = this._data.filter((p) => !this._compare(p, post)); - } - - clear() { - this._data = []; - } - - update(data: Post[]) { - data.forEach((a) => this.add(this.containsPrototype(a))); - } - - containsPrototype(component): Post | PrototypePost { - if (component?.url?.includes('prototype')) { - return new PrototypePost(component.host_id, component.service_id, component.id); - } - - return new Post(component.host_id, component.service_id, component.component_id, component.id); - } -} -/** - *``` - { - link: Tile; - linkSource: Tile[]; - selected: Tile; - } - *``` - */ -export interface IStream { - link: Tile; - linkSource: Tile[]; - selected: Tile; -} diff --git a/web/src/app/shared/material.module.ts b/web/src/app/shared/material.module.ts deleted file mode 100644 index c4ca99fc4d..0000000000 --- a/web/src/app/shared/material.module.ts +++ /dev/null @@ -1,74 +0,0 @@ -// Licensed 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 { CdkTableModule } from '@angular/cdk/table'; -import { NgModule } from '@angular/core'; -import { MatAutocompleteModule } from '@angular/material/autocomplete'; -import { MatButtonModule } from '@angular/material/button'; -import { MatCardModule } from '@angular/material/card'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatDialogModule } from '@angular/material/dialog'; -import { MatExpansionModule } from '@angular/material/expansion'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { MatListModule } from '@angular/material/list'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatPaginatorModule } from '@angular/material/paginator'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatSelectModule } from '@angular/material/select'; -import { MatSidenavModule } from '@angular/material/sidenav'; -import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { MatSliderModule } from '@angular/material/slider'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; -import { MatSortModule } from '@angular/material/sort'; -import { MatStepperModule } from '@angular/material/stepper'; -import { MatTableModule } from '@angular/material/table'; -import { MatToolbarModule } from '@angular/material/toolbar'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { MatButtonToggleModule } from '@angular/material/button-toggle'; -import { MatDatepickerModule } from "@angular/material/datepicker"; -import { MatNativeDateModule } from "@angular/material/core"; - -@NgModule({ - exports: [ - MatStepperModule, - CdkTableModule, - MatSlideToggleModule, - MatToolbarModule, - MatSidenavModule, - MatMenuModule, - MatCardModule, - MatExpansionModule, - MatFormFieldModule, - MatSelectModule, - MatInputModule, - MatCheckboxModule, - MatButtonModule, - MatAutocompleteModule, - MatDialogModule, - MatTooltipModule, - MatSnackBarModule, - MatProgressSpinnerModule, - MatProgressBarModule, - MatIconModule, - MatListModule, - MatTableModule, - MatPaginatorModule, - MatSortModule, - MatSliderModule, - MatButtonToggleModule, - MatDatepickerModule, - MatNativeDateModule, - ], -}) -export class MaterialModule {} diff --git a/web/src/app/shared/pipes/break-row.pipe.spec.ts b/web/src/app/shared/pipes/break-row.pipe.spec.ts deleted file mode 100644 index 7f3927ba07..0000000000 --- a/web/src/app/shared/pipes/break-row.pipe.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed 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 { BreakRowPipe } from './break-row.pipe'; - -describe('BreakRowPipe', () => { - it('create an instance', () => { - const pipe = new BreakRowPipe(); - expect(pipe).toBeTruthy(); - }); -}); diff --git a/web/src/app/shared/pipes/break-row.pipe.ts b/web/src/app/shared/pipes/break-row.pipe.ts deleted file mode 100644 index 78e3fe30be..0000000000 --- a/web/src/app/shared/pipes/break-row.pipe.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed 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 { Pipe, PipeTransform } from '@angular/core'; -@Pipe({ - name: 'breakRow', -}) -export class BreakRowPipe implements PipeTransform { - transform(value: string, args?: any): any { - return value.replace(/\n|\\n/g, '
'); - } -} diff --git a/web/src/app/shared/pipes/false-as-empty-array/false-as-empty-array.module.ts b/web/src/app/shared/pipes/false-as-empty-array/false-as-empty-array.module.ts deleted file mode 100644 index 273360a16a..0000000000 --- a/web/src/app/shared/pipes/false-as-empty-array/false-as-empty-array.module.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { FalseAsEmptyArrayPipe } from './false-as-empty-array.pipe'; - - - -@NgModule({ - declarations: [ - FalseAsEmptyArrayPipe - ], - exports: [ - FalseAsEmptyArrayPipe - ], - imports: [ - CommonModule - ] -}) -export class FalseAsEmptyArrayModule { } diff --git a/web/src/app/shared/pipes/false-as-empty-array/false-as-empty-array.pipe.ts b/web/src/app/shared/pipes/false-as-empty-array/false-as-empty-array.pipe.ts deleted file mode 100644 index 70c3dfc5ad..0000000000 --- a/web/src/app/shared/pipes/false-as-empty-array/false-as-empty-array.pipe.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'falseAsEmptyArray' -}) -export class FalseAsEmptyArrayPipe implements PipeTransform { - - transform(value: any): any[] { - return !Array.isArray(value) ? [] : value; - } - -} diff --git a/web/src/app/shared/pipes/index.ts b/web/src/app/shared/pipes/index.ts deleted file mode 100644 index 8be27f259f..0000000000 --- a/web/src/app/shared/pipes/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed 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 * from './break-row.pipe'; -export * from './tag-esc.pipe'; diff --git a/web/src/app/shared/pipes/tag-esc.pipe.ts b/web/src/app/shared/pipes/tag-esc.pipe.ts deleted file mode 100644 index 79d9a12010..0000000000 --- a/web/src/app/shared/pipes/tag-esc.pipe.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed 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 { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'tagEsc', -}) -export class TagEscPipe implements PipeTransform { - transform(value: string, args?: any): any { - if (value) return value.replace(//g, '>').replace(/\\n/g, '
'); - } -} diff --git a/web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.html b/web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.html deleted file mode 100644 index 1e0e9519bd..0000000000 --- a/web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.html +++ /dev/null @@ -1,9 +0,0 @@ -
- -
\ No newline at end of file diff --git a/web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.scss b/web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.scss deleted file mode 100644 index c6ed78dad3..0000000000 --- a/web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -.limit-exceed { - color: #ff8c00; -} - -.limit-acceptable { - color: #78909c; -} \ No newline at end of file diff --git a/web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.ts b/web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.ts deleted file mode 100644 index ef92f44ffa..0000000000 --- a/web/src/app/shared/reset-login-attempts-button/reset-login-attempts-button.component.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ApiService } from '@app/core/api'; -import { RbacUserModel } from '@app/models/rbac/rbac-user.model'; -import { RbacUserService } from '@app/services/rbac-user.service'; -import { IConfig } from '../configuration/types'; - -const NO_FAILED_ATTEMPTS = 'There are no failed login attempts'; -const ATTEMPTS_EXCEEDED = 'Failed login attempts are exceeded. Reset to 0'; - -@Component({ - selector: 'app-reset-login-attempts-button', - templateUrl: './reset-login-attempts-button.component.html', - styleUrls: ['./reset-login-attempts-button.component.scss'] -}) -export class ResetLoginAttemptsButtonComponent implements OnInit { - loginAttemptsLimit: number; - tooltip: string = NO_FAILED_ATTEMPTS; - row: RbacUserModel; - - constructor( - protected rbacUserService: RbacUserService, - protected api: ApiService - ) { } - - get failedLoginAttempts() { - return this?.row?.failed_login_attempts; - } - - get limitClass(): string { - if (this.failedLoginAttempts === 0) { - this.tooltip = NO_FAILED_ATTEMPTS; - } else if (this.failedLoginAttempts >= this.loginAttemptsLimit) { - this.tooltip = ATTEMPTS_EXCEEDED; - return 'limit-exceed'; - } else if (this.failedLoginAttempts > 0 && this.failedLoginAttempts <= this.loginAttemptsLimit) { - this.tooltip = `Failed login attempts are ${this.failedLoginAttempts}. Reset to 0`; - return 'limit-acceptable'; - } - } - - get isDisabled() { - return !this.failedLoginAttempts || this.failedLoginAttempts === 0; - } - - ngOnInit() { - this.getGlobalSettings().subscribe((resp: IConfig) => { - this.loginAttemptsLimit = resp.config['auth_policy'].login_attempt_limit - }) - } - - resetFailureLoginAttempts(event) { - event.stopPropagation(); - event.preventDefault(); - this.rbacUserService.resetLoginAttemps(this.row.id).subscribe(() => { - this.tooltip = NO_FAILED_ATTEMPTS; - }); - } - - getGlobalSettings() { - return this.api.get('/api/v1/adcm/1/config/current/?noview'); - } -} diff --git a/web/src/app/shared/shared.module.ts b/web/src/app/shared/shared.module.ts deleted file mode 100644 index fd800411d9..0000000000 --- a/web/src/app/shared/shared.module.ts +++ /dev/null @@ -1,182 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { RouterModule } from '@angular/router'; -import { TranslateModule } from '@ngx-translate/core'; -import { MatTreeModule } from '@angular/material/tree'; -import { AddingModule } from './add-component/adding.module'; -import { UpgradeMasterComponent } from "@app/shared/components/upgrades/master/master.component"; -import { - ActionMasterComponent, - ButtonSpinnerComponent, - DialogComponent, - ExportComponent, - ImportComponent, - IssueInfoComponent, - MainInfoComponent, - StatusInfoComponent, - UpgradeComponent, -} from './components'; -import { ActionMasterConfigComponent } from './components/actions/master/action-master-config.component'; -import { MultiSortDirective } from './components/list/multi-sort.directive'; -import { ConfigurationModule } from './configuration/configuration.module'; -import { DetailsModule } from './details/details.module'; -import { HoverDirective } from './directives'; -import { FormElementsModule } from './form-elements/form-elements.module'; -import { HostComponentsMapModule } from './host-components-map/host-components-map.module'; -import { MaterialModule } from './material.module'; -import { BreakRowPipe, TagEscPipe } from './pipes'; -import { StuffModule } from './stuff.module'; -import { StatusColumnComponent } from '@app/components/columns/status-column/status-column.component'; -import { StateColumnComponent } from '@app/components/columns/state-column/state-column.component'; -import { EditionColumnComponent } from '@app/components/columns/edition-column/edition-column.component'; -import { ClusterColumnComponent } from '@app/components/columns/cluster-column/cluster-column.component'; -import { ServiceComponentsComponent } from '@app/components/service-component/service-components.component'; -import { JobService } from '@app/services/job.service'; -import { TaskService } from '@app/services/task.service'; -import { ToDataSourcePipe } from '@app/pipes/to-data-source.pipe'; -import { PickKeysPipe } from '@app/pipes/pick-keys.pipe'; -import { TranslateKeysPipe } from '@app/pipes/translate-object-keys.pipe'; -import { TooltipModule } from '@app/shared/components/tooltip/tooltip.module'; -import { StatusTreeComponent } from '@app/components/status-tree/status-tree.component'; -import { HostStatusComponent } from '@app/components/host/host-status/host-status.component'; -import { EntityStatusToStatusTreePipe } from '@app/pipes/entity-status-to-status-tree.pipe'; -import { ServiceStatusComponent } from '@app/components/service/service-status/service-status.component'; -import { ServiceComponentStatusComponent } from '@app/components/service-component/service-component-status/service-component-status.component'; -import { StatusTreeLinkPipe } from '@app/pipes/status-tree-link.pipe'; -import { RbacUserService } from '@app/services/rbac-user.service'; -import { RbacGroupService } from '@app/services/rbac-group.service'; -import { RbacRoleService } from '@app/services/rbac-role.service'; -import { RbacPolicyService } from '@app/services/rbac-policy.service'; -import { DynamicModule } from '@app/shared/directives/dynamic/dynamic.module'; -import { RbacObjectCandidateService } from '@app/services/rbac-object-candidate.service'; -import { UpgradeMasterConfigComponent } from "@app/shared/components/upgrades/master/upgrade-master-config.component"; -import { RbacAuditOperationsService } from "@app/services/rbac-audit-operations.service"; -import { HistoryColumnComponent } from "@app/components/columns/history-column/history-column.component"; -import { WrapperColumnComponent } from "@app/components/columns/wrapper-column/wrapper-column.component"; -import { - DownloadButtonColumnComponent -} from "@app/components/columns/download-button-column/download-button-column.component"; -import { RbacAuditLoginService } from "@app/services/rbac-audit-login.service"; -import { ResetLoginAttemptsButtonComponent } from "./reset-login-attempts-button/reset-login-attempts-button.component"; -import { SignatureColumnComponent } from "@app/components/columns/signature-column/signature-column.component"; - -@NgModule({ - imports: [ - CommonModule, - MaterialModule, - FormsModule, - ReactiveFormsModule, - RouterModule, - StuffModule, - FormElementsModule, - ConfigurationModule, - AddingModule, - HostComponentsMapModule, - DetailsModule, - TranslateModule, - TooltipModule, - MatTreeModule, - DynamicModule, - ], - declarations: [ - DialogComponent, - BreakRowPipe, - HoverDirective, - ButtonSpinnerComponent, - TagEscPipe, - IssueInfoComponent, - HostStatusComponent, - ServiceStatusComponent, - StatusInfoComponent, - MainInfoComponent, - MultiSortDirective, - ImportComponent, - ExportComponent, - ActionMasterComponent, - ActionMasterConfigComponent, - UpgradeMasterComponent, - UpgradeMasterConfigComponent, - StatusColumnComponent, - SignatureColumnComponent, - StateColumnComponent, - EditionColumnComponent, - ClusterColumnComponent, - ServiceComponentsComponent, - ServiceComponentStatusComponent, - ToDataSourcePipe, - PickKeysPipe, - TranslateKeysPipe, - StatusTreeComponent, - EntityStatusToStatusTreePipe, - StatusTreeLinkPipe, - HistoryColumnComponent, - WrapperColumnComponent, - DownloadButtonColumnComponent, - ResetLoginAttemptsButtonComponent, - ], - exports: [ - FormsModule, - ReactiveFormsModule, - MaterialModule, - StuffModule, - FormElementsModule, - ConfigurationModule, - AddingModule, - HostComponentsMapModule, - DetailsModule, - DialogComponent, - BreakRowPipe, - HoverDirective, - ButtonSpinnerComponent, - UpgradeComponent, - TagEscPipe, - HostStatusComponent, - ServiceStatusComponent, - StatusInfoComponent, - MainInfoComponent, - ImportComponent, - ExportComponent, - StatusColumnComponent, - SignatureColumnComponent, - StateColumnComponent, - EditionColumnComponent, - ClusterColumnComponent, - ServiceComponentsComponent, - ServiceComponentStatusComponent, - ToDataSourcePipe, - PickKeysPipe, - TranslateKeysPipe, - TooltipModule, - StatusTreeComponent, - EntityStatusToStatusTreePipe, - StatusTreeLinkPipe, - HistoryColumnComponent, - WrapperColumnComponent, - DownloadButtonColumnComponent, - ResetLoginAttemptsButtonComponent - ], - providers: [ - JobService, - TaskService, - RbacUserService, - RbacGroupService, - RbacRoleService, - RbacPolicyService, - RbacAuditOperationsService, - RbacAuditLoginService, - RbacObjectCandidateService, - ], -}) -export class SharedModule {} diff --git a/web/src/app/shared/stuff.module.ts b/web/src/app/shared/stuff.module.ts deleted file mode 100644 index aea995e168..0000000000 --- a/web/src/app/shared/stuff.module.ts +++ /dev/null @@ -1,113 +0,0 @@ -// Licensed 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 { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; - -import { ActionsComponent, CrumbsComponent, UpgradeComponent } from './components'; -import { ActionListComponent } from './components/actions/action-list/action-list.component'; -import { ActionsDirective } from './components/actions/actions.directive'; -import { UpgradesDirective } from './components/upgrades/upgrade.directive'; -import { TooltipDirective } from '@app/shared/components/tooltip'; -import { PopoverDirective } from '@app/directives/popover.directive'; -import { - BaseDirective, - ForTestDirective, - InfinityScrollDirective, - MTextareaDirective, - ScrollDirective, - SocketListenerDirective -} from './directives'; -import { MaterialModule } from './material.module'; -import { MenuItemComponent } from './components/actions/action-list/menu-item/menu-item.component'; -import { PopoverComponent } from '@app/components/popover/popover.component'; -import { KeysPipe } from '@app/pipes/keys.pipe'; -import { IsArrayPipe } from '@app/pipes/is-array.pipe'; -import { IssuePathPipe } from '@app/pipes/issue-path.pipe'; -import { ConcernComponent } from '@app/components/concern/concern.component'; -import { ConcernService } from '@app/services/concern.service'; -import { ConcernItemComponent } from '@app/components/concern/concern-item/concern-item.component'; -import { IssueMessagePlaceholderPipe } from '@app/pipes/issue-message-placeholder.pipe'; -import { ConcernListComponent } from '@app/components/concern/concern-list/concern-list.component'; -import { ConcernListRefComponent } from '@app/components/concern/concern-list-ref/concern-list-ref.component'; -import { TooltipModule } from '@app/shared/components/tooltip/tooltip.module'; -import { HasSelectedPipe } from '@app/pipes/has-selected.pipe'; -import { ActionsButtonComponent } from "@app/components/actions-button/actions-button.component"; - -@NgModule({ - declarations: [ - ForTestDirective, - MTextareaDirective, - BaseDirective, - SocketListenerDirective, - CrumbsComponent, - UpgradeComponent, - ScrollDirective, - InfinityScrollDirective, - ActionsComponent, - ActionsDirective, - UpgradesDirective, - ActionListComponent, - MenuItemComponent, - PopoverDirective, - PopoverComponent, - ConcernComponent, - ConcernItemComponent, - IssueMessagePlaceholderPipe, - ConcernListComponent, - ConcernListRefComponent, - KeysPipe, - IsArrayPipe, - HasSelectedPipe, - IssuePathPipe, - ActionsButtonComponent, - ], - imports: [ - CommonModule, - MaterialModule, - RouterModule, - TooltipModule - ], - exports: [ - ForTestDirective, - TooltipDirective, - MTextareaDirective, - BaseDirective, - SocketListenerDirective, - CrumbsComponent, - UpgradeComponent, - ScrollDirective, - InfinityScrollDirective, - ActionsComponent, - ActionsDirective, - UpgradesDirective, - ActionListComponent, - MenuItemComponent, - PopoverDirective, - PopoverComponent, - ConcernComponent, - ConcernItemComponent, - IssueMessagePlaceholderPipe, - ConcernListComponent, - KeysPipe, - IsArrayPipe, - HasSelectedPipe, - IssuePathPipe, - ConcernListRefComponent, - TooltipModule, - ActionsButtonComponent - ], - providers: [ - ConcernService, - ], -}) -export class StuffModule {} diff --git a/web/src/app/shared/translate/intializer.ts b/web/src/app/shared/translate/intializer.ts deleted file mode 100644 index 2d2504d57f..0000000000 --- a/web/src/app/shared/translate/intializer.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { TranslateHttpLoader } from '@ngx-translate/http-loader'; -import { TranslateService } from '@ngx-translate/core'; -import { Injector } from '@angular/core'; -import { LOCATION_INITIALIZED } from '@angular/common'; - -export function translateLoader(http: HttpClient) { - return new TranslateHttpLoader(http, './assets/i18n/static/', '.json'); -} - -export function appInitializer(translate: TranslateService, injector: Injector) { - return () => new Promise( - (resolve: any) => { - const locationInitialized = injector.get(LOCATION_INITIALIZED, Promise.resolve(null)); - locationInitialized.then( - () => { - const langToSet = 'en'; - translate.setDefaultLang('en'); - translate.use(langToSet).subscribe( - () => { }, - (e) => console.error('Error while changing the currently used language', e), - () => { - resolve(null); - }); - }, - (e) => console.error('Error initializing location', e)); - }); -} diff --git a/web/src/app/shared/validators/custom-validators.ts b/web/src/app/shared/validators/custom-validators.ts deleted file mode 100644 index 1c645a0bcd..0000000000 --- a/web/src/app/shared/validators/custom-validators.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { AbstractControl, ValidationErrors } from '@angular/forms'; -import { isEmptyObject } from '../../core/types'; - -export class CustomValidators { - static required(control: T): ValidationErrors | null { - const value = control.value; - const error = { 'required': true }; - if (!value) { - return error; - } - - if (typeof value === 'string' && value.trim() === '') { - return error; - } - - if (Array.isArray(value) && value.length === 0) { - return error; - } - - if (isEmptyObject(value)) { - return error; - } - - return null; - } - -} diff --git a/web/src/app/store/navigation/navigation-effects.ts b/web/src/app/store/navigation/navigation-effects.ts deleted file mode 100644 index 8a35335f5a..0000000000 --- a/web/src/app/store/navigation/navigation-effects.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { concatMap, filter, map, switchMap, take } from 'rxjs/operators'; -import { Observable } from 'rxjs'; -import { AdcmEntity, AdcmTypedEntity } from '@app/models/entity'; -import { TypeName } from '@app/core/types'; -import { Action, Store } from '@ngrx/store'; - -import { ApiService } from '@app/core/api'; -import { ServiceComponentService } from '@app/services/service-component.service'; -import { ClusterService } from '@app/core/services/cluster.service'; -import { EntityNames } from '@app/models/entity-names'; -import { - getEventEntityType, - getNavigationPath, - getPath, - setPath, - setPathOfRoute -} from '@app/store/navigation/navigation.store'; -import { EventMessage, socketResponse } from '@app/core/store/sockets/socket.reducer'; -import { IClusterService } from '@app/models/cluster-service'; -import { ConfigGroupListService } from '@app/config-groups/service/config-group-list.service'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - -@Injectable() -export class NavigationEffects { - - setPathOfRoute$ = createEffect( - () => - this.actions$.pipe( - ofType(setPathOfRoute), - filter(action => !!action.params), - switchMap(action => { - const getters: Observable[] = action.params.keys?.reduce((acc, param) => { - const getter = this.entityGetter(param as TypeName, +action.params.get(param)); - if (getter) { - acc.push(getter); - } - - return acc; - }, []); - return getPath(getters); - }), - ), - ); - - changePathOfEvent$ = createEffect(() => this.actions$.pipe( - ofType(socketResponse), - filter(action => - [ConcernEventType.Service, ConcernEventType.Cluster, ConcernEventType.Host, ConcernEventType.HostProvider, ConcernEventType.ServiceComponent].includes(action.message.object.type as any) - ), - concatMap((event: { message: EventMessage }) => { - return new Observable(subscriber => { - this.store.select(getNavigationPath).pipe(take(1)).subscribe((path) => { - if (path?.some(item => item.typeName === getEventEntityType(event.message.object.type) && event.message.object.id === item.id)) { - this.entityGetter(getEventEntityType(event.message.object.type), event.message.object.id) - .subscribe((entity) => { - subscriber.next(setPath({ - path: path.reduce((acc, item) => - acc.concat(getEventEntityType(event.message.object.type) === item.typeName && item.id === event.message.object.id ? entity : item), []), - })); - subscriber.complete(); - }, () => subscriber.complete()); - } else { - subscriber.complete(); - } - }, () => subscriber.complete()); - }); - }), - )); - - constructor( - private actions$: Actions, - private api: ApiService, - private serviceComponentService: ServiceComponentService, - private store: Store, - private clusterService: ClusterService, - private configGroupService: ConfigGroupListService - ) {} - - entityGetter(type: TypeName, id: number): Observable { - const entityToTypedEntity = (getter: Observable, typeName: TypeName) => getter.pipe( - map(entity => ({ - ...entity, - typeName, - } as AdcmTypedEntity)) - ); - - if (EntityNames.includes(type)) { - if (type === 'bundle') { - return entityToTypedEntity( - this.clusterService.one_bundle(id), - type, - ); - } else if (type === 'servicecomponent' || type === 'component') { - return entityToTypedEntity( - this.serviceComponentService.get(id), - type, - ); - } - if (type === 'service') { - return entityToTypedEntity( - this.api.getOne(type, id), - type, - ).pipe(switchMap((entity) => { - return this.api.getOne('cluster', (entity as any as IClusterService).cluster_id) - .pipe(map(cluster => ({ ...entity, cluster }))); - })); - } else if (type === 'group_config') { - return entityToTypedEntity( - this.configGroupService.get(id), - type, - ); - } else { - return entityToTypedEntity( - this.api.getOne(type, id), - type, - ); - } - } - } - -} diff --git a/web/src/app/store/navigation/navigation.store.ts b/web/src/app/store/navigation/navigation.store.ts deleted file mode 100644 index a0f7d1b6e5..0000000000 --- a/web/src/app/store/navigation/navigation.store.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - Action, - createAction, - createFeatureSelector, - createReducer, - createSelector, - on, - props, -} from '@ngrx/store'; -import { ParamMap } from '@angular/router'; -import { map } from 'rxjs/operators'; -import { Observable, zip } from 'rxjs'; - -import { AdcmTypedEntity } from '@app/models/entity'; -import { TypeName } from '@app/core/types'; -import { ConcernEventType } from '@app/models/concern/concern-reason'; - - -export const setPath = createAction('[Navigation] Set path', props<{ path: AdcmTypedEntity[] }>()); -export const setPathOfRoute = createAction('[Navigation] Set path', props<{ params: ParamMap }>()); - -export interface NavigationState { - path: AdcmTypedEntity[]; -} - -const initialState: NavigationState = { - path: [], -}; - -const reducer = createReducer( - initialState, - on(setPath, (state, { path }) => ({ path })), -); - -export function navigationReducer(state: NavigationState, action: Action) { - return reducer(state, action); -} - -export const getNavigationState = createFeatureSelector('navigation'); -export const getNavigationPath = createSelector( - getNavigationState, - state => state.path -); - -export function getEventEntityType(type: string): TypeName { - switch (type) { - case 'component': - return 'servicecomponent'; - case ConcernEventType.Cluster: - return 'cluster'; - case ConcernEventType.Service: - return 'service'; - case ConcernEventType.ServiceComponent: - return 'servicecomponent'; - case ConcernEventType.Host: - return 'host'; - case ConcernEventType.HostProvider: - return 'provider'; - } -} - -export function getPath(getters: Observable[]): Observable { - return zip(...getters).pipe( - map((path: AdcmTypedEntity[]) => setPath({ path })), - ); -} - diff --git a/web/src/app/styles/_fonts.scss b/web/src/app/styles/_fonts.scss deleted file mode 100644 index ad5b91882c..0000000000 --- a/web/src/app/styles/_fonts.scss +++ /dev/null @@ -1,73 +0,0 @@ -@font-face { - font-family: "Material Icons"; - font-style: normal; - font-weight: 400; - src: url(fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format("woff2"); -} - -@font-face { - font-family: "Ubuntu Mono"; - src: url("fonts/UbuntuMono-Regular.eot"); - src: local("fonts/Ubuntu Mono"), - local("fonts/UbuntuMono-Regular"), - url("fonts/UbuntuMono-Regular.eot?#iefix") - format("embedded-opentype"), - url("fonts/UbuntuMono-Regular.woff") format("woff"), - url("fonts/UbuntuMono-Regular.ttf") format("truetype"); - font-weight: normal; - font-style: normal; -} - -@font-face { - font-family: "Ubuntu Mono"; - src: url("fonts/UbuntuMono-Bold.eot"); - src: local("fonts/Ubuntu Mono Bold"), - local("fonts/UbuntuMono-Bold"), - url("fonts/UbuntuMono-Bold.eot?#iefix") format("embedded-opentype"), - url("fonts/UbuntuMono-Bold.woff") format("woff"), - url("fonts/UbuntuMono-Bold.ttf") format("truetype"); - font-weight: bold; - font-style: normal; -} - -@font-face { - font-family: "Ubuntu Mono"; - src: url("fonts/UbuntuMono-BoldItalic.eot"); - src: local("fonts/Ubuntu Mono Bold Italic"), - local("fonts/UbuntuMono-BoldItalic"), - url("fonts/UbuntuMono-BoldItalic.eot?#iefix") - format("embedded-opentype"), - url("fonts/UbuntuMono-BoldItalic.woff") format("woff"), - url("fonts/UbuntuMono-BoldItalic.ttf") format("truetype"); - font-weight: bold; - font-style: italic; -} - -@font-face { - font-family: "Ubuntu Mono"; - src: url("fonts/UbuntuMono-Italic.eot"); - src: local("fonts/Ubuntu Mono Italic"), - local("fonts/UbuntuMono-Italic"), - url("fonts/UbuntuMono-Italic.eot?#iefix") format("embedded-opentype"), - url("fonts/UbuntuMono-Italic.woff") format("woff"), - url("fonts/UbuntuMono-Italic.ttf") format("truetype"); - font-weight: normal; - font-style: italic; -} - -.material-icons { - font-family: "Material Icons"; - font-weight: normal; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - font-feature-settings: "liga"; - -webkit-font-feature-settings: "liga"; - -webkit-font-smoothing: antialiased; -} diff --git a/web/src/app/styles/_grid.scss b/web/src/app/styles/_grid.scss deleted file mode 100644 index 8892f0503a..0000000000 --- a/web/src/app/styles/_grid.scss +++ /dev/null @@ -1,156 +0,0 @@ -.container { - margin: 0 auto; - max-width: 1280px; - width: 90%; -} -@media #{$medium-and-up} { - .container { - width: 85%; - } -} -@media #{$large-and-up} { - .container { - width: 70%; - } -} -.col .row { - margin-left: (-1 * $gutter-width / 2); - margin-right: (-1 * $gutter-width / 2); -} - -.section { - padding-top: 1rem; - padding-bottom: 1rem; - - &.no-pad { - padding: 0; - } - &.no-pad-bot { - padding-bottom: 0; - } - &.no-pad-top { - padding-top: 0; - } -} - - -// Mixins to eliminate code repitition -@mixin reset-offset { - margin-left: auto; - left: auto; - right: auto; -} -@mixin grid-classes($size, $i, $perc) { - &.offset-#{$size}#{$i} { - margin-left: $perc; - } - &.pull-#{$size}#{$i} { - right: $perc; - } - &.push-#{$size}#{$i} { - left: $perc; - } -} - - -.row { - margin-left: auto; - margin-right: auto; - margin-bottom: 20px; - - // Clear floating children - &:after { - content: ""; - display: table; - clear: both; - } - - .col { - float: left; - box-sizing: border-box; - padding: 0 $gutter-width / 2; - min-height: 1px; - - &[class*="push-"], - &[class*="pull-"] { - position: relative; - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - &.s#{$i} { - width: $perc; - @include reset-offset; - } - $i: $i + 1; - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - @include grid-classes("s", $i, $perc); - $i: $i + 1; - } - - @media #{$medium-and-up} { - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - &.m#{$i} { - width: $perc; - @include reset-offset; - } - $i: $i + 1 - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - @include grid-classes("m", $i, $perc); - $i: $i + 1; - } - } - - @media #{$large-and-up} { - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - &.l#{$i} { - width: $perc; - @include reset-offset; - } - $i: $i + 1; - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - @include grid-classes("l", $i, $perc); - $i: $i + 1; - } - } - - @media #{$extra-large-and-up} { - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - &.xl#{$i} { - width: $perc; - @include reset-offset; - } - $i: $i + 1; - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - @include grid-classes("xl", $i, $perc); - $i: $i + 1; - } - } - } -} diff --git a/web/src/app/styles/_normalize.scss b/web/src/app/styles/_normalize.scss deleted file mode 100644 index fa4e73dd41..0000000000 --- a/web/src/app/styles/_normalize.scss +++ /dev/null @@ -1,447 +0,0 @@ -/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ - -/* Document - ========================================================================== */ - -/** - * 1. Correct the line height in all browsers. - * 2. Prevent adjustments of font size after orientation changes in - * IE on Windows Phone and in iOS. - */ - -html { - line-height: 1.15; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/* Sections - ========================================================================== */ - -/** - * Remove the margin in all browsers (opinionated). - */ - -body { - margin: 0; -} - -/** - * Add the correct display in IE 9-. - */ - -article, -aside, -footer, -header, -nav, -section { - display: block; -} - -/** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/* Grouping content - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - * 1. Add the correct display in IE. - */ - -figcaption, -figure, -main { /* 1 */ - display: block; -} - -/** - * Add the correct margin in IE 8. - */ - -figure { - margin: 1em 40px; -} - -/** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ - -hr { - box-sizing: content-box; /* 1 */ - height: 0; /* 1 */ - overflow: visible; /* 2 */ -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -pre { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/* Text-level semantics - ========================================================================== */ - -/** - * 1. Remove the gray background on active links in IE 10. - * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. - */ - -a { - background-color: transparent; /* 1 */ - -webkit-text-decoration-skip: objects; /* 2 */ -} - -/** - * 1. Remove the bottom border in Chrome 57- and Firefox 39-. - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ - -abbr[title] { - border-bottom: none; /* 1 */ - text-decoration: underline; /* 2 */ - text-decoration: underline dotted; /* 2 */ -} - -/** - * Prevent the duplicate application of `bolder` by the next rule in Safari 6. - */ - -b, -strong { - font-weight: inherit; -} - -/** - * Add the correct font weight in Chrome, Edge, and Safari. - */ - -b, -strong { - font-weight: bolder; -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -code, -kbd, -samp { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/** - * Add the correct font style in Android 4.3-. - */ - -dfn { - font-style: italic; -} - -/** - * Add the correct background and color in IE 9-. - */ - -mark { - background-color: #ff0; - color: #000; -} - -/** - * Add the correct font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - */ - -audio, -video { - display: inline-block; -} - -/** - * Add the correct display in iOS 4-7. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Remove the border on images inside links in IE 10-. - */ - -img { - border-style: none; -} - -/** - * Hide the overflow in IE. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Forms - ========================================================================== */ - -/** - * 1. Change the font styles in all browsers (opinionated). - * 2. Remove the margin in Firefox and Safari. - */ - -button, -input, -optgroup, -select, -textarea { - font-family: sans-serif; /* 1 */ - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ -} - -/** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - */ - -button, -input { /* 1 */ - overflow: visible; -} - -/** - * Remove the inheritance of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritance of text transform in Firefox. - */ - -button, -select { /* 1 */ - text-transform: none; -} - -/** - * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` - * controls in Android 4. - * 2. Correct the inability to style clickable types in iOS and Safari. - */ - -button, -html [type="button"], /* 1 */ -[type="reset"], -[type="submit"] { - -webkit-appearance: button; /* 2 */ -} - -/** - * Remove the inner border and padding in Firefox. - */ - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -/** - * Restore the focus styles unset by the previous rule. - */ - -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} - -/** - * Correct the padding in Firefox. - */ - -fieldset { - padding: 0.35em 0.75em 0.625em; -} - -/** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ - -legend { - box-sizing: border-box; /* 1 */ - color: inherit; /* 2 */ - display: table; /* 1 */ - max-width: 100%; /* 1 */ - padding: 0; /* 3 */ - white-space: normal; /* 1 */ -} - -/** - * 1. Add the correct display in IE 9-. - * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ - -progress { - display: inline-block; /* 1 */ - vertical-align: baseline; /* 2 */ -} - -/** - * Remove the default vertical scrollbar in IE. - */ - -textarea { - overflow: auto; -} - -/** - * 1. Add the correct box sizing in IE 10-. - * 2. Remove the padding in IE 10-. - */ - -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ - -[type="search"] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/** - * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. - */ - -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * 1. Correct the inability to style clickable types in iOS and Safari. - * 2. Change font properties to `inherit` in Safari. - */ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* Interactive - ========================================================================== */ - -/* - * Add the correct display in IE 9-. - * 1. Add the correct display in Edge, IE, and Firefox. - */ - -details, /* 1 */ -menu { - display: block; -} - -/* - * Add the correct display in all browsers. - */ - -summary { - display: list-item; -} - -/* Scripting - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - */ - -canvas { - display: inline-block; -} - -/** - * Add the correct display in IE. - */ - -template { - display: none; -} - -/* Hidden - ========================================================================== */ - -/** - * Add the correct display in IE 10-. - */ - -[hidden] { - display: none; -} diff --git a/web/src/app/styles/details.scss b/web/src/app/styles/details.scss deleted file mode 100644 index 10184177f0..0000000000 --- a/web/src/app/styles/details.scss +++ /dev/null @@ -1,75 +0,0 @@ -@import "node_modules/@angular/material/theming"; - -:host { - flex: 1; - display: flex; - flex-direction: column; - overflow: auto; -} - -mat-drawer { - min-width: 240px; - background-color: transparent; - padding-left: 10px; -} - -.mat-card { - flex: 1; - padding: 10px; - display: flex; - flex-direction: column; - overflow: auto; - - & .mat-card-header { - min-height: 40px; - padding: 6px 10px 0; - - & .mat-card-title { - font-size: 26px; - } - } - - .mat-card-content { - display: flex; - flex: 1; - overflow: auto; - } -} - -.mat-toolbar { - height: auto; - min-height: 50px; -} - -.issue-warning { - width: 40px; - height: 40px; - position: relative; - cursor: pointer; - - .mat-icon { - margin: 8px 0 0 8px; - } - - div { - width: 40px; - height: 40px; - position: absolute; - background: mat-color($mat-orange, 500); - border-radius: 20px; - top: 0; - opacity: 0; - animation: ripple 2s infinite ease-in-out; - } -} - - -@keyframes ripple { - 0% { - opacity: .5; - } - - 100% { - opacity: 0; - } -} diff --git a/web/src/app/styles/lib.theme.scss b/web/src/app/styles/lib.theme.scss deleted file mode 100644 index 8cad319a2f..0000000000 --- a/web/src/app/styles/lib.theme.scss +++ /dev/null @@ -1,126 +0,0 @@ -@import '~@angular/material/theming'; - -@include mat-core(); - -$app-primary: mat-palette($mat-blue-grey, A400); -$app-secondary: mat-palette($mat-light-green, A500); -$app-accent: mat-palette($mat-green, A400); -$app-warn: mat-palette($mat-orange); -$app-theme: mat-dark-theme($app-primary, $app-accent, $app-warn); - -@include angular-material-theme($app-theme); - -@import "normalize"; -// Media Query Ranges -$small-screen-up: 601px !default; -$medium-screen-up: 993px !default; -$large-screen-up: 1201px !default; -$small-screen: 600px !default; -$medium-screen: 992px !default; -$large-screen: 1200px !default; - -$medium-and-up: "only screen and (min-width : #{$small-screen-up})" !default; -$large-and-up: "only screen and (min-width : #{$medium-screen-up})" !default; -$extra-large-and-up: "only screen and (min-width : #{$large-screen-up})" !default; -$small-and-down: "only screen and (max-width : #{$small-screen})" !default; -$medium-and-down: "only screen and (max-width : #{$medium-screen})" !default; -$medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default; - -$num-cols: 12 !default; -$gutter-width: 1.5rem !default; -$element-top-margin: $gutter-width/3 !default; -$element-bottom-margin: ($gutter-width*2)/3 !default; - -@import "grid"; -@import "fonts"; -@import "style"; - -a { - color: mat-color($mat-blue, 200); - text-decoration: none; - - &:hover { - color: mat-color($mat-blue, 300); - text-decoration: underline; - } -} - -.select-table-item { - background-color: mat-color($mat-blue-grey, 500) !important; - - & button.mat-icon-button.mat-primary { - color: mat-color($mat-green, A400); - } -} - -.primary { - color: mat-color($app-primary); - border-color: mat-color($app-primary); -} - -.secondary { - color: mat-color($app-secondary); - border-color: mat-color($app-secondary); -} - -.accent { - color: mat-color($mat-green, A400); -} - -.warn { - color: mat-color($mat-orange, 500); -} - -.running { - color: mat-color($mat-yellow, 500); -} - -.success { - color: mat-color($mat-green, A400); -} - -.failed { - color: mat-color($mat-red, A100); -} - -.created { - color: mat-color($mat-blue-grey, 200); -} - -.aborted { - color: mat-color($mat-deep-orange, 200); -} - -.mat-list-item.primary { - border: solid 1px mat-color($mat-blue-grey, A400); -} - -.mat-list-item.accent { - border: solid 1px mat-color($mat-green, A400); -} - -.mat-list-item.warn { - border: solid 1px mat-color($mat-orange, 500); -} - -.mat-list-item.mat-warn { - color: mat-color($mat-orange, 500) !important; -} - -//.mat-list-item.mat-accent { -// color: mat-color($mat-green, A400); -//} - -a.active .mat-list-item-content { - // font-weight: bold; - text-decoration: none; - color: mat-color($mat-green, A400); -} - -.mat-nav-list a:not(.top) { - color: mat-color($mat-blue-grey, 200) !important; - - &:hover { - color: mat-color($mat-blue-grey, 50) !important; - } -} diff --git a/web/src/app/styles/status-tree.scss b/web/src/app/styles/status-tree.scss deleted file mode 100644 index 19eb894d16..0000000000 --- a/web/src/app/styles/status-tree.scss +++ /dev/null @@ -1,18 +0,0 @@ -:host { - flex: 1; -} - -.controls { - position: fixed; - top: 130px; - right: 10px; - - .notify { - opacity: 0; - - &>span { - line-height: 24px; - vertical-align: text-bottom; - } - } -} diff --git a/web/src/app/styles/style.scss b/web/src/app/styles/style.scss deleted file mode 100644 index 1fe3965cf1..0000000000 --- a/web/src/app/styles/style.scss +++ /dev/null @@ -1,396 +0,0 @@ -@import "normalize"; - -// Media Query Ranges -$small-screen-up: 601px !default; -$medium-screen-up: 993px !default; -$large-screen-up: 1201px !default; -$small-screen: 600px !default; -$medium-screen: 992px !default; -$large-screen: 1200px !default; - -$medium-and-up: "only screen and (min-width : #{$small-screen-up})" !default; -$large-and-up: "only screen and (min-width : #{$medium-screen-up})" !default; -$extra-large-and-up: "only screen and (min-width : #{$large-screen-up})" !default; -$small-and-down: "only screen and (max-width : #{$small-screen})" !default; -$medium-and-down: "only screen and (max-width : #{$medium-screen})" !default; -$medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default; - -$num-cols: 12 !default; -$gutter-width: 1.5rem !default; -$element-top-margin: $gutter-width/3 !default; -$element-bottom-margin: ($gutter-width*2)/3 !default; - -@import "grid"; - -body { - margin: 0; - padding: 0; - font-family: Roboto, "Helvetica Neue", sans-serif; - color: #ffffff; - background-color: #303030; -} - -app-root { - overflow: hidden; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - display: flex; - flex-direction: column; - - & main { - flex: 1; - display: flex; - overflow: auto; - } - - & footer { - color: #ccc; - - & div { - text-align: right; - padding: 4px 10px; - font-size: .8em; - - & .left { - float: left; - } - } - } -} - -.top .mat-list-item-content { - justify-content: center; -} - -/** css for list only - TODO: make the list as module and lazy loading */ -mat-toolbar.toolbar { - height: auto; - min-height: 50px; - justify-content: space-between; -} - -mat-form-field textarea { - min-height: 100px; - padding: 8px !important; - box-sizing: border-box; -} - -.overflow { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - margin-right: 10px; -} - -.noflex, -.noflex > .mat-list-item-content { - display: block !important; -} - -mat-checkbox.advanced > label > span { - border-bottom: dotted 1px #00e676; - line-height: 20px !important; -} - -.mat-dialog-title { - margin: -6px -16px 20px !important; - padding: 2px 10px; - background-color: #2d2d2d; - border-radius: 2px; - font-size: large; - //box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12); -} - -.icon-locked { - animation: rotate 2s infinite linear; -} - -@keyframes rotate { - 0% { - transform: rotate(0deg) - } - - 100% { - transform: rotate(360deg) - } -} - -.mat-menu-panel { - max-width: none !important; -} - -.snack-bar-notify { - max-width: 60vw !important; - overflow: auto; - background-color: #595959; - color: #00e676; - - & button { - color: #78909c; - } -} - -.snack-bar-error { - max-width: 60vw !important; - overflow: auto; - background-color: #595959; - color: #ff9800; - - & button { - color: #78909c; - } -} - -.mat-card-header { - margin-bottom: 10px; -} - -.mat-card-header-text { - margin: 0 !important; -} - -.mat-dialog-container { - padding: 8px 18px !important; -} - -.mat-dialog-content { - margin: 0 -18px !important; - max-height: 80vh !important; -} - -.mat-dialog-actions { - margin-bottom: auto !important; -} - -.mat-card-subtitle { - margin-bottom: 0 !important; -} - -.row { - - & .star { - flex-basis: 20px; - text-align: right; - line-height: 60px; - - &.ddn { - padding-top: 12px; - } - } -} - -.mat-form-field, -.full-width { - flex-grow: 1; -} - -*:focus { - outline: none; -} - -.job-status .mat-mini-fab .mat-button-wrapper { - display: inline; - font-size: 11px; -} - -mat-sidenav { - width: 200px; - min-height: 100vh; -} - -mat-cell { - padding: 2px; -} - -mat-header-cell { - padding: 2px; -} - -mat-header-cell.control, -mat-cell.control { - flex-grow: 0; - flex-basis: 100px; - text-align: center; -} - -.item-title { - cursor: pointer; - - &:hover { - text-decoration: underline; - } - - &.has-checkbox { - margin-left: 36px; - } -} - -.mat-expansion-panel { - box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.6), 0px 2px 2px 0px rgba(2, 2, 2, 0.8), 0px 1px 5px 0px rgba(10, 10, 10, 0.9) !important; - - &.panel { - margin: 6px 0; - } -} - -.mat-column-controls { - text-align: right; -} - -.mat-column-select { - overflow: initial; -} - -.mat-list-icon { - color: rgba(0, 0, 0, 0.54); -} - -.mat-form-field { - // there isn't visible underscore in the firefox - line-height: normal; -} - -.hidden { - display: none !important; -} - -.login-icon { - padding: 0 14px; - cursor: pointer; - vertical-align: text-bottom; -} - -.on-center { - display: flex; - justify-content: center; -} - -.controls { - display: flex; - justify-content: flex-end; - - & button { - margin: 0 4px; - - &[color="accent"]:focus { - border: solid 1px #008444; - } - } -} - -// component for displaying some group - -.group { - background-color: #474747; - padding: 8px 20px 2px; - margin-top: 1px; - margin-bottom: 8px; - box-shadow: inset 2px 2px 5px rgba(90, 90, 90, 0.5), 1px 1px 5px #383838; -} - -.component { - border: solid 1px #696969; - padding: 2px 6px; - margin: 8px; - box-shadow: 0 14px 28px rgba(41, 41, 41, 0.25), 0 10px 10px rgba(29, 29, 29, 0.22); -} - -.alone > .field-group { - margin: 0 24px; -} - -.alone > .read-only { - margin: 0 14px !important; -} - -@font-face { - font-family: 'Material Icons'; - font-style: normal; - font-weight: 400; - src: url(fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format("woff2"); -} - -@font-face { - font-family: 'Ubuntu Mono'; - src: url("fonts/UbuntuMono-Regular.eot"); - src: local("fonts/Ubuntu Mono"), local("fonts/UbuntuMono-Regular"), url("fonts/UbuntuMono-Regular.eot?#iefix") format("embedded-opentype"), url("fonts/UbuntuMono-Regular.woff") format("woff"), url("fonts/UbuntuMono-Regular.ttf") format("truetype"); - font-weight: normal; - font-style: normal; -} - -@font-face { - font-family: 'Ubuntu Mono'; - src: url("fonts/UbuntuMono-Bold.eot"); - src: local("fonts/Ubuntu Mono Bold"), local("fonts/UbuntuMono-Bold"), url("fonts/UbuntuMono-Bold.eot?#iefix") format("embedded-opentype"), url("fonts/UbuntuMono-Bold.woff") format("woff"), url("fonts/UbuntuMono-Bold.ttf") format("truetype"); - font-weight: bold; - font-style: normal; -} - -@font-face { - font-family: 'Ubuntu Mono'; - src: url("fonts/UbuntuMono-BoldItalic.eot"); - src: local("fonts/Ubuntu Mono Bold Italic"), local("fonts/UbuntuMono-BoldItalic"), url("fonts/UbuntuMono-BoldItalic.eot?#iefix") format("embedded-opentype"), url("fonts/UbuntuMono-BoldItalic.woff") format("woff"), url("fonts/UbuntuMono-BoldItalic.ttf") format("truetype"); - font-weight: bold; - font-style: italic; -} - -@font-face { - font-family: 'Ubuntu Mono'; - src: url("fonts/UbuntuMono-Italic.eot"); - src: local("fonts/Ubuntu Mono Italic"), local("fonts/UbuntuMono-Italic"), url("fonts/UbuntuMono-Italic.eot?#iefix") format("embedded-opentype"), url("fonts/UbuntuMono-Italic.woff") format("woff"), url("fonts/UbuntuMono-Italic.ttf") format("truetype"); - font-weight: normal; - font-style: italic; -} - -.material-icons { - font-family: 'Material Icons'; - font-weight: normal; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - font-feature-settings: 'liga'; - -webkit-font-feature-settings: 'liga'; - -webkit-font-smoothing: antialiased; -} - -// BEGIN: Paginator - -@mixin paginator { - font-size: 14px; - margin: 0 6px; - color: #bbb; -} - -.page-button { - @include paginator; - cursor: pointer; -} - -.page-button:hover { - text-decoration: none; - color: #ccc; -} - -.page-button.current { - color: mat-color($mat-orange, 500); -} - -.page-additional { - @include paginator; -} - -// END: Paginator - - -adwp-dropdown-box { - z-index: 2000 !important; -} diff --git a/web/src/app/templates/details.html b/web/src/app/templates/details.html deleted file mode 100644 index 1d72c0d3f2..0000000000 --- a/web/src/app/templates/details.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - {{ currentName }} - - - - - - - - - - - diff --git a/web/src/app/templates/status-tree.html b/web/src/app/templates/status-tree.html deleted file mode 100644 index 52ad56d1a4..0000000000 --- a/web/src/app/templates/status-tree.html +++ /dev/null @@ -1,17 +0,0 @@ - -

Loading...

-
- - - -
- -
- - - -
diff --git a/web/src/app/ws-logs/log.component.html b/web/src/app/ws-logs/log.component.html deleted file mode 100644 index 6633b29a61..0000000000 --- a/web/src/app/ws-logs/log.component.html +++ /dev/null @@ -1,37 +0,0 @@ -
-
-
- - - - {{ item }} - - -
-
- - - - {{ item }} - - -
- Timeout - - - - -
- -
-
-
{{ log.event | json }}
-
-
-

{{ log.response.title }}

-
{{ log.response.value | json }}
-
-
-
diff --git a/web/src/app/ws-logs/log.component.scss b/web/src/app/ws-logs/log.component.scss deleted file mode 100644 index ac8331fb65..0000000000 --- a/web/src/app/ws-logs/log.component.scss +++ /dev/null @@ -1,21 +0,0 @@ -.tools, .logs { - display: flex; - margin: 10px 0; -} - -.tools { - justify-content: space-evenly; -} - -.logs div:last-child { - margin-left: 40px; -} - -mat-select { - width: 250px; -} - -pre { font-size: 12px;} - -label {font-size: 12px;} -mat-select {margin-left: 20px; border: solid 1px #ccc; padding: 4px 8px;} diff --git a/web/src/app/ws-logs/log.component.ts b/web/src/app/ws-logs/log.component.ts deleted file mode 100644 index 50f1a3f192..0000000000 --- a/web/src/app/ws-logs/log.component.ts +++ /dev/null @@ -1,101 +0,0 @@ -// Licensed 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 { Component, OnInit, ViewChild } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { MatSlider } from '@angular/material/slider'; -import { ApiService } from '@app/core/api'; -import { EventMessage, getMessage, State } from '@app/core/store'; -import { select, Store } from '@ngrx/store'; -import { BehaviorSubject, Subject } from 'rxjs'; -import { filter, takeUntil } from 'rxjs/operators'; - -@Component({ - selector: 'app-log', - templateUrl: './log.component.html', - styleUrls: ['./log.component.scss'], -}) -export class LogComponent implements OnInit { - destroy$ = new Subject(); - - typeName: string; - eventName: string; - - form = new FormGroup({ - typesName: new FormControl('cluster'), - eventsName: new FormControl('change_state'), - timeOut: new FormControl(false), - }); - - logs$ = new BehaviorSubject<{ event: EventMessage; response: any }[]>([]); - - events = [ - 'all', - 'change_state', - 'add', - 'create', - 'delete', - 'remove', - 'change_config', - 'change_status', - 'change_job_status', - 'change_hostcomponentmap', - 'upgrade', - ]; - - types = ['all', 'job', 'task', 'cluster', 'host', 'service']; - - @ViewChild('slider') slider: MatSlider; - - constructor(private store: Store, private api: ApiService) { - // this.store.dispatch(socketInit()); - } - - ngOnInit() { - this.store - .pipe( - select(getMessage), - filter((m: EventMessage) => !!m && !!m.event), - takeUntil(this.destroy$) - ) - .subscribe(m => this.reflect(m)); - } - - reflect(m: EventMessage) { - const typeName = this.form.get('typesName').value, - eventName = this.form.get('eventsName').value; - if ((m.object.type === typeName || typeName === 'all') && (m.event === eventName || eventName === 'all')) { - if (this.form.get('timeOut').value) - setTimeout( - () => this.api.getOne(m.object.type, m.object.id).subscribe(value => this.list(m, value)), - this.slider.value - ); - else this.api.getOne(m.object.type, m.object.id).subscribe(value => this.list(m, value)); - } - // else this.list(m, `Not request for ${eventName} event.`); - } - - list(m: EventMessage, value: any) { - const { type, id } = m.object; - const list = [ - ...this.logs$.getValue(), - { - event: m, - response: { title: `Request for [ /api/v1/${type}/${id}/ ]`, value }, - }, - ]; - this.logs$.next(list.reverse()); - } - - refresh() { - this.logs$.next([]); - } -} diff --git a/web/src/assets/.gitkeep b/web/src/assets/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/assets/adcm-logo.png b/web/src/assets/adcm-logo.png deleted file mode 100755 index c31b37c6e721925133a21f532dfbff792b1f7157..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9214 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 Uk{^$_S^xk507*qoM6N<$g0f%krvLx| diff --git a/web/src/assets/favicon.ico b/web/src/assets/favicon.ico deleted file mode 100644 index 99d6086aa1593c3c14b084e9cae3e2a20236c61e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15406 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

gWuzP$Zc&unTK7d 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 diff --git a/web/src/assets/fonts/UbuntuMono-Bold.ttf b/web/src/assets/fonts/UbuntuMono-Bold.ttf deleted file mode 100644 index 7a41a357d050847419b3500a928bad59aca7c29b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 182336 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

v6FE-ctXw%zX) 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

N*n9IlxJF=i!clobrb=qQZa=vaVG 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

m_H{wiCT^Tyo;dmG@YdFc!%L> z*5P&wX0O}9-C=ex%1LGC;MM^-UjVhsy<*L}czS$HazFgRUX9`Zq52=tSdFfE_D{aD zT#nbg3;vp%8QU&(cs*8IiWgGBfZu2E`3-@fA(;Y+Uxq$F8aeDtCisxi;0w~$fHlB7 zymDB!e85`Sz`=3FXLS2aBCarV5uZ-fPv@%He8XsSI8D6AWjEdt; zPwq(Go1~MQ%w~f}D92z-4iKr-#Tiyks{yEKHP=&jPh38asGK=6C@KQ}G_!P~`4e|R z3Kmxnq=!6?*l6p(j=@y*4DU($3$4t1%eI$e$XoXFZJjpm<7R7g=}mV#QbGHYEKuiy zX@uv3X|(tok_VoqzO(p&WN97df_4|j zDR)X2gQ)R>?1R_kBQLH%PB;bn$7M%c;|19le_Hj$YkBu!o0P;E%zMXWhg{(Wl8ct~ zG1J%w=vtW!Al598Lt9DT2g&0@`gl^Ci~K}s*khTXsHNkOYOnPXK=A*7`3*j(@C>Oz z?l4jgU2bcKmfLztTWe5aV{U6XF7J>Qmp7%XH4tmog7UOBTeLRyxO1dXqZAB{%PDfS zdC6@*t+idl9eRRoctXvoN@TU;Dp^f*y8IKgr)8Y-#Pog0bq=0Z>m1Z%6+K}>OkhP% zShXkgabzA4$91YgjuBwQabvVG8Mcprgkv-mqP?q3rdo`czD^ZZv5lc&B_$**sgDE; zraS`t0mXY#!C=zEQ?Eh6lhTEK1zMM;Qp;NX)d_zK`nI&iUmxccK;v63HF=|oB;yD# z14#NJH_Y;oPekwYdJW@27~E_VTxy7yx*1ZDBfK=}t;Kh-IALG}s%5pV3g`NHQ-S+F z+uDLY{(^074Ba}@T`YD(e^*;um!4j9uAW{D4O88~Fu_o5<204HCcWrpJ-x^ih+d2p zJz-7Mc!K0gBz$*N(G9=TYDCOSmTVs#ouC5k<1mocbOXtaK=|&(dU>MKJsg;z!i8}d zPS*O6^Se9L{O)>ri6^|Zh|^kZ>LE2YRg)KEGDTuj(~7*vZMJA_>g0t=cA-Wo&^j(B zj@NJ_xBax%_MIkW+}3oD1wVnt4Xzq@S?z-gAseUkkxiya9~tySqOp&^r{>f?s8CAj zqdA==eKesbQnfxvj#x5}FJ2}0ffg4(L77tH(B#wik=Nw@oAq)p`13Ag#?c&*b6Cq0 zkV1a!FNr^~N-A(t1guq08oji`c+B{7B$^hSiw_Eh^@*yob!CVFB zSU)4zs>#<9#N(H3I7R%S>Hj0Ai2wCL9M`ZF^@-yeOvs1vBM-*F7hoBVqfTgsXGaal zpB%-}dh>EsIFh=Kq{tvIb#c?Mb^2Dg^PfnLot@R+qIr{?sRUO?8s&kGb#Q?R#?(Ac zn<9E#k=!W+S10P_fzI@bt_j9o9H;F%dXOBsq|QOVT(@BHUA4}^zeuK*=CCjU`FyR; zft-IB=XbbCj=O#r=%B^)1QhdX+;wBy_t$D7CIm@a`jNY%n`0w9nsd!VYLy?!>mIq*Gf?frkk4v;G+nfxCDVoZgL&G|DbT=hR2;6U|z2+oE_QT^Ur&_@7eURm@uz*?$*rNREyT(}Ol zy8#wff2G0xYA)#2!{!=bt<`_fVEN)iEWSNXaTR^e+3nz}j=B-JuB z4qHk!9%_V_`5IgIf0Had@*`ckN3Qh@RQuq%+OFVC61XvHS;+n#zjCSN_T!kwA3235G~vkh>ddOM*Bnq_tCoM<6{GEJ(l zHo#h{yEWK5<{WjfKWu=7)lX@#pO_QPde|2mV6D|VHP{_<4n3?==lfl?&bO-b;9^xW zxuT@hcT&siQ4d?=4Fu~+5?GfW_N)$8;|S(uJJ}yvIOKue7Z-j z^^C?FHlIuD!(HFUU+UmB-Vg&Wt%C;mlSF^5)#*HCOwk;9WXZTZ>AErLp0QoyndbUu z7H=Zw2Qa1vR&Uf`Z$vz(hy5*qJ+Hx1)kiegN9Mfo z4}-N`A6Cg-^sZWWug2Spn72u7dX2XmU~9a+hPS=WUV@3Gtnv6YrTFo)_CRR23SjVrv|$d z>sKA@$p%bv)x$0}z}l++Q-l4V z^{~p?`dxJ|gzz@mJ&ol_%|~@lv;mIrHGxYM2wdzsaGH;5PsPdJN@<+ZuhkpjE$Utj z$jI=i4~K`f_G4Q6@$18D{;53^)7r1WFYYCKJ^R%CB*bSI6o0UKVJ?<;`BgrvhpX`! zh4?H{P~obNHNdHShJCiJbE!B1RQap{R^>AcyK^p62m59NEUfO=VE50ZVtUx`Ho#h| z(;DpbTt*M8)b@N=t?jAu1B8w+sqI-`15|@k`2j*#oWMDBaA$RJnvQdNoTLV6dK@xW z)hw;STeNkYPloq=IJ~Cc93F?(zVrIo^Y1H_tn=>ZG^Wq z!Z+2yFHV!Q)BDtQDB`0Zsru?ibKaC))mJ}ifU{ITt;zJK=Yk%)PW~TnfVEaPXs{dR zf^I$R&j{>!4c1n@TZ6rOF4nArRqDCEtJZU^vxDseq@=5)+O`JRIy+dB2yFZHU^O1G zcXc30ibuXVuk-&K;p^;RkNilN?vZOfQ?r9z?OGol*Y88)6MIj))7KD&B!bwUoNMk;;i?Zc zz=7&AjsDB#T5<$X;gu&FU@g_P8tmG+wmR6KG{C~@UJZ8dTuYN4_WKR6R^6K9Q*&)~ zu#4(iRe`1IY+Grm9=6&5Ypb)Fb+F1l#%tOhLsVYZQpV;cvI&z@^jRZZvkI5X61b+i z_3vxi`Z21mlRG=e;u|Zn9wVTnA2VPxQD5oLhmD z{k+#SA57OCaZ)|kfz!1|;M{d~|256ds`#@fpF1i_?*|QMg5v4YifJ;&JLoCO4or?+p{;+tZrJov9|9eW@wVtl*VtA<$aS6=2qa1 zDII^+!DD^+--1UvQH7UGjJoBAz^?;u(b~7a$jBYEYEN7P9yYWuZ}(lleQV=*TCV}G z?%5%D>gw@y3^a~M2XFgu_{A5H9R3&58Cj$O7Z)EBjr4m&KmM_LA8EYzYxk>XwELj? zS>63#X!kAEFX`_8n|2>o|5SJXpS1hd>YwQPZ6o*3qx%%r$k(`U)89vOdSh+Rp~gR7 z2eN)zd~>dVcTIHrD|PTH|LEb9jqqo6@CyHYozRP>prz!N!LQT4MQh*wB8@v(n5#W; z4S3klzMPP1k_e_CIR;Qyb6x+{#?zcy#c#4~Jh|kLdEg!arXlbXg?y zs;Ku7|GZecUp=JV2i29j`_F3kE!9oB`_F6lA@=yS`%h^1t<@WJ_unD+W&WAI=6##~ zKGIV+*8Gzi{{#Ure;YY9?bv&$`5ASvD(|SUr4NHu_$H{*Np{I*ML`jsv6(u$1^a}I369m?Ze?0cPa9pVRH5U7ghbvTxU61 zQvI)bxSIb(RlhvfJ*dJ}A8LS8{V%*W>z?cFB7my@)c~vdUl?|HuD=fUCk?Qw|Ak>c zIoI2%hy8v7tm=PZ*t_TY>tGiZeWt>y{uhS*++2A~4_j@3RsAmv`$#>k;#a+(`c;%y z_Z}?Yb*=Ychg4WFwWz@Ut7OXR+_jqBdQGz{QO$0dzfCLNUF|&+f`#vB@9i)Yc@u>0iX8H>&Of>JniToWKoZb)}bnxEIX4ZdS0HD8dEM=tR zYRC9=S)W{?;jDP+%0eEejB79UB-v!Qqo?F?c$3~Xy31a&yFA`>iT=ksTz7=J0|$d$ zfls{O)Dh$-#ZdK2YcgN?%C}+bp+~B3zQ`Lw&Amz3U;SPz$@~dS5FCAj;@}w4G4hHQ zf@cveCKmr1*nr~|gUu{jP55jxexv_Jdy$-AbK~QSaE?Z&9Fis{UryrVJO2^w%6e|1 zBOXtL+UCi2Q7<@CU2!(!_h;C6SISB9L~o}Y@KL&l(5V%lTW<9wl5OUf9N;Bmo9{P? z#RQdjDh$I-2hY2q`$b@bw&%~Apy@?GL;87K`>{fPE>_;asUvY*sra@$AadSGo}^dz zJ&TKvS}7clOR_IqO!@qYgx{Asg)Ye?`eh@uy8LFd-(`Wr(3fow2HUe6@89$S5g#{UFn){@|xxgL_PJs()?V~eU)!T&zFoW)dqHdW1KoSBgpVx8YPs%7+b?MT;0F!<-FtH-pRVo2KJspEm-=oF z$?DUx48rQub2f|izHvnZ-2K%TRJa%BtY!@^tJEr2-iM&}4y$lap!T$PN9_%8_g5cN z;hsb7$#6=3-uD&RpOUeZDJTopg79F)pUbWyk#L@>9{mSs=`h!RIa>HD_BM%3^WY^`)=7e zIk^*B71e-irjv@wyA~D}zM$6(a{dho$?qJJUm8hWT(Uw6&?3w5l#>M(EXkKIpM{09 zXD(klcNu4f@UmI9L8#&AT}$?T7fZG~5emo3Me3K|$RFERlkVKOQbTAR>g%~$Ur4ej zk>Op?$lb<-hStV`mh&2kGI1 zNZ#Eb3%aFX*5ePolR&yqcn7Dic4z%j_agcx8ls?Z<=mCZDe>|-Sh)Olq>+Wzc+~QK9gHueHKSJ5H$OPai{Jb)(h$$ z1m(S~$kE%9$(Oj+JGDb9ESOSZuSh1BZfgU>x(V#xYkM2v-vAJoy}o~z?EV;nriHd~ zN=T?L)oOlb!?RTMTF!gLlkkx-2I}ThdsjyPD}s&4{rpU_%Kg+j>6ANB zV+o0m&{FRsKp+MHKHOA0KQ6;MR9M|vMrgJWSgYnEq?H&&6?U-tKUDeu3f4R7d$?!= z-2G?;rNAAp3`uOI)C3ihv zEXPqF9)~6FCQ|iwV;_2%%1f?nDt;megMu6ILX#(Aa0}u=)EAx#6t7&wkr$OS*qyja zkZ@uhefQUvqmKuZE;iu~1k84mPqj?aC7~+y7wegBxgX*EZ3?(H=={BovTBzu~q^bQDGbKLhLlbOUy&&>(k?< z_HKv9=_i7c1C1NVFvs?E2$#UbhCfndF$q?~F>ydi9&?diB^`C}*M+pFTqY zOgm!NgCHll&5t_#!2o#F81e-kvi*_!EA$_kzM@2cV%z-2TNg=Su+IB4=siIs*57Cf z2D8~FssPZlNmCWHK5{Bx1^E<@@0m3IE7raLAkk!DlH0yq9_njZS4&O`xDgOtt#)_ zGndb4@0v;taQ9cAP~o1RYnET%$oUQMdhkJ{Axp65Boe1na~3ODlg25cM6fn3*Aqf_ zQWE+#C0R&v8*6<6M-0g;=@LmoN0WdfKt+;x?!A{hU@faa8^5DVlj=cVn3AhRJzJV9 zQ9>zL`a+2=6)=c1Fp58=oyg%VZ0Kx-u~y{jwTi7&t3&eP>}qDPcHFVU@uuVF4#u&; zB;jhg!h~={poM}3T8_sdh>P)9oQ|hYh0cel(1v%wduYPxRA+%NZEiB9HzhdJCV}&A zR>DKnx`UT-l(BfRQn^yOSb3{*ZoZPwU#aY`}s^;)oH;#>N3?`&MKED8+T+yJOuwiaf9KlU;M%szPRGx(#mGB zYiK;58SackyGF9j<10GF&6TB}tNwMPZ(J{PfMR4*D$5+UqVV3oX!~>Oj>(muYFG!` zOtfeO56SCb*#I`!+gNEuHXKTM9Tud1xx|Ft&f+-2%kWj$r^-4FzAX2Pqs!y&csKl9 z^#Ry-GZ`a5upbau$19Y9W+(;tlz6JWh?D)p52|JYtcMj}rVuE6nt40)Ssiavmhfm5O!=x~S z(M7qej~cim2svn&pLYtMSBF`-bZ+4ay3EV@a_ex?(|9A?Ff4VLts(S#VYrQg4TDP4 zE3UdDU7CJ~0MVwd#XLV8w1HpFAw3;&=Jb3pZIPv=Eo)ybyMql6g z^2;Q*a6jtvWs=|Fu9LuvG2#mUF;r&IYPSutDC7rzsEHDH5P;8`;c2%6w%&Ij0O zH}4Xr?Ife1b&rjr@!%G4v7$?I4U$U7#SUEY1bv)U;{TQMT6m1Q0!D7wMseIK&IAvl z|L!?-=+Lc8@9OWnd+Emx;Q=4|7?H7Q@C|qX{ut5EEtzcS2JbT11Vu;U46O|@cJP2R zS&GIwl1^u`BNiw$<|Jig~_2$2Gt>R>zuQO z@9^nRBoYcm!aoS3|ANto`f1Mj{Y^QaKiBw)d6^}7uKq8HpTuKE)*qC?YUn6`co7vtNzHC7Tyc;_NKJs}A8}tMz{ETj#PQVxjeLV(482Tq6h!bJGg8vkNyavWY z4uk!KgADm(Afbc#-+f2P6N9=d%t&bnt!wX&k5I2$hLF)z+588+oYqnD74 zzjOwDRu;%Fq{dt&U;j`3uSbXY9y!^NoS#W|Kb=i`Y2Dx8b)Fe7wiVHTZN)uSo7G}L zmmS3dzEdbx|J@IN>>sh(Y!-{nX03i)4~qV?S!V`Ut{fa385vB)Vk!Ki{C>RU|8K3H zP;SDnV2GiSk)c#Hno37yfBa#Pg){IiU;w=*kz-0+Hj*IG$s=zJ0@`R`0Ho1!Nx(&& zNNRnYXaV}fE0-^y!qS&UetVA>#<$(^r7zu4eZKfNmkP3dd;+!oCDQiIFEdT3Vfs6Z zzr$W0gPF!ee*ar3f-5xO5+;B#P%Na4EJIVk0BHklV6m&BWr*zSv-e@$)Q2n*?iwg5 zgM07*p1{3tgU=N%{Y~+Cxqn>G^zV@_qLJ+sz=Je=kYb<_;4FOD`d>tL!UU5L{(beC z+hGOoFyhS5G}sAQcvzEx4k>7S7-!9+%)WgQ$HO4y-W!b5CR5tBmxh3Z533crFx$-6 z2N3ItoYl$b&b6Z}*REYTy7qs2A`!no67l#%t5w85@YL4H$*uUO(BEGu_VtxS5B3K= zNCLJ(3*1Xh12fX*1}C1r zU6+p;?``A2baD_IU@&ymZCON@c8`ceoop6Z@sRz;hxD|4^^rOf8FiuT`vlv9Y zE}JpT?&A;h$9S6GOTUVg;@$v_{zbf=VK;+Qaw*3A5AJno9j3;J5nxZDiR zl;KViZxzn0xFNRO?Q&$|{bMU>gMp#m`W!`V9)$b41_fc96;ctiudlD&w%!!wsU@;) zzZK2xKI%TeBmMJ$EL=)X7g!UR<&Ge<&j2foStqSeS!rwh zaQIl53ez*5*ggX^>~$g+4(}ZY_WEg{<_3RFBuW3~U#pOUe3jF+lz#~$Yn1EfWVJ-$ zn2RuRmce%gpV83kb$W%tUNPR07+$&mKBheE;KJ~mMtUM>_j;BuZS%DzT;pT6O-)d- z2xBDju?t!iUMfpX0(M<_eBokld~x6luDfbxX<)DbU}fq1j0zoamC@4|FP_!%_u|Yu zaW`@XpRsf_9fJ->D&{jn>z3K>8&|uQj%~~%8sCX<`FSK)VUPn|;Oi$rJK_su5!*3; z;B24YS^O)ke{$+lF@n`XlyNG_vn z{kw^mrl!rtJjD{R#&oelP0+o|ApHE`x|ZIU5cByx_IN3g?TlJNo_OE~?r_MHj@TUA zU0$!t6L#3)RAGrLlC;ILHb*MxN{8)^P*U_YTU@!I#pktp{6^k?SnzrUTae>DgeUhS z9dH!kkq2>bkVxE|3t!E8D*a{oij@Su&0z)J>Z+;8{z2JI2#J>?Uw^`o~=jZ@JWV${V& zuygT0@hZ;2GD`uden9qS_5%uj4eoTXV2^fh3f((^;lL+r_t3Mm!oa5I!I&ea-4)KjQ6k0iz+PF$Vc{VBMPefnpE6dAX z^zGi6tzjt{%pW{-^U$cMCJdh473kIUAGtKMDt^D%7KKPA~-N9LRa;DDK zjhu}`W@lqpfw$advwPde`!<$0*6i`m$lBl!PNGHAdC7#NnT}aW^^bSRZ$cBgP}n^{ zD1gc*@<-m2ve=Ly$z_0RNMNzcd|rg2&*nnjJ#D5eUJqw*D8+)keM-iF3PHq~imt!_ zbR%~GSvTY|kROt;2;GCd6Pf#G#xnP=PTl(q{J}F5X*e{TUf=t~Er|`Kk>tA0CwK0= zHN6(k!;O68e?;=v1@1cul32zp4qThb;lfuN@>ao!!x`9-f~lTDaHQ4Los?oQwkqcU z_o0PJ(RW|4HCRIb%&DA-GpsVxa`sQzD=mrG=SLUW%ALM6k6-1Tee0qkaZoKAm{s#$ zVtY+ekH=L9lw^m^kR=<@%y7WalTMDfQo+rAw|oq?f80M1{M+h}VP7u2F_sYGt^Mig zJCkcY-JzG^pIgjLF}G!h7`Sx{GLl=}3Hw&s)RJ~Ncd&M=X>zk=t2Ztp86r7j=k&@p-?JqHm1Gdq*b^f4w6jD%Xzr4HGvDMCpHO5 zZk)N7p_omi%4MbFO2Fn(El%*lp-@w1l`nGPh#O+&#hIs$d@_;W| zUefKpDUjTPb#51;`M0Q-k;W~6PAQxo6Flu!IgjgxC=}x`UUWP5`q}1Lqe$vjk|aw= zA}by89#D^6XE`)7DVgFBBQAs5_TUj;Q+GI12%2_oY;Fx_#JE?=w+y6gOJd*ZlNhtx zZuL2YUqWi>`Zi~%wL7rmt0UQRpGR2c@&;O$#MtKIfzAil*djg~AL+s`QveCmAnQ64 zupl{1ga0jc+XB%5;{5JNEVL*YUl7blZj%w`~ai=tsp;slB~aD$Y6t zvnZMc2fU;D1huPr60Tf$^u1f*#G3K(HESj&))dp}VtYC*`+*1wzKwXD1u5`{(v6}O zno~Gq9cQxHJka9_j86RbG zah%mfSwDlllFt~a{Yu*T3OO#}=qnQsr4JS=Q&ZFP;+21%T3DF6G=*~jEydLnaJDH8o7pX%m<@5@uVHs zYqpadlp_8r$_cQo{D@7Aij;WV^{R_1x}Xar!~~UyjDS>AdNj!;keRTI+Bp9zgR;+F zF3U@BoJ_HD8m+%o_cHI)$qv~|uL%pXU-DMEHMe3@Ys;p=T&j8f-z2&Oe?At=2Zi>` z-)(G8!&_J1IT(!&-nn|kLjyZE=N_2IuI!D+dsk*B9>{IpIj|qoIEd`?-@$_*2HL?b zaz;avguV&6OE`IE=|mJ3qUGql(S6awQ3Hs==-~pjuLZWuxI1ixDDok96z(nTD;zJp zTHp$qz%wFVGG9DfAv-v@Kue_}%2m){z9$ieXz;S-Eysm0&He?`837Ic7a@LjnMS3s`AH5Uva{~CYshmFd_xSZ?dT#QXlZDw*H`CQ=?kF@h z6*}mAv30VQYJD=#aI?Hm2!{n9J)1JwXK{JW$3b}tQQt1F@*REinDL26UM`hOi2ZQ^ z&9~5^?+4;r^Z5Vshw_K^o>onIS}B~VD=}I#jjUEy3F17#a*@_FUi0ULEONmIoSuNw zCfJ)yUR!Uts}OE>CR&5x4tw>V5*@zsCRfM_U#R}@cDQuJAebzHKAtymW<$4N%>^CHF7@DVV=G5i9v>ZZjgF3uthOSA2Um}->YS0JT>mOWUm4$H%;-ws5$@-56<$ zKM2+gc{h5g)%UJjvi)D3#9%DMV6w7|OivtBv zE)@`y=VHiPPe=%taeV2(>(36nqu`VL0pu2vtA|`kdA*oY0MIEf1+al3pMmHo*^Ima zYb0sK@)gI+lB+D0hgxU)`UZz0jv0Dr`CuYB7&~wbsgiqk}yT%Q2hk7WHvK7=T9*WvqVLaaZ%9)qj=t|&@Br_kw&i)y)+k!fi<0E35HY= z)0yg|2sNS#Rl=%%3d;Hk|3OgxAgF)fl|S&xABg_ig8#B+)!3@ztJk%+Td-Vl+wcjf{y^5s|34Suk;yR+1JysO*Q)zw{!AY+~`Ct#wfqocjGxhHmj z2v!dgHe}Szo#qmg=$LIPW?(ThnK_a1)B*G@%>X-xZhI zIE%5Xy{EIdbk{9A1UpChtyWw0Zq1IoNYM8x&D$v|mu>Fs?AtIwKSonAn@tG7A2#|y z3@~VTD-lcaehFFm^Z|T(O)%^e``D z(urU&k*1@?*kp`~JsD-XW^=hEZL>bhl3C$#y&lmsJ#muox`4c|#l#U`S81Tw=Bu{r zJzftcgO2NAXC|w?n)5`7p~g0VV4rfhEp}%l>vClyPOCjl!EULvd=Y4}@VTVV<+s}W zBMvXc2~M-gvxA_1*qSi&A(tcQFq!NDyFDbh@{wYOvT6?2jb<||I0fD`V>ELR{cs!$ zUr=Pm0BD4Nymkm6d07i?0^7mgzC0?q$@|h%(!*GKfRw;kcO$GX#Y~@)u<}WgYg`I~ zwKs3CY(Kv3X4kfxw@t=p`g1eg{pjE14uJRmkAdT8xjQpDIO8_XtlNYLGg;YDT(M(2 zQ!(Fc-p2IymLjvo@?`l$nJ#}dxj)k~TcX#`j*M(sjp(wajxLA*$P(i{37=+uk?({F zBVyv@?b_RedPfR=D3$2nb6NLc6cik8t9TU!e~XQ^Z$L5DS-#O&Ka0rfv(?DTyFdP6 zWQBkHA(p%PSJ$Vs0qMqnCu{HkSOP}C4PY}|CVBfMyx{1^^waI}s|f6_+bSth0Oov(CzOh;_E!xMj(KzKLGgo7u9NxzW7IypieO z-^X<9&jf?XUZ#1rn1r%j`|7H4dHoP#q4l#ie#lObZi?PbZpzUZQD*dw#_@v9eetjdFOqf|LE(~skQ6W z@5?z=>#S?lTKm+sM?96WPVU!SG%R%ouJ=Y*UEoB?n5(_X^}K3DJJ|~9YLl%>%w|tE zRK0;TB5L0&maQHHZG9*3>mFpbuS}iCwZhrEf(r*W+6=?i)dQ(PQgdR9AF}0uzK}bzw_vkHro_ zPjAawRjYfoyrn01t-|U%#1t+Jn|svuHmXxdVygZW0``%*XVUggu%)rUj! zpiTlfHi$aZ8l3Diu)Jcv6ZBph$gV8^P42bQUu*GAWm`M?B>BfGU3)2&kYTR?{(e4DcdCAH&GsWb* zb68q;RJByCZxBKkNo;ei3GNoML$8mV~R= zHHH__jVXtU0xR;oLsXU3f{^wVpS*35TWkuFHac#(9(jK4EE1|%|0-1T4|)tDxhMZa z%1s0!F;*^xBiSJu3975@FQ7~MW3`NzmMAW!>rjt;kYO{VSHiM=et99$t>4+D+pMw1 z!3qAO>6|fpdYao35vdkGVyEHH=ix#mV=U5DG+kP1!mEGV-o=r3)B7e$UdRqauEgg+ zM&M2LOQ^SdC#--@56;uJurczHlL8VM*=mL_VRnGcevS}GtbGu5QN~v?KoMkJXN+|< zM>x<%wm}p2Tgafbgd)qzisbz>>W1w5#;YGeq8Ojs!e|i731J=UNf-(Hh8ZNv1D6TR z9|Z=%#FYM}CQbWFi+uCNy-s}xFvFX$@W>;}CQvYunTyK05=QtoprFxa0V1<4Ph>A# zYjG1P*_mxQs(x$r!r+bZxDECu9ETw*XhWB|U;PS`7-R7+JKLGYCMcPe8^up1u&U?H zaEm}p2=kUOYoJzoOTN4}%7bPNCEaWg4faPHYAPub#Jj^{2DQSG1}s8Q5In z)9ai?wQMug*JAG7D_2Fe%xe3n#RoI>qY?XSh+ZOR#*&p2Rc<|L8{n+5kbA#(qX%&2 zd=t28H32Cb6SG|GZAZ*4)dv-3@nYkh?F!wO@r7$7Fg5i;3{}e}5t~ky_*C>5vKmtsOk2P{#PI=zO>)54x(#|o zNW_^KvC=#6sw03zvbCI8*}7-%)>fSCE?tlCMdrPj0NUoSSBR?DS3JJnH?&F(?eNb` z0=Izzo;%EtQ-|I>O~<)&Dmx{wH4A^#ifiW5@MoweVKSpNH2R#o;zUY$P6;8SZ;YsK zqo&d`dDc#n`Y8wBf-jKsczHUjckT=8HUj$3g{!)&Kzi1iR>C8K`3z?Tham)CZKqB6 z9hm0OFNxZ5h5D{_GP)r+iBTaZ|3EfG3Zy@alu*7oODN5>+M`i%45YgU3jo&QLh}t9 z;YkC!mKp~RrBBQUipnMw0hOA5NusWcr_CGB%a$DN-J0SXJVnygD}oCDXAQ%tU??L~ zO`#0up?)&MJ59@=VG-9%3xrj|(N|V-JJ2XtHd7s=IM4%>P|m6*>9eXY8d!^Yp<6>1 zQznCoFXu9RMo{!yaIP5g(Jwei9M9-P@oWfT;*p@Q^z`)j$MujAJflGUP!rl-d1Ms? z9~6AG8KG7zL}@SBpkASGnUIkyTz`#&0j8L6K8eFhFD%Ey7lc4`EJ-PS{|I<=2hYL{ z>Ss^~qI0Jurho4D%%LlS7I7vqQJtM2Wmvwjn0j8Iv*0l?d=^4MCWs~&eC0RDSeCH{ z>FvLIL>Q}FX`BY{70YLthfuIHn58cA$d)VSot9}GaC>`iCvh1Z{MOXn5hN|8h>D2W z5x5SOx&s)WeLQ+ajF)Lo9n^$bK=_U$;ISyjQO1i?xRY8%5=THnsWXd45vrs0%-W0l^Q^YfpV&+IRTZ%7vFJL>xKCmGZ zQQxA*w*~?a-E`1`LLX*eJ<1|th4NPtiM9uBLFoQ8f%h;lNUVIkqd23)A>4Y*A}{HK zC9LkHR&s^znZxA!(xmEQf>@QvL#ufUF)FE?=-A1bMCQHG7^h5fB)V`0O#DWLazj*H zQkV%0hw^#Ca*=FL*!MUgB&JlJ(6O?-ao#BSRYJn3#5NO^lC_LN=V!RbSa%v9KwQ$nNFgi{2Y(=())l1*Dm=5oQ} z;TQzDUS@>fs<%&?kVg3;ky(d98W7MW40IokE>aGedxl^!00uexLS9o{HyPBxi@YY3 zf-X6x*k#z!rb;DKr1o&mL|XD|1$FwhZPIh`Q75Ww5BtD9>^8xgp@zFj%bB6N#(0sd zv0qq&M(zmm5N;+se|Lt00;j{B!Hf6A4(+yz{s|0nxvT+lG9cJ6;vA)S(WW;;JWFk>6Zy)FeuB#PW%Z*` z$9O;&3~<56p#*~uINye&;^vhi6Ap2WDd{OrYFYoq415XsOA%7%s1aN@Uu@c2Dk5dE zhg0C&{A!4pLSMvAC8%qvn7=b+NlNALC=#r`D9pt%(En3qG@P%T^bg^EjjqZ?^hyTa zECYkva~S$s=e|deiO^M8}=1Z}!rY$t+@;K5I{ zOGNp^C*JT8;fU7cw7kzycUWVjc-b#Ag~gaE#|p|IGLeVQXn=(&s*gU_j}u@a`pDXd ziRSMpIwzvJ7uNI9+7}$j-Rt!%S@ReMm*SZ^P3RHL$p~pcryHgkYcCQq>hoC0mC(U7KWnI=}> zf<`7wi7ltdj02i*m`|CCnZu$r1wRWP)u58jH0o=#bZN|A{VkTos>jgnFY59~z;Xq( zMlWOghB$mNw^~QK)}P{(y1LB2DWS%7L|Wihs{fbWyF=2wc|uJw;LFjk98+JB}rpAZp!+=M8Cy4HZC$EqF!5!=C@M#6#(@ zCMrsUk(51dEI)Y^kxSJ)rW}~jUi?yRsSM5JMv$NOnHJY6%gJtLw^rIH_Iw1w2t*Sc zU}g4A+?~!lz{zFB+V==2kPkwgNB|i{z+g5j!!Yyrc>BP~F=$I3)JJ?8tS5_;;`x{9 z`gO{QCSPW`q>-?;_(Pl>BLp3c0)$oMN-6XZVm;YqO_s$qqRT;v!>m}hsu3%&n)Rd% z_CWT42(qt{k@EiK4|k_oyRAE>7EID-y#s;^yKZxCy)w)N1`2hcJKJhQ*%^BH^h*P} zx@8MKdrXcH%YgOFAXtQXvR=pJqbS^@zMSr;fFtfyBSn@woD=6j_W>0RU&x&unmku; zN<;>we3yKgT(mS3R?KNa!x&-RI$NoeXWd}e!Aod`JC?ppx{^isU*t*6y4NMJg9dd= zRPrnnRqPYZj|n8Kgzig;-UaFtJ`+Cq37uLW;4S7n+IPf*Hk8A1xW!A+w7r>{(YalOb5!LUEy}kM!ke3>#C@j?l+#S^pn0?WQLeHHX7g4pWHh3O z!XGJ7#jPg$auupNneo4LwX`O>>Ac?AeN$1l=6201Ho0sBjms{F^5yy>xx)W6g^iey zQXt)nPr|~Rq3X^A@zFbdr9+0d294uUY@o-0(sMOqN|uOz4lCC92IbfDZ1y6?bB{3<|jlAb;^l-xnHb#e#!Seyzwg zhNINT2Ac-D8#N|Y?x#VurXjM$uoDX;1gHpo^Z|PzI%5vynksQEbrGEpEu9YqVErMa z@yTJ7Fr>#5DI$4(YNZ~*lhVf>r(nt!;v1NF%F(p4v^L3(_~H>MlaBbdx+MoiijOq1 zYTa>{CJ{)Q^h6xVdH-cS#JMp)I~+Nj$kNr7*#_KW4$^agr5>#s3jAmiv;7A` zAYQ+`A=Mh99i*Fo*Feu6?OxR$2@?__Xk1{>9+Nv9AAD~R5kqXyDJZcr$v%BuXy-Sw zRi{81jlpwW^rD&Goy+m}_hVfYQQ;tVEb_dcA{tNU2*BinY{0rv;X-Wj@JRcS~ zheUBUu$TZ7Jwz@yz>yxN=T6g!P#ave53*G*rRHLD+(%qfGdcSm0K9_7pZvz-l^9{@ z-RpfAQ!DJb{`OGk!=_`Ooz!~{ntT6h5U)cCIJic;|6IM=-r@33QBudDh$~gl9`AVMo&= z^U2i|KDccQ(MQ+p+JLI-P;BK*f>LK^uL&1Z|7Dx5 zu!dwHMpaJ;Yxp@2xe{j}UZa01pD<rlDOSzK)miMzOXPB9zHBxh zeN?NnVY6oufU3+bTh{By!)nZ7V9UMauNlstH=Fl_!k-Z?LvqFJL@%a7p}wKbHfk3M zFIj8#OeoyG%}jlv!xeS~x0iZ7nFrE^=ZW|W(M|USY!0({(Sw{hvUSAAuF7M8{SE}J zp8o5ewsfe6zCI$YAALy*F+3FbA0c+76;! z8I=$+*2%OKl1~DHxWkKBg|L7Gi-XULAKv1u*{XxRvSqYmXO8f%v<%A`?_>FU#MC^( zMnVVey-?@`Ms%ux36!~V(UqQ0g%|oEY%_ZUZNLhpp&}Ti!r=U1r&!}n#PB@CMnXI7 zolu}OO6D;0P^DNh$~GQBTw%?;o>DUhoK6wHl4XKU{S9ifo4{Sm_jy2LtXrGs8W)D7fi{TokcU z-NY=bkq$91{G@y|y*~@P#LBVEP;tbA2wc}aYST8SnYY2WxZEP&!xvw;U-<1pMcten z5TWJq`Tq6{6e!q1hdq$zEFhmVhZ(JYFAX_@#8f8mRh<6|m~DS!8O{2MMJ@e+Z0 z%{oXMb9)ng8;n}ZBodKtXv6cJ8-PID4kojyyMqP8dHUm6O2yf%^R0GvK*Y`mDdbNE zKH49YlRd8v#Xn~qTe2N}f0^Tsa{m_iaJ!3Mui$sGK&KrOyQe3US~O|d`uye&p9thG zo)xAH(_uh!_x!{rYaT5V6i$C))2;b+ z(NISu}=W*)e-?x4|3IWHQr{)Wq3q}0Y;$)>52RNvSi-Yy|^@WSD z_7Y+D$v}N%{lN#@{inb%6b1_hZ5J!q2VDl!f^Xoye_G0ed8_$LhG0P+q2Y!QfCa(I zgN118ysaYOTOhHXfq@H}?%|&BKz)V>NaAdb=pr28NCy{M9vvt15hMTYI(GCBS#ilp zG)NLm%($6!@IPVxvCi1`cgiodk18+K!gLzLNg`9;!xEU7pk9 z+hy2ur!rurMExQ65uMg^0ghAKzMeG3r2})@(r3eSkVo&V+1gos0=JEYl2!;zM0U0) z4%PF=z#|NU_$@a?o(RgEr~}NE@C&D~00r5cm#4jJJr@@r7hgBlck7QPor%?-i5uFN z{4wY<635uDh-vWXm)Wf~$JsS9+1^viNLUwVlT_G*gtgg)Qgw;)2cpgi7B^Pe*fR$c zll8_T0d@1Kwz5B>*l4+<;|{rMogM4b$<^|BH+RS}cK-IJ$oB@hdHMPBWYNzo(|5H9 z2v4;B2?%FD#+r+R^m=w~<34EFUSX-7M~%Z?v#iX(3?tsj?CC%~)o zmIr627p_j_ByQt8lQ9VyZ0CR&EHHmhg+Q>2#2ykj+CJhquVoQ64Gs?^IOtQo5nO2b zecFf>x$abF@U!<%D_7D~@r3M!_wt6g9-Z9fx6kovXGbd#PVnV?r^lED+twNmDv1%t zV+F9^lEt~3IjMy%yI8mhXYg$;YGNW<-QY;gA}ie0+~W*#y?$*Cu)k-aDJ}c`l(%2@ z(ktgq$gVuD;!G#xMrmn{a6YchDA5)`0Z#_4C1n`;$`$=?X7Nid3Nite)BQuBvwjxu z`kvy2Ug>Q8h_y4md%|kisfFG@5S8ZJnVG2L5WumIFDxjv@W^GVm6u8kaSAKKt=s5`qfVPKv5!3l*GM zDP0&X)>Oy*$zpcu+7z4l7s5E}*M?>$a(wg|c-;MXS2?$M|Jujiy8P^)=4LN527a$w z-S2gpoWUp8Z&5YptLjb%e!7FH?pVja*fsVd7@LXIJusmO44Gd%gl)<2t;wFCs0Y*3 z8xK`YFp_W=mg$1H8r_wA=fzHqB`r=5J`z)>&_+*AXzTfa2*HnB}Cy!TWIM$%GTHHl|qoJW7+@IZ7y1m$;qV1jG z7viA4T6xJSD#6J)%XBej0*DIy_Zg99fkKdb#%MB2~eZ!Q^e~||Z%9b8zdeD*RH>CzJ~O;J{#`@0p=6SC9 zWM?*Z3UvAbRP$i_e|+*?arAM9^GnEiHT6&Re z(I&%g$sjEnrJ_+kb2(|ZFvzV)Kbo0Z8ozZIk*EW8bDpy0@hMW*O|Vwkvej=H$v1b~ zac&zK++Lf%mV&t4w5RFO!8vqWub%tepo#H&ZUnn}>aEnZschbBM0-gI=d!N^5oVbD zbGq@Xn6DT9el2ROhVZs2kXj;rMaXsOWPXphD6Lpq!nl=tX|6UDBep)Xj$gJjRnGaD ztFz0i6OMHMBA)0Ce!HhasLleyJ9yd3{!nUWwFq#M>Y$f-bf{HhPj^KGB>N`u%BTb4 z8${H2c!uxZ?5s{7vY6~xYp(l`-mqqvl%0^+K&?KIubg_>D% zRBlE*hoCdd?R?V;)6k^jDx?Ast+ACw`9cIl(izm*Wd;sNhceT;h59tRmVVk$*`gJ69q!}E6FJoMC)qiC?m^pexlf_*%a}jykcw=!o z{5kc|v064Gub5D9O)6hR3i2}sy-Vyu*BJuAJoWZR>=`aIVg0WAV*a#5%j6+@(7$TQ z6yb#xza#rPu){+FM{XM;M}(^1cD+E4Flt*hXj980$57y^+!5>qN4QH*hRD5lqEg)F z3W!;BqaG830@z!>A>xd17McI#3Nd0ZkO?8A(GPf*8b9o^nYVfUL>kiE0RQK{%Y-n- zhY(=+t4sW}XZajTFj#|4QGEXw3RI(M8qHf;6*KnV(4u>uvBA`Sc$$Jkc%09TrCg^5 z!a!U`t9_knC6)G=U^sn=@ZLVZN<(0h(XwLba`=Yaew0=5F;}9sm0gCVJh!%v$}|oo z&!C0&V&f_SZd=!)d^;%3o+@DO7fcA!gbAU1`_!F#Okf>0pt3V39ndSXvaKGVm)y{Q z;^blXGsW7&y875ErsrzcMA}Vf>Z3L47A00KYsL51Bu9T`XNVzXbD%Pd|naAlC4+#YdSr|76AKo6rdhi%dzvk zhCatZgswC#nmUcLX23M*ooeIbD@oU872;18M*YOK+Z<#Ih`os|E70%Nrq?6-f(K zp{M30$9XO!#W6frV^cV`o3w$T)aI?$9WfzCg`*qy4+pEN7gq*VZw(I-(CI=>9hPu~3@ww~zHwplbqNvV->U!j5gTptVpaNjaxQ^EWLT|v0#gg+Q$ zUD<9Ru?yXsG#(nWzTi8emedkYx*e#Qt2z^#q4#!>c~#i!GCK<1h#{_46gTF&*TUL; zla=Ssh%ZdjI_eWDyHp47Z>@>yJ45>qNe_B4=1-irCND^_s2Hz)Ki$!UL969aFmb4! zSaXR73|yiARn1z`$cS~;g%`G>!JgB zR!lS!1u>A){@1tUAUfc!tz1~G?!&X7c=8abG(WeIr{a=E3ZWlZ1-Dhjmgn=7A^Ic( z#e9JF&vrL&mQse03PDqBt0a2{S>XLL&vy^uHBe!OOj}O3YIzF2k?JRo8&|cuQnNO} z(YD2pwgK5Q(KmT+9T-r`X^dO0HpQY%s$VEUB=yjWrw^Cdd=+?PqaT0qrV0-jOQs`V z1KQ~L;^}k5iS+Bu=7X^8>YmEp^tKpR=ANtR-A{$a8g}f!IDc?C^mK8bQyU(yY{?PX z$)ySe&Hs$l{>c7I>I&`?ne0%@u#Uk!MK)hP;#W=BK;v5fcTfKul}7ppcv)jbE4eUX zRw-0nfjXr^>b&+ux?;BmGuk3t1Tv*`fM}R-4t5@QsYYXA&clRp`!1k*GMxE%OI9u%8o!Y6TP;0Ig*s`3%tlV2z>wpzcRpaWB@WEjc788ZP_ZOA{`j%D5QbM9o9u2riH?i?T|cSda@QgP41+y7 zgwMp)%;l3ea{Hh;pXZds@IrZ8hFq^Dtdy28sgH1fTR4mUZ15f)t@Bl!)VI7&?_~d;gEZuiVR5c1MZKyp?KOgyf ze4$YrXc?oh;@CCX9}fuBj;1o3$uP&%fcV^AWK1Cjzx zbmj-zepdvcsIG(>L-Z8(W-7QUXvAygwaQ_$XxL%+N!T{YsYQm?v$(j#&FE8;QLJ(& z`&Uf=uWYAap2paM0f+s@!XF}SEsg1%E7`Qxo07%`yo~)%O^)%6hFmQFa(7#_iKU3@ zSD;rAb#(|zJw!_*l_AH5Prw)x^sdJ{V~AUM-sPfrK)DqduXMKJ&->)|1L`c|Y!%^7 z16r<6jwZT^Y{Nwhwm>;$g$cT~$2z0+jZqJBVf&>`ddHb7rVDv4*DIOAG$IkjAp$wK z^)TwIjk1DYPY_6MAH(;%^Se(Ex4-1rb+7{bhI#!dP)#-8Fsv!ZR1C&rzQ$A2@_}REVD{Q#eq}R1p=duVvf5 zCzrQuptU1v-C}jbxif~fTX+IL+iu9RbXp4q>uk0}FPze7|7hy;Er-yp<~0r^*Q|0F zk}Z_AAQ~5aR>&yFVEyC7JE-|V`dd&L{ zj3%$N^RMj{RaB969rrKU*iRW59N=XPGX2m?;1M%az3;ojFD60t}jy!=epYk3!Lnj;ZrynX~HaiX4_E8 zmwq0PU5xzlP|HXbf`%_bFak{yOnVR~i0PTW7GpEz6t4}(xl}KjSVTM5 zMm^h#pRhZF8yrzrT)K`~bLl88ZRO04`f(~=(KNrhLM#GPH*&7bn9ek%NTp0}g4=Dr3YDeuq^0jV+wmzbMLE~%bd7$g|e2=_>=o*vwETQG{X#0^$kZfo=67RDV zd+FE{3fpc5OUHSx2?m9}h{y$<({)!qPs9d=Ge_0LqNwgSkdL2SP-f7t8_=x4dJcUY zIh0#?kg4j(Ek?jN&kTui|3Fc9ke>WgY$2l}jUTE?O6hgQ`{df}#p1UNhjyRySWefV z;Cm>EWq4c3qK2N!GNR9>jAl&1^s4=4BM^!UbUq=~)Fl19n&c?>8`FnKP{T0CY-Phg zfOn8^;IU|kn~?r;xIm@%ayQ}?%U&`GOK&VRM>)MG_Kw4axQspdX%e-Liu8R^xQfO8 z8_653R;0-3?I}Uqr_1^{6=8$p_+$O@@=}S<{+s<#k_b{LoVAa7dPbo3&EV9pKR>C- zATK$So$~w>Kh3YTwVP7wt-JQ)rP!v{8<6I5EDV^J@wjlp6+y{+D8>XE>GK3E^58lF z0G^q#(gujr)n&0zsS2x$)sm|QagYp;QxlU@+s+l z#E`^A%|l*x*T ztNOO+nOQ4c;UtXv6=h}amTCs|Sb4>wHg>v6g}#j{+o7kvk~((v=ig{V@*LACjGxka z9>2~js#L688$BvS@^{7x{yn7C?@u31N*x<3{hFeH60dVBw5^1i7t*4a3TXZM_g{ej#@=j|tY3jk zvY`KIc^aPAblKGSlvc~(%K(1B}#{zpYP_YVclg&yRheJy_r%ARz7=ElK?LxXjpN-zN;PFyzFd7;4r>jPc-wNT@29 zg;FW`I*q(;NZBAnovb43K*&zjoXt8^mm93Jr3#%AI)crPxM|TWP7D{A)T!Co$=$fm z7m!O>@POkRL;)sv)w`^Y;9pDW;N2MDCn$(_u^!;;j?>){oi793A*&^jPB@PXoF{PS z!WkWrSOYpIxOY@1P?ZB3CzOMGp&ocK^$IEB^&(Zzy)(`ALdoj_3t&Wd(%nT`1xCoj!|{2$DE)+;L{hmOMY7R#78W1;BAx8p z*krTa`Ms!kpBxF4e}nhfx@MFOC8R)KDM&sgPsrg`MO zxtv3G6H^rAask~^tYn+>M(017O|FLZ7NSF}sfha2jOTPobLEPGotQ&mp7-a_?eH6Pou@ zXEau1Mrs-U$Yh)*ZCbmudSZD`@0q?j0c*-zU%j+PVlv3GpUx@9$p2woVzgxb#qs@% z*X0)#BIkEv0V-Q!DsiC_TV`r;iKUfxXllu^rH6KadU48>{fV1)hI)aT6}xuMN`}0fr}Ntb{y1OWBRc z)>1BtpVHJaDxsqbT)2vx=@-+8&Ghp5SC*vmg%i#E@&y%a(;rq}EJRs~mONKNtd^1+ z5#|ds&G1(;UGsDsIgM;tp5!qP)&W>;e#Wrd=1k13*3F2@AsjsGiA$MPmS1&&1rqG60TeYHraf z0Mau-zc3Ae>6xNmvv-x5_=2l0C;by zy+tfP^O!uZmv??YtyrHI-bKHvc=*7F;kn5IL!Ho@kYr$gT^9`Bg4L(48f=a{2I?>e6M zn4v@GI>GB$pu>PL9{QNXLz6H;@|f8}H#eT@nA$@-H^JhV+e2SJ9_yIGLrXtFO^gnD$k>H^Kgx_f_9Fp6HnBRm(TQ z;MfnC^}*mbo(D|(p#L84vrbM{Q)SPm->4jFmfvg<<#lO~olEEpj$N4VEM_Q?y8z|Rt-8SNEUhiEx!~!ntu4E_fa)x;E5^IP-WKa(D|aO(5GWgD058h*xNF~rl(JS z+=p||@mV6VYGg=G_nZhgwJEGzxkM@~Tk+_*&Ea$wT^F;uSZs^CEpI!gUe{{n)bMXq zap#!Ct_WPMcF!z(@Z<++&lS$B@;4Wo)ub;@AD_rMg}y3Ob@uBTE3jE)O-?zUm^wu= zEQxoPF|71B+iy!gFMm4w@e3g@1w9z@iy&Mq}Q*z!xxF5f?R_Xshvxt)o7Hs~8)b0VLWcxLF=YMiC~lfjzRvlh=B z{W{LGn15X6TZ{%K=%+*#3ExRy|wmdS^osH=H{&HEw{Ih=q&7?ZdT`=mAz&7)*76py`}ip z?4Gr~<@nYKp2fW-eO33J)x8OR%KNPfJ}7?5ey{jF?E1t0@&`wo6C$2NvqVIIZ-(3e zCkUA7zwHn2AMZyCPzsn2pwOub@z&7jhG$;JC7OCljtp6;#?m=xlI?)(NUg@xJ{;*a zCgH4OzZi)%RqS0-A;@Np*IAlpE#6G(8Ifr%qtYmEetv1BSWc=byL=R>Ocm6zk_S%* zXSxD)va?h~ruh5X$R5M;N8eW33&+Xs40}^m)j&nbB<#=QYon8`qN4*-l(4~KzKO0% z?iWeTp}B?ZhJlwQj===-!-+P~&XOQb0eEKGy(+!4*?CvaeIriThj@DGYP&d`&Rfje z_Pf@4#}CS`T~CXg6hBeP*{!kQO7bBTz!I60Fk^SIG>uNId9ZyMPMdlr_oFCmvsT7P9+kO zX;sSp$cfSTeNu++MSC8s8O1l1EtT(Xbx5Hb&H=t^R&pIa-U4Nv9rKn;w zMBcNEvgb73E(74wzJ_?k8pg0Q(u;tA0qb+0gpKlTRfVCC){xu z!WfM?Bwb?4eI9i8Ut9fuZW9ock65xHLJePM1W`q&Tx*W?hlXPVu|WjTyhyJ2m;VDS z1^^hEc!uTjcOlkb>(LFV`W5_hKzKo2!7l$N$iIPj;*I!J2+V^Jg!M)HAb*j*P1>Ux zQ2b9&)~^_l2PO#V3-^KXLVc^U_kRZiia~i$f{4DjAI@%*nm4sKPT;YDxlsIwp12Qe zXI68I`DMbh{<)z1;GR$q2xmCXdBV^C0;u3&^Vmfl`Hp<f-0IAh4B9jB&uj46#o$h6@u&0NiM};K2TmrZbkRP`jG>OpacrTKs{&+AT<@+R1^pSW!tTSI!ZBe*R!&XPkw*6ce#5j5);zru-h!cHfGq{a%`G&?3;U3ANyo`O1B<) zx^`3z{-yTq?eY_Ui!e}(GVdV!%ggbUW{S?mq0 z|GNCUN4je3BR!}Kf1xG)iVW`~J=ef|w263Y5&P6G^gSuh<36{Deak5FJxR~wK6%Ew z$6?Mx{m-!ff-q*mB`|b{6FckR9eT)m%e?N2d^Pf`6^iz3m%GKU7g)DnTVGdQ*Xe_K zr?#ZQY{0$8c^zXoXR%M#8#2&{8eN1fiDwdZ)^n<<2@h{$WJFI_9TL(~-w^G$igZ=- z{AEhOgv;Ju9cyfGWd>d=to`g+_S>O+Ip znwp64RYpeabpH#E4#WlJfe^V44cck0A;NbV8FA8GhK6j{*W>;8{{b%UmHiVBwm%xYn!y%iP_7mCjjoGkSE>b#pM(dVM0R zy$tVM%lf(uo;e&_1c6L@*lrlc7=tR0s70}%wZ1KWaVhjl>T zqwJUW&jR86FF@Wd?U1xbIUpaH1;GhxhxUI3a9bGd)D9|prTwx2Y5!XQ{0js00xtz# z3cM6}DR5HYq`*molLjXZP8ysv`b*=yrol~vn+7)xZW`P)xM}p620smc8vG1+8SpaT zWx&aRlL03KP6nI|I2mv<;AGP7=h?b#jCC%~m5Sx+{9GwtEOpK)R!c*J{DNF#&{57W zYUttR+=5)eALa6W{S|*vAz$zpxw-R&IbMchA?NGLLjU;iN`EQmKjT&~G^kbJuc=kw zuW>8zM{WiFqIw05fu^gaV!i25mv_^Iy1bjA7CrkC35H?~753f;Lcy9j&Xp_q!E7bh zJFHfBr9WTlZL1aSigNwXocx?hfBldv${lVOo^G%A;K};TTHTfYc6T%Ds@zsP=2qO_ z=`QkgxuZSIwUz@sw>Kf2K_wlk-+SMV$ZzRfl9eQ+nWoxkFCA)yjVLI>8^}>pQdqN z)jpPXwb##g{oGah>(@AB*}KLYBkwNr2lWdB1NSb2u3tK}OWC`~T;W|<4VhoyJzZN= zUjgl2GoEg%-+g0h_oAE16SY*XXm<;8Wm`QdR4u1BuU3aQ&&};gH?=phev5g^W7KXp zk5Lycqb3@RngqjDE~7rrWz^?^QI}xUCwh#Uk~y>Twf_U|9@qA|vvHA+>FNr$1g6%12jO_7BT>rs%*$2k)7la>>Ha{{iKFh4w)!CF=5dvKaQN72 zexTN2-$4C|mPEA{D=q0lZ*6r;daxcw_*2{!?de551KGje;=+Qvcpx`ebg?7+kvp$* z`)d95t5~Sd?CdR8XAk6Nxdy7e{u|FM*KLh#Sgcvz56$hp#R}vI|0#FT(9m5tG<3gM z?{t5*#>zH##+YomXT;Et$@O7l`^!C}|C_vaa^{czFW|q2TuA-U2>%N__nZeRxk6vA zrQ~+kGOv`a%*(d9-{;mRci@wyd&2SQvPs9AbfQTon{=v4r<-(UNIOmWou>RwQ+}r@ zztfc8Y0B?3<#(F$$D8uUoASq-^2eL<$D8uUoASq-^2eLw2osAdA`kmI< zc!8`B{tpY-R@?vp00001|Nj62c-muNWME+60b(m4W@2DxU}UHT;yQ)~Ag_@njDe9Q zoF$2Yi6xn35sco>c&-h6SvH0RY7B2B!c3c-rk+3vg8B75>iNbMx3d2}uZn z##JK*1q4J;NJ5ASuOy|7RKq52vk6j4LvXT5hk~`yTHDf=(w17szL=Vqc@e@Z@(3ZN zHMWWoQIVI_+LqcE?f3$f^z6N-Hgq;jozAq*^iC%KxBvg2`=9Te^Ph8e<}L_;n|!W9 z7?q!^sY2qXYVP_BHdXm+tI>sI7`Y3IJ(yBdkmtd|+lq5Nr~rnB5Gl_QTrl894B`-v zQP#Tq{dFF3#~g7dY}gLVYH&Adn5Jmijn)0DV9xXAdysQ$@lp@GMN0}js4ZSnB;(TJ z0uMG=Pe%`XI_i?=FV!4ABBzLd*@=*y%h??{Y$w6LqNWnnmHxn8Si8J>&1%%IsPR|g z!KyWtRoG~ao2~H?YusXuP1e|6UAMXh-D_%=SEDE3uc}3F;M3JBFc1h#orc3QPRFr8 zT}1$|1nTY%;H)q()Vd%;(Qa|F`35Zy&J1g0Yc#D9$~-udHHKMZxOLuWBqGV0M_n@i zrzTR{BQXY3aWitT5FbMc%CQo6V=e0O6>P%8*n$?hQ9bCx00wakXH;8{;y%Sb#Y2h% ziccvH+DJ1LvlTmSbfqb7RJ>?gYed-dwCReOww-BPbgt)KF~Pp&?%-&Q2RM(5;O4E|FEMjT zlw7F7JyxvqP^{YXIG^Y90$#|Acrh1nAs1QmeAyYk7D_I}nw)Cd+Jn4A=X&{z<}BeA z^FEWH-mTol+qj#z^A6t0yLdPESo1E~8NL=uF2vf1dW%Hwwl?NBF>qdX+=DNSAxbdGH^Scb#)u}a3Y^J6U?<{ zd)Q~gb0UsJu5!y1y3FB$b(!j94RCMGAINlHvwm()2X zC&is|bZk}X%+yt>gK}aqywVj`p$6-4ztr7t;}QG>t?0%c^y3#eg5!7vui^e-xY~*6`giVX zbgO#0RXyFRo^DW2H>jr@)YA>>=?3+*S3T%e4|>&uUiF|?Jy@ciDN)aqsAo#lGbQSo zf8UZuW!R_;8-RzjuYfS1j zCiNPVdW}gOJd!CR_D62hNVI7r+B6bv8i_WIM3dUtq;@u`olRyaGHh3d?aHuS8MZ6KW@Xr{44aiC>$AYb5*{ z3BN|duaWR;Bux2^lPDE29h104IkYH;7Uj^Q9Bk~93YjdGassAcCbBUfAC+3|;|{g7 zLoMx4OFPuk4z;vGnN=vW3T0NI%ql`K>(sM5_3TbPyHn4$vERwz4`B{Fo$kZd>71(S zRMihsRhDOZtCQGz$5Y5x% z-rtBBxJk6klDxb{vS1D}ktKKki+BKE!h`s-dHgs;RrQ>wcm}6uabB%e@Z%I6mhkUu&3#95Sk{mBUA&TUlFOeGbamo1G zuoRz=yK;wAq-B!-r6|LllJ$?G0gY%vGg|PN)POd$qXV7TiY{!Eim)9!uoJtm8$D7T z_F^CQqZbFzhlBVjeugLTBz}pf@eH2Db9f#v;w7BGDZGqd;n(;Leuv-V5BL-Qg1_Po zyoK|)fOl~*_=5vt3Zn@5o)ASb6i1_IG$qj(8cXBoBXk8_NmtV~bS+J!>uECGK-1_( zx`}4dEtE;wltU-zl#yv<8#zWUKOuK41(EzZzrkzc-muNWME+6Vz6PbV_;6MEXrXJNiRyxW{}HCEXiZg zU|<2tGW`D!B(Sl7004KB3;O^70000100000)ubl~00000$>qMw00000%BD~M;lKXk diff --git a/web/src/assets/fonts/UbuntuMono-BoldItalic.eot b/web/src/assets/fonts/UbuntuMono-BoldItalic.eot deleted file mode 100644 index 531188cd7bef142db8a758ed9a2f116a779ac670..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208930 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
  • +e({sE;`s0}& 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%0D7^@h1_@U{C_B>T;0kq74?Fl><=g&V;14CWEM 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 diff --git a/web/src/assets/fonts/UbuntuMono-BoldItalic.woff b/web/src/assets/fonts/UbuntuMono-BoldItalic.woff deleted file mode 100644 index 8ec89417fd40b47dcc33a4175443a588abac2268..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123756 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

    aSd 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%0D$Gh#}F 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 XQx|P%eQm`3Z?1gM(g!Y?{?>m3r1UOB diff --git a/web/src/assets/fonts/UbuntuMono-Italic.ttf b/web/src/assets/fonts/UbuntuMono-Italic.ttf deleted file mode 100644 index 96afce3c674e6c5ef51020631104f8c261caf390..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201172 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%0AH*1&13fg}f8V*#=`qqH&*yW(0F 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 z%0AKEpR|~8_q;Xt`ai;7;oiH-Z=SxR_-2|1+_RWtPhyURFvlcUAjo+f0nB|GDQk|g z*o7m9uB|NR2A(dSzh^MX;xRVM`tot%L)7UVi7Pppq-i!ak2w~@Jb6s`U0iqQQ|yAp zH)35y@zb=nto6h{_NMM@g||JBMNo_U=-)%0DI;J~VN_#W-3-PIfCro*pXdzOO~@nm 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 diff --git a/web/src/assets/fonts/UbuntuMono-Italic.woff b/web/src/assets/fonts/UbuntuMono-Italic.woff deleted file mode 100644 index 9836befb4f488187a83dfe2fde22b63ab65a7e65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 109468 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 z%0D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

      WDcyS6tK6a;8=-~lNBEqeGGkp zQ-ccj&J@T+`KN*X7*oGP5vL!NMgiQog0~kAk5zgAMp^f)6$)aypTLHN;Tjg2duxh= zVNktcK7m9bJ>}MPV9f4;fdTE^oiyH5eOab&^~#AxdZMp-z47W)qJ4BMl<&X#*xLDD zE6k6jrQH`e-}q<38>MtAyD%1s35Pv$z@P7)ZT5cZ_3Ia->6w06E1NTi@mYHYowZBM zBj~Jss+(lnK4HvP!S%fTV5maS{tm+Jqu>|oWW*5kiqa^Jj%D8cr2!Vx@ z$vG{P$^$@w>*n!kq;XuTU6p$Edbn3=RrNIuDeh#fpZ9yc{yxQyLZi~epB)eVz|`|E>(nVqf$GQ8>41KFhT0s3}z_XVUxu0bV}k6UE8TA6vQ_qij(v9JPQucsZq zGKKXb6rhJ72*$crbv_@7K$64=Qn@UhrD?+NsjBD!SUpR{XkyEfvxY$_XLCA*6q>Z< z^-_bzPYfH?x-k?sob+)GE_wt73TJ*sEH8lPqqk2x!LgDbofoB=cO@B z`p0+Q24OOR>p__8u_KkCKw0?+wl!a19z!;GgZjBERNXPW>o^vu0w67*(t<3oV-ds* zZ-hLWCdVxeHg+=r$|O=M@toI-L;pVB$B$DztywBn`&Kq?`Fvil#d1tP!1Dnp764e< zC5)EwSAVGNS)RkC*`tKMMjOlrr?hRal4#EW9~hI5dPM6$9o@!Gc$B2Ag11t;MH7~T1;LwoZV^JcYY!V4sz~9)!1Xrayi_}S>CkT^V zK9gT31eKFkJQH7!Sw<{o)p{wTX)uNno5++oE8~gBm_|RC$M|dj&t}aypvV`lIi3Fd zD6~e{w{fwuIbh_N>Wr}toh;p9C%{HAox&jI-t?(c$KsMAaC%`Xo2l6RayOWW7@kco zpy<59{DT@GqNO&bJ&#)>5>;`7Pk zmL5X8Q4T6Xxm+m3J)ZP%rlsNLr`*=1k*L^H0P#3jrWf|;1xA}I2i`K9C7o>8&L_gg zX&9DXo~)>bDyw`nc-x8pvN0o;rDjSqHS}FgB`7YQTokSRv@lakulH9h)$;PYZ(x2& z{{MJ>vSJ_UuSKJ_l$xp2)b6($$EOHC&+no=tzi9oTX(`}BB>eEpwCzecBe%dmPO(6 zOk|H(!JuV@ZLekFNPwTC)) ziPQtMypmd-#^nmTZ%Uc5SkSxT56(=KW}WW~eJ%;yhxbr-P6Mj)pezbO!Qr6e)`cK) zNrDU$3<{DY@I11g1i>_@;F{_Y*JxQ*8BPFmYRS^{1XLp%kfbG>~oJ;%Y z_l@1E+&cMsb@zAG*H4~T&X3{#CMN%T%g^+B&n*95ujka1GY?^Z&gMIu%*NhP8Q zD-u~(LukE)&?&yIO6WI9;4L{(#nI1`QWR*09-InS_^ixB`_ zf!hhL9yd)RujNcLy&aKtL(nK> z76;`4L9_;)7;T$$^JDF{S3qMA8N}%B75Z~;^9+eVCw$OuPexWBqK@?X{&N2D_NDNl z)x!~Myk3-cQk%``Ge0bZz+A}kAA&P?dW>|v)@g9(-wiRI8Nq5FT; z^>5K%#C7`jb*G?P^oC0OP$=Q|CukbV@u3!9q&9h$J*WoXVf!4~UxQ`3kIJ2teqinl z-;EXbFT6GQR_M-Hdm{KmdSAu;+TvGxyI)xR@qN|ycrKBTLjM!Ce|{3U%%ATbN2k?< zMyqO+=cBn)G_{k?8R>LR3q?aare>gfpy_BdZI;qSEl;UIMp1I$&_tDJD$1fUIVqJE zLZ-lNOR@v(jhFFl7ut7NSq`tDM>R9dGh21QjWR4SP~o`@TXL_86X2dSE> zY1o8C3aVPJFv&zhRhU#ft_6d6t6!oR9t@jy3m+W#>}WUe0W!3WM-Gp{*^ws%JK5nn z2Pohr8GKj8>TUXy-BzqB+vApbzObI0a6)$p6r6UU@5a_oajG^>Yg z`X6>JEvVY2M~no&_mUOROwPkpz)t@F=}|~hk6fYD>tF0HArD7YX*H6J91p2RNF6Hb zNGJE~cVxb&klmgNMffmp*-TPp1_nIVUrV@Hfga-1+bdKcO$)&5yU&m(tqU;I5A%k* zJM};=E584%mQ6+Z2adh(m?xYqYPp4acwo}cz5cZijzi1B*c;yZjzzcc<5t}F;bo5F zy6|;0$6@3b17}&4`t7b#h1hr%ieRgXNsY$|EP2>H-&h9=IE@>n=|_&90}SP@skK}2<7#GhEGzDQ%fmK5oS7NRO0>v& z8qA}&-{asVyN@q@F1L8HX4TEr1^PR=`I8m1X7m=3*$MLdA?DAhAT>t)NjF}B3{1sw zltDx}>?h}-4|fCz1B)byu~H$T4=)uVEGH^%$EV*Zr6+Fkko5K*1K7*Jf73Xe4PHqv z6bdVWUNqX|dih3JQB0~|WBGo@kLCC@UVjc`V!Pcw00Co@8YyDw_$;UrZD_ zqawBj*g1V>oQfc=^D$sr!>bPn);1zbs7`b6z zXtl0AbM2tuf<Gtiv0`T;g62xEO8>|Mvl$0b^h5Qhu1F0|X%4v2Z- z^<@nRYFKD@B3=U)Fvj!LaSIJvqn^o$X~`~59jS%#vek&Ua~$`o6R%{XP*9AB3=7wK zRWlz|{=qC}VuqME3-Iu+@+)5T%G0f&t}30PQ8jjF=->2@g`$S&my>$=m2gqc&C~z0 zeB|84+e`h*ksWv-H3_#eH2o!{GiRxv>sl2YA*(erLjss>Y6lf2MpQyKd<&oRh5ye5Xr7lR3O6S z0&Yd|HH;(D7)?Cw&sw`A%-AQ@Z%9B@X&)V}A37%6NmbBBU#f=GcSE{kb{E4mQ!ciXBVy@# zO1G-xx$Y#$qq>3ITdJK^)J#TIcQoD5G(8&Cb!|e=WRlx9pipKDP|nb9?nj}#M%w&G zVN>=;MQ%i*9Pt?Tp;G?4Rn@EAvXMXWy3<11UpVto!OV7C^CX+{U-rj^_UV~~->#%W zV*&cFSP!Xn=y1$`VLmyCK-NpUMN;gMkE=X8;0ITb%)-bTe{WYUz}Z>=X{DWJGg8}t zky#fY{vI@f>rMlyTr#X&&+9Ew@q`%)hmpMoO$)Yd6-~dfmPoK6ix0~2$XeKTiX8sD z1vG3+4u4kbAdG+PkPK0gkpd8xa|q0{ED~7Tg6b)^UXkZuHJNN6ptf2 zBZTz*IQ9Eis4-$(jghGP7cNYs6dMBNjl04PE7wz!z_EEK$(podJ*Lnh=fOwdE3 zq72j$EH?(MIR>Z|0=-y_s?+s$p~o5qT39^WN>jS7^!YGbtCjl{sTY{RKHOd!@Tm)} z11$^^2pXnq9pM9TgYvZRj-A5Nsd8?nWY(Kg{g5OT$6D6rsl>$5YNk7$m~Ss{7(PDJ zoDUpdX|J_1vKUU5W0`VHTJ_12@7P>prI`&%;q+L#o{I@bIZ5Ox(qH!X^fSl~{%LF% zYq*Z~e)RVYUV9%!`}M!0wO6DjspH*3w%v|;eZHMY)QCi))o3&#%aKTD$`^?Qwlr@v z;Vm^O8OU`pBE@KcXc(0OEghnRv28j>`@9)9{;2QO3OHDXSVe>7aCl{c;~wPv$!ZD8 zi&K*Y!{@!rC@ImrC77i-E|k%|>_oOE+WlzUw4{UPg6iFtRSzAq9zY)keP71VT!R>W7`m< zZCu+r2K7cY zHPzX=-EFixb=a7i)3^eA-RDV%J~aM#MO;;xl~ ziKgq4dPxv7ll@j^KA7Z-g;Xu6`-D%bpG4DFNF}F-x>r7Xq*CuS!V=$QMKxKAln32Q zxbFz9+v7N%d%RmTO$~Vv>qB@*JWr`Kuc~3&($)-yQdO=mQJ5&vO*+A9+~1Hk-sIqG zj|6U=PBich$9S9f@kw=VOdu_2!9d7gW|=O_wd>Iu1aomr5b5g=A-}Lh-QQizgN>aB z8^*wPVX0VLmqbI7M6Tx*MX3^v#n!_SBOHl@%OY1|q7fz*4i_aULrSqo*ktMHkrs!i zTgsQO4Hu6C(KC+t4U$27e8o<5o&JuUP?sZQLk&1TiS0i7UPPAyG2jUebgk6r&)=2oVKbjOc$kH<=I zF2|Y})YQg6+W>_C$4tA`+99{R;e~si%;s`C>5P%iWYQBN*QT-=Dwj^TB&oI)7BzhU z5PR^A6ONgo1cQ6;1b<@yS$dOh5BiUcaL`MiW|U+jJm`(GP=`qbnPb%e2lUCOX1{3f5{nUW78V5qa%*Q2(!$oOy zcEkaN0I7SRI!&sbHnVY$sx?mD+c|Z~sw@=lRG$jum&aq%&HUkZG8B^jh{@;AH81?+ zofGHpsNZ$x`9iN9zxBRXjdd5Qx4iN6m7CEVxz z**>WUA<3sN40${+J$>7S0||?7+yaj63Ncjr9m}ibQ?EN->ZE1Cw{_+gK9H=9omt3< zp>!yq`NS0S!0Fr1{KA{hSfx%XHlL#J+x5Vh_)ywsGA>_C9iD)9*e8-uuK+N;2*SDEP`WdQD{nQmI@6<}>Nv$M2c41;;3dCSy zHnc3LB=Q7&eqCtKmdk}QNpTeXDL=zB(i^GNSSU1BkmK>Obc%{>>E5#6@7<Gla9-y?3Fs1F~aYkaJ!{T75OicHyayTT})p9i)YD{&D*0>PiOKM>;o{n;7 zY1S8%%CqT!6)(`w$V(g-OU&PP`dB%)P>%@w3eQcKU-k7jly1B0p2o3v9E+7B68f&V zzXL!K7x%K{tMBal>QsQ{;p?A8 zUmw0b74V;x1ozutCEp&StnK^$9AHQ*Z^IA6chMfc3n=pYhP7I`Q+{XZaOmHZ-H!(B zUh#IkvVANdZ7V+(;^Fk#(6?|gp16f zP5wq~e!8XazM#;LNZQ20a`NQr*!o?a#zv{AE>E1lb9GatFN8Z&O|3U>Ow7(jrPcYl zvr`d0)D^8Gt5YqfpZ*2hD_Wx->?-(FwBQu56hC3Tl%4XxZUyPjVj`PZuN942u~y6H zgJapOw->Hwi)*-5#Eu!P%JI3+OtRCd4Zi={F$UABr7@!Et}khsHK zK=eh&y18_BvcN}YrrX9uPn(#T3E}x$yM8NUqBWSK-rZGA3<#~kA*hv{I^sVj#b219 ziYF0rp46#>hu>|$Bscxg`VzHwa!DhX%;nQwdM|)nm;g+Qjs92;G1D`ZnH!RqEHeW*&kU321vwKx8@rvo8_f zohKpb;d=)q%oAUp!&RyQ!lNXj;U#pKYRdLn*o+@J6PP-e`e%hcPXBc3Y@J(fm!^xhpBGegeu#|hxA|f-q56EPorx5x zp6TLh;)vsqE+Bo&F^^JZ>X(3v{yD-u?DX}NNKB&yw;cvzsSK>A3{-0d!RC}fNid{L z24|PX(X)msSv}V4D7@+^|3&|+{j6U~r8G^dB$JVT-m9*$hLLB9(jMsShO4x%UU1ft zHZyZg9WA}3kwZUF-AI*Sokt@7ZqX*gO=Q=DZ$EsmOv~!-fA*!D^XZGqFODq~+TnUG z#>b>WV=7)Q|6&Z=mLKj~X^7^h zp#vs{BV&3=(MaX7M!G^&hZqx!&=1>Aa4vN5&gvn5N+<(RLnd!zkU5$u6evS67~Uu` z`L$wZ&F3pJ$R_Ov_cYG%iO?P@#~A4jqmfkhbSiF*V_jPmFCu14`&%v;40!IpH@SRw zFFIb1adEGmt=PGxM)bbdSy}ar#@yf2#v0Y2cW1qRY9Yr9lII933A~Y?N-wvWjd{<3cm2(S|5$ku*RRp%GQ~1N0Z9ICzz;6@jc3O!E_0H>e8IGCNkp zz>MF~D8Mb%+oz6`5%%6Y^xz{a|6RA0|7)_SA%85(of|U zHX37VMp&6{N5}J)T3%`9wMgJ_kUky!eUD%8d!~=o^$*q;OIkoY%*(u)i)t}LY#pzz ztcdYMRA9{9xO3LLNPmmDi0rwa?254xxM5(Vg-9nyh>$G1Egv`$)`m6VXiSZdsYYKMWfxi19MIv4)7#s z%PqnyjDqQO{%!zm!Fn0N)+6<_mYO>~zHrh=tIOlz@q#_s)KiAXPyaX$>xkjBrSg)U zD8&l1B_kpNP>vQ4CG)1=Ds+kv*9%_1mHsyUx0tu=v2HQ~0hI{ku}xbcaZnQy*oNX@ z@ILn`AUJ_EYd4SNWo=MYTw^_|>hbJwUW4;`xtJ<%dHuAu#j+lVgF#l+X<8m4Y1kKM zr!jgriMAIZvhEb*)8GE|AH+7^9ld>~wp7$Ulc@#H_FuV@;6nv^>ha%fy_UIE42SFU zvjVsK)1lcTr|Nnxra}Dj1L(efllg7UOWls+nTzP$4Whpb)a~08IuvjJsH0ma(DM=I zw<(=^Lw8Bn(Z)k2632+V&%;WrB<%zkgVt0zz%YS;Y525F+Cz)-rpl{9I!QA;trUa$5Q@vIK5=Zl{|V(2kzZFovA({J zf1}?*PwoEc$}3lPf1h4hc_q59kE3<{vk<4HJm`KrlzIJo%tzQN#Ze)uKuyznS4lvi zB@Xk4dFo~2sK}(0Uv|}CfSeHl_X%nE=#}@5UY-=K@=mFONUhfXy`M=$+b=weRGz66T@|wW^Jv(Tamu5 z@P&Ne@G?VgTuSTxI-ii>Pb zi0r97`ovp0y{V&*J@necJv@IJn!kscx1#y8k&U!K`@2aTDM^99nS_m*gfv8=q(P29 zK>SS+{7_jThuQOcO^^Y?|16PX&*6ps;^4H~M0P)94t2~=M zZ~}wLutI;ReX4)F*_&E9*FRi6g7@Ex%v+dGqxrL_3e};$c7hHP_>?+8~RG_Vd8 zp*{nOH1H;c*0XA<-076dI~CigRP2f!>_YQ$w+}%wBWRrSiiX!K27{6_KVHhDdDHZI zC26L$k(w@7B+%CxCtcwme4})TQnekMjkR zD3YXkKsL||4vJA_ZqAYv+Ixhtn56f^axbslncu)DD1O91s2p+xzNl(@q z6mM7Q7nT40o-=R$c(EP{c<(v$pg%UY(g^i>%>6HYiPlo}DE(`@jlxXPpjgb!vc|k0 z>+cNp!&fN3Q+xuuxVr%KK&cecTgHwzgqA@lB+EE8h1NmN!*S~jYcS{rvgleaZkZuU z-4eYccYywX_Nr5LH&QgbA1)rw<~+U=?&iSow5|Tjd(XU?ZUZQMRUw?>5(b4Y16sUu zlM@HS!9%^>S#-aEVW3bksz$x(3dK72i~FADf!;3?QG&9(f*)Tic2YmWq@g0hfVWCGpV%>I|Pg=#F3JUNI(JNAD0=B>HaWrt_j^ zWywuD5c#`bovZo0mp5O_@w%-Yc<(PgD;#Q?b({VxdDqels+HnL*Q$s%>yzDk?+?-I zq4Oc;kg}mL;|iTsXfMYd=Y0mx`+TCvhfQ78PY^;DC1iz8I6VxvBD2H_2CTpd3?_Yx zMO(6Msv%xC7)w!tzzfMCVfIBJp4lUxTO#05czIlKJ4G(I<+pA37kfySXwhGQ|MCO0 ztt?bZv~}ph$+GlhvS7=;dsiRS&TW2pVd1?ia&}?yeJk>jU}7u@Yya5E?|qNCe|P;i zUwY|%^r!H;fPHWt?E?|5ixTyz?mZ_2dO@Hc_B`QXx*mGML#GObSTqvZkz$4<#bSmb zRs25AcMf2(ct7tEMByCgF*we{i7YMB=kVSTnQ}yuD%p56Mp;`bSoeP3$1@`9VQ9vo zfpEpJZ>u<>cv(r{h4hExO)QSiunca#u6`2B!jT9qNlCP(0!fTzgw|AFv0+W6D#HTW zz3t}vDNN*MA*oGJ@4Z6#klr{hk`@@dWY~78)hd;2r1x+FN)#oDPNnQA%CdF{RR%p- zu(sk8sY0%9PqE07!wT8`GNz!p1r+5jQCS4+@xST7Z{(zKZi>Wx$^ zH-r6Sb#SVN7E*iYcL)3L+?jKG*nbz!+%9E1rjK6-eIx%s;{CPds1ot(W z!E2oN`QG4t{=s=4LjHX4`+P%iUz6DPK3^NW&)0r{_xUIP&E9A4`~1J(-1k1XcKJny zqQ6ARRFnEo-Et!ZQMdx`$14!5BKR2t`xm>WF^BS#M7=HIs6tGpTL!8_1(U797%IDA z7_G4}ZX+?CMc<$#Y=^~qy|fjiM_S2U2Jw9r@_7j2I_rcTl=qPoz?1_60N^$BM;$`K zxP|6AeQR@w#c=uV$LCosH<@yH4E4=tXu+qOZ!+J_z2Rtt$tmXl zHp_@4kvdI&X6E1j{QxmhL{9pUoW4r99)Lg`@LZ8e$y~;mv~MSvw2wRIiqGLMA4B8Q z7?bvw0VAKf?575}LNVr10{n;gokkV$Z997VtuF-V5i37ZMc&<_|!eiWM}Q>0CaQPo>tW0y=67rBa~)b@ogq zqiIwv+T*K*d?meB%;f?JT@UpGY%0;GSij3%*C3O3wKc>%(c0hIc|(L@xQ2@`CG0_$ zw_8qC7v@r=ei!U`qxTH(aQC!}OLA=Vb)Rq{}aXCT|^&A0y*+f)O6U++4T^7ISmO zsGsSc)=YCpQjw#gdRfVb?A{%q4Gl4pPYU^bYN8trTNh(7HpGO6NK*k+DXyu4DM^%% zLe7q5hhsGJt`H$5d-ls$TTrB}IqYPF_Ki#m(n;+>WbJ84(+%^K4LS z&eG3p-gZDk?Ai44mi;L6WAg3~-_QulMhI&v^nvZ*KDr7uOI_`Xvyg+EpjbqV2MKzo zl*}N_FHQGCq4{P{n#)sj)xOTQ`w73_;gTlEZn*AdW`HPtBLT%8BP2~azaStvj4rK@ zw2OUxyqGdMFSpcpTJ4UW6U=mDp&;ebc2M&JI`Tc^>yy!D1%5Uh7D(2|@V8%ZJHnDD z&YnFsuX08t9wZcye>2=fMiF~!hyE`83_1}fslU8JO*--3NfPg!ga}d?;=Q;Mtqyec zbr4S-s_qOjEe4qugT(knqSw*mcW}pp@oVCpMkL*yjFB2 z9jz9N$W&95PGDnfDv_Jwx7u`w+NwgruzjQC4;Fm2Gtxemclc{=#HL=No!mT{nD3Rk zHLKLbKj|^OG+)wliXSkk4F}ab71DdB;>-7}^*5G=JIem8x^w!FA=vwXr~~xov5D7Q zT-w4q0IzX4U+G^P!F*@*1>(2uIDAm_$A|f#+S4vhGt}~c4xt|%_1k<7mURmE$RHiW zXu~+o`3e~iIw}g+30I<-bGQ;i*so)8F6f6a*Ha4FmtX2CHl*_`$OMIyz({EYK5cxY z;mrs6aMi&{g}*uSI)-dfhTwm}-=Bi?5AL>HMDI{&R2s+A1tXmn9KS0e=vu` zT>incH!RNGoWz)nijiF1Xj zQ7BX!jat0-{}cD-@sV8Rx$rqvU0u~x-PKiH)m_#5QoZksq?R;VTBA`TCwOhTO8kUe(HO(4D)8#@bukV&|~ zU?5oYo%d9At2Hww;rr*3jHK$8+Er(H&$~SD^Kg@s`FyoHlhd?yr>%TCKXJN?8kN&^ zf%rduuaL{ED)u0@$4BwXV#`z4DzIojMor~A|G#P}cl=mY6npJH%N%1qg;cVqTIm0w zOggX@%WzzfwODenm?fHzkcN^(6pES2wXBw9?PLRbHXFzWJe=&2&jNi8;yfO=-w&|3 zPIWWVwz6`ru$@WbR%1I5l#qN{MIP?7AUX)SYZgXEBZ#kE3&B4|5oF=VD}Uho|I>w! zk$(Kh$Jx`Q5({Jc@gpAx-EG?^|4{EHK>ohLTtsQ~>%E&rI9){(Sg%CrB^D`m&FA&* z_+{Pimt}uC5=JN-rb$E)td0AvXet?tC6hZta)eAII!LEd@nnLD#Rae5A7&VSTbIa3 zVY+(vVcZ>Q@N4kuG&*BIg8jrgK>UQACK^ZIu#TZ4gA$!|@Y!P*1)OPGthikz&FmtNL@daMEESse~P4bDOh&O!}*k3cH0zwQbS4P5tf0<@@$V%)Eg;4K;*iWTFS zvg#M2<|@N8WM~?l7b2hD*G*Qx1QA;juRo>E+~-8*d#Mf*vEvR+Bt{;I z&~!(olAg4q^Szjz-;2{h(UzwpXge7A-b?EnskP0mirTc&?SLW>yUW~}KhydX&i9)8 z{qL%W1A#F7`^ZOn?|R?+4~LS(YUhoN*uVeXKQ+(z=kLG%`gh@0wYvC)pkV}q(1$dP z<1t&a<9NmG`rD}eI>hfgbPoQDvwzRq{)J$U#qST=@%uyWHgIyzt)49NA_1ZN8at~2w zEYk=V*Us?0c|3qdKZH#7PuO=R%npt26BBk2>QZw8vuJF^xnz z&h|ZoO2d1wbs0Y~)Jb&af-G;%z6bj=sw17n;W#kH%$Tm@hetY#aYw)91!^5*a{)q2 zb`J}yHk6%6m zdVaQk+?a;&2KoJUsyW=XUw_7a{T<|W%v`W_#NhQT&A(m#8aZ2J<{n}-KM%M~8g3OF z6i>lH@mSzK!eKmOPobTWH^EO-1v+9of_xngD4Vd=4+oYXPAHx#x0p0{ z1pI{kWHQ6`bM0EK6%Mx~sg;oiUT+MomQ6Fb8nbCeX`ps#29GGIl&3DWUw}Qu7@<46 zS8~H&p`+1F;MSqnT{oGUT(-(ewtSlSICB%HOi$!|_rh)KCnsu4cYbhNt%^ZU{JhaV zF_W%FrGBWgSgbcq-?AKDJJGv66+BTr{)&|(X8JafF7b1&gWhIxlKuCGP|K!-Zw=k= zmUAqV?~nBWgkPbQHIQ7Rq~I~Qj1_5Cfim5~Nbyec0Xq>94S*~%J*>9rPHvLr(kYk2 zVX0jzWw#n^_;e)Fz+RiX7@)#4<2Y(iZ&j}5@WFdS({vnAZ&-TN?*=OM!>s6W9~|lkEz!MJ*k4w5ZQL(+JG$_jtw=TKDZG zutv%@03z)=1!bPK^H{Z?KhxIhMsYT)3htSW3Ae8}S+j1~8s@Pc6+EHBR4Q0E|M|<| zNz-b`yKfjKvY_AQIwnr`Vi>R~f}JB7;vvW4<*(DdNSPO^e#(Hl=96`wtoVF#lsLsB zzb@jJRi7^$T4gvE(tD#?dgICpI?dFL*Eu`Zh>c=@;r#B6_ttJH*OrQ!z}>g;7Pq(2 zi%hA^IiE})tY$p_mrOD|VOR~0gV?Hhd7E;&Wr+T<8iK&1er%B&&{0vf^C(_mOha?ETwipUfZ`(+&Mn`%6sYmP*Av8aYcdtVO8jUrsO|3ObNDX!5 zI zF6gIoccr{h`8f9ayf{Cd3q+nWGMXFXNJNc?e1=Coc5Lz0*L5+*kIB!!Qx?@&P6tMV z^%LcnpX3C5h=gIdIXInfwJlugR_z%hEyolf&`%*7B1(t3KEL{sG zyaf|pchZ7&CoNbWDhQXIsVqVIPo~UX@WmWTO*pHg2i8)7sZ<~nsK6{LkZ*+aVXp$M zY7>1S-zNvOFdYjf`%%-Z_5)om7%Z%&)6qOau_)76_1Wk(fN_EOv|D~Vjp5e0rU4z1 z+TwkrwiLzHv0K_njL7cG)iMz*n3Zg@lvsSxO8sC(Ke3`~nc#6PbvWBfD(nYS2WqkT zrZra$FEAIaQzs58O1DSXVg&xT7`0W1_%!_ z@KYLI1I3q~4EqJ=O}G0%B)%EeLZR-aGMg{RtfsZM zQmIG)S3s!0ST1i#5*>1TxEF^5-mw|yIxi$PKGrF9jS&wy-R9&1?@Q(~ac{SsD8v_T zT+Ypvjg3Jtk_sM&JYr`tAh?P9tF6 zmsF}3>gnpzAhnPxtvvr7Yx;1uHe-K9PXDCMIi5y`dY0elySYR-F{D;@TghZNqj@tZ zF-S9EZeR*dB8X96TA#1wgumI)K z0=xSMO5>$3ds)-zR;|AFt#6s?7Z)la%KcL*`wz|k-FGS6J&t~=MdYuc3>*}h>r@&iQ-T9YNk;)9$HH_h$- zA7Aw3&Y6_moobxE>4wapv``9CQjuytI90gehEuT>C+7Pi)i2CC`h`gcPi2h7eD58_ zd}h>+`5I$d<~cG)7P__9r5eQ+)hIUN@o+euizQRhXeu=%Fv=oL%lh2epro;pAARc`pF+5L~IRd<9Q&w2nE!xtvei26)i0BhV<|Q_^i77 zz4|xQZ%p8X`kH-e!?KS9{pE}O-|auqck~9g@N@VHvik?v_Yk?H)$+s6LE4AyE0WDR zPqS;2jyafg%)z9?Z&Y)(bj_*36r9%!PVqhKI4Id+k7RZzPndO0sUZmIvq5ve)fI4Uq{Z%iXq2bnEPiBmEX~Za_6!nAPZF3mJ z1)Q>5z#%&e*hM>_gfMBq22gM);CP^_z&q{}?-XdT!%#>~eV+Wne7BV=6e_J&+}H1E zSX<)y@m?V-tVTSu^@$={ReqXGo6XT=PnYu7=U~@3aJy?7_d#b#kJ4aLa!UBoUK1{PLfiJ~$0umu3#1y)k?4rt?Q?!|#t@ z4Jfj67>r6WF?J5*?{o({BxHx!p?&i-kCxDr{}*SeLVjU!X=%D#=}u2Ov$RZR>EO}= z%u>00V4~jb7V5*PA`?S47XaM$&(~LAZ~fTw<*-KB&E5r@Qo;_*VJ3g%jGYjJQo!)! z0+qZ!;v2s>4s-dV=k7L63j0heBMQSGZk`$9GQPtE#^&$qx|72ykLR#rqa2n=HL4+p zl^x4ry?2zuGHt9bB!@G?=V(|+4%U&g)3ZeD9sRxNi3rb}woMvhfXuwnu8regE(9TAa ze*e~khTY)^bLSgQs>dN4pe^A(M@q2Q@{n~1OxEU&3rl#wrS*x0?I}!{8 zvWl*0iaUIovFXf7H2EZPlAn5{Jrcbi=hPxD*jKKeK&{)kDtIJba}-}0GCrvO@1N0Z zqPt;~_$r=xw_rzx;Rrd-d=frgS^o#_bHf+ey1| zj-oQ>@O^N5^bSw=4nf>VqWjHm7lnht9aJSNs#-GV$4(z991I+zVttLem6 zwtzF1h}b5X6~BMhrz(mM8jzhCp>r}yxPWxPXiC2HNML5a5MTQW28a z*Fe9+{E`?;#=ZaRis@xgjO;0uxj;Pd7W$drGMXM8t!Y%pP^V!2$9qfgQ$y{9BawvL z&2oar<#D-o*o2;B*aV9Z%N91HW}=<&c)TeRpO-_Ca5&@^lBXHy@?{Wh@$S$*!o9U` zcg?gfb*@Q!sM4H^y$!Ts`}==x1H3zMQ)0{dT;O+(>4kmC5;B-O3;PlzP9Oa4r>+`5 zeAn)KuNW)H6K~@uNvst>JrWyI51e6HC&Ls_RWN57t3rFbJ8&AF`_iZ#u(8M25BWL` zqzuV%>gdgNwTBffzruL=#?jf77)>O66Vvi}a(lZ|7mj6D1h0pyAHZ*=xw&V_`S&R@ zUo|v~)rU~$^7kk@r0v82G*3Mf0F`oh*@8U2)uh~VKA;*STP6hFyWPJ}399Ta{-S8N zbbsrU4w3p}jtVqQ*6(u3b~27Ap?V_1Q&wQ#a3=1}PY)0FD^Nyv=Ii5kz@eJb5b$su7DA4-!Cp`+ym42&t0<`8~ zqJ5Bw6^if%4@uH=eHP6!wahF+J2<1`Oa^0dax)T{D{YD}Bk80>W+aF++3kQI*DBi# zCn4+}PD$q)bK;;Zloy&2!|Lt_x9r=$nlk}p{EfYd;lH+8RAT;wTmijMWLQnpEEI`G_=sOI!*bZiNBA|trwamE>;OBE^{^Zf!ewIH z1QZrH2D=BvY$}=b@r86+*L_+b5CK96UU0E2s0q;np4h;SbJE+wbQCn*rrj4bm~t=) zLqGyeF~e61)HNG6K?F9Rw0~$d(_M?0z+v|QhEfK_Ca^rfr8NNR;(PJ-PfXvnvA&T$ zzICo~6XRkQyBFPp+l61QRU1v?rO<3|pD=p(

      %OO| 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 If@OF9Ct~b_OaK4? diff --git a/web/src/assets/fonts/UbuntuMono-Regular.ttf b/web/src/assets/fonts/UbuntuMono-Regular.ttf deleted file mode 100644 index 037d73ffcb26253dcc779ef8188137a3754bab6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 196728 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 diff --git a/web/src/assets/fonts/UbuntuMono-Regular.woff b/web/src/assets/fonts/UbuntuMono-Regular.woff deleted file mode 100644 index eac2087adc4b709e5146a94669eeba00db7c8bf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106580 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

      5*lxWPJEJN~CElsA2gCZ`37 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 diff --git a/web/src/assets/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 b/web/src/assets/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 deleted file mode 100644 index 2b86ebfe6826a4ce14ed3682edb20d4d12a88978..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82512 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 - - - btn_google_dark_normal_ios - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/i18n/static/en.json b/web/src/assets/i18n/static/en.json deleted file mode 100644 index 11d86035cd..0000000000 --- a/web/src/assets/i18n/static/en.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "display_name": "Name", - "version": "Version", - "license_path": "License text", - "license": "License status" -} diff --git a/web/src/assets/ico_32x32.png b/web/src/assets/ico_32x32.png deleted file mode 100755 index f6439487c418d606ec8f5bdcf167ea2707a2b088..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 874 zcmV-w1C{)VP)p(;1N88^ROS66yA>&@=q%~%W+B~cqYc+^Te zCkmyy@T4?F<@91XUKLW$OCZySAp9r3MMqNMKze>B+R!GeU-!qjfzHx|2`XJ(M3WOE zT$hTvCKY^nX4A3`(Zw(0F?^GlP8Cg9jot*&enU)Ff+wqIoboPo3rw8@I^O>oF+p#Vsy9155F7o8dWu+xJQ~(@3NXa$0 z3JXdJ>|)%OlDAXN__E^YXsae~N>#KZGWXyE z;a!e_!u@+VsgPu4s(c$xL?hYjN)7e9nzQRCwVqpD*I)Q%jOd9uc%m%!_EloreOy@4 zi?c8Zqf&y3IGBD;iEc;=ED{Y|h`PD-uI=kR^u9Ppmf)hK)-)U^Y+hOxO|%maistG} zAp68b^d#1ku&{tK7WW+u4%yZ6!wW~9(>&hS?Kg=NwnZr~RG1yKr~!zW4so%-Nam0B3)@zdd_C z=XZX;vl!Mq8-|F8l*&L}0ucd+h=4;xz#$^w5D{qsXRUEsa_!_^BX*tGeU#o?uRcIDzZKk>R2Z8G7^4>@TuJZSOpliS2m0oR4OGn~fIlH=&^C zoICJvPOR%|IP$Gb<6Yy?orfNcjS_vPIVUXG*54GZOCR&M>_o1P;ah*A&hAU7;pAt? zWUC`9xN{d$azw_P75i`-ILnI@od(c9Ia(5&IVUa1r!Jk9_vci5 z4?QrmnzNnYVIc54pX+oDSIb^abP3z+udFC&olz4wO8UrvbF+T{{m|0J>dMtV^v~_v z_}uvTII2EYkDdyN5RC$G59WY-aBb4F3!Hp_uHX0_+k-#ux%H8WihZ~Z9Ivmf_+{RE zFctrt|3RuGIFH2fqrmEjNHqJ)EPQ@Zc?u7LyKB;AKNB}fEv!h<1dftEGT@x~?yO4~ z3JQzSA2<84O}o8Y@IG62ypC;J+wIsMU<->eN%kEg8XTp2$|P;o`p^uHUuradkzS{* zC@>Vlc^)!Q%R}Jv;flcl`I|P-QRj?R7jPhwd2~_F)cX>8C@)SGI7<5{1`ea(us9qM z;Ml$Q9hWw(7wq^vEJufH>hSNC)gS8$j#?j@!I@ua#xIpwCLqs%zag}%0cTAx^#H%* z<7G<^aNwE;H^XWtPUQ_;l41R59^ zL{9{VnIHB9QkfI>%Y~EvcXZ)M-yN^*!M5kyIy8f$)rTf!(Ip+wS80qPW|yFI^s|O zF>P(_owyBVKi9st@e_OwmKiPJX!W5Q940}8ndj;}4A{(sk_!&Zeuyd{-zu}C1UJdb zSJdPMvBp5^Wa2mE=q0!K?9<${xuyBX&g zBO`yaRTU(v%mIVvO3YDI{DvxU^zfkyoMokn>`v~y28*CzuLJC6!XT6!GbJ)o|H{?l_yn14m0A<$x1n+=%+F{fh10Dyv`<)`7tx+y;@TrM2Cqdauy? zKNmW>6oaFe4^`m641<^TKvBG?-GT!tbVX8SmQ_{FtIxpa7Vl4XJ2;>vZznr{MwkJP zmOhGs0|N)8F6^Da(b0L4Jy%rnCT{!f`VCQ^@Y!H&Y>ZbC$pJ?%ABw?&>H=@3Q56t3 zGH|sjA&MRps*(wCB#>g@z~&sD!Bo}bmlDnYRz)SW0GE&;N+^PDtr6YTl*t1}YabbK zAV)Yy&0a=V`>vtU(NXqW6)YJ~heY!BP~JOKEjdWd-=D*_HMPeTfuolX#o)kx2E3>R z2U2C-jMNouWZNn9Hj2aO>l+4(bEU{M=m1rAAm#z93lb^5dnvYh=4;x gz#$^w5dDAkAGmvs1VsA(8UO$Q07*qoM6N<$f`uR{g8%>k diff --git a/web/src/assets/scss/_grid.scss b/web/src/assets/scss/_grid.scss deleted file mode 100644 index 8892f0503a..0000000000 --- a/web/src/assets/scss/_grid.scss +++ /dev/null @@ -1,156 +0,0 @@ -.container { - margin: 0 auto; - max-width: 1280px; - width: 90%; -} -@media #{$medium-and-up} { - .container { - width: 85%; - } -} -@media #{$large-and-up} { - .container { - width: 70%; - } -} -.col .row { - margin-left: (-1 * $gutter-width / 2); - margin-right: (-1 * $gutter-width / 2); -} - -.section { - padding-top: 1rem; - padding-bottom: 1rem; - - &.no-pad { - padding: 0; - } - &.no-pad-bot { - padding-bottom: 0; - } - &.no-pad-top { - padding-top: 0; - } -} - - -// Mixins to eliminate code repitition -@mixin reset-offset { - margin-left: auto; - left: auto; - right: auto; -} -@mixin grid-classes($size, $i, $perc) { - &.offset-#{$size}#{$i} { - margin-left: $perc; - } - &.pull-#{$size}#{$i} { - right: $perc; - } - &.push-#{$size}#{$i} { - left: $perc; - } -} - - -.row { - margin-left: auto; - margin-right: auto; - margin-bottom: 20px; - - // Clear floating children - &:after { - content: ""; - display: table; - clear: both; - } - - .col { - float: left; - box-sizing: border-box; - padding: 0 $gutter-width / 2; - min-height: 1px; - - &[class*="push-"], - &[class*="pull-"] { - position: relative; - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - &.s#{$i} { - width: $perc; - @include reset-offset; - } - $i: $i + 1; - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - @include grid-classes("s", $i, $perc); - $i: $i + 1; - } - - @media #{$medium-and-up} { - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - &.m#{$i} { - width: $perc; - @include reset-offset; - } - $i: $i + 1 - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - @include grid-classes("m", $i, $perc); - $i: $i + 1; - } - } - - @media #{$large-and-up} { - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - &.l#{$i} { - width: $perc; - @include reset-offset; - } - $i: $i + 1; - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - @include grid-classes("l", $i, $perc); - $i: $i + 1; - } - } - - @media #{$extra-large-and-up} { - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - &.xl#{$i} { - width: $perc; - @include reset-offset; - } - $i: $i + 1; - } - - $i: 1; - @while $i <= $num-cols { - $perc: unquote((100 / ($num-cols / $i)) + "%"); - @include grid-classes("xl", $i, $perc); - $i: $i + 1; - } - } - } -} diff --git a/web/src/assets/scss/_mixins.scss b/web/src/assets/scss/_mixins.scss deleted file mode 100644 index f2117bce1c..0000000000 --- a/web/src/assets/scss/_mixins.scss +++ /dev/null @@ -1,42 +0,0 @@ -// https://css-tricks.com/almanac/properties/l/line-clamp/ -@mixin adcm-line-clamp($lines: 1) { - -webkit-box-orient: vertical; - display: -webkit-box; - -webkit-line-clamp: $lines; - overflow: hidden; - text-overflow: ellipsis; -} - -// https://css-tricks.com/snippets/css/prevent-long-urls-from-breaking-out-of-container/ -@mixin adcm-word-break-anywhere { - overflow-wrap: anywhere; - word-wrap: break-word; - -ms-word-break: break-all; - word-break: break-all; -} - -@mixin adcm-long-word-break { - /* These are technically the same, but use both */ - overflow-wrap: break-word; - word-wrap: break-word; - - -ms-word-break: break-all; - /* This is the dangerous one in WebKit, as it breaks things wherever */ - word-break: break-all; - /* Instead use this non-standard one: */ - word-break: break-word; - - /* Adds a hyphen where the word breaks, if supported (No Blink) */ - -ms-hyphens: auto; - -moz-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -@mixin adcm-cut-one-line-string { - @include adcm-line-clamp(1); - @include adcm-long-word-break; - - min-height: auto; - hyphens: none; -} diff --git a/web/src/assets/scss/_normalize.scss b/web/src/assets/scss/_normalize.scss deleted file mode 100644 index fa4e73dd41..0000000000 --- a/web/src/assets/scss/_normalize.scss +++ /dev/null @@ -1,447 +0,0 @@ -/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ - -/* Document - ========================================================================== */ - -/** - * 1. Correct the line height in all browsers. - * 2. Prevent adjustments of font size after orientation changes in - * IE on Windows Phone and in iOS. - */ - -html { - line-height: 1.15; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/* Sections - ========================================================================== */ - -/** - * Remove the margin in all browsers (opinionated). - */ - -body { - margin: 0; -} - -/** - * Add the correct display in IE 9-. - */ - -article, -aside, -footer, -header, -nav, -section { - display: block; -} - -/** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/* Grouping content - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - * 1. Add the correct display in IE. - */ - -figcaption, -figure, -main { /* 1 */ - display: block; -} - -/** - * Add the correct margin in IE 8. - */ - -figure { - margin: 1em 40px; -} - -/** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ - -hr { - box-sizing: content-box; /* 1 */ - height: 0; /* 1 */ - overflow: visible; /* 2 */ -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -pre { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/* Text-level semantics - ========================================================================== */ - -/** - * 1. Remove the gray background on active links in IE 10. - * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. - */ - -a { - background-color: transparent; /* 1 */ - -webkit-text-decoration-skip: objects; /* 2 */ -} - -/** - * 1. Remove the bottom border in Chrome 57- and Firefox 39-. - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ - -abbr[title] { - border-bottom: none; /* 1 */ - text-decoration: underline; /* 2 */ - text-decoration: underline dotted; /* 2 */ -} - -/** - * Prevent the duplicate application of `bolder` by the next rule in Safari 6. - */ - -b, -strong { - font-weight: inherit; -} - -/** - * Add the correct font weight in Chrome, Edge, and Safari. - */ - -b, -strong { - font-weight: bolder; -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -code, -kbd, -samp { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/** - * Add the correct font style in Android 4.3-. - */ - -dfn { - font-style: italic; -} - -/** - * Add the correct background and color in IE 9-. - */ - -mark { - background-color: #ff0; - color: #000; -} - -/** - * Add the correct font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - */ - -audio, -video { - display: inline-block; -} - -/** - * Add the correct display in iOS 4-7. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Remove the border on images inside links in IE 10-. - */ - -img { - border-style: none; -} - -/** - * Hide the overflow in IE. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Forms - ========================================================================== */ - -/** - * 1. Change the font styles in all browsers (opinionated). - * 2. Remove the margin in Firefox and Safari. - */ - -button, -input, -optgroup, -select, -textarea { - font-family: sans-serif; /* 1 */ - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ -} - -/** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - */ - -button, -input { /* 1 */ - overflow: visible; -} - -/** - * Remove the inheritance of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritance of text transform in Firefox. - */ - -button, -select { /* 1 */ - text-transform: none; -} - -/** - * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` - * controls in Android 4. - * 2. Correct the inability to style clickable types in iOS and Safari. - */ - -button, -html [type="button"], /* 1 */ -[type="reset"], -[type="submit"] { - -webkit-appearance: button; /* 2 */ -} - -/** - * Remove the inner border and padding in Firefox. - */ - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -/** - * Restore the focus styles unset by the previous rule. - */ - -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} - -/** - * Correct the padding in Firefox. - */ - -fieldset { - padding: 0.35em 0.75em 0.625em; -} - -/** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ - -legend { - box-sizing: border-box; /* 1 */ - color: inherit; /* 2 */ - display: table; /* 1 */ - max-width: 100%; /* 1 */ - padding: 0; /* 3 */ - white-space: normal; /* 1 */ -} - -/** - * 1. Add the correct display in IE 9-. - * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ - -progress { - display: inline-block; /* 1 */ - vertical-align: baseline; /* 2 */ -} - -/** - * Remove the default vertical scrollbar in IE. - */ - -textarea { - overflow: auto; -} - -/** - * 1. Add the correct box sizing in IE 10-. - * 2. Remove the padding in IE 10-. - */ - -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ - -[type="search"] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/** - * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. - */ - -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * 1. Correct the inability to style clickable types in iOS and Safari. - * 2. Change font properties to `inherit` in Safari. - */ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* Interactive - ========================================================================== */ - -/* - * Add the correct display in IE 9-. - * 1. Add the correct display in Edge, IE, and Firefox. - */ - -details, /* 1 */ -menu { - display: block; -} - -/* - * Add the correct display in all browsers. - */ - -summary { - display: list-item; -} - -/* Scripting - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - */ - -canvas { - display: inline-block; -} - -/** - * Add the correct display in IE. - */ - -template { - display: none; -} - -/* Hidden - ========================================================================== */ - -/** - * Add the correct display in IE 10-. - */ - -[hidden] { - display: none; -} diff --git a/web/src/environments/environment.prod.ts b/web/src/environments/environment.prod.ts deleted file mode 100644 index 1a0402e52f..0000000000 --- a/web/src/environments/environment.prod.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed 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. -const p = location.protocol; -export const environment = { - production: true, - apiRoot: '/api/v1/', - apiUI: '/api/ui/', - SERVER_URL_EVENT: `${p === 'https:' ? 'wss' : 'ws'}://${location.host}/ws/event/`, - SERVER_URL_STATUS: `${p === 'https:' ? 'wss' : 'ws'}://${location.host}/ws/status/` -}; diff --git a/web/src/environments/environment.ts b/web/src/environments/environment.ts deleted file mode 100644 index 7f3ba84b0e..0000000000 --- a/web/src/environments/environment.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Licensed 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. -// The file contents for the current environment will overwrite these during build. -// The build system defaults to the dev environment which uses `environment.ts`, but if you do -// `ng build --env=prod` then `environment.prod.ts` will be used instead. -// The list of which env maps to which file can be found in `.angular-cli.json`. -const p = location.protocol; -export const environment = { - production: false, - apiRoot: '/api/v1/', - apiUI: '/api/ui/', - SERVER_URL_EVENT: `${p === 'https:' ? 'wss' : 'ws'}://localhost:8000/ws/event/`, - SERVER_URL_STATUS: `${p === 'https:' ? 'wss' : 'ws'}://localhost:8000/ws/status/` -}; diff --git a/web/src/index.html b/web/src/index.html deleted file mode 100644 index fe49709f77..0000000000 --- a/web/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Arenadata Cluster Manager - - - - - - - - diff --git a/web/src/main.ts b/web/src/main.ts deleted file mode 100644 index 7863a7745a..0000000000 --- a/web/src/main.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Licensed 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 { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; - -if (environment.production) { - enableProdMode(); -} - -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.log(err)); diff --git a/web/src/polyfills.ts b/web/src/polyfills.ts deleted file mode 100644 index 91e2a148ce..0000000000 --- a/web/src/polyfills.ts +++ /dev/null @@ -1,77 +0,0 @@ -// Licensed 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. -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), - * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. - * - * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** IE9, IE10 and IE11 requires all of the following polyfills. **/ -// import 'core-js/es6/symbol'; -// import 'core-js/es6/object'; -// import 'core-js/es6/function'; -// import 'core-js/es6/parse-int'; -// import 'core-js/es6/parse-float'; -// import 'core-js/es6/number'; -// import 'core-js/es6/math'; -// import 'core-js/es6/string'; -// import 'core-js/es6/date'; -// import 'core-js/es6/array'; -// import 'core-js/es6/regexp'; -// import 'core-js/es6/map'; -// import 'core-js/es6/weak-map'; -// import 'core-js/es6/set'; - -/** IE10 and IE11 requires the following for NgClass support on SVG elements */ -// import 'classlist.js'; // Run `npm install --save classlist.js`. - -/** IE10 and IE11 requires the following for the Reflect API. */ -// import 'core-js/es6/reflect'; - - -/** Evergreen browsers require these. **/ -// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. -//import 'core-js/es7/reflect'; - - -/** - * Required to support Web Animations `@angular/platform-browser/animations`. - * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation - **/ -// import 'web-animations-js'; // Run `npm install --save web-animations-js`. - - - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ diff --git a/web/src/stories/Introduction.stories.mdx b/web/src/stories/Introduction.stories.mdx deleted file mode 100644 index 0e27fd589b..0000000000 --- a/web/src/stories/Introduction.stories.mdx +++ /dev/null @@ -1,230 +0,0 @@ -import { Meta } from '@storybook/addon-docs'; -import Code from './assets/code-brackets.svg'; -import Colors from './assets/colors.svg'; -import Comments from './assets/comments.svg'; -import Direction from './assets/direction.svg'; -import Flow from './assets/flow.svg'; -import Plugin from './assets/plugin.svg'; -import Repo from './assets/repo.svg'; -import StackAlt from './assets/stackalt.svg'; -import GlassesImg from './assets/glasses.jpg'; - - - - - -# Welcome to ADCM - -

      - - - -# About Storybook - -Storybook helps you build UI components in isolation from your app's business logic, data, and context. -That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA. - -Browse example stories now by navigating to them in the sidebar. -View their code in the `src/stories` directory to learn how they work. -We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages. - -
      Configure
      - - - -
      Learn
      - - - -
      - TipEdit the Markdown in{' '} - src/stories/Introduction.stories.mdx -
      diff --git a/web/src/stories/assets/code-brackets.svg b/web/src/stories/assets/code-brackets.svg deleted file mode 100644 index 73de947760..0000000000 --- a/web/src/stories/assets/code-brackets.svg +++ /dev/null @@ -1 +0,0 @@ -illustration/code-brackets \ No newline at end of file diff --git a/web/src/stories/assets/colors.svg b/web/src/stories/assets/colors.svg deleted file mode 100644 index 17d58d516e..0000000000 --- a/web/src/stories/assets/colors.svg +++ /dev/null @@ -1 +0,0 @@ -illustration/colors \ No newline at end of file diff --git a/web/src/stories/assets/comments.svg b/web/src/stories/assets/comments.svg deleted file mode 100644 index 6493a139f5..0000000000 --- a/web/src/stories/assets/comments.svg +++ /dev/null @@ -1 +0,0 @@ -illustration/comments \ No newline at end of file diff --git a/web/src/stories/assets/direction.svg b/web/src/stories/assets/direction.svg deleted file mode 100644 index 65676ac272..0000000000 --- a/web/src/stories/assets/direction.svg +++ /dev/null @@ -1 +0,0 @@ -illustration/direction \ No newline at end of file diff --git a/web/src/stories/assets/flow.svg b/web/src/stories/assets/flow.svg deleted file mode 100644 index 8ac27db403..0000000000 --- a/web/src/stories/assets/flow.svg +++ /dev/null @@ -1 +0,0 @@ -illustration/flow \ No newline at end of file diff --git a/web/src/stories/assets/glasses.jpg b/web/src/stories/assets/glasses.jpg deleted file mode 100644 index 9db99154a9a3adc26ac861c052bf6e408d12f47e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10064 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 diff --git a/web/src/stories/assets/plugin.svg b/web/src/stories/assets/plugin.svg deleted file mode 100644 index 29e5c690c0..0000000000 --- a/web/src/stories/assets/plugin.svg +++ /dev/null @@ -1 +0,0 @@ -illustration/plugin \ No newline at end of file diff --git a/web/src/stories/assets/repo.svg b/web/src/stories/assets/repo.svg deleted file mode 100644 index f386ee902c..0000000000 --- a/web/src/stories/assets/repo.svg +++ /dev/null @@ -1 +0,0 @@ -illustration/repo \ No newline at end of file diff --git a/web/src/stories/assets/stackalt.svg b/web/src/stories/assets/stackalt.svg deleted file mode 100644 index 9b7ad27435..0000000000 --- a/web/src/stories/assets/stackalt.svg +++ /dev/null @@ -1 +0,0 @@ -illustration/stackalt \ No newline at end of file diff --git a/web/src/stories/bell.stories.ts b/web/src/stories/bell.stories.ts deleted file mode 100644 index 4cc0bc5ae5..0000000000 --- a/web/src/stories/bell.stories.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Meta, moduleMetadata } from '@storybook/angular'; -import { APP_BASE_HREF, CommonModule } from '@angular/common'; -import { RouterModule } from '@angular/router'; -import { MatIconModule } from '@angular/material/icon'; -import { provideMockStore } from '@ngrx/store/testing'; -import { HttpClientModule } from '@angular/common/http'; - -import { NotificationsComponent } from '../app/components/notifications/notifications.component'; -import { BellComponent } from '../app/components/bell/bell.component'; -import { TaskService } from '../app/services/task.service'; -import { ApiService } from '../app/core/api'; -import { AuthService } from '../app/core/auth/auth.service'; -import { PopoverDirective } from '../app/directives/popover.directive'; - -export default { - title: 'ADCM/Custom Components', - decorators: [ - moduleMetadata({ - providers: [ - { - provide: APP_BASE_HREF, - useValue: '/', - }, - TaskService, - ApiService, - AuthService, - provideMockStore({}), - ], - declarations: [ - NotificationsComponent, - BellComponent, - PopoverDirective, - ], - imports: [ - CommonModule, - RouterModule.forRoot([], { useHash: true }), - MatIconModule, - HttpClientModule, - ], - }), - ], - component: BellComponent, - parameters: { - docs: { - page: null - } - }, -} as Meta; - -export const Bell = () => ({ }); diff --git a/web/src/stories/concern/concern-list-popup.stories.ts b/web/src/stories/concern/concern-list-popup.stories.ts deleted file mode 100644 index b3bd093b99..0000000000 --- a/web/src/stories/concern/concern-list-popup.stories.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Meta, moduleMetadata, Story } from '@storybook/angular'; -import { CommonModule } from '@angular/common'; -import { MatIconModule } from '@angular/material/icon'; -import { MatButtonModule } from '@angular/material/button'; -import { provideMockStore } from '@ngrx/store/testing'; - -import { ConcernService } from '../../app/services/concern.service'; -import { ConcernComponent } from '../../app/components/concern/concern.component'; -import { ConcernItemComponent } from '../../app/components/concern/concern-item/concern-item.component'; -import { IssueMessagePlaceholderPipe } from '../../app/pipes/issue-message-placeholder.pipe'; -import { ConcernListComponent } from '../../app/components/concern/concern-list/concern-list.component'; -import { ISSUE_MESSAGES_LIST_MOCK } from './mock'; -import { ConcernListRefComponent } from '../../app/components/concern/concern-list-ref/concern-list-ref.component'; -import { PopoverDirective } from '../../app/directives/popover.directive'; - -export default { - title: 'ADCM/Concern', - decorators: [ - moduleMetadata({ - providers: [ - ConcernService, - provideMockStore({}), - ], - declarations: [ - ConcernComponent, - ConcernItemComponent, - IssueMessagePlaceholderPipe, - ConcernListComponent, - ConcernListRefComponent, - PopoverDirective, - ], - imports: [ - CommonModule, - MatIconModule, - MatButtonModule, - ], - }), - ], - component: ConcernListRefComponent, - argTypes: { - concerns: { - control: { type: 'object' } - }, - }, - parameters: { - docs: { - page: null - } - }, -} as Meta; - -const Template: Story = (args) => ({ - props: args, - template: ``, -}); - -export const ListOfMessagesPopup = Template.bind({}); -ListOfMessagesPopup.args = ISSUE_MESSAGES_LIST_MOCK; diff --git a/web/src/stories/concern/concern-list.stories.ts b/web/src/stories/concern/concern-list.stories.ts deleted file mode 100644 index a43f745cfb..0000000000 --- a/web/src/stories/concern/concern-list.stories.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Meta, moduleMetadata, Story } from '@storybook/angular'; -import { CommonModule } from '@angular/common'; -import { MatIconModule } from '@angular/material/icon'; -import { MatButtonModule } from '@angular/material/button'; -import { provideMockStore } from '@ngrx/store/testing'; - -import { ConcernService } from '../../app/services/concern.service'; -import { ConcernComponent } from '../../app/components/concern/concern.component'; -import { ConcernItemComponent } from '../../app/components/concern/concern-item/concern-item.component'; -import { IssueMessagePlaceholderPipe } from '../../app/pipes/issue-message-placeholder.pipe'; -import { ConcernListComponent } from '../../app/components/concern/concern-list/concern-list.component'; -import { ISSUE_MESSAGES_LIST_MOCK } from './mock'; - -export default { - title: 'ADCM/Concern', - decorators: [ - moduleMetadata({ - providers: [ - ConcernService, - provideMockStore({}), - ], - declarations: [ - ConcernComponent, - ConcernItemComponent, - IssueMessagePlaceholderPipe, - ConcernListComponent, - ], - imports: [ - CommonModule, - MatIconModule, - MatButtonModule, - ], - }), - ], - component: ConcernListComponent, - argTypes: { - concerns: { - control: { type: 'object' } - }, - }, - parameters: { - docs: { - page: null - } - }, -} as Meta; - -const Template: Story = (args) => ({ - props: args, - template: ``, -}); - -export const ListOfMessages = Template.bind({}); -ListOfMessages.args = ISSUE_MESSAGES_LIST_MOCK; diff --git a/web/src/stories/concern/concern.stories.mdx b/web/src/stories/concern/concern.stories.mdx deleted file mode 100644 index f2fe942bfe..0000000000 --- a/web/src/stories/concern/concern.stories.mdx +++ /dev/null @@ -1,7 +0,0 @@ -import { Meta } from '@storybook/addon-docs'; - - - -# Issue/Flag Popup - -https://spec.adsw.io/adcm_core/feature-adcm-1765/ui/elements.html#issue-flag-popup diff --git a/web/src/stories/concern/concern.stories.ts b/web/src/stories/concern/concern.stories.ts deleted file mode 100644 index c15f9640f8..0000000000 --- a/web/src/stories/concern/concern.stories.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Meta, moduleMetadata, Story } from '@storybook/angular'; -import { MatIconModule } from '@angular/material/icon'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { provideMockStore } from '@ngrx/store/testing'; - -import { ConcernComponent } from '../../app/components/concern/concern.component'; -import { ConcernService } from '../../app/services/concern.service'; -import { ConcernItemComponent } from '../../app/components/concern/concern-item/concern-item.component'; -import { IssueMessagePlaceholderPipe } from '../../app/pipes/issue-message-placeholder.pipe'; -import { ISSUE_MESSAGES_DEFAULT_MOCK, ISSUE_MESSAGES_VERY_LONG_MOCK } from './mock'; - -export default { - title: 'ADCM/Concern', - decorators: [ - moduleMetadata({ - providers: [ - ConcernService, - provideMockStore({}), - ], - declarations: [ - ConcernComponent, - ConcernItemComponent, - IssueMessagePlaceholderPipe, - ], - imports: [ - CommonModule, - MatIconModule, - MatButtonModule, - ], - }), - ], - component: ConcernComponent, - argTypes: { - concern: { - control: { type: 'object' } - }, - }, - parameters: { - docs: { - page: null - } - }, -} as Meta; - -const Template: Story = args => ({ - props: { - ...args, - } -}); - -export const OnlyMessage = Template.bind({}); -OnlyMessage.args = ISSUE_MESSAGES_DEFAULT_MOCK; - -export const VeryLongMessage = Template.bind({}); -VeryLongMessage.args = ISSUE_MESSAGES_VERY_LONG_MOCK; diff --git a/web/src/stories/concern/mock.ts b/web/src/stories/concern/mock.ts deleted file mode 100644 index e275e95c71..0000000000 --- a/web/src/stories/concern/mock.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { IMPlaceholderItemType } from '../../app/models/concern/concern-reason'; -import { Concern } from '../../app/models/concern/concern'; - -export const ISSUE_MESSAGES_FIRST_MESSAGE: Concern = { - id: 2039, - blocking: true, - type: 'issue', - cause: 'config', - reason: { - message: 'Run ${action1} action on ${component1}.', - placeholder: { - action1: { - type: IMPlaceholderItemType.ComponentActionRun, - ids : { - cluster: 1, - service: 2, - component: 2, - action: 22 - }, - name: 'Restart' - }, - component1: { - type: IMPlaceholderItemType.ComponentConfig, - ids : { - cluster: 1, - service: 2, - component: 2 - }, - name: 'My Component' - } - } - } -}; - -export const ISSUE_MESSAGES_SECOND_MESSAGE: Concern = { - id: 2040, - blocking: true, - type: 'issue', - cause: 'config', - reason: { - message: 'Run the following ${action2} action on this ${component2}.', - placeholder: { - action2: { - type: IMPlaceholderItemType.ComponentActionRun, - ids : { - cluster: 1, - service: 2, - component: 2, - action: 22 - }, - name: 'Restart' - }, - component2: { - type: IMPlaceholderItemType.ComponentConfig, - ids : { - cluster: 1, - service: 2, - component: 2 - }, - name: 'My Component' - } - } - } -}; - -export const ISSUE_MESSAGES_VERY_LONG_MESSAGE: Concern = { - id: 2041, - blocking: true, - type: 'issue', - cause: 'config', - reason: { - message: 'Run ${action1} action on ${component1}. This is a very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' very very very very very very very very very very very very very very very very very very very very very very very' + - ' long message. Bonus ${action2}!', - placeholder: { - action1: { - type: IMPlaceholderItemType.ComponentActionRun, - ids : { - cluster: 1, - service: 2, - component: 2, - action: 22 - }, - name: 'Restart' - }, - component1: { - type: IMPlaceholderItemType.ComponentConfig, - ids : { - cluster: 1, - service: 2, - component: 2 - }, - name: 'My Component' - }, - action2: { - type: IMPlaceholderItemType.ComponentActionRun, - ids: { - cluster: 1, - service: 2, - component: 2, - action: 22 - }, - name: '' - } - } - } -}; - -export const ISSUE_MESSAGES_LIST_MOCK = { - concerns: [ - ISSUE_MESSAGES_FIRST_MESSAGE, - ISSUE_MESSAGES_SECOND_MESSAGE, - ISSUE_MESSAGES_VERY_LONG_MESSAGE, - ], -}; - -export const ISSUE_MESSAGES_DEFAULT_MOCK = { - concern: ISSUE_MESSAGES_FIRST_MESSAGE, -}; - -export const ISSUE_MESSAGES_VERY_LONG_MOCK = { - concern: ISSUE_MESSAGES_VERY_LONG_MESSAGE, -}; diff --git a/web/src/stories/status-tree/status-tree.stories.ts b/web/src/stories/status-tree/status-tree.stories.ts deleted file mode 100644 index ea1f74ba49..0000000000 --- a/web/src/stories/status-tree/status-tree.stories.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { Meta, moduleMetadata, Story } from '@storybook/angular'; -import { CommonModule } from '@angular/common'; -import { MatIconModule } from '@angular/material/icon'; -import { MatButtonModule } from '@angular/material/button'; -import { MatTreeModule } from '@angular/material/tree'; - -import { Folding, StatusTreeComponent } from '../../app/components/status-tree/status-tree.component'; -import { StatusTree } from '../../app/models/status-tree'; - -export default { - title: 'ADCM/Status Tree', - decorators: [ - moduleMetadata({ - declarations: [ - StatusTreeComponent, - ], - imports: [ - CommonModule, - MatIconModule, - MatButtonModule, - MatTreeModule, - ], - }), - ], - component: StatusTreeComponent, - argTypes: { - tree: { - control: { type: 'object' } - }, - folding: { - options: ['Collapse all', 'Expand all'], - mapping: { 'Collapse all': Folding.Collapsed, 'Expand all': Folding.Expanded }, - control: { - type: 'select' - } - } - }, - parameters: { - docs: { - page: null - } - }, -} as Meta; - -const Template: Story = args => ({ - props: { - ...args, - }, -}); - -export const RegularTree = Template.bind({}); -RegularTree.args = { - folding: Folding.Expanded, - tree: [ - { - subject: { - name: 'ADB Spark', - status: 16, - }, - children: [ - { - subject: { - name: 'Hosts', - status: 16, - }, - children: [ - { - subject: { - name: 'adb-spark-m.ru-central1.internal', - status: 0, - } - }, - { - subject: { - name: 'adb-spark-seg1.ru-central1.internal', - status: 1, - } - }, - { - subject: { - name: 'adb-spark-seg2.ru-central1.internal', - status: 1, - } - } - ] - }, - { - subject: { - name: 'Services', - status: 1, - }, - children: [ - { - subject: { - name: 'Chrony', - status: 0, - }, - children: [ - { - subject: { - name: 'NTP Master', - status: 0, - }, - children: [ - { - subject: { - name: 'adb-spark-m.ru-central1.internal', - status: 0, - } - } - ] - }, - { - subject: { - name: 'NTP Slave', - status: 0, - }, - children: [ - { - subject: { - name: 'adb-spark-seg1.ru-central1.internal', - status: 0, - } - }, - { - subject: { - name: 'adb-spark-seg2.ru-central1.internal', - status: 0, - } - } - ] - } - - ] - }, - { - subject: { - name: 'ADB', - status: 1, - }, - children: [ - { - subject: { - name: 'ADB Master', - status: 0, - }, - children: [ - { - subject: { - name: 'adb-spark-m.ru-central1.internal', - status: 0, - } - } - ] - }, - { - subject: { - name: 'ADB Segment', - status: 1, - }, - children: [ - { - subject: { - name: 'adb-spark-seg1.ru-central1.internal', - status: 0, - } - }, - { - subject: { - name: 'adb-spark-seg2.ru-central1.internal', - status: 1, - } - } - ] - } - ] - }, - { - subject: { - name: 'PXF', - status: 0, - }, - children: [ - { - subject: { - name: 'PXF', - status: 0, - }, - children: [ - { - subject: { - name: 'adb-spark-seg1.ru-central1.internal', - status: 0, - } - }, - { - subject: { - name: 'adb-spark-seg2.ru-central1.internal', - status: 0, - } - } - ] - } - - ] - }, - ] - }, - ] - } - ] as StatusTree[], -} ; diff --git a/web/src/styles.scss b/web/src/styles.scss deleted file mode 100644 index a8850ae70f..0000000000 --- a/web/src/styles.scss +++ /dev/null @@ -1,453 +0,0 @@ -@use './assets/scss/mixins' as mixins; -@import "./assets/scss/normalize"; - -// Media Query Ranges -$small-screen-up: 601px !default; -$medium-screen-up: 993px !default; -$large-screen-up: 1201px !default; -$small-screen: 600px !default; -$medium-screen: 992px !default; -$large-screen: 1200px !default; - -$medium-and-up: "only screen and (min-width : #{$small-screen-up})" !default; -$large-and-up: "only screen and (min-width : #{$medium-screen-up})" !default; -$extra-large-and-up: "only screen and (min-width : #{$large-screen-up})" !default; -$small-and-down: "only screen and (max-width : #{$small-screen})" !default; -$medium-and-down: "only screen and (max-width : #{$medium-screen})" !default; -$medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default; - -$num-cols: 12 !default; -$gutter-width: 1.5rem !default; -$element-top-margin: $gutter-width/3 !default; -$element-bottom-margin: ($gutter-width*2)/3 !default; - -$spacer: 1rem !default; - -@import "./assets/scss/grid"; - -html, body { - height: 100%; -} - -body { - display: flex; - flex: 1; - min-height: 100%; - overflow-x: hidden; - margin: 0; - padding: 0; - color: #ffffff; - background-color: #303030; - font-family: Roboto, "Helvetica Neue", sans-serif; -} - -app-root { - display: flex; - flex: 1; - position: relative; - - adwp-portal-host { - display: flex !important; - flex: 1; - } - - adwp-portal-host > .content { - overflow: hidden; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - display: flex; - flex-direction: column; - - & main { - flex: 1; - display: flex; - overflow: auto; - } - - & footer { - color: #ccc; - - & div { - text-align: right; - padding: 4px 10px; - font-size: .8em; - - & .left { - float: left; - } - } - } - } -} - -.top .mat-list-item-content { - justify-content: center; -} - -/** css for list only - TODO: make the list as module and lazy loading */ -mat-toolbar.toolbar { - height: auto; - min-height: 50px; - justify-content: space-between; - background-color: #21212163; -} - -mat-form-field textarea { - background-color: #cccccc !important; - color: #333 !important; - min-height: 100px; - padding: 8px !important; - box-sizing: border-box; -} - -.overflow { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - margin-right: 10px; -} - -.noflex, -.noflex > .mat-list-item-content { - display: block !important; -} - -mat-checkbox.advanced > label > span { - border-bottom: dotted 1px #00e676; - line-height: 20px !important; -} - -.mat-dialog-title { - margin: -6px -16px 20px !important; - padding: 2px 10px; - background-color: #2d2d2d; - border-radius: 2px; - font-size: large; - //box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12); -} - -.icon-locked { - animation: rotate 2s infinite linear; -} - -@keyframes rotate { - 0% { - transform: rotate(0deg) - } - - 100% { - transform: rotate(360deg) - } -} - -.mat-menu-panel { - max-width: none !important; -} - -.snack-bar-notify { - max-width: 60vw !important; - overflow: auto; - background-color: #595959; - color: #00e676; - - & button { - color: #78909c; - } -} - -.snack-bar-error { - max-width: 60vw !important; - overflow: auto; - background-color: #595959; - color: #ff9800; - - & button { - color: #78909c; - } -} - -.mat-card-header { - margin-bottom: 10px; -} - -.mat-card-header-text { - margin: 0 !important; -} - -.mat-dialog-container { - padding: 8px 18px !important; -} - -.mat-dialog-content { - margin: 0 -18px !important; - max-height: 80vh !important; - padding-top: 2px !important; - padding-bottom: 2px !important; -} - -.mat-dialog-actions { - margin-bottom: auto !important; -} - -.mat-card-subtitle { - margin-bottom: 0 !important; -} - -.row { - - & .star { - flex-basis: 20px; - text-align: right; - line-height: 60px; - - &.ddn { - padding-top: 12px; - } - } -} - -.mat-form-field, -.full-width { - flex-grow: 1; -} - -*:focus { - outline: none; -} - -.job-status .mat-mini-fab .mat-button-wrapper { - display: inline; - font-size: 11px; -} - -mat-sidenav { - width: 200px; - min-height: 100vh; -} - -mat-header-cell.control, -mat-cell.control { - flex-grow: 0; - flex-basis: 100px; - text-align: center; -} - -.item-title { - cursor: pointer; - - &:hover { - text-decoration: underline; - } - - &.has-checkbox { - margin-left: 36px; - } -} - -.mat-expansion-panel { - box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.6), 0px 2px 2px 0px rgba(2, 2, 2, 0.8), 0px 1px 5px 0px rgba(10, 10, 10, 0.9) !important; - - &.panel { - margin: 6px 0; - } -} - -.mat-column-controls { - text-align: right; -} - -.mat-column-select { - overflow: initial; -} - -.mat-list-icon { - color: rgba(0, 0, 0, 0.54); -} - -.mat-form-field { - // there isn't visible underscore in the firefox - line-height: normal; -} - -.hidden { - display: none !important; -} - -.login-icon { - padding: 0 14px; - cursor: pointer; - vertical-align: text-bottom; -} - -.on-center { - display: flex; - justify-content: center; -} - -.controls { - display: flex; - justify-content: flex-end; - - & button { - margin: 0 4px; - - &[color="accent"]:focus { - border: solid 1px #008444; - } - } -} - -// component for displaying some group - -.group { - background-color: #474747; - padding: 8px 20px 2px; - margin-top: 1px; - margin-bottom: 8px; - box-shadow: inset 2px 2px 5px rgba(90, 90, 90, 0.5), 1px 1px 5px #383838; -} - -.component { - border: solid 1px #696969; - padding: 2px 6px; - margin: 8px; - box-shadow: 0 14px 28px rgba(41, 41, 41, 0.25), 0 10px 10px rgba(29, 29, 29, 0.22); -} - -.alone > .field-group { - margin: 0 24px; -} - -.alone > .read-only { - margin: 0 14px !important; -} - -@font-face { - font-family: 'Material Icons'; - font-style: normal; - font-weight: 400; - src: url(assets/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format("woff2"); -} - -@font-face { - font-family: 'Ubuntu Mono'; - src: url("assets/fonts/UbuntuMono-Regular.eot"); - src: local("assets/fonts/Ubuntu Mono"), local("assets/fonts/UbuntuMono-Regular"), url("assets/fonts/UbuntuMono-Regular.eot?#iefix") format("embedded-opentype"), url("assets/fonts/UbuntuMono-Regular.woff") format("woff"), url("assets/fonts/UbuntuMono-Regular.ttf") format("truetype"); - font-weight: normal; - font-style: normal; -} - -@font-face { - font-family: 'Ubuntu Mono'; - src: url("assets/fonts/UbuntuMono-Bold.eot"); - src: local("assets/fonts/Ubuntu Mono Bold"), local("assets/fonts/UbuntuMono-Bold"), url("assets/fonts/UbuntuMono-Bold.eot?#iefix") format("embedded-opentype"), url("assets/fonts/UbuntuMono-Bold.woff") format("woff"), url("assets/fonts/UbuntuMono-Bold.ttf") format("truetype"); - font-weight: bold; - font-style: normal; -} - -@font-face { - font-family: 'Ubuntu Mono'; - src: url("assets/fonts/UbuntuMono-BoldItalic.eot"); - src: local("assets/fonts/Ubuntu Mono Bold Italic"), local("assets/fonts/UbuntuMono-BoldItalic"), url("assets/fonts/UbuntuMono-BoldItalic.eot?#iefix") format("embedded-opentype"), url("assets/fonts/UbuntuMono-BoldItalic.woff") format("woff"), url("assets/fonts/UbuntuMono-BoldItalic.ttf") format("truetype"); - font-weight: bold; - font-style: italic; -} - -@font-face { - font-family: 'Ubuntu Mono'; - src: url("assets/fonts/UbuntuMono-Italic.eot"); - src: local("assets/fonts/Ubuntu Mono Italic"), local("assets/fonts/UbuntuMono-Italic"), url("assets/fonts/UbuntuMono-Italic.eot?#iefix") format("embedded-opentype"), url("assets/fonts/UbuntuMono-Italic.woff") format("woff"), url("assets/fonts/UbuntuMono-Italic.ttf") format("truetype"); - font-weight: normal; - font-style: italic; -} - -.material-icons { - font-family: 'Material Icons', serif; - font-weight: normal; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - font-feature-settings: 'liga'; - -webkit-font-feature-settings: 'liga'; - -webkit-font-smoothing: antialiased; -} - -* { - scrollbar-width: auto; - scrollbar-color: #B5C6CA #FFF; -} - -*::-webkit-scrollbar, -*::-webkit-scrollbar { - width: 8px; -} - -*::-webkit-scrollbar-track, -*::-webkit-scrollbar-track { - background: inherit; -} - -*::-webkit-scrollbar-thumb, -*::-webkit-scrollbar-thumb { - background-color: #B5C6CA; - border-radius: 2.5px; - border: 3px solid inherit; -} - -.info-tooltip.mat-tooltip { - display: flex; - max-width: 900px; - text-align: left; - font-family: Roboto, "Helvetica Neue", sans-serif; - color: #fff; - font-size: 16px; - border: solid 1px #455A64; - padding: 8px 14px; - background-color: #37474F; - border-radius: 5px; - box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), - 0px 2px 2px 0px rgba(0, 0, 0, 0.14), - 0px 1px 5px 0px rgba(0, 0, 0, 0.12); - z-index: 1100; -} - -.d-flex { - display: flex; -} - -.flex-row { - flex-direction: row; -} - -.flex-column { - flex-direction: column; -} - -.w100 { - width: 100%; -} - -adwp-dropdown-box { - z-index: 2000 !important; -} - -.mat-select-panel { - .mat-selection-list { - max-height: 200px; - overflow-y: auto; - } -} - -.one-line-string { - @include mixins.adcm-cut-one-line-string; -} - diff --git a/web/src/test.ts b/web/src/test.ts deleted file mode 100644 index 3103565d90..0000000000 --- a/web/src/test.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed 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. -// This file is required by karma.conf.js and loads recursively all the .spec and framework files - -import 'zone.js/dist/long-stack-trace-zone'; -import 'zone.js/dist/proxy.js'; -import 'zone.js/dist/sync-test'; -import 'zone.js/dist/jasmine-patch'; -import 'zone.js/dist/async-test'; -import 'zone.js/dist/fake-async-test'; -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; - -// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. -declare const __karma__: any; -declare const require: any; - -// Prevent Karma from running prematurely. -__karma__.loaded = function () {}; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); -// Finally, start Karma to run the tests. -__karma__.start(); diff --git a/web/src/tsconfig.app.json b/web/src/tsconfig.app.json deleted file mode 100644 index 64ac555fc2..0000000000 --- a/web/src/tsconfig.app.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "compilerOptions": { - "target": "es5", - "lib": [ - "es2020.string", - "es2019", - "dom" - ], - "outDir": "../out-tsc/app", - "baseUrl": "./", - "types": [] - }, - "files": [ - "main.ts", - "polyfills.ts" - ], - "exclude": [ - "**/*.stories.*" - ] -} diff --git a/web/src/tsconfig.spec.json b/web/src/tsconfig.spec.json deleted file mode 100644 index b019e30f99..0000000000 --- a/web/src/tsconfig.spec.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "compilerOptions": { - "outDir": "../out-tsc/spec", - "baseUrl": "./", - "types": [ - "jasmine", - "node" - ] - }, - "files": [ - "test.ts", - "polyfills.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] -} diff --git a/web/src/uml/host.wsd b/web/src/uml/host.wsd deleted file mode 100644 index 313b3ddc00..0000000000 --- a/web/src/uml/host.wsd +++ /dev/null @@ -1,92 +0,0 @@ -@startuml host -title -Requests for Host page -end title - -skinparam BoxPadding 10 - -database HTTP - -box "Host list" -collections "Host list" as list -endbox - -box "Form for add Host" -collections Clusters -collections "Host from stack" as stack -actor "Add new host" as sh -endbox - -box "Configuration" -collections "Fields config" as cf -collections History as ch -actor "Save config" as cs -endbox - -== Initialization == - -HTTP -> list: "GET /api/v1/host/" -activate HTTP -HTTP -> Clusters: "GET /api/v1/cluster/" -HTTP -> stack: "GET /api/v1/stack/host/" -deactivate HTTP - -||40|| - -== Add host == - -sh -> HTTP: "POST /api/v1/host/" -activate sh -activate HTTP -Clusters --> sh: Internal request if had select cluster -activate sh -sh --> HTTP: "POST /api/v1/cluster/{cluster_id}/host/" -deactivate sh -HTTP -> sh -deactivate sh -HTTP -> list: "GET /api/v1/host/" -deactivate HTTP - -||40|| - -== Configuration == -list -> cf: "GET /api/v1/host/{host_id}/config/?view=interface" -activate list -list -> ch: "GET /api/v1/host/{host_id}/config/history/" -deactivate list - -cs -> HTTP: "POST /api/v1/host/{host_id}/config/?view=interface" -activate cs -activate HTTP -HTTP --> cf: "GET /api/v1/host/{host_id}/config/?view=interface" -activate HTTP -HTTP --> ch: "GET /api/v1/host/{host_id}/config/history/" -deactivate HTTP -HTTP -> cs -deactivate HTTP -deactivate cs - -ch -> HTTP: "Change history" -activate ch -activate HTTP -HTTP --> cf: "GET /api/v1/host/{host_id}/config/?view=interface" -activate HTTP -HTTP --> ch: "GET /api/v1/host/{host_id}/config/history/" -deactivate HTTP -HTTP -> ch -deactivate HTTP -deactivate ch - -||40|| - -== Actions == - -box "Actions" -collections "Actions" as act -endbox - -list -> act: "GET /api/v1/host/{host_id}/action/" -act -> HTTP: "POST /api/v1/cluster/{host_id}/action/{action_id}/run/" - -||40|| -@enduml \ No newline at end of file diff --git a/web/storybook.sh b/web/storybook.sh deleted file mode 100755 index 24fbdb0cd6..0000000000 --- a/web/storybook.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -cd /web || exit -npm config set registry https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ -yarn install -yarn run storybook diff --git a/web/tsconfig.base.json b/web/tsconfig.base.json deleted file mode 100644 index 0c1a628590..0000000000 --- a/web/tsconfig.base.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "compileOnSave": false, - "compilerOptions": { - "downlevelIteration": true, - "outDir": "./dist/out-tsc", - "sourceMap": true, - "declaration": false, - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - - // "noImplicitAny": true, - "noImplicitThis": true, - // "strictNullChecks": true, - // "strictPropertyInitialization": true, - "strictBindCallApply": true, - // "strictFunctionTypes": true, - // ...or - //"strict": true, - - "target": "es2015", - "typeRoots": [ - "node_modules/@types" - ], - "lib": [ - "es2018", - "dom", - "es2020.string" - ], - "baseUrl": "src", - "paths": { - "@app/*": [ - "app/*" - ], - "@env/*": [ - "environments/*" - ], - "@adwp-ui/widgets": [ - "app/adwp/index" - ], - "@adwp-ui/widgets/*": [ - "app/adwp/*" - ] - }, - "module": "esnext" - }, - "exclude": [] -} diff --git a/web/tsconfig.json b/web/tsconfig.json deleted file mode 100644 index 26abde9a1b..0000000000 --- a/web/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -/* - This is a "Solution Style" tsconfig.json file, and is used by editors and TypeScript’s language server to improve development experience. - It is not intended to be used to perform a compilation. - - To learn more about this file see: https://angular.io/config/solution-tsconfig. -*/ -{ - "files": [], - "references": [ - { - "path": "./src/tsconfig.app.json" - }, - { - "path": "./src/tsconfig.spec.json" - } - ] -} \ No newline at end of file diff --git a/web/tslint.json b/web/tslint.json deleted file mode 100644 index 6a9327b6bf..0000000000 --- a/web/tslint.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "rulesDirectory": [ - "node_modules/codelyzer" - ], - "rules": { - "arrow-return-shorthand": true, - "callable-types": true, - "class-name": true, - "comment-format": [ - false, - "check-space" - ], - "curly": false, - "deprecation": { - "severity": "warn" - }, - "eofline": true, - "forin": true, - "import-blacklist": [ - true, - "rxjs/Rx" - ], - "import-spacing": true, - "indent": [ - true, - "spaces" - ], - "interface-over-type-literal": true, - "label-position": true, - "max-line-length": [ - true, - 200 - ], - "member-access": false, - "member-ordering": [ - true, - { - "order": [ - "static-field", - "instance-field", - "static-method", - "instance-method" - ] - } - ], - "no-arg": true, - "no-bitwise": true, - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-construct": true, - "no-debugger": true, - "no-duplicate-super": true, - "no-empty": false, - "no-empty-interface": true, - "no-eval": true, - "no-inferrable-types": [ - true, - "ignore-params" - ], - "no-misused-new": true, - "no-non-null-assertion": true, - "no-shadowed-variable": true, - "no-string-literal": false, - "no-string-throw": true, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": false, - "no-unnecessary-initializer": true, - "no-unused-expression": true, - "no-var-keyword": true, - "object-literal-sort-keys": false, - "one-line": [ - true, - "check-open-brace", - "check-catch", - "check-else", - "check-whitespace" - ], - "prefer-const": false, - "quotemark": [ - true, - "single" - ], - "radix": true, - "semicolon": [ - true, - "always" - ], - "triple-equals": [ - true, - "allow-null-check" - ], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "typeof-compare": true, - "unified-signatures": true, - "variable-name": false, - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type" - ], - "directive-selector": [ - true, - "attribute", - "app", - "camelCase" - ], - "component-selector": [ - true, - "element", - "app", - "kebab-case" - ], - "angular-whitespace": [true, "check-interpolation", "check-semicolon"], - "no-output-on-prefix": true, - "no-inputs-metadata-property": true, - "no-outputs-metadata-property": true, - "no-host-metadata-property": true, - "no-input-rename": true, - "no-output-rename": true, - "use-lifecycle-interface": true, - "use-pipe-transform-interface": true, - "component-class-suffix": true, - "directive-class-suffix": true, - - "template-banana-in-box": true, - "template-no-negated-async": true, - "use-component-view-encapsulation": true, - "no-attribute-decorator": true, - "no-output-native": true, - "no-forward-ref": true, - "no-unused-css": true, - "contextual-lifecycle": true, - "template-use-track-by-function": false, - "no-pipe-impure": true, - "template-i18n": [false, "check-id", "check-text"] - } -} diff --git a/web/yarn.lock b/web/yarn.lock deleted file mode 100644 index 1e0b18fff9..0000000000 --- a/web/yarn.lock +++ /dev/null @@ -1,16075 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@aduh95/viz.js@^3.1.0": - version "3.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@aduh95/viz.js/-/viz.js-3.5.0.tgz#23f075b11a5555f33195c033b3330a8deab4bc2b" - integrity sha1-I/B1sRpVVfMxlcAzszMKjeq0vCs= - -"@angular-devkit/architect@0.1102.17": - version "0.1102.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular-devkit/architect/-/architect-0.1102.17.tgz#675b5ea866d9783a517e74e9a2288c4bb5c18b01" - integrity sha1-Z1teqGbZeDpRfnTpoiiMS7XBiwE= - dependencies: - "@angular-devkit/core" "11.2.17" - rxjs "6.6.3" - -"@angular-devkit/build-angular@~0.1102.14": - version "0.1102.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular-devkit/build-angular/-/build-angular-0.1102.17.tgz#9f7016be9dff8d661bdf3a046e03344ce9cc91de" - integrity sha1-n3AWvp3/jWYb3zoEbgM0TOnMkd4= - dependencies: - "@angular-devkit/architect" "0.1102.17" - "@angular-devkit/build-optimizer" "0.1102.17" - "@angular-devkit/build-webpack" "0.1102.17" - "@angular-devkit/core" "11.2.17" - "@babel/core" "7.12.10" - "@babel/generator" "7.12.11" - "@babel/plugin-transform-async-to-generator" "7.12.1" - "@babel/plugin-transform-runtime" "7.12.10" - "@babel/preset-env" "7.12.11" - "@babel/runtime" "7.12.5" - "@babel/template" "7.12.7" - "@discoveryjs/json-ext" "0.5.2" - "@jsdevtools/coverage-istanbul-loader" "3.0.5" - "@ngtools/webpack" "11.2.17" - ansi-colors "4.1.1" - autoprefixer "10.2.4" - babel-loader "8.2.2" - browserslist "^4.9.1" - cacache "15.0.5" - caniuse-lite "^1.0.30001032" - circular-dependency-plugin "5.2.2" - copy-webpack-plugin "6.3.2" - core-js "3.8.3" - critters "0.0.12" - css-loader "5.0.1" - cssnano "5.0.2" - file-loader "6.2.0" - find-cache-dir "3.3.1" - glob "7.1.6" - https-proxy-agent "5.0.0" - inquirer "7.3.3" - jest-worker "26.6.2" - karma-source-map-support "1.4.0" - less "4.1.1" - less-loader "7.3.0" - license-webpack-plugin "2.3.11" - loader-utils "2.0.0" - mini-css-extract-plugin "1.3.5" - minimatch "3.0.4" - open "7.4.0" - ora "5.3.0" - parse5-html-rewriting-stream "6.0.1" - pnp-webpack-plugin "1.6.4" - postcss "8.2.15" - postcss-import "14.0.0" - postcss-loader "4.2.0" - raw-loader "4.0.2" - regenerator-runtime "0.13.7" - resolve-url-loader "4.0.0" - rimraf "3.0.2" - rollup "2.38.4" - rxjs "6.6.3" - sass "1.32.6" - sass-loader "10.1.1" - semver "7.3.4" - source-map "0.7.3" - source-map-loader "1.1.3" - source-map-support "0.5.19" - speed-measure-webpack-plugin "1.4.2" - style-loader "2.0.0" - stylus "0.54.8" - stylus-loader "4.3.3" - terser "5.5.1" - terser-webpack-plugin "4.2.3" - text-table "0.2.0" - tree-kill "1.2.2" - webpack "4.44.2" - webpack-dev-middleware "3.7.2" - webpack-dev-server "3.11.2" - webpack-merge "5.7.3" - webpack-sources "2.2.0" - webpack-subresource-integrity "1.5.2" - worker-plugin "5.0.0" - -"@angular-devkit/build-optimizer@0.1102.17": - version "0.1102.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular-devkit/build-optimizer/-/build-optimizer-0.1102.17.tgz#7911d893c0d1077837db7fb3a36b6084e698c7cf" - integrity sha1-eRHYk8DRB3g323+zo2tghOaYx88= - dependencies: - loader-utils "2.0.0" - source-map "0.7.3" - tslib "2.1.0" - typescript "4.1.5" - webpack-sources "2.2.0" - -"@angular-devkit/build-webpack@0.1102.17": - version "0.1102.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular-devkit/build-webpack/-/build-webpack-0.1102.17.tgz#18ba41cc1d91a60a8926b62c8021a303b96db953" - integrity sha1-GLpBzB2RpgqJJrYsgCGjA7ltuVM= - dependencies: - "@angular-devkit/architect" "0.1102.17" - "@angular-devkit/core" "11.2.17" - rxjs "6.6.3" - -"@angular-devkit/core@11.2.17": - version "11.2.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular-devkit/core/-/core-11.2.17.tgz#4e0281b2e15c4c738775ded8f4abdf42e8518578" - integrity sha1-TgKBsuFcTHOHdd7Y9KvfQuhRhXg= - dependencies: - ajv "6.12.6" - fast-json-stable-stringify "2.1.0" - magic-string "0.25.7" - rxjs "6.6.3" - source-map "0.7.3" - -"@angular-devkit/schematics@11.2.17": - version "11.2.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular-devkit/schematics/-/schematics-11.2.17.tgz#a26111a64208e3b2720f15a37746d71e56be72a8" - integrity sha1-omERpkII47JyDxWjd0bXHla+cqg= - dependencies: - "@angular-devkit/core" "11.2.17" - ora "5.3.0" - rxjs "6.6.3" - -"@angular/animations@^11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/animations/-/animations-11.2.14.tgz#cf119ea779bf11bd3759f1355c85e4e8e9e7bb03" - integrity sha1-zxGep3m/Eb03WfE1XIXk6OnnuwM= - dependencies: - tslib "^2.0.0" - -"@angular/cdk@^11.2.13": - version "11.2.13" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/cdk/-/cdk-11.2.13.tgz#d54c9187e3b8cf3f8ba190b1edddc08ed2b740de" - integrity sha1-1UyRh+O4zz+LoZCx7d3AjtK3QN4= - dependencies: - tslib "^2.0.0" - optionalDependencies: - parse5 "^5.0.0" - -"@angular/cli@^11.2.14": - version "11.2.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/cli/-/cli-11.2.17.tgz#fe34ee37e873ffdfc9beccb8b033b062cf089d3c" - integrity sha1-/jTuN+hz/9/Jvsy4sDOwYs8InTw= - dependencies: - "@angular-devkit/architect" "0.1102.17" - "@angular-devkit/core" "11.2.17" - "@angular-devkit/schematics" "11.2.17" - "@schematics/angular" "11.2.17" - "@schematics/update" "0.1102.17" - "@yarnpkg/lockfile" "1.1.0" - ansi-colors "4.1.1" - debug "4.3.1" - ini "2.0.0" - inquirer "7.3.3" - jsonc-parser "3.0.0" - npm-package-arg "8.1.0" - npm-pick-manifest "6.1.0" - open "7.4.0" - ora "5.3.0" - pacote "11.2.4" - resolve "1.19.0" - rimraf "3.0.2" - semver "7.3.4" - symbol-observable "3.0.0" - universal-analytics "0.4.23" - uuid "8.3.2" - -"@angular/common@^11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/common/-/common-11.2.14.tgz#52887277b0ae0438e584f9ae97b417ee51a694b5" - integrity sha1-Uohyd7CuBDjlhPmul7QX7lGmlLU= - dependencies: - tslib "^2.0.0" - -"@angular/compiler-cli@11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/compiler-cli/-/compiler-cli-11.2.14.tgz#fdd22aeec25aa2477595bed631d19e977254ecc5" - integrity sha1-/dIq7sJaokd1lb7WMdGel3JU7MU= - dependencies: - "@babel/core" "^7.8.6" - "@babel/types" "^7.8.6" - canonical-path "1.0.0" - chokidar "^3.0.0" - convert-source-map "^1.5.1" - dependency-graph "^0.7.2" - fs-extra "4.0.2" - magic-string "^0.25.0" - minimist "^1.2.0" - reflect-metadata "^0.1.2" - semver "^6.3.0" - source-map "^0.6.1" - sourcemap-codec "^1.4.8" - tslib "^2.0.0" - yargs "^16.2.0" - -"@angular/compiler@9.0.0": - version "9.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/compiler/-/compiler-9.0.0.tgz#87e0bef4c369b6cadae07e3a4295778fc93799d5" - integrity sha1-h+C+9MNptsra4H46QpV3j8k3mdU= - -"@angular/compiler@^11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/compiler/-/compiler-11.2.14.tgz#9d3ea26b4d2d858aab935f69af9e201f53453a0f" - integrity sha1-nT6ia00thYqrk19pr54gH1NFOg8= - dependencies: - tslib "^2.0.0" - -"@angular/core@9.0.0": - version "9.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/core/-/core-9.0.0.tgz#227dc53e1ac81824f998c6e76000b7efc522641e" - integrity sha1-In3FPhrIGCT5mMbnYAC378UiZB4= - -"@angular/core@^10.0.0": - version "10.2.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/core/-/core-10.2.5.tgz#2050b0dbb180aa98c2ec46bba6d4827565ba2a2d" - integrity sha1-IFCw27GAqpjC7Ea7ptSCdWW6Ki0= - dependencies: - tslib "^2.0.0" - -"@angular/core@^11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/core/-/core-11.2.14.tgz#3ebe298c79d5413dc670d56b7f503bd4d788d4a8" - integrity sha1-Pr4pjHnVQT3GcNVrf1A71NeI1Kg= - dependencies: - tslib "^2.0.0" - -"@angular/elements@^12.1.2": - version "12.2.15" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/elements/-/elements-12.2.15.tgz#6fa6ae2d8d1c8e9ae674b34cd689c0232282c27d" - integrity sha1-b6auLY0cjprmdLNM1onAIyKCwn0= - dependencies: - tslib "^2.2.0" - -"@angular/forms@^11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/forms/-/forms-11.2.14.tgz#dc858408f7647f4fd033996a03aa74df18a02079" - integrity sha1-3IWECPdkf0/QM5lqA6p03xigIHk= - dependencies: - tslib "^2.0.0" - -"@angular/language-service@11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/language-service/-/language-service-11.2.14.tgz#452369cdffe76ac6d07836596fb47f9e69a6d119" - integrity sha1-RSNpzf/nasbQeDZZb7R/nmmm0Rk= - -"@angular/material@^11.2.13": - version "11.2.13" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/material/-/material-11.2.13.tgz#99960316d3ce58aac7497d7bb8b0c05468f502b9" - integrity sha1-mZYDFtPOWKrHSX17uLDAVGj1Ark= - dependencies: - tslib "^2.0.0" - -"@angular/platform-browser-dynamic@^11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.2.14.tgz#3c7fff1a1daacba5390acf033d28c377ec281166" - integrity sha1-PH//Gh2qy6U5Cs8DPSjDd+woEWY= - dependencies: - tslib "^2.0.0" - -"@angular/platform-browser@^11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/platform-browser/-/platform-browser-11.2.14.tgz#e52ad7a54a42a865033a17e57e213013919f1b1d" - integrity sha1-5SrXpUpCqGUDOhflfiEwE5GfGx0= - dependencies: - tslib "^2.0.0" - -"@angular/router@^11.2.14": - version "11.2.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@angular/router/-/router-11.2.14.tgz#4a8eb6d010a1a45c8e7f0c3b5b705959bdb69294" - integrity sha1-So620BChpFyOfww7W3BZWb22kpQ= - dependencies: - tslib "^2.0.0" - -"@babel/code-frame@7.10.4": - version "7.10.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" - integrity sha1-Fo2ho26Q2miujUnA8bSMfGJJITo= - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha1-9K1DWqJj25NbjxDyxVLSP7cWpj8= - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" - integrity sha1-DfyAMJvuyEEeZecGRhxAiwu5tDE= - dependencies: - "@babel/highlight" "^7.16.0" - -"@babel/compat-data@^7.12.7", "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.0", "@babel/compat-data@^7.16.4": - version "7.16.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" - integrity sha1-CB1rvDNuxcJDXGNGsq4fuYtaxo4= - -"@babel/core@7.12.10": - version "7.12.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd" - integrity sha1-t5ouG59w7T2Eu/ttjE74JfYGvM0= - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.10" - "@babel/helper-module-transforms" "^7.12.1" - "@babel/helpers" "^7.12.5" - "@babel/parser" "^7.12.10" - "@babel/template" "^7.12.7" - "@babel/traverse" "^7.12.10" - "@babel/types" "^7.12.10" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@7.12.9": - version "7.12.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8" - integrity sha1-/UUMTsEM27mA4pKLeqeihIRZP8g= - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.5" - "@babel/helper-module-transforms" "^7.12.1" - "@babel/helpers" "^7.12.5" - "@babel/parser" "^7.12.7" - "@babel/template" "^7.12.7" - "@babel/traverse" "^7.12.9" - "@babel/types" "^7.12.7" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.14.6", "@babel/core@^7.16.0", "@babel/core@^7.7.5", "@babel/core@^7.8.6": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/core/-/core-7.16.5.tgz#924aa9e1ae56e1e55f7184c8bf073a50d8677f5c" - integrity sha1-kkqp4a5W4eVfcYTIvwc6UNhnf1w= - dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/generator" "^7.16.5" - "@babel/helper-compilation-targets" "^7.16.3" - "@babel/helper-module-transforms" "^7.16.5" - "@babel/helpers" "^7.16.5" - "@babel/parser" "^7.16.5" - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.5" - "@babel/types" "^7.16.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" - -"@babel/generator@7.12.11": - version "7.12.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af" - integrity sha1-mKffe4w1jJo3qweiQFaFMBaro68= - dependencies: - "@babel/types" "^7.12.11" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/generator@^7.12.10", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/generator/-/generator-7.16.5.tgz#26e1192eb8f78e0a3acaf3eede3c6fc96d22bedf" - integrity sha1-JuEZLrj3jgo6yvPu3jxvyW0ivt8= - dependencies: - "@babel/types" "^7.16.0" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" - integrity sha1-mh8OvNpT2aLQAQjEzqzmpdXx8I0= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.5.tgz#a8429d064dce8207194b8bf05a70a9ea828746af" - integrity sha1-qEKdBk3OggcZS4vwWnCp6oKHRq8= - dependencies: - "@babel/helper-explode-assignable-expression" "^7.16.0" - "@babel/types" "^7.16.0" - -"@babel/helper-compilation-targets@^7.12.5", "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.3": - version "7.16.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" - integrity sha1-W0gM0T9oNj327E3IrI4toRNjy/A= - dependencies: - "@babel/compat-data" "^7.16.0" - "@babel/helper-validator-option" "^7.14.5" - browserslist "^4.17.5" - semver "^6.3.0" - -"@babel/helper-create-class-features-plugin@^7.16.0", "@babel/helper-create-class-features-plugin@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.5.tgz#5d1bcd096792c1ebec6249eebc6358eec55d0cad" - integrity sha1-XRvNCWeSwevsYknuvGNY7sVdDK0= - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-environment-visitor" "^7.16.5" - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-member-expression-to-functions" "^7.16.5" - "@babel/helper-optimise-call-expression" "^7.16.0" - "@babel/helper-replace-supers" "^7.16.5" - "@babel/helper-split-export-declaration" "^7.16.0" - -"@babel/helper-create-regexp-features-plugin@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz#06b2348ce37fccc4f5e18dcd8d75053f2a7c44ff" - integrity sha1-BrI0jON/zMT14Y3NjXUFPyp8RP8= - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - regexpu-core "^4.7.1" - -"@babel/helper-define-polyfill-provider@^0.1.5": - version "0.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz#3c2f91b7971b9fc11fe779c945c014065dea340e" - integrity sha1-PC+Rt5cbn8Ef53nJRcAUBl3qNA4= - dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-define-polyfill-provider@^0.3.0": - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz#c5b10cf4b324ff840140bb07e05b8564af2ae971" - integrity sha1-xbEM9LMk/4QBQLsH4FuFZK8q6XE= - dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-environment-visitor@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz#f6a7f38b3c6d8b07c88faea083c46c09ef5451b8" - integrity sha1-9qfzizxtiwfIj66gg8RsCe9UUbg= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-explode-assignable-expression@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778" - integrity sha1-dTAXM3oV9G+cCfZ0z/EM7pudd3g= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-function-name@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" - integrity sha1-t90Hl9ALv+5PB+nE6lsOMMi7FIE= - dependencies: - "@babel/helper-get-function-arity" "^7.16.0" - "@babel/template" "^7.16.0" - "@babel/types" "^7.16.0" - -"@babel/helper-get-function-arity@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" - integrity sha1-AIjHSGspqctdlIsaHeRttm4InPo= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-hoist-variables@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" - integrity sha1-TJAjwvHe9+KP9G/B2802o5vqqBo= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-member-expression-to-functions@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.5.tgz#1bc9f7e87354e86f8879c67b316cb03d3dc2caab" - integrity sha1-G8n36HNU6G+IecZ7MWywPT3Cyqs= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.12.5", "@babel/helper-module-imports@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" - integrity sha1-kFOOYLZy7PG0SPX09UM9N+eaPsM= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz#530ebf6ea87b500f60840578515adda2af470a29" - integrity sha1-Uw6/bqh7UA9ghAV4UVrdoq9HCik= - dependencies: - "@babel/helper-environment-visitor" "^7.16.5" - "@babel/helper-module-imports" "^7.16.0" - "@babel/helper-simple-access" "^7.16.0" - "@babel/helper-split-export-declaration" "^7.16.0" - "@babel/helper-validator-identifier" "^7.15.7" - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.5" - "@babel/types" "^7.16.0" - -"@babel/helper-optimise-call-expression@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" - integrity sha1-zs2xRdcMVAlrFWT46fEM19GTszg= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-plugin-utils@7.10.4": - version "7.10.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" - integrity sha1-L3WoMSadT2d95JmG3/WZJ1M883U= - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz#afe37a45f39fce44a3d50a7958129ea5b1a5c074" - integrity sha1-r+N6RfOfzkSj1Qp5WBKepbGlwHQ= - -"@babel/helper-remap-async-to-generator@^7.12.1", "@babel/helper-remap-async-to-generator@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.5.tgz#e706646dc4018942acb4b29f7e185bc246d65ac3" - integrity sha1-5wZkbcQBiUKstLKffhhbwkbWWsM= - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-wrap-function" "^7.16.5" - "@babel/types" "^7.16.0" - -"@babel/helper-replace-supers@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-replace-supers/-/helper-replace-supers-7.16.5.tgz#96d3988bd0ab0a2d22c88c6198c3d3234ca25326" - integrity sha1-ltOYi9CrCi0iyIxhmMPTI0yiUyY= - dependencies: - "@babel/helper-environment-visitor" "^7.16.5" - "@babel/helper-member-expression-to-functions" "^7.16.5" - "@babel/helper-optimise-call-expression" "^7.16.0" - "@babel/traverse" "^7.16.5" - "@babel/types" "^7.16.0" - -"@babel/helper-simple-access@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" - integrity sha1-IdaidiDjg+N1NM9sELugGab5BRc= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" - integrity sha1-DuM4gHAUfDrgUeSH7KPrsOLouwk= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-split-export-declaration@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" - integrity sha1-KWcvQ2Y+k23zcKrrIr7ds7rsdDg= - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-validator-identifier@^7.15.7": - version "7.15.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" - integrity sha1-Ig35k7/pBKSmsCq08zhaXr9uI4k= - -"@babel/helper-validator-option@^7.12.11", "@babel/helper-validator-option@^7.14.5": - version "7.14.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" - integrity sha1-bnKh//GNXfy4eOHmLxoCHEty1aM= - -"@babel/helper-wrap-function@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helper-wrap-function/-/helper-wrap-function-7.16.5.tgz#0158fca6f6d0889c3fee8a6ed6e5e07b9b54e41f" - integrity sha1-AVj8pvbQiJw/7opu1uXge5tU5B8= - dependencies: - "@babel/helper-function-name" "^7.16.0" - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.5" - "@babel/types" "^7.16.0" - -"@babel/helpers@^7.12.5", "@babel/helpers@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/helpers/-/helpers-7.16.5.tgz#29a052d4b827846dd76ece16f565b9634c554ebd" - integrity sha1-KaBS1LgnhG3Xbs4W9WW5Y0xVTr0= - dependencies: - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.5" - "@babel/types" "^7.16.0" - -"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" - integrity sha1-bOsysspLj182H7f9gh4/3fShclo= - dependencies: - "@babel/helper-validator-identifier" "^7.15.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.16.0", "@babel/parser@^7.16.5": - version "7.16.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/parser/-/parser-7.16.6.tgz#8f194828193e8fa79166f34a4b4e52f3e769a314" - integrity sha1-jxlIKBk+j6eRZvNKS05S8+dpoxQ= - -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.2": - version "7.16.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.2.tgz#2977fca9b212db153c195674e57cfab807733183" - integrity sha1-KXf8qbIS2xU8GVZ05Xz6uAdzMYM= - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz#358972eaab006f5eb0826183b0c93cbcaf13e1e2" - integrity sha1-NYly6qsAb16wgmGDsMk8vK8T4eI= - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-proposal-optional-chaining" "^7.16.0" - -"@babel/plugin-proposal-async-generator-functions@^7.12.1", "@babel/plugin-proposal-async-generator-functions@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.5.tgz#fd3bd7e0d98404a3d4cbca15a72d533f8c9a2f67" - integrity sha1-/TvX4NmEBKPUy8oVpy1TP4yaL2c= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-remap-async-to-generator" "^7.16.5" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.5.tgz#3269f44b89122110f6339806e05d43d84106468a" - integrity sha1-Mmn0S4kSIRD2M5gG4F1D2EEGRoo= - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-proposal-class-static-block@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.5.tgz#df58ab015a7d3b0963aafc8f20792dcd834952a9" - integrity sha1-31irAVp9OwljqvyPIHktzYNJUqk= - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-proposal-decorators@^7.12.12": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.5.tgz#4617420d3685078dfab8f68f859dca1448bbb3c7" - integrity sha1-RhdCDTaFB436uPaPhZ3KFEi7s8c= - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-decorators" "^7.16.5" - -"@babel/plugin-proposal-dynamic-import@^7.12.1", "@babel/plugin-proposal-dynamic-import@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.5.tgz#2e0d19d5702db4dcb9bc846200ca02f2e9d60e9e" - integrity sha1-Lg0Z1XAttNy5vIRiAMoC8unWDp4= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - -"@babel/plugin-proposal-export-default-from@^7.12.1": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.16.5.tgz#8771249ffc9c06c9eb27342cf5c072a83c6d3811" - integrity sha1-h3Ekn/ycBsnrJzQs9cByqDxtOBE= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-export-default-from" "^7.16.5" - -"@babel/plugin-proposal-export-namespace-from@^7.12.1", "@babel/plugin-proposal-export-namespace-from@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.5.tgz#3b4dd28378d1da2fea33e97b9f25d1c2f5bf1ac9" - integrity sha1-O03Sg3jR2i/qM+l7nyXRwvW/Gsk= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-json-strings@^7.12.1", "@babel/plugin-proposal-json-strings@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.5.tgz#1e726930fca139caab6b084d232a9270d9d16f9c" - integrity sha1-HnJpMPyhOcqrawhNIyqScNnRb5w= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-json-strings" "^7.8.3" - -"@babel/plugin-proposal-logical-assignment-operators@^7.12.1", "@babel/plugin-proposal-logical-assignment-operators@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.5.tgz#df1f2e4b5a0ec07abf061d2c18e53abc237d3ef5" - integrity sha1-3x8uS1oOwHq/Bh0sGOU6vCN9PvU= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.5.tgz#652555bfeeeee2d2104058c6225dc6f75e2d0f07" - integrity sha1-ZSVVv+7u4tIQQFjGIl3G914tDwc= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-numeric-separator@^7.12.7", "@babel/plugin-proposal-numeric-separator@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.5.tgz#edcb6379b6cf4570be64c45965d8da7a2debf039" - integrity sha1-7ctjebbPRXC+ZMRZZdjaei3r8Dk= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-object-rest-spread@7.12.1": - version "7.12.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069" - integrity sha1-3vm9A86g+bcig9rA7CLSicdpEGk= - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.12.1" - -"@babel/plugin-proposal-object-rest-spread@^7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.5.tgz#f30f80dacf7bc1404bf67f99c8d9c01665e830ad" - integrity sha1-8w+A2s97wUBL9n+ZyNnAFmXoMK0= - dependencies: - "@babel/compat-data" "^7.16.4" - "@babel/helper-compilation-targets" "^7.16.3" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.16.5" - -"@babel/plugin-proposal-optional-catch-binding@^7.12.1", "@babel/plugin-proposal-optional-catch-binding@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.5.tgz#1a5405765cf589a11a33a1fd75b2baef7d48b74e" - integrity sha1-GlQFdlz1iaEaM6H9dbK6731It04= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.12.7", "@babel/plugin-proposal-optional-chaining@^7.16.0", "@babel/plugin-proposal-optional-chaining@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.5.tgz#a5fa61056194d5059366c0009cb9a9e66ed75c1f" - integrity sha1-pfphBWGU1QWTZsAAnLmp5m7XXB8= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-private-methods@^7.12.1", "@babel/plugin-proposal-private-methods@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.5.tgz#2086f7d78c1b0c712d49b5c3fbc2d1ca21a7ee12" - integrity sha1-IIb314wbDHEtSbXD+8LRyiGn7hI= - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-proposal-private-property-in-object@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.5.tgz#a42d4b56005db3d405b12841309dbca647e7a21b" - integrity sha1-pC1LVgBds9QFsShBMJ28pkfnohs= - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-create-class-features-plugin" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - -"@babel/plugin-proposal-unicode-property-regex@^7.12.1", "@babel/plugin-proposal-unicode-property-regex@^7.16.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.5.tgz#35fe753afa7c572f322bd068ff3377bde0f37080" - integrity sha1-Nf51Ovp8Vy8yK9Bo/zN3veDzcIA= - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-syntax-async-generators@^7.8.0", "@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha1-qYP7Gusuw/btBCohD2QOkOeG/g0= - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.12.1", "@babel/plugin-syntax-class-properties@^7.12.13": - version "7.12.13" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha1-tcmHJ0xKOoK4lxR5aTGmtTVErhA= - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha1-GV34mxRrS3izv4l/16JXyEZZ1AY= - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-decorators@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.5.tgz#8d397dee482716a79f1a22314f0b4770a5b67427" - integrity sha1-jTl97kgnFqefGiIxTwtHcKW2dCc= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha1-Yr+Ysto80h1iYVT8lu5bPLaOrLM= - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-default-from@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.5.tgz#bfc148b007cba23cd2ce2f3c16df223afb44ab30" - integrity sha1-v8FIsAfLojzSzi88Ft8iOvtEqzA= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" - integrity sha1-AolkqbqA28CUyRXEh618TnpmRlo= - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha1-AcohtmjNghjJ5kDLbdiMVBKyyWo= - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@7.12.1": - version "7.12.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz#9d9d357cc818aa7ae7935917c1257f67677a0926" - integrity sha1-nZ01fMgYqnrnk1kXwSV/Z2d6CSY= - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-jsx@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz#bf255d252f78bc8b77a17cadc37d1aa5b8ed4394" - integrity sha1-vyVdJS94vIt3oXytw30apbjtQ5Q= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": - version "7.10.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha1-ypHvRjA1MESLkGZSusLp/plB9pk= - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha1-Fn7XA2iIYIH3S1w2xlqIwDtm0ak= - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.10.4": - version "7.10.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha1-ubBws+M1cM2f0Hun+pHA3Te5r5c= - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@7.8.3", "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha1-YOIl7cvZimQDMqLnLdPmbxr1WHE= - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.0", "@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha1-YRGiZbz7Ag6579D9/X0mQCue1sE= - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha1-T2nCq5UWfgGAzVM2YT+MV4j31Io= - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha1-DcZnHsDqIrbpShEU+FeXDNOd4a0= - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.12.1", "@babel/plugin-syntax-top-level-await@^7.14.5": - version "7.14.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha1-wc/a3DWmRiQAAfBhOCR7dBw02Uw= - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.16.0": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.5.tgz#f47a33e4eee38554f00fb6b2f894fa1f5649b0b3" - integrity sha1-9Hoz5O7jhVTwD7ay+JT6H1ZJsLM= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-arrow-functions@^7.12.1", "@babel/plugin-transform-arrow-functions@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.5.tgz#04c18944dd55397b521d9d7511e791acea7acf2d" - integrity sha1-BMGJRN1VOXtSHZ11EeeRrOp6zy0= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-async-to-generator@7.12.1": - version "7.12.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz#3849a49cc2a22e9743cbd6b52926d30337229af1" - integrity sha1-OEmknMKiLpdDy9a1KSbTAzcimvE= - dependencies: - "@babel/helper-module-imports" "^7.12.1" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-remap-async-to-generator" "^7.12.1" - -"@babel/plugin-transform-async-to-generator@^7.12.1", "@babel/plugin-transform-async-to-generator@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.5.tgz#89c9b501e65bb14c4579a6ce9563f859de9b34e4" - integrity sha1-icm1AeZbsUxFeabOlWP4Wd6bNOQ= - dependencies: - "@babel/helper-module-imports" "^7.16.0" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-remap-async-to-generator" "^7.16.5" - -"@babel/plugin-transform-block-scoped-functions@^7.12.1", "@babel/plugin-transform-block-scoped-functions@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.5.tgz#af087494e1c387574260b7ee9b58cdb5a4e9b0b0" - integrity sha1-rwh0lOHDh1dCYLfum1jNtaTpsLA= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-block-scoping@^7.12.11", "@babel/plugin-transform-block-scoping@^7.12.12", "@babel/plugin-transform-block-scoping@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.5.tgz#b91f254fe53e210eabe4dd0c40f71c0ed253c5e7" - integrity sha1-uR8lT+U+IQ6r5N0MQPccDtJTxec= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-classes@^7.12.1", "@babel/plugin-transform-classes@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.5.tgz#6acf2ec7adb50fb2f3194dcd2909dbd056dcf216" - integrity sha1-as8ux621D7LzGU3NKQnb0Fbc8hY= - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-environment-visitor" "^7.16.5" - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-optimise-call-expression" "^7.16.0" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-replace-supers" "^7.16.5" - "@babel/helper-split-export-declaration" "^7.16.0" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.12.1", "@babel/plugin-transform-computed-properties@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.5.tgz#2af91ebf0cceccfcc701281ada7cfba40a9b322a" - integrity sha1-KvkevwzOzPzHASga2nz7pAqbMio= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-destructuring@^7.12.1", "@babel/plugin-transform-destructuring@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.5.tgz#89ebc87499ac4a81b897af53bb5d3eed261bd568" - integrity sha1-ievIdJmsSoG4l69Tu10+7SYb1Wg= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-dotall-regex@^7.12.1", "@babel/plugin-transform-dotall-regex@^7.16.5", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.5.tgz#b40739c00b6686820653536d6d143e311de67936" - integrity sha1-tAc5wAtmhoIGU1NtbRQ+MR3meTY= - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-duplicate-keys@^7.12.1", "@babel/plugin-transform-duplicate-keys@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.5.tgz#2450f2742325412b746d7d005227f5e8973b512a" - integrity sha1-JFDydCMlQSt0bX0AUif16Jc7USo= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-exponentiation-operator@^7.12.1", "@babel/plugin-transform-exponentiation-operator@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.5.tgz#36e261fa1ab643cfaf30eeab38e00ed1a76081e2" - integrity sha1-NuJh+hq2Q8+vMO6rOOAO0adggeI= - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-for-of@^7.12.1", "@babel/plugin-transform-for-of@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.5.tgz#9b544059c6ca11d565457c0ff1f08e13ce225261" - integrity sha1-m1RAWcbKEdVlRXwP8fCOE84iUmE= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-function-name@^7.12.1", "@babel/plugin-transform-function-name@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.5.tgz#6896ebb6a5538a75d6a4086a277752f655a7bd15" - integrity sha1-aJbrtqVTinXWpAhqJ3dS9lWnvRU= - dependencies: - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-literals@^7.12.1", "@babel/plugin-transform-literals@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.5.tgz#af392b90e3edb2bd6dc316844cbfd6b9e009d320" - integrity sha1-rzkrkOPtsr1twxaETL/WueAJ0yA= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-member-expression-literals@^7.12.1", "@babel/plugin-transform-member-expression-literals@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.5.tgz#4bd6ecdc11932361631097b779ca5c7570146dd5" - integrity sha1-S9bs3BGTI2FjEJe3ecpcdXAUbdU= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-modules-amd@^7.12.1", "@babel/plugin-transform-modules-amd@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.5.tgz#92c0a3e83f642cb7e75fada9ab497c12c2616527" - integrity sha1-ksCj6D9kLLfnX62pq0l8EsJhZSc= - dependencies: - "@babel/helper-module-transforms" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-commonjs@^7.12.1", "@babel/plugin-transform-modules-commonjs@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.5.tgz#4ee03b089536f076b2773196529d27c32b9d7bde" - integrity sha1-TuA7CJU28HaydzGWUp0nwyude94= - dependencies: - "@babel/helper-module-transforms" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-simple-access" "^7.16.0" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-systemjs@^7.12.1", "@babel/plugin-transform-modules-systemjs@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.5.tgz#07078ba2e3cc94fbdd06836e355c246e98ad006b" - integrity sha1-BweLouPMlPvdBoNuNVwkbpitAGs= - dependencies: - "@babel/helper-hoist-variables" "^7.16.0" - "@babel/helper-module-transforms" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-validator-identifier" "^7.15.7" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-umd@^7.12.1", "@babel/plugin-transform-modules-umd@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.5.tgz#caa9c53d636fb4e3c99fd35a4c9ba5e5cd7e002e" - integrity sha1-yqnFPWNvtOPJn9NaTJul5c1+AC4= - dependencies: - "@babel/helper-module-transforms" "^7.16.5" - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.12.1", "@babel/plugin-transform-named-capturing-groups-regex@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.5.tgz#4afd8cdee377ce3568f4e8a9ee67539b69886a3c" - integrity sha1-Sv2M3uN3zjVo9Oip7mdTm2mIajw= - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.0" - -"@babel/plugin-transform-new-target@^7.12.1", "@babel/plugin-transform-new-target@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.5.tgz#759ea9d6fbbc20796056a5d89d13977626384416" - integrity sha1-dZ6p1vu8IHlgVqXYnROXdiY4RBY= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-object-super@^7.12.1", "@babel/plugin-transform-object-super@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.5.tgz#8ccd9a1bcd3e7732ff8aa1702d067d8cd70ce380" - integrity sha1-jM2aG80+dzL/iqFwLQZ9jNcM44A= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-replace-supers" "^7.16.5" - -"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.5.tgz#4fc74b18a89638bd90aeec44a11793ecbe031dde" - integrity sha1-T8dLGKiWOL2QruxEoReT7L4DHd4= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-property-literals@^7.12.1", "@babel/plugin-transform-property-literals@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.5.tgz#58f1465a7202a2bb2e6b003905212dd7a79abe3f" - integrity sha1-WPFGWnICorsuawA5BSEt16eavj8= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-react-display-name@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.5.tgz#d5e910327d7931fb9f8f9b6c6999473ceae5a286" - integrity sha1-1ekQMn15Mfufj5tsaZlHPOrlooY= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-react-jsx-development@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.5.tgz#87da9204c275ffb57f45d192a1120cf104bc1e86" - integrity sha1-h9qSBMJ1/7V/RdGSoRIM8QS8HoY= - dependencies: - "@babel/plugin-transform-react-jsx" "^7.16.5" - -"@babel/plugin-transform-react-jsx@^7.12.12", "@babel/plugin-transform-react-jsx@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.5.tgz#5298aedc5f81e02b1cb702e597e8d6a346675765" - integrity sha1-Upiu3F+B4CsctwLll+jWo0ZnV2U= - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-module-imports" "^7.16.0" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/plugin-syntax-jsx" "^7.16.5" - "@babel/types" "^7.16.0" - -"@babel/plugin-transform-react-pure-annotations@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.5.tgz#6535d0fe67c7a3a26c5105f92c8cbcbe844cd94b" - integrity sha1-ZTXQ/mfHo6JsUQX5LIy8voRM2Us= - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-regenerator@^7.12.1", "@babel/plugin-transform-regenerator@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.5.tgz#704cc6d8dd3dd4758267621ab7b36375238cef13" - integrity sha1-cEzG2N091HWCZ2Iat7NjdSOM7xM= - dependencies: - regenerator-transform "^0.14.2" - -"@babel/plugin-transform-reserved-words@^7.12.1", "@babel/plugin-transform-reserved-words@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.5.tgz#db95e98799675e193dc2b47d3e72a7c0651d0c30" - integrity sha1-25Xph5lnXhk9wrR9PnKnwGUdDDA= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-runtime@7.12.10": - version "7.12.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.10.tgz#af0fded4e846c4b37078e8e5d06deac6cd848562" - integrity sha1-rw/e1OhGxLNweOjl0G3qxs2EhWI= - dependencies: - "@babel/helper-module-imports" "^7.12.5" - "@babel/helper-plugin-utils" "^7.10.4" - semver "^5.5.1" - -"@babel/plugin-transform-shorthand-properties@^7.12.1", "@babel/plugin-transform-shorthand-properties@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.5.tgz#ccb60b1a23b799f5b9a14d97c5bc81025ffd96d7" - integrity sha1-zLYLGiO3mfW5oU2XxbyBAl/9ltc= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-spread@^7.12.1", "@babel/plugin-transform-spread@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.5.tgz#912b06cff482c233025d3e69cf56d3e8fa166c29" - integrity sha1-kSsGz/SCwjMCXT5pz1bT6PoWbCk= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - -"@babel/plugin-transform-sticky-regex@^7.12.7", "@babel/plugin-transform-sticky-regex@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.5.tgz#593579bb2b5a8adfbe02cb43823275d9098f75f9" - integrity sha1-WTV5uytait++AstDgjJ12QmPdfk= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-template-literals@^7.12.1", "@babel/plugin-transform-template-literals@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.5.tgz#343651385fd9923f5aa2275ca352c5d9183e1773" - integrity sha1-NDZROF/Zkj9aoidco1LF2Rg+F3M= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-typeof-symbol@^7.12.10", "@babel/plugin-transform-typeof-symbol@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.5.tgz#a1d1bf2c71573fe30965d0e4cd6a3291202e20ed" - integrity sha1-odG/LHFXP+MJZdDkzWoykSAuIO0= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-typescript@^7.16.1": - version "7.16.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz#cc0670b2822b0338355bc1b3d2246a42b8166409" - integrity sha1-zAZwsoIrAzg1W8Gz0iRqQrgWZAk= - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-typescript" "^7.16.0" - -"@babel/plugin-transform-unicode-escapes@^7.12.1", "@babel/plugin-transform-unicode-escapes@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.5.tgz#80507c225af49b4f4ee647e2a0ce53d2eeff9e85" - integrity sha1-gFB8Ilr0m09O5kfioM5T0u7/noU= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/plugin-transform-unicode-regex@^7.12.1", "@babel/plugin-transform-unicode-regex@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.5.tgz#ac84d6a1def947d71ffb832426aa53b83d7ed49e" - integrity sha1-rITWod75R9cf+4MkJqpTuD1+1J4= - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.16.5" - -"@babel/preset-env@7.12.11": - version "7.12.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/preset-env/-/preset-env-7.12.11.tgz#55d5f7981487365c93dbbc84507b1c7215e857f9" - integrity sha1-VdX3mBSHNlyT27yEUHscchXoV/k= - dependencies: - "@babel/compat-data" "^7.12.7" - "@babel/helper-compilation-targets" "^7.12.5" - "@babel/helper-module-imports" "^7.12.5" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-validator-option" "^7.12.11" - "@babel/plugin-proposal-async-generator-functions" "^7.12.1" - "@babel/plugin-proposal-class-properties" "^7.12.1" - "@babel/plugin-proposal-dynamic-import" "^7.12.1" - "@babel/plugin-proposal-export-namespace-from" "^7.12.1" - "@babel/plugin-proposal-json-strings" "^7.12.1" - "@babel/plugin-proposal-logical-assignment-operators" "^7.12.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" - "@babel/plugin-proposal-numeric-separator" "^7.12.7" - "@babel/plugin-proposal-object-rest-spread" "^7.12.1" - "@babel/plugin-proposal-optional-catch-binding" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.12.7" - "@babel/plugin-proposal-private-methods" "^7.12.1" - "@babel/plugin-proposal-unicode-property-regex" "^7.12.1" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-class-properties" "^7.12.1" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.12.1" - "@babel/plugin-transform-arrow-functions" "^7.12.1" - "@babel/plugin-transform-async-to-generator" "^7.12.1" - "@babel/plugin-transform-block-scoped-functions" "^7.12.1" - "@babel/plugin-transform-block-scoping" "^7.12.11" - "@babel/plugin-transform-classes" "^7.12.1" - "@babel/plugin-transform-computed-properties" "^7.12.1" - "@babel/plugin-transform-destructuring" "^7.12.1" - "@babel/plugin-transform-dotall-regex" "^7.12.1" - "@babel/plugin-transform-duplicate-keys" "^7.12.1" - "@babel/plugin-transform-exponentiation-operator" "^7.12.1" - "@babel/plugin-transform-for-of" "^7.12.1" - "@babel/plugin-transform-function-name" "^7.12.1" - "@babel/plugin-transform-literals" "^7.12.1" - "@babel/plugin-transform-member-expression-literals" "^7.12.1" - "@babel/plugin-transform-modules-amd" "^7.12.1" - "@babel/plugin-transform-modules-commonjs" "^7.12.1" - "@babel/plugin-transform-modules-systemjs" "^7.12.1" - "@babel/plugin-transform-modules-umd" "^7.12.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.1" - "@babel/plugin-transform-new-target" "^7.12.1" - "@babel/plugin-transform-object-super" "^7.12.1" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-transform-property-literals" "^7.12.1" - "@babel/plugin-transform-regenerator" "^7.12.1" - "@babel/plugin-transform-reserved-words" "^7.12.1" - "@babel/plugin-transform-shorthand-properties" "^7.12.1" - "@babel/plugin-transform-spread" "^7.12.1" - "@babel/plugin-transform-sticky-regex" "^7.12.7" - "@babel/plugin-transform-template-literals" "^7.12.1" - "@babel/plugin-transform-typeof-symbol" "^7.12.10" - "@babel/plugin-transform-unicode-escapes" "^7.12.1" - "@babel/plugin-transform-unicode-regex" "^7.12.1" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.12.11" - core-js-compat "^3.8.0" - semver "^5.5.0" - -"@babel/preset-env@^7.12.11", "@babel/preset-env@^7.16.4": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/preset-env/-/preset-env-7.16.5.tgz#2e94d922f4a890979af04ffeb6a6b4e44ba90847" - integrity sha1-LpTZIvSokJea8E/+tqa05EupCEc= - dependencies: - "@babel/compat-data" "^7.16.4" - "@babel/helper-compilation-targets" "^7.16.3" - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.2" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.0" - "@babel/plugin-proposal-async-generator-functions" "^7.16.5" - "@babel/plugin-proposal-class-properties" "^7.16.5" - "@babel/plugin-proposal-class-static-block" "^7.16.5" - "@babel/plugin-proposal-dynamic-import" "^7.16.5" - "@babel/plugin-proposal-export-namespace-from" "^7.16.5" - "@babel/plugin-proposal-json-strings" "^7.16.5" - "@babel/plugin-proposal-logical-assignment-operators" "^7.16.5" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.5" - "@babel/plugin-proposal-numeric-separator" "^7.16.5" - "@babel/plugin-proposal-object-rest-spread" "^7.16.5" - "@babel/plugin-proposal-optional-catch-binding" "^7.16.5" - "@babel/plugin-proposal-optional-chaining" "^7.16.5" - "@babel/plugin-proposal-private-methods" "^7.16.5" - "@babel/plugin-proposal-private-property-in-object" "^7.16.5" - "@babel/plugin-proposal-unicode-property-regex" "^7.16.5" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.16.5" - "@babel/plugin-transform-async-to-generator" "^7.16.5" - "@babel/plugin-transform-block-scoped-functions" "^7.16.5" - "@babel/plugin-transform-block-scoping" "^7.16.5" - "@babel/plugin-transform-classes" "^7.16.5" - "@babel/plugin-transform-computed-properties" "^7.16.5" - "@babel/plugin-transform-destructuring" "^7.16.5" - "@babel/plugin-transform-dotall-regex" "^7.16.5" - "@babel/plugin-transform-duplicate-keys" "^7.16.5" - "@babel/plugin-transform-exponentiation-operator" "^7.16.5" - "@babel/plugin-transform-for-of" "^7.16.5" - "@babel/plugin-transform-function-name" "^7.16.5" - "@babel/plugin-transform-literals" "^7.16.5" - "@babel/plugin-transform-member-expression-literals" "^7.16.5" - "@babel/plugin-transform-modules-amd" "^7.16.5" - "@babel/plugin-transform-modules-commonjs" "^7.16.5" - "@babel/plugin-transform-modules-systemjs" "^7.16.5" - "@babel/plugin-transform-modules-umd" "^7.16.5" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.5" - "@babel/plugin-transform-new-target" "^7.16.5" - "@babel/plugin-transform-object-super" "^7.16.5" - "@babel/plugin-transform-parameters" "^7.16.5" - "@babel/plugin-transform-property-literals" "^7.16.5" - "@babel/plugin-transform-regenerator" "^7.16.5" - "@babel/plugin-transform-reserved-words" "^7.16.5" - "@babel/plugin-transform-shorthand-properties" "^7.16.5" - "@babel/plugin-transform-spread" "^7.16.5" - "@babel/plugin-transform-sticky-regex" "^7.16.5" - "@babel/plugin-transform-template-literals" "^7.16.5" - "@babel/plugin-transform-typeof-symbol" "^7.16.5" - "@babel/plugin-transform-unicode-escapes" "^7.16.5" - "@babel/plugin-transform-unicode-regex" "^7.16.5" - "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.16.0" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.4.0" - babel-plugin-polyfill-regenerator "^0.3.0" - core-js-compat "^3.19.1" - semver "^6.3.0" - -"@babel/preset-modules@^0.1.3", "@babel/preset-modules@^0.1.5": - version "0.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" - integrity sha1-75Odbn8miCfhhBY43G/5VRXhFdk= - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/preset-react@^7.12.10": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/preset-react/-/preset-react-7.16.5.tgz#09df3b7a6522cb3e6682dc89b4dfebb97d22031b" - integrity sha1-Cd87emUiyz5mgtyJtN/ruX0iAxs= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-transform-react-display-name" "^7.16.5" - "@babel/plugin-transform-react-jsx" "^7.16.5" - "@babel/plugin-transform-react-jsx-development" "^7.16.5" - "@babel/plugin-transform-react-pure-annotations" "^7.16.5" - -"@babel/preset-typescript@^7.12.7": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/preset-typescript/-/preset-typescript-7.16.5.tgz#b86a5b0ae739ba741347d2f58c52f52e63cf1ba1" - integrity sha1-uGpbCuc5unQTR9L1jFL1LmPPG6E= - dependencies: - "@babel/helper-plugin-utils" "^7.16.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-transform-typescript" "^7.16.1" - -"@babel/register@^7.12.1": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/register/-/register-7.16.5.tgz#657d28b7ca68190de8f6159245b5ed1cfa181640" - integrity sha1-ZX0ot8poGQ3o9hWSRbXtHPoYFkA= - dependencies: - clone-deep "^4.0.1" - find-cache-dir "^2.0.0" - make-dir "^2.1.0" - pirates "^4.0.0" - source-map-support "^0.5.16" - -"@babel/runtime@7.12.5": - version "7.12.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" - integrity sha1-QQ5+SHRB4bNgwpvnFdhw2bmFiC4= - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/runtime/-/runtime-7.16.5.tgz#7f3e34bf8bdbbadf03fbb7b1ea0d929569c9487a" - integrity sha1-fz40v4vbut8D+7ex6g2SlWnJSHo= - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@7.12.7": - version "7.12.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" - integrity sha1-yBcjNpYBjjn7tsSR0vtoTgXtQ7w= - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.12.7" - "@babel/types" "^7.12.7" - -"@babel/template@^7.12.7", "@babel/template@^7.16.0": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" - integrity sha1-0Wo16/TNdOICCDNW+rId2JNj3dY= - dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/parser" "^7.16.0" - "@babel/types" "^7.16.0" - -"@babel/traverse@^7.12.10", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.5": - version "7.16.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/traverse/-/traverse-7.16.5.tgz#d7d400a8229c714a59b87624fc67b0f1fbd4b2b3" - integrity sha1-19QAqCKccUpZuHYk/Gew8fvUsrM= - dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/generator" "^7.16.5" - "@babel/helper-environment-visitor" "^7.16.5" - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-hoist-variables" "^7.16.0" - "@babel/helper-split-export-declaration" "^7.16.0" - "@babel/parser" "^7.16.5" - "@babel/types" "^7.16.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.7", "@babel/types@^7.16.0", "@babel/types@^7.4.4", "@babel/types@^7.8.6": - version "7.16.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" - integrity sha1-2zsxOAT5aq3Qt3bEgj4SetZyibo= - dependencies: - "@babel/helper-validator-identifier" "^7.15.7" - to-fast-properties "^2.0.0" - -"@base2/pretty-print-object@1.0.1": - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz#371ba8be66d556812dc7fb169ebc3c08378f69d4" - integrity sha1-NxuovmbVVoEtx/sWnrw8CDePadQ= - -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha1-+GSuhQBND8q29QvpFBxNo2jRZWo= - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - -"@compodoc/compodoc@^1.1.14": - version "1.1.16" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@compodoc/compodoc/-/compodoc-1.1.16.tgz#a7b03be50b20f5515048ee0ceace2195de68d87e" - integrity sha1-p7A75Qsg9VFQSO4M6s4hld5o2H4= - dependencies: - "@babel/core" "^7.16.0" - "@babel/preset-env" "^7.16.4" - "@compodoc/live-server" "^1.2.2" - "@compodoc/ngd-transformer" "^2.1.0" - chalk "^4.1.2" - cheerio "^1.0.0-rc.10" - chokidar "^3.5.2" - colors "^1.4.0" - commander "^8.3.0" - cosmiconfig "^7.0.1" - decache "^4.6.0" - fancy-log "^1.3.3" - findit2 "^2.2.3" - fs-extra "^10.0.0" - glob "^7.2.0" - handlebars "^4.7.7" - html-entities "^2.3.2" - i18next "^21.5.2" - inside "^1.0.0" - json5 "^2.2.0" - lodash "^4.17.21" - loglevel "^1.8.0" - loglevel-plugin-prefix "^0.8.4" - lunr "^2.3.9" - marked "^4.0.4" - minimist "^1.2.5" - opencollective-postinstall "^2.0.3" - os-name "4.0.1" - pdfmake "^0.2.4" - semver "^7.3.5" - traverse "^0.6.6" - ts-morph "^13.0.1" - uuid "^8.3.2" - -"@compodoc/live-server@^1.2.2": - version "1.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@compodoc/live-server/-/live-server-1.2.2.tgz#25aa1695ad7d2a2687b0702b5686d8e713e258c9" - integrity sha1-JaoWla19KiaHsHArVobY5xPiWMk= - dependencies: - chokidar "^3.5.2" - colors latest - connect "^3.7.0" - cors latest - event-stream "4.0.1" - faye-websocket "0.11.x" - http-auth "4.1.7" - http-auth-connect "^1.0.5" - morgan "^1.10.0" - object-assign latest - open "8.2.1" - proxy-middleware latest - send latest - serve-index "^1.9.1" - -"@compodoc/ngd-core@~2.1.0": - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@compodoc/ngd-core/-/ngd-core-2.1.0.tgz#965c5d34d6331d2608575291afe9498040c69acd" - integrity sha1-llxdNNYzHSYIV1KRr+lJgEDGms0= - dependencies: - ansi-colors "^4.1.1" - fancy-log "^1.3.3" - typescript "^4.0.3" - -"@compodoc/ngd-transformer@^2.1.0": - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@compodoc/ngd-transformer/-/ngd-transformer-2.1.0.tgz#8d335a214d30a139ddc5b74a9127ab924bd10a20" - integrity sha1-jTNaIU0woTndxbdKkSerkkvRCiA= - dependencies: - "@aduh95/viz.js" "^3.1.0" - "@compodoc/ngd-core" "~2.1.0" - dot "^1.1.3" - fs-extra "^9.0.1" - -"@discoveryjs/json-ext@0.5.2": - version "0.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752" - integrity sha1-jwOiKgTeQ3JU6M6MyEujlokoh1I= - -"@discoveryjs/json-ext@^0.5.3": - version "0.5.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz#d5e0706cf8c6acd8c6032f8d54070af261bbbb2f" - integrity sha1-1eBwbPjGrNjGAy+NVAcK8mG7uy8= - -"@emotion/cache@^10.0.27": - version "10.0.29" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" - integrity sha1-h+fmT0EsBgEC1Yn+fG3AQub50eA= - dependencies: - "@emotion/sheet" "0.9.4" - "@emotion/stylis" "0.8.5" - "@emotion/utils" "0.11.3" - "@emotion/weak-memoize" "0.2.5" - -"@emotion/core@^10.1.1": - version "10.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/core/-/core-10.3.1.tgz#4021b6d8b33b3304d48b0bb478485e7d7421c69d" - integrity sha1-QCG22LM7MwTUiwu0eEhefXQhxp0= - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/cache" "^10.0.27" - "@emotion/css" "^10.0.27" - "@emotion/serialize" "^0.11.15" - "@emotion/sheet" "0.9.4" - "@emotion/utils" "0.11.3" - -"@emotion/css@^10.0.27": - version "10.0.27" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c" - integrity sha1-OnRYGY+767U7AbK4f2Tl4hJB4Uw= - dependencies: - "@emotion/serialize" "^0.11.15" - "@emotion/utils" "0.11.3" - babel-plugin-emotion "^10.0.27" - -"@emotion/hash@0.8.0": - version "0.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" - integrity sha1-u7/2iXj+/b5ozLUzvIy+HRr7VBM= - -"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.6": - version "0.8.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" - integrity sha1-2yixxDaKJZtgqXMR1qlS1P0BrBo= - dependencies: - "@emotion/memoize" "0.7.4" - -"@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" - integrity sha1-Gb8PWvGRSREcQNmLsM+CEZ9dnus= - -"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": - version "0.11.16" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" - integrity sha1-3uBfnpatL7JaUga211my0e0zea0= - dependencies: - "@emotion/hash" "0.8.0" - "@emotion/memoize" "0.7.4" - "@emotion/unitless" "0.7.5" - "@emotion/utils" "0.11.3" - csstype "^2.5.7" - -"@emotion/sheet@0.9.4": - version "0.9.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" - integrity sha1-iUN0vqOeww9Im7/DQ4GSuXdNMuU= - -"@emotion/styled-base@^10.3.0": - version "10.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/styled-base/-/styled-base-10.3.0.tgz#9aa2c946100f78b47316e4bc6048321afa6d4e36" - integrity sha1-mqLJRhAPeLRzFuS8YEgyGvptTjY= - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/is-prop-valid" "0.8.8" - "@emotion/serialize" "^0.11.15" - "@emotion/utils" "0.11.3" - -"@emotion/styled@^10.0.27": - version "10.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/styled/-/styled-10.3.0.tgz#8ee959bf75730789abb5f67f7c3ded0c30aec876" - integrity sha1-julZv3VzB4mrtfZ/fD3tDDCuyHY= - dependencies: - "@emotion/styled-base" "^10.3.0" - babel-plugin-emotion "^10.0.27" - -"@emotion/stylis@0.8.5": - version "0.8.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" - integrity sha1-3qyzib1u530ef8rMzp4WxcfnjgQ= - -"@emotion/unitless@0.7.5": - version "0.7.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" - integrity sha1-dyESkcGQCnALinjPr9oxYNdpSe0= - -"@emotion/utils@0.11.3": - version "0.11.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924" - integrity sha1-p1mGOGe++n5YNADTImUqP0SCCSQ= - -"@emotion/weak-memoize@0.2.5": - version "0.2.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" - integrity sha1-ju2YLi7m9/TkTCU+EpYpgHke/UY= - -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha1-nkKYHvA1vrPdSa3ResuW6P9vOUw= - dependencies: - ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@foliojs-fork/fontkit@^1.9.1": - version "1.9.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@foliojs-fork/fontkit/-/fontkit-1.9.1.tgz#8124649168eb5273f580f66697a139fb5041296b" - integrity sha1-gSRkkWjrUnP1gPZml6E5+1BBKWs= - dependencies: - "@foliojs-fork/restructure" "^2.0.2" - brfs "^2.0.0" - brotli "^1.2.0" - browserify-optional "^1.0.1" - clone "^1.0.4" - deep-equal "^1.0.0" - dfa "^1.2.0" - tiny-inflate "^1.0.2" - unicode-properties "^1.2.2" - unicode-trie "^2.0.0" - -"@foliojs-fork/linebreak@^1.1.1": - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@foliojs-fork/linebreak/-/linebreak-1.1.1.tgz#93ecd695b7d2bb0334b9481058c3e610e019a4eb" - integrity sha1-k+zWlbfSuwM0uUgQWMPmEOAZpOs= - dependencies: - base64-js "1.3.1" - brfs "^2.0.2" - unicode-trie "^2.0.0" - -"@foliojs-fork/pdfkit@^0.13.0": - version "0.13.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@foliojs-fork/pdfkit/-/pdfkit-0.13.0.tgz#54f5368d8cf74d8edc81a175ccda1fd9655f2db9" - integrity sha1-VPU2jYz3TY7cgaF1zNof2WVfLbk= - dependencies: - "@foliojs-fork/fontkit" "^1.9.1" - "@foliojs-fork/linebreak" "^1.1.1" - crypto-js "^4.0.0" - png-js "^1.0.0" - -"@foliojs-fork/restructure@^2.0.2": - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@foliojs-fork/restructure/-/restructure-2.0.2.tgz#73759aba2aff1da87b7c4554e6839c70d43c92b4" - integrity sha1-c3Wauir/Hah7fEVU5oOccNQ8krQ= - -"@gar/promisify@^1.0.1": - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" - integrity sha1-MKqCXxHUOGcdWFvUTn/VZFNfwhA= - -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha1-FAeWfUxu7Nc4j4Os8er00Mbljvk= - dependencies: - "@humanwhocodes/object-schema" "^1.2.0" - debug "^4.1.1" - minimatch "^3.0.4" - -"@humanwhocodes/object-schema@^1.2.0": - version "1.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha1-tSBSnsIdjllFoYUd/Rwy6U45/0U= - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha1-/T2x1Z7PfPEh6AZQu4ZxL5tV7O0= - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha1-5F44TkuOwWvOL9kDr3hFD2v37Jg= - -"@jest/transform@^26.6.2": - version "26.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" - integrity sha1-WsV8X6GtF7Kq6D5z5FgTiU3PLks= - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^26.6.2" - babel-plugin-istanbul "^6.0.0" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-regex-util "^26.0.0" - jest-util "^26.6.2" - micromatch "^4.0.2" - pirates "^4.0.1" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha1-vvWlMgMOHYii9abZM/hOlyJu1I4= - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/source-map@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" - integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - -"@jsdevtools/coverage-istanbul-loader@3.0.5": - version "3.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@jsdevtools/coverage-istanbul-loader/-/coverage-istanbul-loader-3.0.5.tgz#2a4bc65d0271df8d4435982db4af35d81754ee26" - integrity sha1-KkvGXQJx341ENZgttK812BdU7iY= - dependencies: - convert-source-map "^1.7.0" - istanbul-lib-instrument "^4.0.3" - loader-utils "^2.0.0" - merge-source-map "^1.1.0" - schema-utils "^2.7.0" - -"@mdx-js/loader@^1.6.22": - version "1.6.22" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@mdx-js/loader/-/loader-1.6.22.tgz#d9e8fe7f8185ff13c9c8639c048b123e30d322c4" - integrity sha1-2ej+f4GF/xPJyGOcBIsSPjDTIsQ= - dependencies: - "@mdx-js/mdx" "1.6.22" - "@mdx-js/react" "1.6.22" - loader-utils "2.0.0" - -"@mdx-js/mdx@1.6.22", "@mdx-js/mdx@^1.6.22": - version "1.6.22" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba" - integrity sha1-inIxV7+Q548X3A8nmVOY5scx8bo= - dependencies: - "@babel/core" "7.12.9" - "@babel/plugin-syntax-jsx" "7.12.1" - "@babel/plugin-syntax-object-rest-spread" "7.8.3" - "@mdx-js/util" "1.6.22" - babel-plugin-apply-mdx-type-prop "1.6.22" - babel-plugin-extract-import-names "1.6.22" - camelcase-css "2.0.1" - detab "2.0.4" - hast-util-raw "6.0.1" - lodash.uniq "4.5.0" - mdast-util-to-hast "10.0.1" - remark-footnotes "2.0.0" - remark-mdx "1.6.22" - remark-parse "8.0.3" - remark-squeeze-paragraphs "4.0.0" - style-to-object "0.3.0" - unified "9.2.0" - unist-builder "2.0.3" - unist-util-visit "2.0.3" - -"@mdx-js/react@1.6.22", "@mdx-js/react@^1.6.22": - version "1.6.22" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@mdx-js/react/-/react-1.6.22.tgz#ae09b4744fddc74714ee9f9d6f17a66e77c43573" - integrity sha1-rgm0dE/dx0cU7p+dbxembnfENXM= - -"@mdx-js/util@1.6.22": - version "1.6.22" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" - integrity sha1-IZ39ia5bl6iAHwFTI/+kti9FcYs= - -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4= - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - -"@ng-web-apis/common@^1.12.1": - version "1.12.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ng-web-apis/common/-/common-1.12.1.tgz#8c916fb0f8a8a31d804e52f0d31eb3597c874ccb" - integrity sha1-jJFvsPioox2ATlLw0x6zWXyHTMs= - dependencies: - tslib "^1.9.0" - -"@ngrx/effects@^10.1.2": - version "10.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ngrx/effects/-/effects-10.1.2.tgz#f1c9daa2e3e13aeb6af272cb52f6dff73d364d68" - integrity sha1-8cnaouPhOutq8nLLUvbf9z02TWg= - dependencies: - tslib "^2.0.0" - -"@ngrx/entity@^10.1.2": - version "10.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ngrx/entity/-/entity-10.1.2.tgz#17c93af662de3083a6914af7400182f75924d61f" - integrity sha1-F8k69mLeMIOmkUr3QAGC91kk1h8= - dependencies: - tslib "^2.0.0" - -"@ngrx/router-store@^10.1.2": - version "10.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ngrx/router-store/-/router-store-10.1.2.tgz#f8083121611ba72450998eb37dffc26dd17f8ab0" - integrity sha1-+AgxIWEbpyRQmY6zff/CbdF/irA= - dependencies: - tslib "^2.0.0" - -"@ngrx/schematics@^10.0.0": - version "10.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ngrx/schematics/-/schematics-10.1.2.tgz#21ff7d5c1cbaee1abb75f8561bcedd017c99bc94" - integrity sha1-If99XBy67hq7dfhWG87dAXyZvJQ= - dependencies: - "@angular/core" "^10.0.0" - -"@ngrx/store-devtools@^10.1.2": - version "10.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ngrx/store-devtools/-/store-devtools-10.1.2.tgz#1dba8c84df4b56a2b15d6abc01c3c378d1518830" - integrity sha1-HbqMhN9LVqKxXWq8AcPDeNFRiDA= - dependencies: - tslib "^2.0.0" - -"@ngrx/store@^10.1.2": - version "10.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ngrx/store/-/store-10.1.2.tgz#a41aee81ea7b7e4a9f927be560e6024830211efb" - integrity sha1-pBrugep7fkqfknvlYOYCSDAhHvs= - dependencies: - tslib "^2.0.0" - -"@ngtools/webpack@11.2.17": - version "11.2.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ngtools/webpack/-/webpack-11.2.17.tgz#f75e92487ef729fa3ec8878c1d4cde146166db1a" - integrity sha1-916SSH73Kfo+yIeMHUzeFGFm2xo= - dependencies: - "@angular-devkit/core" "11.2.17" - enhanced-resolve "5.7.0" - webpack-sources "2.2.0" - -"@ngx-translate/core@^13.0.0": - version "13.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ngx-translate/core/-/core-13.0.0.tgz#60547cb8a0845a2a0abfde6b0bf5ec6516a63fd6" - integrity sha1-YFR8uKCEWioKv95rC/XsZRamP9Y= - dependencies: - tslib "^2.0.0" - -"@ngx-translate/http-loader@^6.0.0": - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ngx-translate/http-loader/-/http-loader-6.0.0.tgz#041393ab5753f50ecf64262d624703046b8c7570" - integrity sha1-BBOTq1dT9Q7PZCYtYkcDBGuMdXA= - dependencies: - tslib "^2.0.0" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha1-dhnC6yGyVIP20WdUi0z9WnSIw9U= - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha1-W9Jir5Tp0lvR5xsF3u1Eh2oiLos= - -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs= - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha1-6Vc36LtnRt3t9pxVaVNJTxlv5po= - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@npmcli/ci-detect@^1.0.0": - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz#18478bbaa900c37bfbd8a2006a6262c62e8b0fe1" - integrity sha1-GEeLuqkAw3v72KIAamJixi6LD+E= - -"@npmcli/fs@^1.0.0": - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@npmcli/fs/-/fs-1.1.0.tgz#bec1d1b89c170d40e1b73ad6c943b0b75e7d2951" - integrity sha1-vsHRuJwXDUDhtzrWyUOwt159KVE= - dependencies: - "@gar/promisify" "^1.0.1" - semver "^7.3.5" - -"@npmcli/git@^2.0.1": - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" - integrity sha1-L7134UdTAkfTfzJZMNRXs+volPY= - dependencies: - "@npmcli/promise-spawn" "^1.3.2" - lru-cache "^6.0.0" - mkdirp "^1.0.4" - npm-pick-manifest "^6.1.1" - promise-inflight "^1.0.1" - promise-retry "^2.0.1" - semver "^7.3.5" - which "^2.0.2" - -"@npmcli/installed-package-contents@^1.0.5": - version "1.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" - integrity sha1-q3QIxhR5EblwqKviYc5RIjKj9Po= - dependencies: - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" - -"@npmcli/move-file@^1.0.1": - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha1-GoLD43L3yuklPrZtclQ9a4aFxnQ= - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - -"@npmcli/node-gyp@^1.0.2": - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" - integrity sha1-qRLmN0GP/F8ts3XpO4WDdpGkOjM= - -"@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": - version "1.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" - integrity sha1-QtTlao6SdPuhgNq8CupuOPKSdPU= - dependencies: - infer-owner "^1.0.4" - -"@npmcli/run-script@^1.3.0": - version "1.8.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" - integrity sha1-GDFIAqZmCw1Lqkw6/n8a052MKLc= - dependencies: - "@npmcli/node-gyp" "^1.0.2" - "@npmcli/promise-spawn" "^1.3.2" - node-gyp "^7.1.0" - read-package-json-fast "^2.0.1" - -"@polka/url@^1.0.0-next.20": - version "1.0.0-next.21" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" - integrity sha1-XeWiOFo1MJQn9gEZkrVEUU1VmqE= - -"@popperjs/core@^2.5.4", "@popperjs/core@^2.6.0": - version "2.11.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@popperjs/core/-/core-2.11.0.tgz#6734f8ebc106a0860dff7f92bf90df193f0935d7" - integrity sha1-ZzT468EGoIYN/3+Sv5DfGT8JNdc= - -"@rollup/plugin-commonjs@^17.0.0": - version "17.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz#757ec88737dffa8aa913eb392fade2e45aef2a2d" - integrity sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew== - dependencies: - "@rollup/pluginutils" "^3.1.0" - commondir "^1.0.1" - estree-walker "^2.0.1" - glob "^7.1.6" - is-reference "^1.2.1" - magic-string "^0.25.7" - resolve "^1.17.0" - -"@rollup/plugin-json@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3" - integrity sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw== - dependencies: - "@rollup/pluginutils" "^3.0.8" - -"@rollup/plugin-node-resolve@^11.1.0": - version "11.2.1" - resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz#82aa59397a29cd4e13248b106e6a4a1880362a60" - integrity sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg== - dependencies: - "@rollup/pluginutils" "^3.1.0" - "@types/resolve" "1.17.1" - builtin-modules "^3.1.0" - deepmerge "^4.2.2" - is-module "^1.0.0" - resolve "^1.19.0" - -"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.0.9", "@rollup/pluginutils@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" - integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== - dependencies: - "@types/estree" "0.0.39" - estree-walker "^1.0.1" - picomatch "^2.2.2" - -"@schematics/angular@11.2.17": - version "11.2.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@schematics/angular/-/angular-11.2.17.tgz#fe63be67dda96a1c7aefb605df0f873d66006ec5" - integrity sha1-/mO+Z92pahx677YF3w+HPWYAbsU= - dependencies: - "@angular-devkit/core" "11.2.17" - "@angular-devkit/schematics" "11.2.17" - jsonc-parser "3.0.0" - -"@schematics/update@0.1102.17": - version "0.1102.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@schematics/update/-/update-0.1102.17.tgz#81caee3e9fa1b695278eabea1cc8f2604bb36a4e" - integrity sha1-gcruPp+htpUnjqvqHMjyYEuzak4= - dependencies: - "@angular-devkit/core" "11.2.17" - "@angular-devkit/schematics" "11.2.17" - "@yarnpkg/lockfile" "1.1.0" - ini "2.0.0" - npm-package-arg "^8.0.0" - pacote "11.2.4" - semver "7.3.4" - semver-intersect "1.4.0" - -"@storybook/addon-actions@6.4.9", "@storybook/addon-actions@^6.3.8": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-actions/-/addon-actions-6.4.9.tgz#1d4e8c00ad304efe6722043dac759f4716b515ee" - integrity sha1-HU6MAK0wTv5nIgQ9rHWfRxa1Fe4= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/theming" "6.4.9" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - polished "^4.0.5" - prop-types "^15.7.2" - react-inspector "^5.1.0" - regenerator-runtime "^0.13.7" - telejson "^5.3.2" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - uuid-browser "^3.1.0" - -"@storybook/addon-backgrounds@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-backgrounds/-/addon-backgrounds-6.4.9.tgz#89033aed6f01d6a2dc134cbdb1ce0c46afd130ec" - integrity sha1-iQM67W8B1qLcE0y9sc4MRq/RMOw= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/theming" "6.4.9" - core-js "^3.8.2" - global "^4.4.0" - memoizerific "^1.11.3" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - -"@storybook/addon-controls@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-controls/-/addon-controls-6.4.9.tgz#286a184336a80981fdd805f44a68f60fb6e38e73" - integrity sha1-KGoYQzaoCYH92AX0Smj2D7bjjnM= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/core-common" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/node-logger" "6.4.9" - "@storybook/store" "6.4.9" - "@storybook/theming" "6.4.9" - core-js "^3.8.2" - lodash "^4.17.21" - ts-dedent "^2.0.0" - -"@storybook/addon-docs@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-docs/-/addon-docs-6.4.9.tgz#dc34c6152085043a771623b2de344bc9d91f0563" - integrity sha1-3DTGFSCFBDp3FiOy3jRLydkfBWM= - dependencies: - "@babel/core" "^7.12.10" - "@babel/generator" "^7.12.11" - "@babel/parser" "^7.12.11" - "@babel/plugin-transform-react-jsx" "^7.12.12" - "@babel/preset-env" "^7.12.11" - "@jest/transform" "^26.6.2" - "@mdx-js/loader" "^1.6.22" - "@mdx-js/mdx" "^1.6.22" - "@mdx-js/react" "^1.6.22" - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/builder-webpack4" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/core" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/csf-tools" "6.4.9" - "@storybook/node-logger" "6.4.9" - "@storybook/postinstall" "6.4.9" - "@storybook/preview-web" "6.4.9" - "@storybook/source-loader" "6.4.9" - "@storybook/store" "6.4.9" - "@storybook/theming" "6.4.9" - acorn "^7.4.1" - acorn-jsx "^5.3.1" - acorn-walk "^7.2.0" - core-js "^3.8.2" - doctrine "^3.0.0" - escodegen "^2.0.0" - fast-deep-equal "^3.1.3" - global "^4.4.0" - html-tags "^3.1.0" - js-string-escape "^1.0.1" - loader-utils "^2.0.0" - lodash "^4.17.21" - nanoid "^3.1.23" - p-limit "^3.1.0" - prettier "^2.2.1" - prop-types "^15.7.2" - react-element-to-jsx-string "^14.3.4" - regenerator-runtime "^0.13.7" - remark-external-links "^8.0.0" - remark-slug "^6.0.0" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - -"@storybook/addon-essentials@^6.3.8": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-essentials/-/addon-essentials-6.4.9.tgz#e761a61a9ac9809b8a5d8b6f7c5a1b50f0e2cd91" - integrity sha1-52GmGprJgJuKXYtvfFobUPDizZE= - dependencies: - "@storybook/addon-actions" "6.4.9" - "@storybook/addon-backgrounds" "6.4.9" - "@storybook/addon-controls" "6.4.9" - "@storybook/addon-docs" "6.4.9" - "@storybook/addon-measure" "6.4.9" - "@storybook/addon-outline" "6.4.9" - "@storybook/addon-toolbars" "6.4.9" - "@storybook/addon-viewport" "6.4.9" - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/node-logger" "6.4.9" - core-js "^3.8.2" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - -"@storybook/addon-links@^6.3.8": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-links/-/addon-links-6.4.9.tgz#2d0a7f813dcef160feb357f6548bb1a7ba425d7d" - integrity sha1-LQp/gT3O8WD+s1f2VIuxp7pCXX0= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/router" "6.4.9" - "@types/qs" "^6.9.5" - core-js "^3.8.2" - global "^4.4.0" - prop-types "^15.7.2" - qs "^6.10.0" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - -"@storybook/addon-measure@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-measure/-/addon-measure-6.4.9.tgz#d4446e0b0686f4f25bbd7eee8c4cf296d8bea216" - integrity sha1-1ERuCwaG9PJbvX7ujEzylti+ohY= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - global "^4.4.0" - -"@storybook/addon-outline@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-outline/-/addon-outline-6.4.9.tgz#0f6b20eb41580686cca4b9f12937932dd5f51c64" - integrity sha1-D2sg60FYBobMpLnxKTeTLdX1HGQ= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - global "^4.4.0" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - -"@storybook/addon-toolbars@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-toolbars/-/addon-toolbars-6.4.9.tgz#147534d0b185a1782f3381a47c627b4a4193297d" - integrity sha1-FHU00LGFoXgvM4GkfGJ7SkGTKX0= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/theming" "6.4.9" - core-js "^3.8.2" - regenerator-runtime "^0.13.7" - -"@storybook/addon-viewport@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addon-viewport/-/addon-viewport-6.4.9.tgz#73753ff62043d3d6e6d845590ed70caf775af960" - integrity sha1-c3U/9iBD09bm2EVZDtcMr3da+WA= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/theming" "6.4.9" - core-js "^3.8.2" - global "^4.4.0" - memoizerific "^1.11.3" - prop-types "^15.7.2" - regenerator-runtime "^0.13.7" - -"@storybook/addons@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/addons/-/addons-6.4.9.tgz#43b5dabf6781d863fcec0a0b293c236b4d5d4433" - integrity sha1-Q7Xav2eB2GP87AoLKTwja01dRDM= - dependencies: - "@storybook/api" "6.4.9" - "@storybook/channels" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/router" "6.4.9" - "@storybook/theming" "6.4.9" - "@types/webpack-env" "^1.16.0" - core-js "^3.8.2" - global "^4.4.0" - regenerator-runtime "^0.13.7" - -"@storybook/angular@^6.3.8": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/angular/-/angular-6.4.9.tgz#966089d911630166838008e6fcae5f4a7fc5855e" - integrity sha1-lmCJ2RFjAWaDgAjm/K5fSn/FhV4= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/core" "6.4.9" - "@storybook/core-common" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/node-logger" "6.4.9" - "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.9" - "@types/webpack-env" "^1.16.0" - autoprefixer "^9.8.6" - core-js "^3.8.2" - find-up "^5.0.0" - fork-ts-checker-webpack-plugin "^4.1.6" - global "^4.4.0" - postcss "^7.0.36" - postcss-loader "^4.2.0" - raw-loader "^4.0.2" - react "16.14.0" - react-dom "16.14.0" - read-pkg-up "^7.0.1" - regenerator-runtime "^0.13.7" - sass-loader "^10.1.0" - strip-json-comments "3.1.1" - telejson "^5.3.2" - ts-dedent "^2.0.0" - ts-loader "^8.0.14" - tsconfig-paths-webpack-plugin "^3.3.0" - util-deprecate "^1.0.2" - webpack "4" - -"@storybook/api@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/api/-/api-6.4.9.tgz#6187d08658629580f0a583f2069d55b34964b34a" - integrity sha1-YYfQhlhilYDwpYPyBp1Vs0lks0o= - dependencies: - "@storybook/channels" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/router" "6.4.9" - "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.4.9" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - regenerator-runtime "^0.13.7" - store2 "^2.12.0" - telejson "^5.3.2" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - -"@storybook/builder-webpack4@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/builder-webpack4/-/builder-webpack4-6.4.9.tgz#86cd691c856eeb7a6a7bcafa57e9a66c1e0b9906" - integrity sha1-hs1pHIVu63pqe8r6V+mmbB4LmQY= - dependencies: - "@babel/core" "^7.12.10" - "@babel/plugin-proposal-class-properties" "^7.12.1" - "@babel/plugin-proposal-decorators" "^7.12.12" - "@babel/plugin-proposal-export-default-from" "^7.12.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" - "@babel/plugin-proposal-object-rest-spread" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.12.7" - "@babel/plugin-proposal-private-methods" "^7.12.1" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.12.1" - "@babel/plugin-transform-block-scoping" "^7.12.12" - "@babel/plugin-transform-classes" "^7.12.1" - "@babel/plugin-transform-destructuring" "^7.12.1" - "@babel/plugin-transform-for-of" "^7.12.1" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-transform-shorthand-properties" "^7.12.1" - "@babel/plugin-transform-spread" "^7.12.1" - "@babel/plugin-transform-template-literals" "^7.12.1" - "@babel/preset-env" "^7.12.11" - "@babel/preset-react" "^7.12.10" - "@babel/preset-typescript" "^7.12.7" - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/channel-postmessage" "6.4.9" - "@storybook/channels" "6.4.9" - "@storybook/client-api" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/core-common" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/node-logger" "6.4.9" - "@storybook/preview-web" "6.4.9" - "@storybook/router" "6.4.9" - "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.9" - "@storybook/theming" "6.4.9" - "@storybook/ui" "6.4.9" - "@types/node" "^14.0.10" - "@types/webpack" "^4.41.26" - autoprefixer "^9.8.6" - babel-loader "^8.0.0" - babel-plugin-macros "^2.8.0" - babel-plugin-polyfill-corejs3 "^0.1.0" - case-sensitive-paths-webpack-plugin "^2.3.0" - core-js "^3.8.2" - css-loader "^3.6.0" - file-loader "^6.2.0" - find-up "^5.0.0" - fork-ts-checker-webpack-plugin "^4.1.6" - glob "^7.1.6" - glob-promise "^3.4.0" - global "^4.4.0" - html-webpack-plugin "^4.0.0" - pnp-webpack-plugin "1.6.4" - postcss "^7.0.36" - postcss-flexbugs-fixes "^4.2.1" - postcss-loader "^4.2.0" - raw-loader "^4.0.2" - react-dev-utils "^11.0.4" - stable "^0.1.8" - style-loader "^1.3.0" - terser-webpack-plugin "^4.2.3" - ts-dedent "^2.0.0" - url-loader "^4.1.1" - util-deprecate "^1.0.2" - webpack "4" - webpack-dev-middleware "^3.7.3" - webpack-filter-warnings-plugin "^1.2.1" - webpack-hot-middleware "^2.25.1" - webpack-virtual-modules "^0.2.2" - -"@storybook/channel-postmessage@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/channel-postmessage/-/channel-postmessage-6.4.9.tgz#b20b7d66f0f2a8ba39fe9002f3a3dc16d9e1f681" - integrity sha1-sgt9ZvDyqLo5/pAC86PcFtnh9oE= - dependencies: - "@storybook/channels" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/core-events" "6.4.9" - core-js "^3.8.2" - global "^4.4.0" - qs "^6.10.0" - telejson "^5.3.2" - -"@storybook/channel-websocket@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/channel-websocket/-/channel-websocket-6.4.9.tgz#f012840894f73bac289ddcdc57efb385c4a0b7ef" - integrity sha1-8BKECJT3O6wondzcV++zhcSgt+8= - dependencies: - "@storybook/channels" "6.4.9" - "@storybook/client-logger" "6.4.9" - core-js "^3.8.2" - global "^4.4.0" - telejson "^5.3.2" - -"@storybook/channels@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/channels/-/channels-6.4.9.tgz#132c574d3fb2e6aaa9c52312c592794699b9d8ec" - integrity sha1-EyxXTT+y5qqpxSMSxZJ5Rpm52Ow= - dependencies: - core-js "^3.8.2" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - -"@storybook/client-api@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/client-api/-/client-api-6.4.9.tgz#e3d90c66356d6f53f8ceb4f31753f670f704fde0" - integrity sha1-49kMZjVtb1P4zrTzF1P2cPcE/eA= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/channel-postmessage" "6.4.9" - "@storybook/channels" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/store" "6.4.9" - "@types/qs" "^6.9.5" - "@types/webpack-env" "^1.16.0" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - qs "^6.10.0" - regenerator-runtime "^0.13.7" - store2 "^2.12.0" - synchronous-promise "^2.0.15" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - -"@storybook/client-logger@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/client-logger/-/client-logger-6.4.9.tgz#ef6af30fac861fea69c8917120ed06b4c2f0b54e" - integrity sha1-72rzD6yGH+ppyJFxIO0GtMLwtU4= - dependencies: - core-js "^3.8.2" - global "^4.4.0" - -"@storybook/components@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/components/-/components-6.4.9.tgz#caed59eb3f09d1646da748186f718a0e54fb8fd7" - integrity sha1-yu1Z6z8J0WRtp0gYb3GKDlT7j9c= - dependencies: - "@popperjs/core" "^2.6.0" - "@storybook/client-logger" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/theming" "6.4.9" - "@types/color-convert" "^2.0.0" - "@types/overlayscrollbars" "^1.12.0" - "@types/react-syntax-highlighter" "11.0.5" - color-convert "^2.0.1" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - markdown-to-jsx "^7.1.3" - memoizerific "^1.11.3" - overlayscrollbars "^1.13.1" - polished "^4.0.5" - prop-types "^15.7.2" - react-colorful "^5.1.2" - react-popper-tooltip "^3.1.1" - react-syntax-highlighter "^13.5.3" - react-textarea-autosize "^8.3.0" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - -"@storybook/core-client@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/core-client/-/core-client-6.4.9.tgz#324119a67609f758e244a7d58bac00e62020a21f" - integrity sha1-MkEZpnYJ91jiRKfVi6wA5iAgoh8= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/channel-postmessage" "6.4.9" - "@storybook/channel-websocket" "6.4.9" - "@storybook/client-api" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/preview-web" "6.4.9" - "@storybook/store" "6.4.9" - "@storybook/ui" "6.4.9" - airbnb-js-shims "^2.2.1" - ansi-to-html "^0.6.11" - core-js "^3.8.2" - global "^4.4.0" - lodash "^4.17.21" - qs "^6.10.0" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - unfetch "^4.2.0" - util-deprecate "^1.0.2" - -"@storybook/core-common@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/core-common/-/core-common-6.4.9.tgz#1a892903061f927b8f7b9fa8d25273a2f5c9e227" - integrity sha1-GokpAwYfknuPe5+o0lJzovXJ4ic= - dependencies: - "@babel/core" "^7.12.10" - "@babel/plugin-proposal-class-properties" "^7.12.1" - "@babel/plugin-proposal-decorators" "^7.12.12" - "@babel/plugin-proposal-export-default-from" "^7.12.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" - "@babel/plugin-proposal-object-rest-spread" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.12.7" - "@babel/plugin-proposal-private-methods" "^7.12.1" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.12.1" - "@babel/plugin-transform-block-scoping" "^7.12.12" - "@babel/plugin-transform-classes" "^7.12.1" - "@babel/plugin-transform-destructuring" "^7.12.1" - "@babel/plugin-transform-for-of" "^7.12.1" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-transform-shorthand-properties" "^7.12.1" - "@babel/plugin-transform-spread" "^7.12.1" - "@babel/preset-env" "^7.12.11" - "@babel/preset-react" "^7.12.10" - "@babel/preset-typescript" "^7.12.7" - "@babel/register" "^7.12.1" - "@storybook/node-logger" "6.4.9" - "@storybook/semver" "^7.3.2" - "@types/node" "^14.0.10" - "@types/pretty-hrtime" "^1.0.0" - babel-loader "^8.0.0" - babel-plugin-macros "^3.0.1" - babel-plugin-polyfill-corejs3 "^0.1.0" - chalk "^4.1.0" - core-js "^3.8.2" - express "^4.17.1" - file-system-cache "^1.0.5" - find-up "^5.0.0" - fork-ts-checker-webpack-plugin "^6.0.4" - fs-extra "^9.0.1" - glob "^7.1.6" - handlebars "^4.7.7" - interpret "^2.2.0" - json5 "^2.1.3" - lazy-universal-dotenv "^3.0.1" - picomatch "^2.3.0" - pkg-dir "^5.0.0" - pretty-hrtime "^1.0.3" - resolve-from "^5.0.0" - slash "^3.0.0" - telejson "^5.3.2" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - webpack "4" - -"@storybook/core-events@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/core-events/-/core-events-6.4.9.tgz#7febedb8d263fbd6e4a69badbfcdce0101e6f782" - integrity sha1-f+vtuNJj+9bkpputv83OAQHm94I= - dependencies: - core-js "^3.8.2" - -"@storybook/core-server@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/core-server/-/core-server-6.4.9.tgz#593fd4cc21a05c908e0eed20767eb6c9cddad428" - integrity sha1-WT/UzCGgXJCODu0gdn62yc3a1Cg= - dependencies: - "@discoveryjs/json-ext" "^0.5.3" - "@storybook/builder-webpack4" "6.4.9" - "@storybook/core-client" "6.4.9" - "@storybook/core-common" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/csf-tools" "6.4.9" - "@storybook/manager-webpack4" "6.4.9" - "@storybook/node-logger" "6.4.9" - "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.9" - "@types/node" "^14.0.10" - "@types/node-fetch" "^2.5.7" - "@types/pretty-hrtime" "^1.0.0" - "@types/webpack" "^4.41.26" - better-opn "^2.1.1" - boxen "^5.1.2" - chalk "^4.1.0" - cli-table3 "0.6.0" - commander "^6.2.1" - compression "^1.7.4" - core-js "^3.8.2" - cpy "^8.1.2" - detect-port "^1.3.0" - express "^4.17.1" - file-system-cache "^1.0.5" - fs-extra "^9.0.1" - globby "^11.0.2" - ip "^1.1.5" - lodash "^4.17.21" - node-fetch "^2.6.1" - pretty-hrtime "^1.0.3" - prompts "^2.4.0" - regenerator-runtime "^0.13.7" - serve-favicon "^2.5.0" - slash "^3.0.0" - telejson "^5.3.3" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - watchpack "^2.2.0" - webpack "4" - ws "^8.2.3" - -"@storybook/core@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/core/-/core-6.4.9.tgz#4bf910d7322b524f8166c97c28875e1e3775f391" - integrity sha1-S/kQ1zIrUk+BZsl8KIdeHjd185E= - dependencies: - "@storybook/core-client" "6.4.9" - "@storybook/core-server" "6.4.9" - -"@storybook/csf-tools@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/csf-tools/-/csf-tools-6.4.9.tgz#7cccb905875ba5962dda83825f763a111932464b" - integrity sha1-fMy5BYdbpZYt2oOCX3Y6ERkyRks= - dependencies: - "@babel/core" "^7.12.10" - "@babel/generator" "^7.12.11" - "@babel/parser" "^7.12.11" - "@babel/plugin-transform-react-jsx" "^7.12.12" - "@babel/preset-env" "^7.12.11" - "@babel/traverse" "^7.12.11" - "@babel/types" "^7.12.11" - "@mdx-js/mdx" "^1.6.22" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - fs-extra "^9.0.1" - global "^4.4.0" - js-string-escape "^1.0.1" - lodash "^4.17.21" - prettier "^2.2.1" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - -"@storybook/csf@0.0.2--canary.87bc651.0": - version "0.0.2--canary.87bc651.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/csf/-/csf-0.0.2--canary.87bc651.0.tgz#c7b99b3a344117ef67b10137b6477a3d2750cf44" - integrity sha1-x7mbOjRBF+9nsQE3tkd6PSdQz0Q= - dependencies: - lodash "^4.17.15" - -"@storybook/manager-webpack4@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/manager-webpack4/-/manager-webpack4-6.4.9.tgz#76edd6f2c627dc64d3362a265c2fe6ae7ee22507" - integrity sha1-du3W8sYn3GTTNiomXC/mrn7iJQc= - dependencies: - "@babel/core" "^7.12.10" - "@babel/plugin-transform-template-literals" "^7.12.1" - "@babel/preset-react" "^7.12.10" - "@storybook/addons" "6.4.9" - "@storybook/core-client" "6.4.9" - "@storybook/core-common" "6.4.9" - "@storybook/node-logger" "6.4.9" - "@storybook/theming" "6.4.9" - "@storybook/ui" "6.4.9" - "@types/node" "^14.0.10" - "@types/webpack" "^4.41.26" - babel-loader "^8.0.0" - case-sensitive-paths-webpack-plugin "^2.3.0" - chalk "^4.1.0" - core-js "^3.8.2" - css-loader "^3.6.0" - express "^4.17.1" - file-loader "^6.2.0" - file-system-cache "^1.0.5" - find-up "^5.0.0" - fs-extra "^9.0.1" - html-webpack-plugin "^4.0.0" - node-fetch "^2.6.1" - pnp-webpack-plugin "1.6.4" - read-pkg-up "^7.0.1" - regenerator-runtime "^0.13.7" - resolve-from "^5.0.0" - style-loader "^1.3.0" - telejson "^5.3.2" - terser-webpack-plugin "^4.2.3" - ts-dedent "^2.0.0" - url-loader "^4.1.1" - util-deprecate "^1.0.2" - webpack "4" - webpack-dev-middleware "^3.7.3" - webpack-virtual-modules "^0.2.2" - -"@storybook/node-logger@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/node-logger/-/node-logger-6.4.9.tgz#7c28f16f5c61feda8f45fa2c06000ebb87b57df7" - integrity sha1-fCjxb1xh/tqPRfosBgAOu4e1ffc= - dependencies: - "@types/npmlog" "^4.1.2" - chalk "^4.1.0" - core-js "^3.8.2" - npmlog "^5.0.1" - pretty-hrtime "^1.0.3" - -"@storybook/postinstall@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/postinstall/-/postinstall-6.4.9.tgz#7b011a2e188bcc54180b16d06f21c9d52a5324ac" - integrity sha1-ewEaLhiLzFQYCxbQbyHJ1SpTJKw= - dependencies: - core-js "^3.8.2" - -"@storybook/preset-scss@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@storybook/preset-scss/-/preset-scss-1.0.3.tgz#8ac834545c642dada0f64f510ef08dfb882e9737" - integrity sha512-o9Iz6wxPeNENrQa2mKlsDKynBfqU2uWaRP80HeWp4TkGgf7/x3DVF2O7yi9N0x/PI1qzzTTpxlQ90D62XmpiTw== - -"@storybook/preview-web@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/preview-web/-/preview-web-6.4.9.tgz#21f7d251af0de64ae796834ead08ae4ed67e6456" - integrity sha1-IffSUa8N5krnloNOrQiuTtZ+ZFY= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/channel-postmessage" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/store" "6.4.9" - ansi-to-html "^0.6.11" - core-js "^3.8.2" - global "^4.4.0" - lodash "^4.17.21" - qs "^6.10.0" - regenerator-runtime "^0.13.7" - synchronous-promise "^2.0.15" - ts-dedent "^2.0.0" - unfetch "^4.2.0" - util-deprecate "^1.0.2" - -"@storybook/router@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/router/-/router-6.4.9.tgz#7cc3f85494f4e14d38925e2802145df69a071201" - integrity sha1-fMP4VJT04U04kl4oAhRd9poHEgE= - dependencies: - "@storybook/client-logger" "6.4.9" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - history "5.0.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - qs "^6.10.0" - react-router "^6.0.0" - react-router-dom "^6.0.0" - ts-dedent "^2.0.0" - -"@storybook/semver@^7.3.2": - version "7.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/semver/-/semver-7.3.2.tgz#f3b9c44a1c9a0b933c04e66d0048fcf2fa10dac0" - integrity sha1-87nEShyaC5M8BOZtAEj88voQ2sA= - dependencies: - core-js "^3.6.5" - find-up "^4.1.0" - -"@storybook/source-loader@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/source-loader/-/source-loader-6.4.9.tgz#918fe93e4bd52622a664398db79d5f71b384ce0b" - integrity sha1-kY/pPkvVJiKmZDmNt51fcbOEzgs= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - estraverse "^5.2.0" - global "^4.4.0" - loader-utils "^2.0.0" - lodash "^4.17.21" - prettier "^2.2.1" - regenerator-runtime "^0.13.7" - -"@storybook/store@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/store/-/store-6.4.9.tgz#613c6f13271276837c6a603a16199d2abf90153e" - integrity sha1-YTxvEycSdoN8amA6FhmdKr+QFT4= - dependencies: - "@storybook/addons" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - regenerator-runtime "^0.13.7" - slash "^3.0.0" - stable "^0.1.8" - synchronous-promise "^2.0.15" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - -"@storybook/theming@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/theming/-/theming-6.4.9.tgz#8ece44007500b9a592e71eca693fbeac90803b0d" - integrity sha1-js5EAHUAuaWS5x7KaT++rJCAOw0= - dependencies: - "@emotion/core" "^10.1.1" - "@emotion/is-prop-valid" "^0.8.6" - "@emotion/styled" "^10.0.27" - "@storybook/client-logger" "6.4.9" - core-js "^3.8.2" - deep-object-diff "^1.1.0" - emotion-theming "^10.0.27" - global "^4.4.0" - memoizerific "^1.11.3" - polished "^4.0.5" - resolve-from "^5.0.0" - ts-dedent "^2.0.0" - -"@storybook/ui@6.4.9": - version "6.4.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@storybook/ui/-/ui-6.4.9.tgz#c01413ca919ede20f84d19e556bf93dd2e7c5110" - integrity sha1-wBQTypGe3iD4TRnlVr+T3S58URA= - dependencies: - "@emotion/core" "^10.1.1" - "@storybook/addons" "6.4.9" - "@storybook/api" "6.4.9" - "@storybook/channels" "6.4.9" - "@storybook/client-logger" "6.4.9" - "@storybook/components" "6.4.9" - "@storybook/core-events" "6.4.9" - "@storybook/router" "6.4.9" - "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.4.9" - copy-to-clipboard "^3.3.1" - core-js "^3.8.2" - core-js-pure "^3.8.2" - downshift "^6.0.15" - emotion-theming "^10.0.27" - fuse.js "^3.6.1" - global "^4.4.0" - lodash "^4.17.21" - markdown-to-jsx "^7.1.3" - memoizerific "^1.11.3" - polished "^4.0.5" - qs "^6.10.0" - react-draggable "^4.4.3" - react-helmet-async "^1.0.7" - react-sizeme "^3.0.1" - regenerator-runtime "^0.13.7" - resolve-from "^5.0.0" - store2 "^2.12.0" - -"@tinkoff/ng-polymorpheus@^3.1.12": - version "3.1.12" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@tinkoff/ng-polymorpheus/-/ng-polymorpheus-3.1.12.tgz#e7a453ac640b330e4962e7eeeb205f872ad0a80f" - integrity sha1-56RTrGQLMw5JYufu6yBfhyrQqA8= - dependencies: - tslib "^1.10.0" - -"@tootallnate/once@1": - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha1-zLkURTYBeaBOf+av94wA/8Hur4I= - -"@trysound/sax@0.2.0": - version "0.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" - integrity sha1-zMqrdYr1Z2Hre/N69vA/Mm3XmK0= - -"@ts-morph/common@~0.12.2": - version "0.12.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@ts-morph/common/-/common-0.12.2.tgz#61d07a47d622d231e833c44471ab306faaa41aed" - integrity sha1-YdB6R9Yi0jHoM8REcaswb6qkGu0= - dependencies: - fast-glob "^3.2.7" - minimatch "^3.0.4" - mkdirp "^1.0.4" - path-browserify "^1.0.1" - -"@types/color-convert@^2.0.0": - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/color-convert/-/color-convert-2.0.0.tgz#8f5ee6b9e863dcbee5703f5a517ffb13d3ea4e22" - integrity sha1-j17muehj3L7lcD9aUX/7E9PqTiI= - dependencies: - "@types/color-name" "*" - -"@types/color-name@*": - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha1-HBJhu+qhCoBVu8XYq4S3sq/IRqA= - -"@types/estree@*": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" - integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== - -"@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - -"@types/glob@*", "@types/glob@^7.1.1": - version "7.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" - integrity sha1-vBtb86qS8lvV3TnzXFc2G9zlsus= - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - -"@types/graceful-fs@^4.1.2": - version "4.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" - integrity sha1-If+6DZjaQ1DbZIkfkqnl2zzbThU= - dependencies: - "@types/node" "*" - -"@types/hast@^2.0.0": - version "2.3.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" - integrity sha1-iqXvksEX0g2XSoK9+2pkiwjAuvw= - dependencies: - "@types/unist" "*" - -"@types/html-minifier-terser@^5.0.0": - version "5.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" - integrity sha1-aTsxatMj6pfu1rOO0aPMArFnK1c= - -"@types/is-function@^1.0.0": - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/is-function/-/is-function-1.0.1.tgz#2d024eace950c836d9e3335a66b97960ae41d022" - integrity sha1-LQJOrOlQyDbZ4zNaZrl5YK5B0CI= - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": - version "2.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha1-hGfUs8CHgF1jWASAiQeRJ3zjXEQ= - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha1-wUwk8Y6oGQwRjudWK3/5mjZVJoY= - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha1-kVP+mLuivVZaY63ZQ21vDX+EaP8= - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jasmine@*": - version "3.10.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/jasmine/-/jasmine-3.10.2.tgz#1b9f9ba9ad7bfd7d322f7ed9d8753220b1c84b52" - integrity sha1-G5+bqa17/X0yL37Z2HUyILHIS1I= - -"@types/jasmine@~3.6.0": - version "3.6.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/jasmine/-/jasmine-3.6.11.tgz#4b1d77aa9dfc757407cb9e277216d8e83553f09d" - integrity sha1-Sx13qp38dXQHy54nchbY6DVT8J0= - -"@types/jasminewd2@~2.0.8": - version "2.0.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/jasminewd2/-/jasminewd2-2.0.10.tgz#ae31c237aa6421bde30f1058b1d20f4577e54443" - integrity sha1-rjHCN6pkIb3jDxBYsdIPRXflREM= - dependencies: - "@types/jasmine" "*" - -"@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": - version "7.0.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha1-l+3JA36gw4WFMgsolk3eOznkZg0= - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - -"@types/luxon@^1.25.0": - version "1.27.1" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-1.27.1.tgz#aceeb2d5be8fccf541237e184e37ecff5faa9096" - integrity sha512-cPiXpOvPFDr2edMnOXlz3UBDApwUfR+cpizvxCy0n3vp9bz/qe8BWzHPIEFcy+ogUOyjKuCISgyq77ELZPmkkg== - -"@types/mdast@^3.0.0": - version "3.0.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" - integrity sha1-RyQkSoKkWYiEy76bz9c9/5J+6K8= - dependencies: - "@types/unist" "*" - -"@types/minimatch@*": - version "3.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" - integrity sha1-EAHMXmo3BLg8I2An538vWOoBD0A= - -"@types/node-fetch@^2.5.7": - version "2.5.12" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" - integrity sha1-im93mx1OYLelf7b9SNhPtUW5zGY= - dependencies: - "@types/node" "*" - form-data "^3.0.0" - -"@types/node@*": - version "17.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/node/-/node-17.0.5.tgz#57ca67ec4e57ad9e4ef5a6bab48a15387a1c83e0" - integrity sha1-V8pn7E5XrZ5O9aa6tIoVOHocg+A= - -"@types/node@^14.0.10", "@types/node@^14.0.13": - version "14.18.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/node/-/node-14.18.3.tgz#b3682cfd9d5542b025df13233d073cb4347f63f3" - integrity sha1-s2gs/Z1VQrAl3xMjPQc8tDR/Y/M= - -"@types/normalize-package-data@^2.4.0": - version "2.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" - integrity sha1-0zV0eaD9/dWQf+Z+F+CoXJBuEwE= - -"@types/npmlog@^4.1.2": - version "4.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/npmlog/-/npmlog-4.1.4.tgz#30eb872153c7ead3e8688c476054ddca004115f6" - integrity sha1-MOuHIVPH6tPoaIxHYFTdygBBFfY= - -"@types/overlayscrollbars@^1.12.0": - version "1.12.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/overlayscrollbars/-/overlayscrollbars-1.12.1.tgz#fb637071b545834fb12aea94ee309a2ff4cdc0a8" - integrity sha1-+2NwcbVFg0+xKuqU7jCaL/TNwKg= - -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha1-L4u0QUNNFjs1+4/9zNcTiSf/uMA= - -"@types/parse5@^5.0.0": - version "5.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" - integrity sha1-57Wuu6wVD4tf3UpG5/C9jmXhkQk= - -"@types/pretty-hrtime@^1.0.0": - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz#72a26101dc567b0d68fd956cf42314556e42d601" - integrity sha1-cqJhAdxWew1o/ZVs9CMUVW5C1gE= - -"@types/prop-types@*": - version "15.7.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" - integrity sha1-/PcgXCXf95Xuea8eMNosl5CAjxE= - -"@types/q@^0.0.32": - version "0.0.32" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" - integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= - -"@types/q@^1.5.1": - version "1.5.5" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" - integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== - -"@types/qs@^6.9.5": - version "6.9.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha1-Y7t9Bn2xB8weRXwwO8JdUR/r9ss= - -"@types/react-syntax-highlighter@11.0.5": - version "11.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.5.tgz#0d546261b4021e1f9d85b50401c0a42acb106087" - integrity sha1-DVRiYbQCHh+dhbUEAcCkKssQYIc= - dependencies: - "@types/react" "*" - -"@types/react@*": - version "17.0.38" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/react/-/react-17.0.38.tgz#f24249fefd89357d5fa71f739a686b8d7c7202bd" - integrity sha1-8kJJ/v2JNX1fpx9zmmhrjXxyAr0= - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/resolve@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" - integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== - dependencies: - "@types/node" "*" - -"@types/scheduler@*": - version "0.16.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" - integrity sha1-GmL4lSVyPd4kuhsBsJK/XfitTTk= - -"@types/selenium-webdriver@^3.0.0": - version "3.0.19" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/selenium-webdriver/-/selenium-webdriver-3.0.19.tgz#28ecede76f15b13553b4e86074d4cf9a0bbe49c4" - integrity sha1-KOzt528VsTVTtOhgdNTPmgu+ScQ= - -"@types/source-list-map@*": - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" - integrity sha1-AHiDYGP/rxdBI0m7o2QIfgrALsk= - -"@types/tapable@^1", "@types/tapable@^1.0.5": - version "1.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/tapable/-/tapable-1.0.8.tgz#b94a4391c85666c7b73299fd3ad79d4faa435310" - integrity sha1-uUpDkchWZse3Mpn9OtedT6pDUxA= - -"@types/uglify-js@*": - version "3.13.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/uglify-js/-/uglify-js-3.13.1.tgz#5e889e9e81e94245c75b6450600e1c5ea2878aea" - integrity sha1-XoienoHpQkXHW2RQYA4cXqKHiuo= - dependencies: - source-map "^0.6.1" - -"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": - version "2.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" - integrity sha1-JQp7FsO5H2cqJFUuxkZ47rHToI0= - -"@types/webpack-env@^1.16.0": - version "1.16.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/webpack-env/-/webpack-env-1.16.3.tgz#b776327a73e561b71e7881d0cd6d34a1424db86a" - integrity sha1-t3YyenPlYbceeIHQzW00oUJNuGo= - -"@types/webpack-sources@*": - version "3.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/webpack-sources/-/webpack-sources-3.2.0.tgz#16d759ba096c289034b26553d2df1bf45248d38b" - integrity sha1-FtdZuglsKJA0smVT0t8b9FJI04s= - dependencies: - "@types/node" "*" - "@types/source-list-map" "*" - source-map "^0.7.3" - -"@types/webpack-sources@^0.1.5": - version "0.1.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/webpack-sources/-/webpack-sources-0.1.9.tgz#da69b06eb34f6432e6658acb5a6893c55d983920" - integrity sha1-2mmwbrNPZDLmZYrLWmiTxV2YOSA= - dependencies: - "@types/node" "*" - "@types/source-list-map" "*" - source-map "^0.6.1" - -"@types/webpack@^4.41.26", "@types/webpack@^4.41.8": - version "4.41.32" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/webpack/-/webpack-4.41.32.tgz#a7bab03b72904070162b2f169415492209e94212" - integrity sha1-p7qwO3KQQHAWKy8WlBVJIgnpQhI= - dependencies: - "@types/node" "*" - "@types/tapable" "^1" - "@types/uglify-js" "*" - "@types/webpack-sources" "*" - anymatch "^3.0.0" - source-map "^0.6.0" - -"@types/yargs-parser@*": - version "20.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" - integrity sha1-O5ziSJkZ2eT+pDm3aRarw0st8Sk= - -"@types/yargs@^15.0.0": - version "15.0.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" - integrity sha1-Jtgh3biecEkhYLZtEKDrbfj2+wY= - dependencies: - "@types/yargs-parser" "*" - -"@webassemblyjs/ast@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" - integrity sha1-vYUGBLQEJFmlpBzX0zjL7Wle2WQ= - dependencies: - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - -"@webassemblyjs/floating-point-hex-parser@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" - integrity sha1-PD07Jxvd/ITesA9xNEQ4MR1S/7Q= - -"@webassemblyjs/helper-api-error@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" - integrity sha1-ID9nbjM7lsnaLuqzzO8zxFkotqI= - -"@webassemblyjs/helper-buffer@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" - integrity sha1-oUQtJpxf6yP8vJ73WdrDVH8p3gA= - -"@webassemblyjs/helper-code-frame@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" - integrity sha1-ZH+Iks0gQ6gqwMjF51w28dkVnyc= - dependencies: - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/helper-fsm@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" - integrity sha1-wFJWtxJEIUZx9LCOwQitY7cO3bg= - -"@webassemblyjs/helper-module-context@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" - integrity sha1-JdiIS3aDmHGgimxvgGw5ee9xLwc= - dependencies: - "@webassemblyjs/ast" "1.9.0" - -"@webassemblyjs/helper-wasm-bytecode@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" - integrity sha1-T+2L6sm4wU+MWLcNEk1UndH+V5A= - -"@webassemblyjs/helper-wasm-section@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" - integrity sha1-WkE41aYpK6GLBMWuSXF+QWeWU0Y= - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - -"@webassemblyjs/ieee754@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" - integrity sha1-Fceg+6roP7JhQ7us9tbfFwKtOeQ= - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" - integrity sha1-8Zygt2ptxVYjoJz/p2noOPoeHJU= - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" - integrity sha1-BNM7Y2945qaBMifoJAL3Y3tiKas= - -"@webassemblyjs/wasm-edit@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" - integrity sha1-P+bXnT8PkiGDqoYALELdJWz+6c8= - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/helper-wasm-section" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-opt" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/wasm-gen@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" - integrity sha1-ULxw7Gje2OJ2OwGhQYv0NJGnpJw= - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wasm-opt@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" - integrity sha1-IhEYHlsxMmRDzIES658LkChyGmE= - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - -"@webassemblyjs/wasm-parser@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" - integrity sha1-nUjkSCbfSmWYKUqmyHRp1kL/9l4= - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wast-parser@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" - integrity sha1-MDERXXmsW9JhVWzsw/qQo+9FGRQ= - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/floating-point-hex-parser" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-code-frame" "1.9.0" - "@webassemblyjs/helper-fsm" "1.9.0" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/wast-printer@1.9.0": - version "1.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" - integrity sha1-STXVTIX+9jewDOn1I3dFHQDUeJk= - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@xtuc/long" "4.2.2" - -"@webcomponents/custom-elements@^1.4.3": - version "1.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@webcomponents/custom-elements/-/custom-elements-1.5.0.tgz#7d07ff4979312dda167cc0a2b7586e76dc1cf6ab" - integrity sha1-fQf/SXkxLdoWfMCit1hudtwc9qs= - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha1-7vAUoxRa5Hehy8AM0eVSM23Ot5A= - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha1-0pHGpOl5ibXGHZrPOWrk/hM6cY0= - -"@yarnpkg/lockfile@1.1.0": - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" - integrity sha1-53qX+9NFt22DJF7c0X05OxtB+zE= - -abab@^2.0.5: - version "2.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" - integrity sha1-wLZ4+zLWD8EhnHhNaoJv44Wut5o= - -abbrev@1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg= - -accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: - version "1.3.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha1-UxvHJlF6OytB+FACHGzBXqq1B80= - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha1-ftW7VZCLOy8bxVxq8WU7rafweTc= - -acorn-node@^1.3.0: - version "1.8.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" - integrity sha1-EUyV1kU55T3t4j3oudlt98euKvg= - dependencies: - acorn "^7.0.0" - acorn-walk "^7.0.0" - xtend "^4.0.2" - -acorn-walk@^7.0.0, acorn-walk@^7.2.0: - version "7.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha1-DeiJpgEgOQmw++B7iTjcIdLpZ7w= - -acorn-walk@^8.0.0: - version "8.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha1-dBIQ8uJCZFRQiFOi9E0KuDt/acE= - -acorn@^6.4.1: - version "6.4.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha1-NYZv1xBSjpLeEM8GAWSY5H454eY= - -acorn@^7.0.0, acorn@^7.4.0, acorn@^7.4.1: - version "7.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo= - -acorn@^8.0.4: - version "8.7.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha1-kJUf3g+PCd+TVJSB5fwUFEW3kc8= - -acorn@^8.5.0: - version "8.8.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== - -address@1.1.2, address@^1.0.1: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" - integrity sha1-vxEWycdYxRt6kz0pa3LCIe2UKLY= - -adjust-sourcemap-loader@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz#fc4a0fd080f7d10471f30a7320f25560ade28c99" - integrity sha1-/EoP0ID30QRx8wpzIPJVYK3ijJk= - dependencies: - loader-utils "^2.0.0" - regex-parser "^2.2.11" - -adm-zip@^0.4.9: - version "0.4.16" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" - integrity sha1-z0xQj9/6sCwmnLx/RxqHXwVXA2U= - -after@0.8.2: - version "0.8.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" - integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= - -agent-base@6, agent-base@^6.0.2: - version "6.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c= - dependencies: - debug "4" - -agent-base@^4.3.0: - version "4.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha1-gWXwHENgCbzK0LHRIvBe13Dvxu4= - dependencies: - es6-promisify "^5.0.0" - -agentkeepalive@^4.1.3: - version "4.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" - integrity sha1-2SgCikhiyxFxjlUieHLoQqRMlFs= - dependencies: - debug "^4.1.0" - depd "^1.1.2" - humanize-ms "^1.2.1" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha1-kmcP9Q9TWb23o+DUDQ7DDFc3aHo= - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -airbnb-js-shims@^2.2.1: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz#db481102d682b98ed1daa4c5baa697a05ce5c040" - integrity sha1-20gRAtaCuY7R2qTFuqaXoFzlwEA= - dependencies: - array-includes "^3.0.3" - array.prototype.flat "^1.2.1" - array.prototype.flatmap "^1.2.1" - es5-shim "^4.5.13" - es6-shim "^0.35.5" - function.prototype.name "^1.1.0" - globalthis "^1.0.0" - object.entries "^1.1.0" - object.fromentries "^2.0.0 || ^1.0.0" - object.getownpropertydescriptors "^2.0.3" - object.values "^1.1.0" - promise.allsettled "^1.0.0" - promise.prototype.finally "^3.1.0" - string.prototype.matchall "^4.0.0 || ^3.0.1" - string.prototype.padend "^3.0.0" - string.prototype.padstart "^3.0.0" - symbol.prototype.description "^1.0.0" - -ajv-errors@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" - integrity sha1-81mGrOuRr63sQQL72FAUlQzvpk0= - -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha1-MfKdpatuANHC0yms97WSlhTVAU0= - -ajv@6.12.6, ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: - version "6.12.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ= - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^7.0.3: - version "7.2.4" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.2.4.tgz#8e239d4d56cf884bccca8cca362f508446dc160f" - integrity sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ajv@^8.0.1: - version "8.8.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" - integrity sha1-AbT+8gB6KL918Lf8AJ9iZ53kq7s= - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -alphanum-sort@^1.0.0, alphanum-sort@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= - -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= - -ansi-align@^3.0.0: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" - integrity sha1-DN8S4RGs53OobpofrRIlxDyxmlk= - dependencies: - string-width "^4.1.0" - -ansi-colors@4.1.1, ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha1-y7muJWv3UK8eqzRPIpqif+lLo0g= - -ansi-colors@^3.0.0: - version "3.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" - integrity sha1-46PaS/uubIapwoViXeEkojQCb78= - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha1-ayKR0dt9mLZSHV8e+kLQ86n+tl4= - dependencies: - type-fest "^0.21.3" - -ansi-gray@^0.1.1: - version "0.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" - integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= - dependencies: - ansi-wrap "0.1.0" - -ansi-html-community@0.0.8: - version "0.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" - integrity sha1-afvE1sy+OD+XNpNK40w/gpDxv0E= - -ansi-html@0.0.7: - version "0.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" - integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc= - -ansi-regex@^5.0.0, ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ= - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0= - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha1-7dgDYornHATIWuegkG7a00tkiTc= - dependencies: - color-convert "^2.0.1" - -ansi-to-html@^0.6.11: - version "0.6.15" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-to-html/-/ansi-to-html-0.6.15.tgz#ac6ad4798a00f6aa045535d7f6a9cb9294eebea7" - integrity sha1-rGrUeYoA9qoEVTXX9qnLkpTuvqc= - dependencies: - entities "^2.0.0" - -ansi-wrap@0.1.0: - version "0.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" - integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha1-vLJLTzeTTZqnrBe0ra+J58du8us= - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -anymatch@^3.0.0, anymatch@^3.0.3, anymatch@~3.1.2: - version "3.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha1-wFV8CWrzLxBhmPT04qODU343hxY= - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -apache-crypt@^1.1.2: - version "1.2.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/apache-crypt/-/apache-crypt-1.2.5.tgz#4eb6b6dbaed2041ce5bc2d802f4421f5fdadc25e" - integrity sha1-Tra2267SBBzlvC2AL0Qh9f2twl4= - dependencies: - unix-crypt-td-js "^1.1.4" - -apache-md5@^1.0.6: - version "1.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/apache-md5/-/apache-md5-1.1.7.tgz#dcef1802700cc231d60c5e08fd088f2f9b36375a" - integrity sha1-3O8YAnAMwjHWDF4I/QiPL5s2N1o= - -app-root-dir@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/app-root-dir/-/app-root-dir-1.0.2.tgz#38187ec2dea7577fff033ffcb12172692ff6e118" - integrity sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg= - -app-root-path@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" - integrity sha1-IQtvQ4cyJ+GKS4EKAyKDMRVV1a0= - -aproba@^1.0.3, aproba@^1.1.1: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha1-aALmJk79GMeQobDVF/DyYnvyyUo= - -"aproba@^1.0.3 || ^2.0.0": - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha1-UlILiuW1aSFbNU78DKo/4eRaitw= - -are-we-there-yet@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" - integrity sha1-Ny4Oe9J52OlMZTqqH2cgCIS/Phw= - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - -are-we-there-yet@~1.1.2: - version "1.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" - integrity sha1-sVR0qTKtq0/4pQ2a36fk6SbyEUY= - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -arg@^4.1.0: - version "4.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha1-Jp/HrVuOQstjyJbVZmAXJhwUQIk= - -argparse@^1.0.7: - version "1.0.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE= - dependencies: - sprintf-js "~1.0.2" - -aria-query@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" - integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= - dependencies: - ast-types-flow "0.0.7" - commander "^2.11.0" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha1-NgSLv/TntH4TZkQxbJlmnqWukfE= - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - -array-flatten@^2.1.0: - version "2.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" - integrity sha1-JO+AoowaiTYX4hSbDG0NeIKTsJk= - -array-from@^2.1.1: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" - integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU= - -array-includes@^3.0.3: - version "3.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" - integrity sha1-9bSTFix2DzU5Yx8AW6K7Rqy0W6k= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - is-string "^1.0.7" - -array-union@^1.0.1, array-union@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha1-t5hCCtvrHego2ErNii4j0+/oXo0= - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -array.prototype.flat@^1.2.1: - version "1.2.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" - integrity sha1-B+CXXYS7x8SM0YedYJ5oJZjTPhM= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - -array.prototype.flatmap@^1.2.1: - version "1.2.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" - integrity sha1-kI3ILYpAaTD984WY1R50EdGNREY= - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.19.0" - -array.prototype.map@^1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/array.prototype.map/-/array.prototype.map-1.0.4.tgz#0d97b640cfdd036c1b41cfe706a5e699aa0711f2" - integrity sha1-DZe2QM/dA2wbQc/nBqXmmaoHEfI= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - -array.prototype.reduce@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz#6b20b0daa9d9734dd6bc7ea66b5bbce395471eac" - integrity sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - -arraybuffer.slice@~0.0.7: - version "0.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" - integrity sha1-O7xCdd1YTMGxCAm4nU6LY6aednU= - -arrify@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -arrify@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" - integrity sha1-yWVekzHgq81YjSp8rX6ZVvZnAfo= - -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha1-EamAuE67kXgc41sP3C7ilON4Pwc= - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - -asn1@~0.2.3: - version "0.2.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha1-DTp7tuZOAqkMAwOzHykoaOoJoI0= - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assert@^1.1.1: - version "1.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha1-VcEJqvbgrv2z3EtxJAxwv1dLGOs= - dependencies: - object-assign "^4.1.1" - util "0.10.3" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -ast-transform@0.0.0: - version "0.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ast-transform/-/ast-transform-0.0.0.tgz#74944058887d8283e189d954600947bc98fe0062" - integrity sha1-dJRAWIh9goPhidlUYAlHvJj+AGI= - dependencies: - escodegen "~1.2.0" - esprima "~1.0.4" - through "~2.3.4" - -ast-types-flow@0.0.7: - version "0.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= - -ast-types@^0.7.0: - version "0.7.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ast-types/-/ast-types-0.7.8.tgz#902d2e0d60d071bdcd46dc115e1809ed11c138a9" - integrity sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk= - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha1-SDFDxWeu7UeFdZwIZXhtx319LjE= - -async-each@^1.0.1: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha1-tyfb+H12UWAvBvTUrDh/R9kbDL8= - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha1-3TeelPDbgxCwgpH51kwyCXZmF/0= - -async@^2.6.2: - version "2.6.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8= - dependencies: - lodash "^4.17.14" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha1-YCzUtG6EStTv/JKoARo8RuAjjcI= - -atob@^2.1.2: - version "2.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k= - -autoprefixer@10.2.4: - version "10.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/autoprefixer/-/autoprefixer-10.2.4.tgz#c0e7cf24fcc6a1ae5d6250c623f0cb8beef2f7e1" - integrity sha1-wOfPJPzGoa5dYlDGI/DLi+7y9+E= - dependencies: - browserslist "^4.16.1" - caniuse-lite "^1.0.30001181" - colorette "^1.2.1" - fraction.js "^4.0.13" - normalize-range "^0.1.2" - postcss-value-parser "^4.1.0" - -autoprefixer@^10.2.4: - version "10.4.13" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.13.tgz#b5136b59930209a321e9fa3dca2e7c4d223e83a8" - integrity sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg== - dependencies: - browserslist "^4.21.4" - caniuse-lite "^1.0.30001426" - fraction.js "^4.2.0" - normalize-range "^0.1.2" - picocolors "^1.0.0" - postcss-value-parser "^4.2.0" - -autoprefixer@^9.8.6: - version "9.8.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" - integrity sha1-/UvUWVOF+m8GWZ3nSaTV96R0lXo= - dependencies: - browserslist "^4.12.0" - caniuse-lite "^1.0.30001109" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - picocolors "^0.2.1" - postcss "^7.0.32" - postcss-value-parser "^4.1.0" - -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.11.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk= - -axobject-query@2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" - integrity sha1-6hh6vluQArN3+SXYv30cVhrfOPk= - dependencies: - ast-types-flow "0.0.7" - -babel-loader@8.2.2: - version "8.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" - integrity sha1-k2POhMEMmkDmx1N0jhRBtgyKC4E= - dependencies: - find-cache-dir "^3.3.1" - loader-utils "^1.4.0" - make-dir "^3.1.0" - schema-utils "^2.6.5" - -babel-loader@^8.0.0, babel-loader@^8.2.2: - version "8.2.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" - integrity sha1-iYa0Dxpkys/LS4QpMgCF72ixNC0= - dependencies: - find-cache-dir "^3.3.1" - loader-utils "^1.4.0" - make-dir "^3.1.0" - schema-utils "^2.6.5" - -babel-plugin-apply-mdx-type-prop@1.6.22: - version "1.6.22" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz#d216e8fd0de91de3f1478ef3231e05446bc8705b" - integrity sha1-0hbo/Q3pHePxR47zIx4FRGvIcFs= - dependencies: - "@babel/helper-plugin-utils" "7.10.4" - "@mdx-js/util" "1.6.22" - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha1-hP2hnJduxcbe/vV/lCez3vZuF6M= - dependencies: - object.assign "^4.1.0" - -babel-plugin-emotion@^10.0.27: - version "10.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz#a1fe3503cff80abfd0bdda14abd2e8e57a79d17d" - integrity sha1-of41A8/4Cr/QvdoUq9Lo5Xp50X0= - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@emotion/hash" "0.8.0" - "@emotion/memoize" "0.7.4" - "@emotion/serialize" "^0.11.16" - babel-plugin-macros "^2.0.0" - babel-plugin-syntax-jsx "^6.18.0" - convert-source-map "^1.5.0" - escape-string-regexp "^1.0.5" - find-root "^1.1.0" - source-map "^0.5.7" - -babel-plugin-extract-import-names@1.6.22: - version "1.6.22" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz#de5f9a28eb12f3eb2578bf74472204e66d1a13dc" - integrity sha1-3l+aKOsS8+sleL90RyIE5m0aE9w= - dependencies: - "@babel/helper-plugin-utils" "7.10.4" - -babel-plugin-istanbul@^6.0.0: - version "6.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha1-+ojsWSMv2bTjbbvFQKjsmptH2nM= - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0: - version "2.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" - integrity sha1-D5WKfMZVax5lNERl2ZERoeXhATg= - dependencies: - "@babel/runtime" "^7.7.2" - cosmiconfig "^6.0.0" - resolve "^1.12.0" - -babel-plugin-macros@^3.0.1: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" - integrity sha1-nvbcdN65NLTbNE3Jc+6FHRSMUME= - dependencies: - "@babel/runtime" "^7.12.5" - cosmiconfig "^7.0.0" - resolve "^1.19.0" - -babel-plugin-polyfill-corejs2@^0.3.0: - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz#407082d0d355ba565af24126fb6cb8e9115251fd" - integrity sha1-QHCC0NNVulZa8kEm+2y46RFSUf0= - dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.3.0" - semver "^6.1.1" - -babel-plugin-polyfill-corejs3@^0.1.0: - version "0.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz#80449d9d6f2274912e05d9e182b54816904befd0" - integrity sha1-gESdnW8idJEuBdnhgrVIFpBL79A= - dependencies: - "@babel/helper-define-polyfill-provider" "^0.1.5" - core-js-compat "^3.8.1" - -babel-plugin-polyfill-corejs3@^0.4.0: - version "0.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz#0b571f4cf3d67f911512f5c04842a7b8e8263087" - integrity sha1-C1cfTPPWf5EVEvXASEKnuOgmMIc= - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.0" - core-js-compat "^3.18.0" - -babel-plugin-polyfill-regenerator@^0.3.0: - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz#9ebbcd7186e1a33e21c5e20cae4e7983949533be" - integrity sha1-nrvNcYbhoz4hxeIMrk55g5SVM74= - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.0" - -babel-plugin-syntax-jsx@^6.18.0: - version "6.18.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" - integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= - -backo2@1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" - integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= - -bail@^1.0.0: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" - integrity sha1-tvoTNASjksvB+MS/Y/WVM1Hnp3Y= - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4= - -base64-arraybuffer@0.1.4: - version "0.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812" - integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI= - -base64-js@1.3.1: - version "1.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha1-WOzoy3XdB+ce0IxzarxfrE2/jfE= - -base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.3.0, base64-js@^1.3.1: - version "1.5.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha1-GxtEAWClv3rUC2UPCVljSBkDkwo= - -base64id@2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" - integrity sha1-J3Csa8R9MSr5eov5pjQ0LgzSXLY= - -base@^0.11.1: - version "0.11.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha1-e95c7RRbbVUakNuH+DxVi060io8= - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -basic-auth@~2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" - integrity sha1-uZgnm/R844NEtPPPkW1Gebv1Hjo= - dependencies: - safe-buffer "5.1.2" - -batch-processor@1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/batch-processor/-/batch-processor-1.0.0.tgz#75c95c32b748e0850d10c2b168f6bdbe9891ace8" - integrity sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg= - -batch@0.6.1: - version "0.6.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" - integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -bcryptjs@^2.4.3: - version "2.4.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" - integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= - -better-opn@^2.1.1: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/better-opn/-/better-opn-2.1.1.tgz#94a55b4695dc79288f31d7d0e5f658320759f7c6" - integrity sha1-lKVbRpXceSiPMdfQ5fZYMgdZ98Y= - dependencies: - open "^7.0.3" - -big.js@^5.2.2: - version "5.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg= - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U= - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0= - -bindings@^1.5.0: - version "1.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha1-EDU8npRTNLwFEabZCzj7x8nFBN8= - dependencies: - file-uri-to-path "1.0.0" - -bl@^4.0.3, bl@^4.1.0: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha1-RRU1JkGCvsL7vIOmKrmM8R2fezo= - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -blob@0.0.5: - version "0.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" - integrity sha1-1oDu7yX4zZGtUz9bAe7UjmTK9oM= - -blocking-proxy@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" - integrity sha1-gdb9H+E6TA1pV99/kbdemNrEDLI= - dependencies: - minimist "^1.2.0" - -bluebird@^3.3.5, bluebird@^3.5.5: - version "3.7.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha1-nyKcFb4nJFT/qXOs4NvueaGww28= - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha1-d1s/J477uXGO7HNh9IP7Nvu/6og= - -bn.js@^5.0.0, bn.js@^5.1.1: - version "5.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha1-NYhgZ0OWxpl3canQUfzBtX1K4AI= - -body-parser@1.19.1, body-parser@^1.19.0: - version "1.19.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" - integrity sha1-FJmruqknSvPsyfbxA5bJlZQ+MdQ= - dependencies: - bytes "3.1.1" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.8.1" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.9.6" - raw-body "2.4.2" - type-is "~1.6.18" - -bonjour@^3.5.0: - version "3.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" - integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= - dependencies: - array-flatten "^2.1.0" - deep-equal "^1.0.1" - dns-equal "^1.0.0" - dns-txt "^2.0.2" - multicast-dns "^6.0.1" - multicast-dns-service-types "^1.1.0" - -boolbase@^1.0.0, boolbase@~1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -boxen@^5.1.2: - version "5.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" - integrity sha1-eIy2hvyDwfSG36ikDGj8K4MdK1A= - dependencies: - ansi-align "^3.0.0" - camelcase "^6.2.0" - chalk "^4.1.0" - cli-boxes "^2.2.1" - string-width "^4.2.2" - type-fest "^0.20.2" - widest-line "^3.1.0" - wrap-ansi "^7.0.0" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0= - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha1-WXn9PxTNUxVl5fot8av/8d+u5yk= - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha1-NFThpGLujVmeI23zNs2epPiv4Qc= - dependencies: - fill-range "^7.0.1" - -brfs@^2.0.0, brfs@^2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/brfs/-/brfs-2.0.2.tgz#44237878fa82aa479ce4f5fe2c1796ec69f07845" - integrity sha1-RCN4ePqCqkec5PX+LBeW7GnweEU= - dependencies: - quote-stream "^1.0.1" - resolve "^1.1.5" - static-module "^3.0.2" - through2 "^2.0.0" - -brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -brotli@^1.2.0: - version "1.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/brotli/-/brotli-1.3.2.tgz#525a9cad4fcba96475d7d388f6aecb13eed52f46" - integrity sha1-UlqcrU/LqWR119OI9q7LE+7VL0Y= - dependencies: - base64-js "^1.1.2" - -browser-resolve@^1.8.1: - version "1.11.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha1-m3y7PQ9RDky4a9vXlhJNKLWJCvY= - dependencies: - resolve "1.1.7" - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha1-Mmc0ZC9APavDADIJhTu3CtQo70g= - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha1-jWR0wbhwv9q807z8wZNKEOlPFfA= - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha1-OvTx9Zg5QDVy8cZiBDdfen9wPpw= - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-optional@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserify-optional/-/browserify-optional-1.0.1.tgz#1e13722cfde0d85f121676c2a72ced533a018869" - integrity sha1-HhNyLP3g2F8SFnbCpyztUzoBiGk= - dependencies: - ast-transform "0.0.0" - ast-types "^0.7.0" - browser-resolve "^1.8.1" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha1-sv0Gtbda4pf3zi3GUfkY9b4VjI0= - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha1-6vSt1G3VS+O7OzbAzxWrvrp5VsM= - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha1-KGlFnZqjviRf6P4sofRuLn9U1z8= - dependencies: - pako "~1.0.5" - -browserslist@4.14.2: - version "4.14.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserslist/-/browserslist-4.14.2.tgz#1b3cec458a1ba87588cc5e9be62f19b6d48813ce" - integrity sha1-GzzsRYobqHWIzF6b5i8ZttSIE84= - dependencies: - caniuse-lite "^1.0.30001125" - electron-to-chromium "^1.3.564" - escalade "^3.0.2" - node-releases "^1.1.61" - -browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.0, browserslist@^4.16.1, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.19.1, browserslist@^4.9.1: - version "4.19.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" - integrity sha1-SsBDWzWrZViWwx1TAYtt1enkyaM= - dependencies: - caniuse-lite "^1.0.30001286" - electron-to-chromium "^1.4.17" - escalade "^3.1.1" - node-releases "^2.0.1" - picocolors "^1.0.0" - -browserslist@^4.21.4: - version "4.21.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" - integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== - dependencies: - caniuse-lite "^1.0.30001400" - electron-to-chromium "^1.4.251" - node-releases "^2.0.6" - update-browserslist-db "^1.0.9" - -browserstack@^1.5.1: - version "1.6.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/browserstack/-/browserstack-1.6.1.tgz#e051f9733ec3b507659f395c7a4765a1b1e358b3" - integrity sha1-4FH5cz7DtQdlnzlcekdlobHjWLM= - dependencies: - https-proxy-agent "^2.2.1" - -bser@2.1.1: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha1-5nh9og7OnQeZhTPP2d5vXDj0vAU= - dependencies: - node-int64 "^0.4.0" - -buffer-equal@0.0.1: - version "0.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" - integrity sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs= - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha1-KxRqb9cugLT1XSVfNe1Zo6mkG9U= - -buffer-indexof@^1.0.0: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" - integrity sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow= - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha1-Iw6tNEACmIZEhBqwJEr4xEu+Pvg= - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -buffer@^5.5.0: - version "5.7.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha1-umLnwTEzBTWCGXFghRqPZI6Z7tA= - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - -builtin-modules@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" - integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - -builtins@^1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" - integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= - -bytes@3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - -bytes@3.1.1: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" - integrity sha1-PwGCkctMutmsy25pcLypyIieh5o= - -cacache@15.0.5: - version "15.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cacache/-/cacache-15.0.5.tgz#69162833da29170d6732334643c60e005f5f17d0" - integrity sha1-aRYoM9opFw1nMjNGQ8YOAF9fF9A= - dependencies: - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.0" - tar "^6.0.2" - unique-filename "^1.1.1" - -cacache@^12.0.2: - version "12.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha1-ZovL0QWutfHZL+JVcOyVJcj6pAw= - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cacache@^15.0.5: - version "15.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" - integrity sha1-3IU4D7L1Vv492kxxm/oOyHWn8es= - dependencies: - "@npmcli/fs" "^1.0.0" - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha1-Cn9GQWgxyLZi7jb+TnxZ129marI= - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw= - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ== - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A== - dependencies: - caller-callsite "^2.0.0" - -callsite@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" - integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ== - -callsites@^3.0.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M= - -camel-case@^4.1.1: - version "4.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" - integrity sha1-lygHKpVPgFIoIlpt7qazhGHhvVo= - dependencies: - pascal-case "^3.1.2" - tslib "^2.0.3" - -camelcase-css@2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" - integrity sha1-7pePaUeRTMMMa0R0G27R338EP9U= - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA= - -camelcase@^6.2.0: - version "6.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/camelcase/-/camelcase-6.2.1.tgz#250fd350cfd555d0d2160b1d51510eaf8326e86e" - integrity sha1-JQ/TUM/VVdDSFgsdUVEOr4Mm6G4= - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA= - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001286: - version "1.0.30001294" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/caniuse-lite/-/caniuse-lite-1.0.30001294.tgz#4849f27b101fd59ddee3751598c663801032533d" - integrity sha1-SEnyexAf1Z3e43UVmMZjgBAyUz0= - -caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426: - version "1.0.30001449" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz#a8d11f6a814c75c9ce9d851dc53eb1d1dfbcd657" - integrity sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw== - -canonical-path@1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" - integrity sha1-/LRwwjlY3vhQgYVr56hukE8YDR0= - -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha1-+5U7+uvreB9iiYI52rtCbQilCaQ= - dependencies: - rsvp "^4.8.4" - -case-sensitive-paths-webpack-plugin@^2.3.0: - version "2.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" - integrity sha1-22QGbGQi7tLgjMFLmGykN5bbxtQ= - -caseless@~0.12.0: - version "0.12.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -ccount@^1.0.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" - integrity sha1-JGaH3rtgFHNRMb6KurLZOJj40EM= - -chalk@2.4.2, chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.1: - version "2.4.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ= - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^1.1.1, chalk@^1.1.3: - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: - version "4.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha1-qsTit3NKdAhnrrFr8CqtVWoeegE= - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -character-entities-legacy@^1.0.0: - version "1.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" - integrity sha1-lLwYRdznClu50uzHSHJWYSk9j8E= - -character-entities@^1.0.0: - version "1.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" - integrity sha1-4Sw5Obfq9OWxXnrUxeKOHUjFsWs= - -character-reference-invalid@^1.0.0: - version "1.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" - integrity sha1-CDMpzaDq4nKrPbvzfpo4LBOvFWA= - -chardet@^0.7.0: - version "0.7.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha1-kAlISfCTfy7twkJdDSip5fDLrZ4= - -cheerio-select@^1.5.0: - version "1.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cheerio-select/-/cheerio-select-1.5.0.tgz#faf3daeb31b17c5e1a9dabcee288aaf8aafa5823" - integrity sha1-+vPa6zGxfF4anavO4oiq+Kr6WCM= - dependencies: - css-select "^4.1.3" - css-what "^5.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - domutils "^2.7.0" - -cheerio@^1.0.0-rc.10: - version "1.0.0-rc.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e" - integrity sha1-K6Pc38wm55VvwfRA5h1RxkM3nz4= - dependencies: - cheerio-select "^1.5.0" - dom-serializer "^1.3.2" - domhandler "^4.2.0" - htmlparser2 "^6.1.0" - parse5 "^6.0.1" - parse5-htmlparser2-tree-adapter "^6.0.1" - tslib "^2.2.0" - -"chokidar@>=2.0.0 <4.0.0", "chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.4.1, chokidar@^3.4.2, chokidar@^3.5.2: - version "3.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha1-26OXb8rbAW9m/TZQIdkWANAcHnU= - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chokidar@^2.1.8: - version "2.1.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha1-gEs6e2qZNYw8XGHnHYco8EHP+Rc= - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - -chokidar@^3.5.1: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chownr@^1.1.1: - version "1.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha1-b8nXtC0ypYNZYzdmbn0ICE2izGs= - -chownr@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" - integrity sha1-Fb++U9LqtM9w8YqM1o6+Wzyx3s4= - -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha1-EBXs7UdB4V0GZkqVfbv1DQQeJqw= - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha1-Z6npZL4xpR4V5QENWObxKDQAL0Y= - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94= - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -circular-dependency-plugin@5.2.2: - version "5.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz#39e836079db1d3cf2f988dc48c5188a44058b600" - integrity sha1-Oeg2B52x088vmI3EjFGIpEBYtgA= - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha1-+TNprouafOAv1B+q0MqDAzGQxGM= - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -clean-css@^4.2.3: - version "4.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178" - integrity sha1-czv0brpOYHxokepXwkqYk1aDEXg= - dependencies: - source-map "~0.6.0" - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha1-7oRy27Ep5yezHooQpCfe6d/kAIs= - -cli-boxes@^2.2.1: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" - integrity sha1-3dUDXSUJT84iDpyrQKRYQKRAMY8= - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha1-JkMFp65JDR0Dvwybp8kl0XU68wc= - dependencies: - restore-cursor "^3.1.0" - -cli-spinners@^2.5.0: - version "2.6.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" - integrity sha1-rclU6+KBw3pjGb+kAebdJIj/tw0= - -cli-table3@0.6.0: - version "0.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cli-table3/-/cli-table3-0.6.0.tgz#b7b1bc65ca8e7b5cef9124e13dc2b21e2ce4faee" - integrity sha1-t7G8ZcqOe1zvkSThPcKyHizk+u4= - dependencies: - object-assign "^4.1.0" - string-width "^4.2.0" - optionalDependencies: - colors "^1.1.2" - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha1-ovSEN6LKqaIkNueUvwceyeYc7fY= - -cliui@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha1-3u/P2y6AB4SqNPRvoI4GhRx7u8U= - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - -cliui@^6.0.0: - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE= - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha1-oCZe5lVHb8gHrqnfPfjfd4OAi08= - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -clone-deep@^4.0.1: - version "4.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" - integrity sha1-wZ/Zvbv4WUK0/ZechNz31fB8I4c= - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -clone@^1.0.2, clone@^1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - -clsx@^1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" - integrity sha1-mLMTT5q73yOyZjSRrOE8XAOnMYg= - -coa@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" - integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== - dependencies: - "@types/q" "^1.5.1" - chalk "^2.4.1" - q "^1.1.2" - -code-block-writer@^11.0.0: - version "11.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/code-block-writer/-/code-block-writer-11.0.0.tgz#5956fb186617f6740e2c3257757fea79315dd7d4" - integrity sha1-WVb7GGYX9nQOLDJXdX/qeTFd19Q= - dependencies: - tslib "2.3.1" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -codelyzer@^6.0.0: - version "6.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/codelyzer/-/codelyzer-6.0.2.tgz#25d72eae641e8ff13ffd7d99b27c9c7ad5d7e135" - integrity sha1-JdcurmQej/E//X2ZsnycetXX4TU= - dependencies: - "@angular/compiler" "9.0.0" - "@angular/core" "9.0.0" - app-root-path "^3.0.0" - aria-query "^3.0.0" - axobject-query "2.0.2" - css-selector-tokenizer "^0.7.1" - cssauron "^1.4.0" - damerau-levenshtein "^1.0.4" - rxjs "^6.5.3" - semver-dsl "^1.0.1" - source-map "^0.5.7" - sprintf-js "^1.1.2" - tslib "^1.10.0" - zone.js "~0.10.3" - -collapse-white-space@^1.0.2: - version "1.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" - integrity sha1-5jYpwAFmZXkgYNu+t5xCI50sUoc= - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0, color-convert@^1.9.3: - version "1.9.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg= - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM= - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI= - -color-string@^1.6.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" - integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color-support@^1.1.2, color-support@^1.1.3: - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI= - -color@^3.0.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" - integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== - dependencies: - color-convert "^1.9.3" - color-string "^1.6.0" - -colord@^2.9.1: - version "2.9.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" - integrity sha1-JeK6y7qmWZFCLAfqIJ4giUKO/7E= - -colorette@^1.2.1, colorette@^1.2.2: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" - integrity sha1-UZD7uHJ2JZqGrXAL/yxtb6o/ykA= - -colors@1.4.0, colors@^1.1.2, colors@^1.4.0, colors@latest: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" - integrity sha1-xQSRR51MG9rtLJztMs98fcI2D3g= - -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha1-w9RaizT9cwYxoRCoolIGgrMdWn8= - dependencies: - delayed-stream "~1.0.0" - -comma-separated-tokens@^1.0.0: - version "1.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" - integrity sha1-YyuAthF4Z6FY8QgK1Jiy++fj9eo= - -commander@^2.11.0, commander@^2.12.1, commander@^2.20.0: - version "2.20.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha1-/UhehMA+tIgcIHIrpIA16FMa6zM= - -commander@^4.1.1: - version "4.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha1-n9YCvZNilOnp70aj9NaWQESxgGg= - -commander@^6.2.1: - version "6.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha1-B5LraC37wyWZm7K4T93duhEKxzw= - -commander@^7.0.0, commander@^7.2.0: - version "7.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc= - -commander@^8.3.0: - version "8.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" - integrity sha1-SDfqGy2me5xhamevuw+v7lZ7ymY= - -commondir@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -component-bind@1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" - integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= - -component-emitter@1.2.1: - version "1.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= - -component-emitter@^1.2.1, component-emitter@~1.3.0: - version "1.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A= - -component-inherit@0.0.3: - version "0.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" - integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= - -compressible@~2.0.16: - version "2.0.18" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha1-r1PMprBw1MPAdQ+9dyhqbXzEb7o= - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.4: - version "1.7.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha1-lVI+/xcMpXwpoMpB5v4TH0Hlu48= - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - -compute-scroll-into-view@^1.0.17: - version "1.0.17" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab" - integrity sha1-aojxis2dQunPS6pr7H4FImB6t6s= - -concat-map@0.0.1: - version "0.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.5.0, concat-stream@~1.6.0: - version "1.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ= - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -connect-history-api-fallback@^1.6.0: - version "1.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" - integrity sha1-izIIk1kwjRERFdgcrT/Oq4iPl7w= - -connect@^3.7.0: - version "3.7.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" - integrity sha1-XUk0iRDKpeB6AYALAw0MNfIEhPg= - dependencies: - debug "2.6.9" - finalhandler "1.1.2" - parseurl "~1.3.3" - utils-merge "1.0.1" - -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha1-ZwY871fOts9Jk6KrOlWECujEkzY= - -console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - -content-disposition@0.5.4: - version "0.5.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha1-i4K076yCUSoCuwsdzsnSxejrW/4= - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha1-4TjMdeBAxyexlm/l5fjJruJW/js= - -convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.5.1, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha1-8zc8MtIbTXgN2ABFFGhPt5HKQ2k= - dependencies: - safe-buffer "~5.1.1" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - -cookie@0.4.1, cookie@~0.4.1: - version "0.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" - integrity sha1-r9cT/ibr0hupXOth+agRblClN9E= - -copy-anything@^2.0.1: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/copy-anything/-/copy-anything-2.0.3.tgz#842407ba02466b0df844819bbe3baebbe5d45d87" - integrity sha1-hCQHugJGaw34RIGbvjuuu+XUXYc= - dependencies: - is-what "^3.12.0" - -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha1-kilzmMrjSTf8r9bsgTnBgFHwteA= - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -copy-to-clipboard@^3.3.1: - version "3.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" - integrity sha1-EVqhqZmP+rYZb5MHatbaO5E2Yq4= - dependencies: - toggle-selection "^1.0.6" - -copy-webpack-plugin@6.3.2: - version "6.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/copy-webpack-plugin/-/copy-webpack-plugin-6.3.2.tgz#0e920a6c181a5052aa6e2861b164bda03f83afeb" - integrity sha1-DpIKbBgaUFKqbihhsWS9oD+Dr+s= - dependencies: - cacache "^15.0.5" - fast-glob "^3.2.4" - find-cache-dir "^3.3.1" - glob-parent "^5.1.1" - globby "^11.0.1" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - webpack-sources "^1.4.3" - -core-js-compat@^3.18.0, core-js-compat@^3.19.1, core-js-compat@^3.8.0, core-js-compat@^3.8.1: - version "3.20.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/core-js-compat/-/core-js-compat-3.20.1.tgz#96917b4db634fbbbc7b36575b2e8fcbf7e4f9691" - integrity sha1-lpF7TbY0+7vHs2V1suj8v35PlpE= - dependencies: - browserslist "^4.19.1" - semver "7.0.0" - -core-js-pure@^3.8.2: - version "3.20.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/core-js-pure/-/core-js-pure-3.20.1.tgz#f7a2c62f98de83e4da8fca7b78846d3a2f542145" - integrity sha1-96LGL5jeg+Taj8p7eIRtOi9UIUU= - -core-js@3.8.3: - version "3.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/core-js/-/core-js-3.8.3.tgz#c21906e1f14f3689f93abcc6e26883550dd92dd0" - integrity sha1-whkG4fFPNon5OrzG4miDVQ3ZLdA= - -core-js@^3.0.4, core-js@^3.6.5, core-js@^3.8.2: - version "3.20.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/core-js/-/core-js-3.20.1.tgz#eb1598047b7813572f1dc24b7c6a95528c99eef3" - integrity sha1-6xWYBHt4E1cvHcJLfGqVUoyZ7vM= - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha1-pgQtNjTCsn6TKPg3uWX6yDgI24U= - -cors@latest: - version "2.8.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha1-6sEdpRWS3Ya58G9uesKTs9+HXSk= - dependencies: - object-assign "^4" - vary "^1" - -cosmiconfig@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" - integrity sha1-2k/uhTxS9rHmk19BwaL8UL1KmYI= - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - -cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: - version "7.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha1-cU11ZSLKzoZ4Z8y0R0xdAbuuXW0= - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - -cp-file@^7.0.0: - version "7.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" - integrity sha1-uUVM/Qf+O5dKueoOXyllV5GpuM0= - dependencies: - graceful-fs "^4.1.2" - make-dir "^3.0.0" - nested-error-stacks "^2.0.0" - p-event "^4.1.0" - -cpy@^8.1.2: - version "8.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cpy/-/cpy-8.1.2.tgz#e339ea54797ad23f8e3919a5cffd37bfc3f25935" - integrity sha1-4znqVHl60j+OORmlz/03v8PyWTU= - dependencies: - arrify "^2.0.1" - cp-file "^7.0.0" - globby "^9.2.0" - has-glob "^1.0.0" - junk "^3.1.0" - nested-error-stacks "^2.1.0" - p-all "^2.1.0" - p-filter "^2.1.0" - p-map "^3.0.0" - -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha1-1uf0v/pmc2CFoHYv06YyaE2rzE4= - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha1-iJB4rxGmN1a8+1m9IhmWvjqe8ZY= - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha1-aRcMeLOrlXFHsriwRXLkfq0iQ/8= - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -critters@0.0.12: - version "0.0.12" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/critters/-/critters-0.0.12.tgz#32baa87526e053a41b67e19921673ed92264e2ab" - integrity sha1-MrqodSbgU6QbZ+GZIWc+2SJk4qs= - dependencies: - chalk "^4.1.0" - css-select "^4.1.3" - parse5 "^6.0.1" - parse5-htmlparser2-tree-adapter "^6.0.1" - postcss "^8.3.7" - pretty-bytes "^5.3.0" - -cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha1-9zqFudXUHQRVUcF34ogtSshXKKY= - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q= - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha1-OWz58xN/A+S45TLFj2mCVOAPgOw= - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -crypto-js@^4.0.0: - version "4.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" - integrity sha1-nkhbzwNSEEG9hYRHhrg/t2GXNs8= - -css-color-names@0.0.4, css-color-names@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - integrity sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q== - -css-declaration-sorter@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" - integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== - dependencies: - postcss "^7.0.1" - timsort "^0.3.0" - -css-declaration-sorter@^6.0.3: - version "6.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz#e9852e4cf940ba79f509d9425b137d1f94438dc2" - integrity sha1-6YUuTPlAunn1CdlCWxN9H5RDjcI= - dependencies: - timsort "^0.3.0" - -css-loader@5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/css-loader/-/css-loader-5.0.1.tgz#9e4de0d6636a6266a585bd0900b422c85539d25f" - integrity sha1-nk3g1mNqYmalhb0JALQiyFU50l8= - dependencies: - camelcase "^6.2.0" - cssesc "^3.0.0" - icss-utils "^5.0.0" - loader-utils "^2.0.0" - postcss "^8.1.4" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^3.0.0" - semver "^7.3.2" - -css-loader@^3.6.0: - version "3.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645" - integrity sha1-Lkssfm4tJ/jI8o9hv/zS5ske9kU= - dependencies: - camelcase "^5.3.1" - cssesc "^3.0.0" - icss-utils "^4.1.1" - loader-utils "^1.2.3" - normalize-path "^3.0.0" - postcss "^7.0.32" - postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^3.0.2" - postcss-modules-scope "^2.2.0" - postcss-modules-values "^3.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^2.7.0" - semver "^6.3.0" - -css-loader@^5.2.7: - version "5.2.7" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.7.tgz#9b9f111edf6fb2be5dc62525644cbc9c232064ae" - integrity sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg== - dependencies: - icss-utils "^5.1.0" - loader-utils "^2.0.0" - postcss "^8.2.15" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^3.0.0" - semver "^7.3.5" - -css-parse@~2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" - integrity sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q= - dependencies: - css "^2.0.0" - -css-select-base-adapter@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" - integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== - -css-select@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" - integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== - dependencies: - boolbase "^1.0.0" - css-what "^3.2.1" - domutils "^1.7.0" - nth-check "^1.0.2" - -css-select@^4.1.3: - version "4.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd" - integrity sha1-nmZdauTH+dZdvmnQMW4yIfsnTN0= - dependencies: - boolbase "^1.0.0" - css-what "^5.1.0" - domhandler "^4.3.0" - domutils "^2.8.0" - nth-check "^2.0.1" - -css-selector-tokenizer@^0.7.1: - version "0.7.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" - integrity sha1-c18mGG5nx0mq8nV4NAXPBmH66PE= - dependencies: - cssesc "^3.0.0" - fastparse "^1.1.2" - -css-tree@1.0.0-alpha.37: - version "1.0.0-alpha.37" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" - integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== - dependencies: - mdn-data "2.0.4" - source-map "^0.6.1" - -css-tree@^1.1.2, css-tree@^1.1.3: - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" - integrity sha1-60hw+2/XcHMn7JXC/yqwm16NuR0= - dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" - -css-what@^3.2.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" - integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== - -css-what@^5.0.1, css-what@^5.1.0: - version "5.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" - integrity sha1-P3tweq32M7r2LCzrhXm1RbtA9/4= - -css@^2.0.0: - version "2.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" - integrity sha1-xkZ1XHOXHyu6amAeLPL9cbEpiSk= - dependencies: - inherits "^2.0.3" - source-map "^0.6.1" - source-map-resolve "^0.5.2" - urix "^0.1.0" - -cssauron@^1.4.0: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" - integrity sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg= - dependencies: - through X.X.X - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4= - -cssnano-preset-default@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz#920622b1fc1e95a34e8838203f1397a504f2d3ff" - integrity sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ== - dependencies: - css-declaration-sorter "^4.0.1" - cssnano-util-raw-cache "^4.0.1" - postcss "^7.0.0" - postcss-calc "^7.0.1" - postcss-colormin "^4.0.3" - postcss-convert-values "^4.0.1" - postcss-discard-comments "^4.0.2" - postcss-discard-duplicates "^4.0.2" - postcss-discard-empty "^4.0.1" - postcss-discard-overridden "^4.0.1" - postcss-merge-longhand "^4.0.11" - postcss-merge-rules "^4.0.3" - postcss-minify-font-values "^4.0.2" - postcss-minify-gradients "^4.0.2" - postcss-minify-params "^4.0.2" - postcss-minify-selectors "^4.0.2" - postcss-normalize-charset "^4.0.1" - postcss-normalize-display-values "^4.0.2" - postcss-normalize-positions "^4.0.2" - postcss-normalize-repeat-style "^4.0.2" - postcss-normalize-string "^4.0.2" - postcss-normalize-timing-functions "^4.0.2" - postcss-normalize-unicode "^4.0.1" - postcss-normalize-url "^4.0.1" - postcss-normalize-whitespace "^4.0.2" - postcss-ordered-values "^4.1.2" - postcss-reduce-initial "^4.0.3" - postcss-reduce-transforms "^4.0.2" - postcss-svgo "^4.0.3" - postcss-unique-selectors "^4.0.1" - -cssnano-preset-default@^5.0.1: - version "5.1.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cssnano-preset-default/-/cssnano-preset-default-5.1.9.tgz#79628ac48eccbdad570f70b4018cc38d43d1b7df" - integrity sha1-eWKKxI7Mva1XD3C0AYzDjUPRt98= - dependencies: - css-declaration-sorter "^6.0.3" - cssnano-utils "^2.0.1" - postcss-calc "^8.0.0" - postcss-colormin "^5.2.2" - postcss-convert-values "^5.0.2" - postcss-discard-comments "^5.0.1" - postcss-discard-duplicates "^5.0.1" - postcss-discard-empty "^5.0.1" - postcss-discard-overridden "^5.0.1" - postcss-merge-longhand "^5.0.4" - postcss-merge-rules "^5.0.3" - postcss-minify-font-values "^5.0.1" - postcss-minify-gradients "^5.0.3" - postcss-minify-params "^5.0.2" - postcss-minify-selectors "^5.1.0" - postcss-normalize-charset "^5.0.1" - postcss-normalize-display-values "^5.0.1" - postcss-normalize-positions "^5.0.1" - postcss-normalize-repeat-style "^5.0.1" - postcss-normalize-string "^5.0.1" - postcss-normalize-timing-functions "^5.0.1" - postcss-normalize-unicode "^5.0.1" - postcss-normalize-url "^5.0.4" - postcss-normalize-whitespace "^5.0.1" - postcss-ordered-values "^5.0.2" - postcss-reduce-initial "^5.0.2" - postcss-reduce-transforms "^5.0.1" - postcss-svgo "^5.0.3" - postcss-unique-selectors "^5.0.2" - -cssnano-util-get-arguments@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" - integrity sha512-6RIcwmV3/cBMG8Aj5gucQRsJb4vv4I4rn6YjPbVWd5+Pn/fuG+YseGvXGk00XLkoZkaj31QOD7vMUpNPC4FIuw== - -cssnano-util-get-match@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" - integrity sha512-JPMZ1TSMRUPVIqEalIBNoBtAYbi8okvcFns4O0YIhcdGebeYZK7dMyHJiQ6GqNBA9kE0Hym4Aqym5rPdsV/4Cw== - -cssnano-util-raw-cache@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" - integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== - dependencies: - postcss "^7.0.0" - -cssnano-util-same-parent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" - integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== - -cssnano-utils@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2" - integrity sha1-hmCqKzfthp0uLyKRgZapqLZJjOI= - -cssnano@5.0.2: - version "5.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cssnano/-/cssnano-5.0.2.tgz#3f6de4fd5ecb7b5fb636c1a606de5f38cd241493" - integrity sha1-P23k/V7Le1+2NsGmBt5fOM0kFJM= - dependencies: - cosmiconfig "^7.0.0" - cssnano-preset-default "^5.0.1" - is-resolvable "^1.1.0" - -cssnano@^4.1.10: - version "4.1.11" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.11.tgz#c7b5f5b81da269cb1fd982cb960c1200910c9a99" - integrity sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g== - dependencies: - cosmiconfig "^5.0.0" - cssnano-preset-default "^4.0.8" - is-resolvable "^1.0.0" - postcss "^7.0.0" - -csso@^4.0.2, csso@^4.2.0: - version "4.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" - integrity sha1-6jpWE0bo3J9UbW/r7dUBh884lSk= - dependencies: - css-tree "^1.1.2" - -csstype@^2.5.7: - version "2.6.19" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/csstype/-/csstype-2.6.19.tgz#feeb5aae89020bb389e1f63669a5ed490e391caa" - integrity sha1-/utarokCC7OJ4fY2aaXtSQ45HKo= - -csstype@^3.0.2: - version "3.0.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" - integrity sha1-KtOnvtcPNbllcHwJLl8wsyfCkOU= - -cuint@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" - integrity sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw== - -custom-event@~1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" - integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU= - -cyclist@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha1-hpgJU3LVjb7jRv/Qxwk/mfj561o= - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - -damerau-levenshtein@^1.0.4: - version "1.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" - integrity sha1-ZDaAA1EqGmmSWTdBoJqdMag29V0= - -dash-ast@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dash-ast/-/dash-ast-2.0.1.tgz#8d0fd2e601c59bf874cc22877ee7dd889f54dee8" - integrity sha1-jQ/S5gHFm/h0zCKHfufdiJ9U3ug= - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -date-format@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf" - integrity sha1-MdW16iEc9f12TNOLr50DPffhJc8= - -date-format@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95" - integrity sha1-64eANlx9KxURB4+0keZHl4DzrZU= - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0: - version "2.6.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8= - dependencies: - ms "2.0.0" - -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha1-BCZuC3CpjURi5uKI44JZITMytmQ= - dependencies: - ms "2.1.2" - -debug@4.3.1: - version "4.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4= - dependencies: - ms "2.1.2" - -debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: - version "3.2.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o= - dependencies: - ms "^2.1.1" - -debug@~3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE= - dependencies: - ms "2.0.0" - -debug@~4.1.0: - version "4.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E= - dependencies: - ms "^2.1.1" - -decache@^4.6.0: - version "4.6.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/decache/-/decache-4.6.1.tgz#5928bfab97a6fcf22a65047a3d07999af36efaf0" - integrity sha1-WSi/q5em/PIqZQR6PQeZmvNu+vA= - dependencies: - callsite "^1.0.0" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -deep-equal@^1.0.0, deep-equal@^1.0.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" - integrity sha1-tcmMlCzv+vfLBR4k4UNKJaLmB2o= - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - -deep-is@^0.1.3, deep-is@~0.1.3: - version "0.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha1-pvLc5hL63S7x9Rm3NVHxfoUZmDE= - -deep-object-diff@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" - integrity sha1-1vq/R2wu0XUfyU1cppPS7YwYvFo= - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha1-RNLqNnm49NT/ujPwPYZfwee/SVU= - -default-gateway@^4.2.0: - version "4.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" - integrity sha1-FnEEx1AMIRX23WmwpTa7jtcgVSs= - dependencies: - execa "^1.0.0" - ip-regex "^2.1.0" - -defaults@^1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha1-P3rkIRKbyqrJvHSQXJigAJ7J7n8= - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE= - dependencies: - object-keys "^1.0.12" - -define-properties@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha1-1Flono1lS6d+AqgX+HENcCyxbp0= - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -del@^2.2.0: - version "2.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - -del@^4.1.1: - version "4.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" - integrity sha1-no8RciLqRKMf86FWwEm5kFKp8LQ= - dependencies: - "@types/glob" "^7.1.1" - globby "^6.1.0" - is-path-cwd "^2.0.0" - is-path-in-cwd "^2.0.0" - p-map "^2.0.0" - pify "^4.0.1" - rimraf "^2.6.3" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -delegates@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -depd@^1.1.2, depd@~1.1.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -depd@~2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8= - -dependency-graph@^0.7.2: - version "0.7.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" - integrity sha1-kdud5utyaZIJ2IrqTB/VIhysHEk= - -des.js@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha1-U4IULhvcU/hdhtU+X0qn3rkeCEM= - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -detab@2.0.4: - version "2.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/detab/-/detab-2.0.4.tgz#b927892069aff405fbb9a186fe97a44a92a94b43" - integrity sha1-uSeJIGmv9AX7uaGG/pekSpKpS0M= - dependencies: - repeat-string "^1.5.4" - -detect-node@^2.0.4: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" - integrity sha1-yccHdaScPQO8LAbZpzvlUPl4+LE= - -detect-port-alt@1.1.6: - version "1.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" - integrity sha1-JHB96r6TLUo89iEwICfCsmZWgnU= - dependencies: - address "^1.0.1" - debug "^2.6.0" - -detect-port@^1.3.0: - version "1.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1" - integrity sha1-2cQOmsyt1N9crGp4Ku/QFNVz0fE= - dependencies: - address "^1.0.1" - debug "^2.6.0" - -dfa@^1.2.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dfa/-/dfa-1.2.0.tgz#96ac3204e2d29c49ea5b57af8d92c2ae12790657" - integrity sha1-lqwyBOLSnEnqW1evjZLCrhJ5Blc= - -di@^0.0.1: - version "0.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" - integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= - -diff@^4.0.1: - version "4.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha1-YPOuy4nV+uUgwRqhnvwruYKq3n0= - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha1-QOjumPVaIUlgcUaSHGPhrl89KHU= - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-glob@^2.2.2: - version "2.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha1-+gnwaUFTyJGLGLoN6vrpR2n8UMQ= - dependencies: - path-type "^3.0.0" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha1-Vtv3PZkqSpO6FYT0U0Bj/S5BcX8= - dependencies: - path-type "^4.0.0" - -dns-equal@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" - integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= - -dns-packet@^1.3.1: - version "1.3.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" - integrity sha1-40VQZYJKJQe6iGxVqJljuxB97G8= - dependencies: - ip "^1.1.0" - safe-buffer "^5.0.1" - -dns-txt@^2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" - integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= - dependencies: - buffer-indexof "^1.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha1-rd6+rXKmV023g2OdyHoSF3OXOWE= - dependencies: - esutils "^2.0.2" - -dom-converter@^0.2.0: - version "0.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" - integrity sha1-ZyGp2u4uKTaClVtq/kFncWJ7t2g= - dependencies: - utila "~0.4" - -dom-serialize@^2.2.1: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" - integrity sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs= - dependencies: - custom-event "~1.0.0" - ent "~2.2.0" - extend "^3.0.0" - void-elements "^2.0.0" - -dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - -dom-serializer@^1.0.1, dom-serializer@^1.3.2: - version "1.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" - integrity sha1-YgZDfTLO767HFhgDIwx6ILwbTZE= - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.0" - entities "^2.0.0" - -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha1-DFSL7wSPTR8qlySQAiNgYNqj/YQ= - -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha1-PTH1AZGmdJ3RN1p/Ui6CPULlTto= - -domelementtype@1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domelementtype@^2.0.1, domelementtype@^2.2.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" - integrity sha1-mgtsJ4LtahxzI9QiZxg9+b2LHVc= - -domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: - version "4.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" - integrity sha1-FsZYxibPlmln4wb5ZrQx931KViY= - dependencies: - domelementtype "^2.2.0" - -domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^2.5.2, domutils@^2.7.0, domutils@^2.8.0: - version "2.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" - integrity sha1-RDfe9dtuLR9dbuhZvZXKfQIEgTU= - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - -dot-case@^3.0.4: - version "3.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" - integrity sha1-mytnDQCkMWZ6inW6Kc0bmICc51E= - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - -dot-prop@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -dot@^1.1.3: - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dot/-/dot-1.1.3.tgz#351360e00a748bce9a1f8f27c00c394a7e4e1e9f" - integrity sha1-NRNg4Ap0i86aH48nwAw5Sn5OHp8= - -dotenv-expand@^5.1.0: - version "5.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" - integrity sha1-P7rwIL/XlIhAcuomsel5HUWmKfA= - -dotenv@^8.0.0: - version "8.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha1-Bhr2ZNGff02PxuT/m1hM4jety4s= - -downshift@^6.0.15: - version "6.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/downshift/-/downshift-6.1.7.tgz#fdb4c4e4f1d11587985cd76e21e8b4b3fa72e44c" - integrity sha1-/bTE5PHRFYeYXNduIei0s/py5Ew= - dependencies: - "@babel/runtime" "^7.14.8" - compute-scroll-into-view "^1.0.17" - prop-types "^15.7.2" - react-is "^17.0.2" - tslib "^2.3.0" - -duplexer2@~0.1.4: - version "0.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= - dependencies: - readable-stream "^2.0.2" - -duplexer@^0.1.1, duplexer@^0.1.2, duplexer@~0.1.1: - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha1-Or5DrvODX4rgd9E23c4PJ2sEAOY= - -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk= - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -electron-to-chromium@^1.3.564, electron-to-chromium@^1.4.17: - version "1.4.29" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/electron-to-chromium/-/electron-to-chromium-1.4.29.tgz#a9b85ab888d0122124c9647c04d8dd246fae94b6" - integrity sha1-qbhauIjQEiEkyWR8BNjdJG+ulLY= - -electron-to-chromium@^1.4.251: - version "1.4.284" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" - integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== - -element-resize-detector@^1.2.2: - version "1.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/element-resize-detector/-/element-resize-detector-1.2.4.tgz#3e6c5982dd77508b5fa7e6d5c02170e26325c9b1" - integrity sha1-PmxZgt13UItfp+bVwCFw4mMlybE= - dependencies: - batch-processor "1.0.0" - -elliptic@^6.5.3: - version "6.5.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha1-2jfOvTHnmhNn6UG1ku0fvr1Yq7s= - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY= - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc= - -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha1-VXBmIEatKeLpFucariYKvf9Pang= - -emotion-theming@^10.0.27: - version "10.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/emotion-theming/-/emotion-theming-10.3.0.tgz#7f84d7099581d7ffe808aab5cd870e30843db72a" - integrity sha1-f4TXCZWB1//oCKq1zYcOMIQ9tyo= - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/weak-memoize" "0.2.5" - hoist-non-react-statics "^3.3.0" - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -encoding@^0.1.12: - version "0.1.13" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha1-VldK/deR9UqOmyeFwFgqLSYhD6k= - dependencies: - iconv-lite "^0.6.2" - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha1-WuZKX0UFe682JuwU2gyl5LJDHrA= - dependencies: - once "^1.4.0" - -engine.io-client@~3.5.0: - version "3.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/engine.io-client/-/engine.io-client-3.5.2.tgz#0ef473621294004e9ceebe73cef0af9e36f2f5fa" - integrity sha1-DvRzYhKUAE6c7r5zzvCvnjby9fo= - dependencies: - component-emitter "~1.3.0" - component-inherit "0.0.3" - debug "~3.1.0" - engine.io-parser "~2.2.0" - has-cors "1.1.0" - indexof "0.0.1" - parseqs "0.0.6" - parseuri "0.0.6" - ws "~7.4.2" - xmlhttprequest-ssl "~1.6.2" - yeast "0.1.2" - -engine.io-parser@~2.2.0: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/engine.io-parser/-/engine.io-parser-2.2.1.tgz#57ce5611d9370ee94f99641b589f94c97e4f5da7" - integrity sha1-V85WEdk3DulPmWQbWJ+UyX5PXac= - dependencies: - after "0.8.2" - arraybuffer.slice "~0.0.7" - base64-arraybuffer "0.1.4" - blob "0.0.5" - has-binary2 "~1.0.2" - -engine.io@~3.5.0: - version "3.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/engine.io/-/engine.io-3.5.0.tgz#9d6b985c8a39b1fe87cd91eb014de0552259821b" - integrity sha1-nWuYXIo5sf6HzZHrAU3gVSJZghs= - dependencies: - accepts "~1.3.4" - base64id "2.0.0" - cookie "~0.4.1" - debug "~4.1.0" - engine.io-parser "~2.2.0" - ws "~7.4.2" - -enhanced-resolve@5.7.0: - version "5.7.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz#525c5d856680fbd5052de453ac83e32049958b5c" - integrity sha1-UlxdhWaA+9UFLeRTrIPjIEmVi1w= - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -enhanced-resolve@^4.0.0, enhanced-resolve@^4.3.0, enhanced-resolve@^4.5.0: - version "4.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" - integrity sha1-Lzz9hNvjtIfxjy2y7x4GSlccpew= - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" - -enhanced-resolve@^5.7.0: - version "5.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" - integrity sha1-bVUtRlzOBCP1s9cYUR6lOCansvA= - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha1-Kn/l3WNKHkElqXXsmU/1RW3Dc00= - dependencies: - ansi-colors "^4.1.1" - -ent@~2.2.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" - integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= - -entities@^2.0.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha1-CY3JDruD2N/6CJ1VJWs1HTTE2lU= - -env-paths@^2.2.0: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" - integrity sha1-QgOZ1BbOH76bwKB8Yvpo1n/Q+PI= - -err-code@^1.0.0: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" - integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= - -err-code@^2.0.2: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" - integrity sha1-I8Lzt1b/38YI0w4nyalBAkgH5/k= - -errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: - version "0.1.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" - integrity sha1-i7Ppx9Rjvkl2/4iPdrSAnrwugR8= - dependencies: - prr "~1.0.1" - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha1-tKxAZIEH/c3PriQvQovqihTU8b8= - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.17.2, es-abstract@^1.20.4: - version "1.21.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" - integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.4" - is-array-buffer "^3.0.1" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.10" - is-weakref "^1.0.2" - object-inspect "^1.12.2" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" - -es-abstract@^1.19.0, es-abstract@^1.19.1: - version "1.19.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha1-1IhXlodpFpWd547aoN9FZicRXsM= - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.1" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha1-hz8+hEGN5O4Zxb51KZCy5EcY0J4= - -es-get-iterator@^1.0.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" - integrity sha1-kjTFSrpxNIbX694CIIZK9eKyg/c= - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.0" - has-symbols "^1.0.1" - is-arguments "^1.1.0" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.5" - isarray "^2.0.5" - -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha1-5VzUyc3BiLzvsDs2bHNjI/xciYo= - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@~0.10.14: - version "0.10.53" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" - integrity sha1-k8WjrP2+8nUiCtcmRK0C7hg2jeE= - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.3" - next-tick "~1.0.0" - -es5-shim@^4.5.13: - version "4.6.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es5-shim/-/es5-shim-4.6.4.tgz#10ce5f06c7bccfdd60b4e08edf95c7e2fbc1dc2a" - integrity sha1-EM5fBse8z91gtOCO35XH4vvB3Co= - -es6-iterator@~2.0.1, es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-map@^0.1.5: - version "0.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - integrity sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA= - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha1-TrIVlMlyvEBVPSduUQU5FD21Pgo= - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - -es6-set@^0.1.5, es6-set@~0.1.5: - version "0.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - integrity sha1-0rPsXU2ADO2BjbU40ol02wpzzLE= - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-shim@^0.35.5: - version "0.35.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es6-shim/-/es6-shim-0.35.6.tgz#d10578301a83af2de58b9eadb7c2c9945f7388a0" - integrity sha1-0QV4MBqDry3li56tt8LJlF9ziKA= - -es6-symbol@3.1.1: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc= - dependencies: - d "1" - es5-ext "~0.10.14" - -es6-symbol@^3.1.1, es6-symbol@~3.1.1, es6-symbol@~3.1.3: - version "3.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha1-utXTwbzawoJp9MszHkMceKxwXRg= - dependencies: - d "^1.0.1" - ext "^1.1.2" - -escalade@^3.0.2, escalade@^3.1.1: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA= - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha1-owME6Z2qMuI7L9IPUbq9B8/8o0Q= - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ= - -escodegen@^1.11.1: - version "1.14.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha1-TnuB+6YVgdyXWC7XjKt/Do1j9QM= - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -escodegen@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" - integrity sha1-XjKxKDPoqo+jXhvwvvqJOASEx90= - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -escodegen@~1.2.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/escodegen/-/escodegen-1.2.0.tgz#09de7967791cc958b7f89a2ddb6d23451af327e1" - integrity sha1-Cd55Z3kcyVi3+Jot220jRRrzJ+E= - dependencies: - esprima "~1.0.4" - estraverse "~1.5.0" - esutils "~1.0.0" - optionalDependencies: - source-map "~0.1.30" - -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha1-ygODMxD2iJoyZHgaqC5j65z+eEg= - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha1-54blmmbLkrP2wfsNUIqrF0hI9Iw= - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha1-0t5eA0JOcH3BDHQGjd7a5wh0Gyc= - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha1-MOvR73wv3/AcOk8VEESvJfqwUj4= - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha1-9lMoJZMFknOSyTjtROsKXJsr0wM= - -eslint@^7.2.0: - version "7.32.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha1-xtMooUvj+wjI0dIeEsAv23oqgS0= - dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.9" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha1-8t8zC3Usb1UBn4vYm3ZgA5wbu7Y= - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha1-E7BM2z5sXRnfkatph6hpVhmwqnE= - -esprima@~1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad" - integrity sha1-n1V+CPw7TSbs6d00+Pv0drYlha0= - -esquery@^1.4.0: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha1-IUj/w4uC6McFff7UhCWz5h8PJKU= - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.1.0, esrecurse@^4.3.0: - version "4.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha1-eteWTWeauyi+5yzsY3WLHF0smSE= - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1, estraverse@^4.2.0: - version "4.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0= - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha1-LupSkHAvJquP5TcDcP+GyWXSESM= - -estraverse@~1.5.0: - version "1.5.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/estraverse/-/estraverse-1.5.1.tgz#867a3e8e58a9f84618afb6c2ddbcd916b7cbaf71" - integrity sha1-hno+jlip+EYYr7bC3bzZFrfLr3E= - -estree-is-function@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/estree-is-function/-/estree-is-function-1.0.0.tgz#c0adc29806d7f18a74db7df0f3b2666702e37ad2" - integrity sha1-wK3CmAbX8Yp0233w87JmZwLjetI= - -estree-walker@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" - integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== - -estree-walker@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q= - -esutils@~1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/esutils/-/esutils-1.0.0.tgz#8151d358e20c8acc7fb745e7472c0025fe496570" - integrity sha1-gVHTWOIMisx/t0XnRywAJf5JZXA= - -etag@~1.8.1: - version "1.8.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= - dependencies: - d "1" - es5-ext "~0.10.14" - -event-stream@4.0.1: - version "4.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/event-stream/-/event-stream-4.0.1.tgz#4092808ec995d0dd75ea4580c1df6a74db2cde65" - integrity sha1-QJKAjsmV0N116kWAwd9qdNss3mU= - dependencies: - duplexer "^0.1.1" - from "^0.1.7" - map-stream "0.0.7" - pause-stream "^0.0.11" - split "^1.0.1" - stream-combiner "^0.2.2" - through "^2.3.8" - -eventemitter3@^4.0.0: - version "4.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha1-Lem2j2Uo1WRO9cWVJqG0oHMGFp8= - -events@^3.0.0: - version "3.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha1-Mala0Kkk4tLEGagTrrLE6HjqdAA= - -eventsource@^1.0.7: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" - integrity sha1-AOjKfJIQnpSw3fMtrGd9hBAoz68= - dependencies: - original "^1.0.0" - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI= - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -exec-sh@^0.3.2: - version "0.3.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" - integrity sha1-/yZPnjJVGaYMteJzaSlDSDzKY7w= - -execa@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg= - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^4.0.2: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha1-TlSRrRVy8vF6d9OIxshXE1sihHo= - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - -exit@^0.1.2: - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -express@^4.17.1: - version "4.17.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/express/-/express-4.17.2.tgz#c18369f265297319beed4e5558753cc8c1364cb3" - integrity sha1-wYNp8mUpcxm+7U5VWHU8yME2TLM= - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.1" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.4.1" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.9.6" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.17.2" - serve-static "1.14.2" - setprototypeof "1.2.0" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext@^1.1.2: - version "1.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" - integrity sha1-OHHVBkHodMwXLitT+RmELRnbTFI= - dependencies: - type "^2.5.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@^3.0.0, extend@~3.0.2: - version "3.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo= - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha1-ywP3QL764D6k0oPK7SdBqD8zVJU= - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM= - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha1-jRcsBkhn8jXAyEpZaAbSeb9LzAc= - -fancy-log@^1.3.3: - version "1.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" - integrity sha1-28GRVPVYaQFQojlToK29A1vkX8c= - dependencies: - ansi-gray "^0.1.1" - color-support "^1.1.3" - parse-node-version "^1.0.0" - time-stamp "^1.0.0" - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU= - -fast-glob@^2.2.6: - version "2.2.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha1-aVOFfDr6R1//ku5gFdUtpwpM050= - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - -fast-glob@^3.1.1, fast-glob@^3.2.4, fast-glob@^3.2.7: - version "3.2.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha1-/Wy3otfpqnp4RhEehaGW1rL3ZqE= - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@2.1.0, fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM= - -fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fastparse@^1.1.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha1-kXKMWllC7O2FMSg8eUQe5BIsNak= - -fastq@^1.6.0: - version "1.13.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha1-YWdg+Ip1Jr38WWt8q4wYk4w2uYw= - dependencies: - reusify "^1.0.4" - -fault@^1.0.0: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" - integrity sha1-6vz8Cm0hT8lGAeFw3ymVSk+ELxM= - dependencies: - format "^0.2.0" - -faye-websocket@0.11.x, faye-websocket@^0.11.3: - version "0.11.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" - integrity sha1-fw2Sdc/dhqHJY9yLZfzEUe3Lsdo= - dependencies: - websocket-driver ">=0.5.1" - -fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha1-/IT7OdJwnPP/bXQ3BhV7tXCKioU= - dependencies: - bser "2.1.1" - -figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha1-tO7oFIq7Adzx0aw0Nn1Z4S+mHW4= - -figures@^3.0.0: - version "3.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha1-YlwYvSk8YE3EqN2y/r8MiDQXRq8= - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha1-IRst2WWcsDlLBz5zI6w8kz1SICc= - dependencies: - flat-cache "^3.0.4" - -file-loader@6.2.0, file-loader@^6.2.0: - version "6.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" - integrity sha1-uu98+OGEDfMl5DkLRISHlIDuvk0= - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -file-system-cache@^1.0.5: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/file-system-cache/-/file-system-cache-1.0.5.tgz#84259b36a2bbb8d3d6eb1021d3132ffe64cfff4f" - integrity sha1-hCWbNqK7uNPW6xAh0xMv/mTP/08= - dependencies: - bluebird "^3.3.5" - fs-extra "^0.30.0" - ramda "^0.21.0" - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90= - -filesize@6.1.0: - version "6.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00" - integrity sha1-6Bvap4DiRR1xTXHA16TzI403rQA= - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha1-GRmmp8df44ssfHflGYU12prN2kA= - dependencies: - to-regex-range "^5.0.1" - -finalhandler@1.1.2, finalhandler@~1.1.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0= - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-cache-dir@3.3.1: - version "3.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" - integrity sha1-ibM/rUpGcNqpT4Vff74x1thP6IA= - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha1-jQ+UzRP+Q8bHwmGg2GEVypGMBfc= - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-cache-dir@^3.3.1: - version "3.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" - integrity sha1-swxbbv8HMHMa6pu9nb7L2AJW1ks= - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-parent-dir@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.1.tgz#c5c385b96858c3351f95d446cab866cbf9f11125" - integrity sha512-o4UcykWV/XN9wm+jMEtWLPlV8RXCZnMhQI6F6OdHeSez7iiJWePw8ijOlskJZMsaQoGR/b7dH6lO02HhaTN7+A== - -find-root@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha1-q8/Iunb3CMQql7PWhbfpRQv7nOQ= - -find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk= - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha1-SRafHXmTQwZG2mHsxa41XCHJe3M= - dependencies: - locate-path "^3.0.0" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha1-TJKBnstwg1YeT0okCoa+UZj1Nvw= - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -findit2@^2.2.3: - version "2.2.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/findit2/-/findit2-2.2.3.tgz#58a466697df8a6205cdfdbf395536b8bd777a5f6" - integrity sha1-WKRmaX34piBc39vzlVNri9d3pfY= - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha1-YbAzgwKy/p+Vfcwy/CqH8cMEixE= - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^2.0.1: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha1-RXWyHivO50NKqb5mL0t7X5wrUTg= - -flatted@^3.1.0: - version "3.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" - integrity sha1-KNmWnqkGYbUTQlnzEqtqp5KaxeI= - -flush-write-stream@^1.0.0: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha1-jdfYc6G6vCB9lOrQwuDkQnbr8ug= - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - -follow-redirects@^1.0.0: - version "1.14.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/follow-redirects/-/follow-redirects-1.14.6.tgz#8cfb281bbc035b3c067d6cd975b0f6ade6e855cd" - integrity sha1-jPsoG7wDWzwGfWzZdbD2reboVc0= - -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -for-in@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -fork-ts-checker-webpack-plugin@4.1.6, fork-ts-checker-webpack-plugin@^4.1.6: - version "4.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz#5055c703febcf37fa06405d400c122b905167fc5" - integrity sha1-UFXHA/6883+gZAXUAMEiuQUWf8U= - dependencies: - "@babel/code-frame" "^7.5.5" - chalk "^2.4.1" - micromatch "^3.1.10" - minimatch "^3.0.4" - semver "^5.6.0" - tapable "^1.0.0" - worker-rpc "^0.1.0" - -fork-ts-checker-webpack-plugin@^6.0.4: - version "6.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz#0282b335fa495a97e167f69018f566ea7d2a2b5e" - integrity sha1-AoKzNfpJWpfhZ/aQGPVm6n0qK14= - dependencies: - "@babel/code-frame" "^7.8.3" - "@types/json-schema" "^7.0.5" - chalk "^4.1.0" - chokidar "^3.4.2" - cosmiconfig "^6.0.0" - deepmerge "^4.2.2" - fs-extra "^9.0.0" - glob "^7.1.6" - memfs "^3.1.2" - minimatch "^3.0.4" - schema-utils "2.7.0" - semver "^7.3.2" - tapable "^1.0.0" - -form-data@^3.0.0: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha1-69U3kbeDVqma+aMA1CgsTV65dV8= - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha1-3M5SwF9kTymManq5Nr1yTO/786Y= - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -format@^0.2.0: - version "0.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" - integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs= - -forwarded@0.2.0: - version "0.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha1-ImmTZCiq1MFcfr6XeahL8LKoGBE= - -fraction.js@^4.0.13: - version "4.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fraction.js/-/fraction.js-4.1.2.tgz#13e420a92422b6cf244dff8690ed89401029fbe8" - integrity sha1-E+QgqSQits8kTf+GkO2JQBAp++g= - -fraction.js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" - integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -from2@^2.1.0: - version "2.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -from@^0.1.7: - version "0.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" - integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= - -fs-extra@4.0.2: - version "4.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" - integrity sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^0.30.0: - version "0.30.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - integrity sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - -fs-extra@^10.0.0: - version "10.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" - integrity sha1-n/YbZV3eU/s0qC34S7IUzoAuF8E= - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha1-SdQ8RaiM2Wd2aMt74bRu/bjS4cA= - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^9.0.0, fs-extra@^9.0.1: - version "9.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha1-WVRGDHZKjaIJS6NVS/g55rmnyG0= - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-minipass@^2.0.0, fs-minipass@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha1-f1A2/b8SxjwWkZDL5BmchSJx+fs= - dependencies: - minipass "^3.0.0" - -fs-monkey@1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" - integrity sha1-rjrJLVO7Mo7+DpodlUH2rY1I4tM= - -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^1.2.7: - version "1.2.13" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha1-8yXLBFVZJCi88Rs4M3DvcOO/zDg= - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - -fsevents@^2.1.2, fsevents@~2.3.1, fsevents@~2.3.2: - version "2.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro= - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0= - -function.prototype.name@^1.1.0, function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha1-zOBQX+H/uAUD5vnkbMZORqEqliE= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -functions-have-names@^1.2.2: - version "1.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/functions-have-names/-/functions-have-names-1.2.2.tgz#98d93991c39da9361f8e50b337c4f6e41f120e21" - integrity sha1-mNk5kcOdqTYfjlCzN8T25B8SDiE= - -fuse.js@^3.6.1: - version "3.6.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/fuse.js/-/fuse.js-3.6.1.tgz#7de85fdd6e1b3377c23ce010892656385fd9b10c" - integrity sha1-fehf3W4bM3fCPOAQiSZWOF/ZsQw= - -gauge@^3.0.0: - version "3.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" - integrity sha1-A79EQcBEODkIvPoGVq2RgDJZs5U= - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.2" - console-control-strings "^1.0.0" - has-unicode "^2.0.1" - object-assign "^4.1.1" - signal-exit "^3.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.2" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha1-MqbudsPX9S1GsrGuXZP+qFgKJeA= - -get-assigned-identifiers@^1.1.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" - integrity sha1-bb9BHeZIy6+NkWnrsNLVdhkeL/E= - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha1-T5RBKoLbMvNuOwuXQfipf+sDH34= - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha1-FfWfN2+FXERpY5SPDSTNNje0q8Y= - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-intrinsic@^1.1.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha1-jeLYA8/0TfO8bEVuZmizbDkm4Ro= - -get-port@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" - integrity sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg== - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha1-wbJVV189wh1Zv8ec09K0axw6VLU= - dependencies: - pump "^3.0.0" - -get-stream@^5.0.0: - version "5.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha1-SWaheV7lrOZecGxLe+txJX1uItM= - dependencies: - pump "^3.0.0" - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha1-f9uByQAQH71WTdXxowr1qtweWNY= - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getpass@^0.1.1: - version "0.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -github-slugger@^1.0.0: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/github-slugger/-/github-slugger-1.4.0.tgz#206eb96cdb22ee56fdc53a28d5a302338463444e" - integrity sha1-IG65bNsi7lb9xToo1aMCM4RjRE4= - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ= - dependencies: - is-glob "^4.0.1" - -glob-promise@^3.4.0: - version "3.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/glob-promise/-/glob-promise-3.4.0.tgz#b6b8f084504216f702dc2ce8c9bc9ac8866fdb20" - integrity sha1-trjwhFBCFvcC3CzoybyayIZv2yA= - dependencies: - "@types/glob" "*" - -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha1-x1KXCHyFG5pXi9IX3VmpL1n+VG4= - -glob@7.1.6: - version "7.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY= - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: - version "7.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha1-0VU1r3cy4C6Uj0xBYovZECk/YCM= - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-modules@2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - integrity sha1-mXYFrSNF8n9RU5vqJldEISFcd4A= - dependencies: - global-prefix "^3.0.0" - -global-prefix@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" - integrity sha1-/IX3MGTfafUEIfR/iD/luRO6m5c= - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - -global@^4.4.0: - version "4.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha1-PnsQUXkAajI+1xqvyj6cV6XMZAY= - dependencies: - min-document "^2.19.0" - process "^0.11.10" - -globals@^11.1.0: - version "11.12.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4= - -globals@^13.6.0, globals@^13.9.0: - version "13.12.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" - integrity sha1-TXM3YDBCMKAILtluIeXFZfiYCJ4= - dependencies: - type-fest "^0.20.2" - -globalthis@^1.0.0: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/globalthis/-/globalthis-1.0.2.tgz#2a235d34f4d8036219f7e34929b5de9e18166b8b" - integrity sha1-KiNdNPTYA2IZ9+NJKbXenhgWa4s= - dependencies: - define-properties "^1.1.3" - -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - -globby@11.0.1: - version "11.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" - integrity sha1-mivxB6Bo8//qvEmtcCx57ejP01c= - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -globby@^11.0.1, globby@^11.0.2: - version "11.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha1-LLr/d8Lypi5x6bKBOme5ejowAaU= - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -globby@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -globby@^6.1.0: - version "6.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -globby@^9.2.0: - version "9.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" - integrity sha1-/QKacGxwPSm90XD0tts6P3p8tj0= - dependencies: - "@types/glob" "^7.1.1" - array-union "^1.0.2" - dir-glob "^2.2.2" - fast-glob "^2.2.6" - glob "^7.1.3" - ignore "^4.0.3" - pify "^4.0.1" - slash "^2.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" - -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.3, graceful-fs@^4.2.4: - version "4.2.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha1-5BK40z9eAGWTy9PO5t+fLOu+gCo= - -gzip-size@5.1.1: - version "5.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" - integrity sha1-y5vuaS+HwGErIyhAqHOQTkwTUnQ= - dependencies: - duplexer "^0.1.1" - pify "^4.0.1" - -gzip-size@^6.0.0: - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" - integrity sha1-BlNn/VDCOcBnHLy61b4+LusQ5GI= - dependencies: - duplexer "^0.1.2" - -handle-thing@^2.0.0: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" - integrity sha1-hX95zjWVgMNA1DCBzGSJcNC7I04= - -handlebars@^4.7.7: - version "4.7.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha1-nOM0FqrQLb1sj6+oJA1dmABJRaE= - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha1-HwgDufjLIMD6E4It8ezds2veHv0= - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha1-ZP5qywIGc+O3jbA1pa9pqp0HsRM= - -has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-binary2@~1.0.2: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" - integrity sha1-d3asYn8+p3JQz8My2rfd9eT10R0= - dependencies: - isarray "2.0.1" - -has-cors@1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" - integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s= - -has-glob@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-glob/-/has-glob-1.0.0.tgz#9aaa9eedbffb1ba3990a7b0010fb678ee0081207" - integrity sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc= - dependencies: - is-glob "^3.0.0" - -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -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://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha1-Fl0wcMADCXUqEjakeTMeOsVvFCM= - -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha1-fhM4GKfTlHNPlB5zw9P5KR5liyU= - dependencies: - has-symbols "^1.0.2" - -has-unicode@^2.0.0, has-unicode@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - -has-value@^0.3.1: - version "0.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.0, has@^1.0.1, has@^1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y= - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha1-VcOB2eBuHSmXqIO0o/3f5/DTrzM= - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha1-C6vKU46NTuSg+JiNaIZlN6ADz0I= - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hast-to-hyperscript@^9.0.0: - version "9.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d" - integrity sha1-m2f9GI5MgeitZvgDhVM0FzkgIY0= - dependencies: - "@types/unist" "^2.0.3" - comma-separated-tokens "^1.0.0" - property-information "^5.3.0" - space-separated-tokens "^1.0.0" - style-to-object "^0.3.0" - unist-util-is "^4.0.0" - web-namespaces "^1.0.0" - -hast-util-from-parse5@^6.0.0: - version "6.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz#554e34abdeea25ac76f5bd950a1f0180e0b3bc2a" - integrity sha1-VU40q97qJax29b2VCh8BgOCzvCo= - dependencies: - "@types/parse5" "^5.0.0" - hastscript "^6.0.0" - property-information "^5.0.0" - vfile "^4.0.0" - vfile-location "^3.2.0" - web-namespaces "^1.0.0" - -hast-util-parse-selector@^2.0.0: - version "2.2.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" - integrity sha1-1Xwj9NoWrjxjs7bKRhZoMxNJnDo= - -hast-util-raw@6.0.1: - version "6.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hast-util-raw/-/hast-util-raw-6.0.1.tgz#973b15930b7529a7b66984c98148b46526885977" - integrity sha1-lzsVkwt1Kae2aYTJgUi0ZSaIWXc= - dependencies: - "@types/hast" "^2.0.0" - hast-util-from-parse5 "^6.0.0" - hast-util-to-parse5 "^6.0.0" - html-void-elements "^1.0.0" - parse5 "^6.0.0" - unist-util-position "^3.0.0" - vfile "^4.0.0" - web-namespaces "^1.0.0" - xtend "^4.0.0" - zwitch "^1.0.0" - -hast-util-to-parse5@^6.0.0: - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz#1ec44650b631d72952066cea9b1445df699f8479" - integrity sha1-HsRGULYx1ylSBmzqmxRF32mfhHk= - dependencies: - hast-to-hyperscript "^9.0.0" - property-information "^5.0.0" - web-namespaces "^1.0.0" - xtend "^4.0.0" - zwitch "^1.0.0" - -hastscript@^6.0.0: - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" - integrity sha1-6HaNfqxWw/3qyKkoMNWOgR5b9kA= - dependencies: - "@types/hast" "^2.0.0" - comma-separated-tokens "^1.0.0" - hast-util-parse-selector "^2.0.0" - property-information "^5.0.0" - space-separated-tokens "^1.0.0" - -he@^1.2.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha1-hK5l+n6vsWX922FWauFLrwVmTw8= - -hex-color-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" - integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== - -highlight.js@^10.1.1, highlight.js@~10.7.0: - version "10.7.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha1-aXJy45kTVuQMPKxWanTu9oF1ZTE= - -history@5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/history/-/history-5.0.0.tgz#0cabbb6c4bbf835addb874f8259f6d25101efd08" - integrity sha1-DKu7bEu/g1rduHT4JZ9tJRAe/Qg= - dependencies: - "@babel/runtime" "^7.7.6" - -history@^5.2.0: - version "5.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/history/-/history-5.2.0.tgz#7cdd31cf9bac3c5d31f09c231c9928fad0007b7c" - integrity sha1-fN0xz5usPF0x8JwjHJko+tAAe3w= - dependencies: - "@babel/runtime" "^7.7.6" - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hoist-non-react-statics@^3.3.0: - version "3.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha1-7OCsr3HWLClpwuxZ/v9CpLGoW0U= - dependencies: - react-is "^16.7.0" - -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha1-3/wL+aIcAiCQkPKqaUKeFBTa8/k= - -hosted-git-info@^3.0.6: - version "3.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hosted-git-info/-/hosted-git-info-3.0.8.tgz#6e35d4cc87af2c5f816e4cb9ce350ba87a3f370d" - integrity sha1-bjXUzIevLF+Bbky5zjULqHo/Nw0= - dependencies: - lru-cache "^6.0.0" - -hosted-git-info@^4.0.1: - version "4.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" - integrity sha1-XkJVB+7eT+qEa3Ji8IOEVsQgmWE= - dependencies: - lru-cache "^6.0.0" - -hpack.js@^2.1.6: - version "2.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" - integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= - dependencies: - inherits "^2.0.1" - obuf "^1.0.0" - readable-stream "^2.0.1" - wbuf "^1.1.0" - -hsl-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" - integrity sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A== - -hsla-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" - integrity sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA== - -html-entities@^1.3.1: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" - integrity sha1-z70bAdKvr5rcobEK59/6uYxx0tw= - -html-entities@^2.1.0, html-entities@^2.3.2: - version "2.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/html-entities/-/html-entities-2.3.2.tgz#760b404685cb1d794e4f4b744332e3b00dcfe488" - integrity sha1-dgtARoXLHXlOT0t0QzLjsA3P5Ig= - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha1-39YAJ9o2o238viNiYsAKWCJoFFM= - -html-minifier-terser@^5.0.1: - version "5.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054" - integrity sha1-ki6W8fO7YIMsJjS3mIQJY4mx8FQ= - dependencies: - camel-case "^4.1.1" - clean-css "^4.2.3" - commander "^4.1.1" - he "^1.2.0" - param-case "^3.0.3" - relateurl "^0.2.7" - terser "^4.6.3" - -html-tags@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" - integrity sha1-e15vfmZen7QfMAB+2eDUHpf7IUA= - -html-void-elements@^1.0.0: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483" - integrity sha1-zpFZSU6G2V5FeVsWbCAhws/KRIM= - -html-webpack-plugin@^4.0.0: - version "4.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz#76fc83fa1a0f12dd5f7da0404a54e2699666bc12" - integrity sha1-dvyD+hoPEt1ffaBASlTiaZZmvBI= - dependencies: - "@types/html-minifier-terser" "^5.0.0" - "@types/tapable" "^1.0.5" - "@types/webpack" "^4.41.8" - html-minifier-terser "^5.0.1" - loader-utils "^1.2.3" - lodash "^4.17.20" - pretty-error "^2.1.1" - tapable "^1.1.3" - util.promisify "1.0.0" - -htmlparser2@^6.1.0: - version "6.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" - integrity sha1-xNditsM3GgXb5l6UrkOp+EX7j7c= - dependencies: - domelementtype "^2.0.1" - domhandler "^4.0.0" - domutils "^2.5.2" - entities "^2.0.0" - -http-auth-connect@^1.0.5: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-auth-connect/-/http-auth-connect-1.0.5.tgz#7796d361f9ac56d80ada8ff54c61aa857768335f" - integrity sha1-d5bTYfmsVtgK2o/1TGGqhXdoM18= - -http-auth@4.1.7: - version "4.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-auth/-/http-auth-4.1.7.tgz#0b8119c83813bd7ac4a934c04a2f8c568b2107ee" - integrity sha1-C4EZyDgTvXrEqTTASi+MVoshB+4= - dependencies: - apache-crypt "^1.1.2" - apache-md5 "^1.0.6" - bcryptjs "^2.4.3" - uuid "^3.4.0" - -http-cache-semantics@^4.1.0: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha1-SekcXL82yblLz81xwj1SSex045A= - -http-deceiver@^1.2.7: - version "1.2.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" - integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= - -http-errors@1.8.1: - version "1.8.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" - integrity sha1-fD8oV3y8iiBziEVdvWIpXtB71ow= - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.1" - -http-errors@~1.6.2: - version "1.6.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -http-parser-js@>=0.5.1: - version "0.5.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-parser-js/-/http-parser-js-0.5.5.tgz#d7c30d5d3c90d865b4a2e870181f9d6f22ac7ac5" - integrity sha1-18MNXTyQ2GW0ouhwGB+dbyKsesU= - -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha1-ioyO9/WTLM+VPClsqCkblap0qjo= - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -http-proxy-middleware@0.19.1: - version "0.19.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" - integrity sha1-GDx9xKoUeRUDBkmMIQza+WCApDo= - dependencies: - http-proxy "^1.17.0" - is-glob "^4.0.0" - lodash "^4.17.11" - micromatch "^3.1.10" - -http-proxy@^1.17.0, http-proxy@^1.18.1: - version "1.18.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" - integrity sha1-QBVB8FNIhLv5UmAzTnL4juOXZUk= - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - -https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha1-4qkFQqu2inYuCghQ9sntrf2FBrI= - dependencies: - agent-base "6" - debug "4" - -https-proxy-agent@^2.2.1: - version "2.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" - integrity sha1-TuenN6vZJniik9mzShr00NCMeHs= - dependencies: - agent-base "^4.3.0" - debug "^3.1.0" - -human-signals@^1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha1-xbHNFPUK6uCatsWf5jujOV/k36M= - -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= - dependencies: - ms "^2.0.0" - -i18next@^21.5.2: - version "21.6.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/i18next/-/i18next-21.6.4.tgz#4da52a429094112b33d4383b5f44aa4890dcb081" - integrity sha1-TaUqQpCUESsz1Dg7X0SqSJDcsIE= - dependencies: - "@babel/runtime" "^7.12.0" - -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: - version "0.4.24" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha1-ICK0sl+93CHS9SSXSkdKr+czkIs= - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@^0.6.2, iconv-lite@^0.6.3: - version "0.6.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE= - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -icss-utils@^4.0.0, icss-utils@^4.1.1: - version "4.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" - integrity sha1-IRcLU3ie4nRHwvR91oMIFAP5pGc= - dependencies: - postcss "^7.0.14" - -icss-utils@^5.0.0, icss-utils@^5.1.0: - version "5.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" - integrity sha1-xr5oWKvQE9do6YNmrkfiXViHsa4= - -ieee754@^1.1.13, ieee754@^1.1.4: - version "1.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha1-jrehCmP/8l0VpXsAFYbRd9Gw01I= - -iferr@^0.1.5: - version "0.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - -ignore-walk@^3.0.3: - version "3.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" - integrity sha1-yaCfabfHtHml10rBo8DUI20qYzU= - dependencies: - minimatch "^3.0.4" - -ignore@^4.0.3, ignore@^4.0.6: - version "4.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw= - -ignore@^5.1.4: - version "5.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha1-bTusj6f+DUXZ+b57rC/CeVd+NFo= - -image-size@~0.5.0: - version "0.5.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" - integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= - -immediate@~3.0.5: - version "3.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= - -immer@8.0.1: - version "8.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" - integrity sha1-nHPbaD4rOXXEJPsFcq9YiYd65lY= - -immutable@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" - integrity sha1-uG943mre82CDle+yaakUYnl+LCM= - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg== - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha1-NxYsJfy566oublPVtNiM4X2eDCs= - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-local@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha1-VQcL44pZk88Y72236WH1vuXFoJ0= - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE= - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA== - -indexof@0.0.1: - version "0.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= - -infer-owner@^1.0.3, infer-owner@^1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha1-xM78qo5RBRwqQLos6KPScpWvlGc= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - 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.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w= - -inherits@2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - -inherits@2.0.3: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -ini@2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" - integrity sha1-5f1Vbs3VcmvpePoQAYYurLCpS8U= - -ini@^1.3.4, ini@^1.3.5: - version "1.3.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha1-op2kJbSIBvNHZ6Tvzjlyaa8oQyw= - -injection-js@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/injection-js/-/injection-js-2.4.0.tgz#ebe8871b1a349f23294eaa751bbd8209a636e754" - integrity sha512-6jiJt0tCAo9zjHbcwLiPL+IuNe9SQ6a9g0PEzafThW3fOQi0mrmiJGBJvDD6tmhPh8cQHIQtCOrJuBfQME4kPA== - dependencies: - tslib "^2.0.0" - -inline-style-parser@0.1.1: - version "0.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" - integrity sha1-7Io7QpJ06cCh8cT/qUU6f+9yzqE= - -inquirer@7.3.3: - version "7.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha1-BNF2sq8Er8FXqD/XwQDpjuCq0AM= - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -inside@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/inside/-/inside-1.0.0.tgz#db45e993573cdb3db70b9832e8285bad46424770" - integrity sha1-20Xpk1c82z23C5gy6ChbrUZCR3A= - -internal-ip@^4.3.0: - version "4.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" - integrity sha1-hFRSuq2dLKO2nGNaE3rLmg2tCQc= - dependencies: - default-gateway "^4.2.0" - ipaddr.js "^1.9.0" - -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha1-c0fjB97uovqsKsYgXUvH00ln9Zw= - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - -internal-slot@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3" - integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - side-channel "^1.0.4" - -interpret@^2.2.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" - integrity sha1-GnigtZZcQKVBbQB61vUK0nxBffk= - -invariant@^2.2.4: - version "2.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY= - dependencies: - loose-envify "^1.0.0" - -ip-regex@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= - -ip@^1.1.0, ip@^1.1.5: - version "1.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - -ipaddr.js@1.9.1, ipaddr.js@^1.9.0: - version "1.9.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha1-v/OFQ+64mEglB5/zoqjmy9RngbM= - -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" - integrity sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg== - -is-absolute-url@^3.0.0, is-absolute-url@^3.0.3: - version "3.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" - integrity sha1-lsaiK2ojkpsR6gr7GDbDatSl1pg= - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY= - dependencies: - kind-of "^6.0.0" - -is-alphabetical@1.0.4, is-alphabetical@^1.0.0: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" - integrity sha1-nn1rlJFr4iFTdF0YTCmMv5hqaG0= - -is-alphanumerical@^1.0.0: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" - integrity sha1-frmiQx+FX2se8aeOMm31FWlsTb8= - dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - -is-arguments@^1.0.4, is-arguments@^1.1.0: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha1-FbP4j9oB8ql/7ITKdhpWDxI++ps= - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-array-buffer@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a" - integrity sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-typed-array "^1.1.10" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha1-CBR6GHW8KzIAXUHM2Ckd/8ZpHfM= - dependencies: - has-bigints "^1.0.1" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk= - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha1-XG3CACRt2TIa5LiFoRS7H3X2Nxk= - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha1-76ouqdqg16suoTqXsritUf776L4= - -is-buffer@^2.0.0: - version "2.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha1-68JS5ADSL/jXf6CYiIIaJKZYwZE= - -is-callable@^1.1.3, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha1-RzAdWN0CWUB4ZVR4U99tYf5HGUU= - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha1-a8YzQYGBDgS1wis9WJ/cpVAmQEw= - dependencies: - ci-info "^2.0.0" - -is-color-stop@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" - integrity sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA== - dependencies: - css-color-names "^0.0.4" - hex-color-regex "^1.1.0" - hsl-regex "^1.0.0" - hsla-regex "^1.0.0" - rgb-regex "^1.0.1" - rgba-regex "^1.0.0" - -is-core-module@^2.1.0, is-core-module@^2.2.0: - version "2.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" - integrity sha1-AyEzbD0JJeSX/Zf12VyxFKXM1Ug= - dependencies: - has "^1.0.3" - -is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== - dependencies: - has "^1.0.3" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc= - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha1-CEHVU25yTCVZe/bqYuG9OCmN8x8= - dependencies: - has-tostringtag "^1.0.0" - -is-decimal@^1.0.0: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" - integrity sha1-ZaOllYocW2OnBuGzM9fNn2MNP6U= - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco= - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw= - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw== - -is-docker@^2.0.0, is-docker@^2.1.1: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha1-M+6r4jz+hvFL3kQIoCwM+4U6zao= - -is-dom@^1.0.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-dom/-/is-dom-1.1.0.tgz#af1fced292742443bb59ca3f76ab5e80907b4e8a" - integrity sha1-rx/O0pJ0JEO7Wco/dqtegJB7Too= - dependencies: - is-object "^1.0.1" - is-window "^1.0.2" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ= - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0= - -is-function@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - integrity sha1-Twl/MKv2762smDOxfKXcA/gUTgg= - -is-glob@^3.0.0, is-glob@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha1-ZPYeQsu7LuwgcanawLKLoeZdUIQ= - dependencies: - is-extglob "^2.1.1" - -is-hexadecimal@^1.0.0: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" - integrity sha1-zDXJdYjaS9Saju3WvECC1E3LI6c= - -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha1-zqbmrlyHCnsKAAQHC3tYfgJSkS4= - -is-lambda@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" - integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= - -is-map@^2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha1-AJItuMm/c+gbejNYJ7wqQ/K5ESc= - -is-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" - integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== - -is-negative-zero@^2.0.1, is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha1-e/bwOigAO4s5Zd46wm9mTXZfMVA= - -is-number-object@^1.0.4: - version "1.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha1-anqvg4x/BoalC0VT9+VKlklOifA= - dependencies: - has-tostringtag "^1.0.0" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss= - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-object@^1.0.1: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" - integrity sha1-pWVS4cZlyelQtKAlRh2ofnL4b88= - -is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= - -is-path-cwd@^2.0.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" - integrity sha1-Z9Q7gmZKe1GR/ZEZEn6zAASKn9s= - -is-path-in-cwd@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" - integrity sha1-WsSLNF72dTOb1sekipEhELJBz1I= - dependencies: - is-path-inside "^1.0.0" - -is-path-in-cwd@^2.0.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" - integrity sha1-v+Lcomxp85cmWkAJljYCk1oFOss= - dependencies: - is-path-inside "^2.1.0" - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= - dependencies: - path-is-inside "^1.0.1" - -is-path-inside@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" - integrity sha1-fJgQWH1lmkDSe8201WFuqwWUlLI= - dependencies: - path-is-inside "^1.0.2" - -is-plain-obj@^2.0.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha1-ReQuN/zPH0Dajl927iFRWEDAkoc= - -is-plain-object@5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha1-RCf1CrNCnpAl6n1S6QQ6nvQVk0Q= - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc= - dependencies: - isobject "^3.0.1" - -is-reference@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" - integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== - dependencies: - "@types/estree" "*" - -is-regex@^1.0.4, is-regex@^1.1.2, is-regex@^1.1.4: - version "1.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha1-7vVmPNWfpMCuM5UFMj32hUuxWVg= - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-resolvable@^1.0.0, is-resolvable@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg= - -is-root@2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" - integrity sha1-gJ4YEpzxEpZEMCpPhUQDXVGYSpw= - -is-set@^2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha1-kHVfpMJWLcHF1AJHYNYRm5TKGOw= - -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha1-l7DIX72stZycRG/mU7gs8rW3z+Y= - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha1-+sHj1TuXrVqdCunO8jifWBClwHc= - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha1-DdEr8gBvJVu1j2lREO/3SR7rwP0= - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha1-ptrJO2NbBjymhyI23oiRClevE5w= - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - -is-typedarray@^1.0.0, is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha1-PybHaoCVk7Ur+i7LVxDtJ3m1Iqc= - -is-weakref@^1.0.1, is-weakref@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha1-lSnzg6kzggXol2XgOS78LxAPBvI= - dependencies: - call-bind "^1.0.2" - -is-what@^3.12.0: - version "3.14.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1" - integrity sha1-4SIvRt3ahd6tD9HJ3xMXYOd3VcE= - -is-whitespace-character@^1.0.0: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" - integrity sha1-CFjt2UqVWUx8ndC1wXTsbkXuSqc= - -is-window@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-window/-/is-window-1.0.2.tgz#2c896ca53db97de45d3c33133a65d8c9f563480d" - integrity sha1-LIlspT25feRdPDMTOmXYyfVjSA0= - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0= - -is-word-character@^1.0.0: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" - integrity sha1-zg5zIW+YWZBgWS9i/zE1TdvrAjA= - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - -is-wsl@^2.1.1, is-wsl@^2.2.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha1-dKTHbnfKn9P5MvKQwX6jJs0VcnE= - dependencies: - is-docker "^2.0.0" - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isarray@2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" - integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= - -isarray@^2.0.5: - version "2.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha1-ivHkwSISRMxiRZ+vOJQNTmRKVyM= - -isbinaryfile@^4.0.6: - version "4.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf" - integrity sha1-XTS5SGW9SUZjPsx4oCb8dsWxH88= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -isobject@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" - integrity sha1-PxyRVec7GSAiqAgZus0DQ3EWl7A= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -istanbul-lib-coverage@^2.0.5: - version "2.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" - integrity sha1-Z18KtpUD+tSx2En3NrqsqAM0T0k= - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha1-GJ55CdCjn6Wj361bA/cZR3cBkdM= - -istanbul-lib-instrument@^4.0.3: - version "4.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha1-hzxv/4l0UBGCIndGlqPyiQLXfB0= - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - -istanbul-lib-instrument@^5.0.4: - version "5.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" - integrity sha1-e0kZi2V7J6cwuOnLYB8eG/8kxZo= - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha1-dRj+UupE3jcvRgp2tezan/tz2KY= - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^3.0.6: - version "3.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" - integrity sha1-KEmXxIIRdS7EhiU9qX44ed77qMg= - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - rimraf "^2.6.3" - source-map "^0.6.1" - -istanbul-reports@^3.0.2: - version "3.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/istanbul-reports/-/istanbul-reports-3.1.2.tgz#b80e13cbab0120e1c367ebaa099862361aed5ead" - integrity sha1-uA4Ty6sBIOHDZ+uqCZhiNhrtXq0= - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -iterate-iterator@^1.0.1: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/iterate-iterator/-/iterate-iterator-1.0.2.tgz#551b804c9eaa15b847ea6a7cdc2f5bf1ec150f91" - integrity sha1-VRuATJ6qFbhH6mp83C9b8ewVD5E= - -iterate-value@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/iterate-value/-/iterate-value-1.0.2.tgz#935115bd37d006a52046535ebc8d07e9c9337f57" - integrity sha1-k1EVvTfQBqUgRlNevI0H6ckzf1c= - dependencies: - es-get-iterator "^1.0.2" - iterate-iterator "^1.0.1" - -jasmine-core@^3.6.0: - version "3.10.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jasmine-core/-/jasmine-core-3.10.1.tgz#7aa6fa2b834a522315c651a128d940eca553989a" - integrity sha1-eqb6K4NKUiMVxlGhKNlA7KVTmJo= - -jasmine-core@~2.8.0: - version "2.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" - integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= - -jasmine-core@~3.6.0: - version "3.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jasmine-core/-/jasmine-core-3.6.0.tgz#491f3bb23941799c353ceb7a45b38a950ebc5a20" - integrity sha1-SR87sjlBeZw1POt6RbOKlQ68WiA= - -jasmine-spec-reporter@~5.0.0: - version "5.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jasmine-spec-reporter/-/jasmine-spec-reporter-5.0.2.tgz#b61288ab074ad440dc2477c4d42840b0e74a6b95" - integrity sha1-thKIqwdK1EDcJHfE1ChAsOdKa5U= - dependencies: - colors "1.4.0" - -jasmine@2.8.0: - version "2.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e" - integrity sha1-awicChFXax8W3xG4AUbZHU6Lij4= - dependencies: - exit "^0.1.2" - glob "^7.0.6" - jasmine-core "~2.8.0" - -jasminewd2@^2.1.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" - integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= - -jest-haste-map@^26.6.2: - version "26.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" - integrity sha1-3X5g/n3A6fkRoj15xf9/tcLK/qo= - dependencies: - "@jest/types" "^26.6.2" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^26.0.0" - jest-serializer "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.1.2" - -jest-regex-util@^26.0.0: - version "26.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" - integrity sha1-0l5xhLNuOf1GbDvEG+CXHoIf7ig= - -jest-serializer@^26.6.2: - version "26.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" - integrity sha1-0Tmq/UaVfTpEjzps2r4pGboHQtE= - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" - -jest-util@^26.6.2: - version "26.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" - integrity sha1-kHU12+TVpstMR6ybkm9q8pV2y8E= - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - micromatch "^4.0.2" - -jest-worker@26.6.2, jest-worker@^26.5.0, jest-worker@^26.6.2: - version "26.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha1-f3LLxNZDw2Xie5/XdfnQ6qnHqO0= - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - -js-string-escape@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" - integrity sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8= - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha1-GSA/tZmR35jjoocFDUZHzerzJJk= - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha1-2ugS/bOCX6MGYJqHFzg8UMNqBTc= - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q= - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk= - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha1-fEeAWpQxmSjgV3dAXcEuH3pO4C0= - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha1-afaofZUTq4u4/mO9sJecRI5oRmA= - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha1-rnvLNlard6c7pcSb9lTzjmtoYOI= - -json-schema@0.4.0: - version "0.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha1-995M9u+rg4666zI2R0y7paGTCrU= - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json3@^3.3.3: - version "3.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" - integrity sha1-f8EON1/FrkLEcFpcwKpvYr4wW4E= - -json5@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4= - dependencies: - minimist "^1.2.0" - -json5@^2.1.2, json5@^2.1.3, json5@^2.2.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha1-Lf7+cgxrpSXZ69kJlQ8FFTFsiaM= - dependencies: - minimist "^1.2.5" - -jsonc-parser@3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" - integrity sha1-q914VwHH5+rKip7IzwcMpRp0WiI= - -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha1-vFWyY0eTxnnsZAMJTrE2mKbsCq4= - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonparse@^1.3.1: - version "1.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= - -jsprim@^1.2.2: - version "1.4.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" - integrity sha1-cSxlUzoVyHi6WentXw4m1bd8X+s= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - -jszip@^3.1.3: - version "3.7.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9" - integrity sha1-vWNAEiHBViWhIoxVbKimjab9o9k= - dependencies: - lie "~3.3.0" - pako "~1.0.2" - readable-stream "~2.3.6" - set-immediate-shim "~1.0.1" - -junk@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" - integrity sha1-MUmQmNkCt+mMXZucgPQ0V6iKv6E= - -karma-chrome-launcher@~3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz#805a586799a4d05f4e54f72a204979f3f3066738" - integrity sha1-gFpYZ5mk0F9OVPcqIEl58/MGZzg= - dependencies: - which "^1.2.1" - -karma-cli@~2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/karma-cli/-/karma-cli-2.0.0.tgz#481548d28661af4cc68f3d8e09708f17d2cba931" - integrity sha1-SBVI0oZhr0zGjz2OCXCPF9LLqTE= - dependencies: - resolve "^1.3.3" - -karma-coverage-istanbul-reporter@~3.0.2: - version "3.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz#f3b5303553aadc8e681d40d360dfdc19bc7e9fe9" - integrity sha1-87UwNVOq3I5oHUDTYN/cGbx+n+k= - dependencies: - istanbul-lib-coverage "^3.0.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^3.0.6" - istanbul-reports "^3.0.2" - minimatch "^3.0.4" - -karma-jasmine-html-reporter@^1.5.0: - version "1.7.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz#52c489a74d760934a1089bfa5ea4a8fcb84cc28b" - integrity sha1-UsSJp012CTShCJv6XqSo/LhMwos= - -karma-jasmine@~4.0.0: - version "4.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/karma-jasmine/-/karma-jasmine-4.0.1.tgz#b99e073b6d99a5196fc4bffc121b89313b0abd82" - integrity sha1-uZ4HO22ZpRlvxL/8EhuJMTsKvYI= - dependencies: - jasmine-core "^3.6.0" - -karma-source-map-support@1.4.0: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz#58526ceccf7e8730e56effd97a4de8d712ac0d6b" - integrity sha1-WFJs7M9+hzDlbv/Zek3o1xKsDWs= - dependencies: - source-map-support "^0.5.5" - -karma@~5.2.1: - version "5.2.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/karma/-/karma-5.2.3.tgz#3264024219bad2728e92542e0058a2492d7a46e4" - integrity sha1-MmQCQhm60nKOklQuAFiiSS16RuQ= - dependencies: - body-parser "^1.19.0" - braces "^3.0.2" - chokidar "^3.4.2" - colors "^1.4.0" - connect "^3.7.0" - di "^0.0.1" - dom-serialize "^2.2.1" - glob "^7.1.6" - graceful-fs "^4.2.4" - http-proxy "^1.18.1" - isbinaryfile "^4.0.6" - lodash "^4.17.19" - log4js "^6.2.1" - mime "^2.4.5" - minimatch "^3.0.4" - qjobs "^1.2.0" - range-parser "^1.2.1" - rimraf "^3.0.2" - socket.io "^2.3.0" - source-map "^0.6.1" - tmp "0.2.1" - ua-parser-js "0.7.22" - yargs "^15.3.1" - -killable@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" - integrity sha1-TIzkQRh6Bhx0dPuHygjipjgZSJI= - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha1-cpyR4thXt6QZofmqZWhcTDP1hF0= - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0= - -klaw@^1.0.0: - version "1.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= - optionalDependencies: - graceful-fs "^4.1.9" - -kleur@^3.0.3: - version "3.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha1-p5yezIbuHOP6YgbRIWxQHxR/wH4= - -klona@^2.0.4: - version "2.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" - integrity sha1-0WZXTZAHY5XZljqnqSj6u412r7w= - -lazy-universal-dotenv@^3.0.1: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz#a6c8938414bca426ab8c9463940da451a911db38" - integrity sha1-psiThBS8pCarjJRjlA2kUakR2zg= - dependencies: - "@babel/runtime" "^7.5.0" - app-root-dir "^1.0.2" - core-js "^3.0.4" - dotenv "^8.0.0" - dotenv-expand "^5.1.0" - -less-loader@7.3.0: - version "7.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/less-loader/-/less-loader-7.3.0.tgz#f9d6d36d18739d642067a05fb5bd70c8c61317e5" - integrity sha1-+dbTbRhznWQgZ6Bftb1wyMYTF+U= - dependencies: - klona "^2.0.4" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -less@4.1.1: - version "4.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/less/-/less-4.1.1.tgz#15bf253a9939791dc690888c3ff424f3e6c7edba" - integrity sha1-Fb8lOpk5eR3GkIiMP/Qk8+bH7bo= - dependencies: - copy-anything "^2.0.1" - parse-node-version "^1.0.1" - tslib "^1.10.0" - optionalDependencies: - errno "^0.1.1" - graceful-fs "^4.1.2" - image-size "~0.5.0" - make-dir "^2.1.0" - mime "^1.4.1" - needle "^2.5.2" - source-map "~0.6.0" - -less@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/less/-/less-4.1.3.tgz#175be9ddcbf9b250173e0a00b4d6920a5b770246" - integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA== - dependencies: - copy-anything "^2.0.1" - parse-node-version "^1.0.1" - tslib "^2.3.0" - optionalDependencies: - errno "^0.1.1" - graceful-fs "^4.1.2" - image-size "~0.5.0" - make-dir "^2.1.0" - mime "^1.4.1" - needle "^3.1.0" - source-map "~0.6.0" - -levn@^0.4.1: - version "0.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha1-rkViwAdHO5MqYgDUAyaN0v/8at4= - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -levn@~0.3.0: - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -license-webpack-plugin@2.3.11: - version "2.3.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/license-webpack-plugin/-/license-webpack-plugin-2.3.11.tgz#0d93188a31fce350a44c86212badbaf33dcd29d8" - integrity sha1-DZMYijH841CkTIYhK6268z3NKdg= - dependencies: - "@types/webpack-sources" "^0.1.5" - webpack-sources "^1.2.0" - -lie@~3.3.0: - version "3.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" - integrity sha1-3Pgt7lRfRgdNryAMfBxaCOD0D2o= - dependencies: - immediate "~3.0.5" - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha1-7KKE910pZQeTCdwK2SVauy68FjI= - -loader-runner@^2.4.0: - version "2.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha1-7UcGa/5TTX6ExMe5mYwqdWB9k1c= - -loader-utils@2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" - integrity sha1-5MrOW4FtQloWa18JfhDNErNgZLA= - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - -loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha1-xXm140yzSxp07cbB+za/o3HVphM= - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - -loader-utils@^2.0.0: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" - integrity sha1-1uO0+4GHByGuTghoqxHdY4NowSk= - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4= - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha1-Gvujlq/WdqbUJQTQpno6frn2KqA= - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha1-VTIeswn+u8WcSAHZMackUqaB0oY= - dependencies: - p-locate "^5.0.0" - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo= - -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - -lodash.uniq@4.5.0, lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: - version "4.17.21" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw= - -log-symbols@^4.0.0, log-symbols@^4.1.0: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha1-P727lbRoOsn8eFER55LlWNSr1QM= - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -log4js@^6.2.1: - version "6.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" - integrity sha1-EN+vu0NDUaPjAnegC5h5RG9xW8s= - dependencies: - date-format "^3.0.0" - debug "^4.1.1" - flatted "^2.0.1" - rfdc "^1.1.4" - streamroller "^2.2.4" - -loglevel-plugin-prefix@^0.8.4: - version "0.8.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz#2fe0e05f1a820317d98d8c123e634c1bd84ff644" - integrity sha1-L+DgXxqCAxfZjYwSPmNMG9hP9kQ= - -loglevel@^1.6.8, loglevel@^1.8.0: - version "1.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" - integrity sha1-5+xzpX4ee0GctsasBr8FC2c1YRQ= - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8= - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lower-case@^2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" - integrity sha1-b6I3xj29xKgsoP2ILkci3F5jTig= - dependencies: - tslib "^2.0.3" - -lowlight@^1.14.0: - version "1.20.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888" - integrity sha1-3bGX0zRirQ2TvxnRe2wwGqOUGIg= - dependencies: - fault "^1.0.0" - highlight.js "~10.7.0" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA= - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ= - dependencies: - yallist "^4.0.0" - -lunr@^2.3.9: - version "2.3.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" - integrity sha1-GLEjFCgyM33W6WTfGlp3B7JdNeE= - -luxon@^1.25.0: - version "1.28.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/luxon/-/luxon-1.28.0.tgz#e7f96daad3938c06a62de0fb027115d251251fbf" - integrity sha1-5/ltqtOTjAamLeD7AnEV0lElH78= - -macos-release@^2.5.0: - version "2.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/macos-release/-/macos-release-2.5.0.tgz#067c2c88b5f3fb3c56a375b2ec93826220fa1ff2" - integrity sha1-BnwsiLXz+zxWo3Wy7JOCYiD6H/I= - -magic-string@0.25.1: - version "0.25.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/magic-string/-/magic-string-0.25.1.tgz#b1c248b399cd7485da0fe7385c2fc7011843266e" - integrity sha1-scJIs5nNdIXaD+c4XC/HARhDJm4= - dependencies: - sourcemap-codec "^1.4.1" - -magic-string@0.25.7, magic-string@^0.25.0: - version "0.25.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" - integrity sha1-P0l9b9NMZpxnmNy4IfLvMfVEUFE= - dependencies: - sourcemap-codec "^1.4.4" - -magic-string@^0.25.7: - version "0.25.9" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" - integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== - dependencies: - sourcemap-codec "^1.4.8" - -make-dir@^2.0.0, make-dir@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha1-XwMQ4YuL6JjMBwCSlaMK5B6R5vU= - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0, make-dir@~3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8= - dependencies: - semver "^6.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha1-LrLjfqm2fEiR9oShOUeZr0hM96I= - -make-fetch-happen@^8.0.9: - version "8.0.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" - integrity sha1-qrpzrgq1WGrY6qaL2DMyZpOT4iI= - dependencies: - agentkeepalive "^4.1.3" - cacache "^15.0.5" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - promise-retry "^2.0.1" - socks-proxy-agent "^5.0.0" - ssri "^8.0.0" - -makeerror@1.0.12: - version "1.0.12" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha1-Pl3SB5qC6BLpg8xmEMSiyw6qgBo= - dependencies: - tmpl "1.0.5" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-or-similar@^1.5.0: - version "1.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/map-or-similar/-/map-or-similar-1.5.0.tgz#6de2653174adfb5d9edc33c69d3e92a1b76faf08" - integrity sha1-beJlMXSt+12e3DPGnT6Sobdvrwg= - -map-stream@0.0.7: - version "0.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" - integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -markdown-escapes@^1.0.0: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" - integrity sha1-yVQV70UUmddgK5EJXzyOiXX3hTU= - -markdown-to-jsx@^7.1.3: - version "7.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/markdown-to-jsx/-/markdown-to-jsx-7.1.5.tgz#caf72ad8a8c34a2bb692c4d17e44aabbe4eb19fd" - integrity sha1-yvcq2KjDSiu2ksTRfkSqu+TrGf0= - -marked@^4.0.4: - version "4.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/marked/-/marked-4.0.8.tgz#ef127626ac65786460f9420d57cc8d5ffdcacbed" - integrity sha1-7xJ2JqxleGRg+UINV8yNX/3Ky+0= - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha1-tdB7jjIW4+J81yjXL3DR5qNCAF8= - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -mdast-squeeze-paragraphs@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz#7c4c114679c3bee27ef10b58e2e015be79f1ef97" - integrity sha1-fEwRRnnDvuJ+8QtY4uAVvnnx75c= - dependencies: - unist-util-remove "^2.0.0" - -mdast-util-definitions@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz#c5c1a84db799173b4dcf7643cda999e440c24db2" - integrity sha1-xcGoTbeZFztNz3ZDzamZ5EDCTbI= - dependencies: - unist-util-visit "^2.0.0" - -mdast-util-to-hast@10.0.1: - version "10.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz#0cfc82089494c52d46eb0e3edb7a4eb2aea021eb" - integrity sha1-DPyCCJSUxS1G6w4+23pOsq6gIes= - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - mdast-util-definitions "^4.0.0" - mdurl "^1.0.0" - unist-builder "^2.0.0" - unist-util-generated "^1.0.0" - unist-util-position "^3.0.0" - unist-util-visit "^2.0.0" - -mdast-util-to-string@^1.0.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527" - integrity sha1-JwVVABA/UWN70H0B2gHrGWekNSc= - -mdn-data@2.0.14: - version "2.0.14" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" - integrity sha1-cRP8QoGRfWPOKbQ0RvcB5owlulA= - -mdn-data@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" - integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== - -mdurl@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= - -media-typer@0.3.0: - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -memfs@^3.1.2: - version "3.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/memfs/-/memfs-3.4.0.tgz#8bc12062b973be6b295d4340595736a656f0a257" - integrity sha1-i8EgYrlzvmspXUNAWVc2plbwolc= - dependencies: - fs-monkey "1.0.3" - -memoizerific@^1.11.3: - version "1.11.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/memoizerific/-/memoizerific-1.11.3.tgz#7c87a4646444c32d75438570905f2dbd1b1a805a" - integrity sha1-fIekZGREwy11Q4VwkF8tvRsagFo= - dependencies: - map-or-similar "^1.5.0" - -memory-fs@^0.4.1: - version "0.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -memory-fs@^0.5.0: - version "0.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha1-MkwBKIuIZSlm0WHbd4OHIIRajjw= - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - -merge-source-map@1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/merge-source-map/-/merge-source-map-1.0.4.tgz#a5de46538dae84d4114cc5ea02b4772a6346701f" - integrity sha1-pd5GU42uhNQRTMXqArR3KmNGcB8= - dependencies: - source-map "^0.5.6" - -merge-source-map@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" - integrity sha1-L93n5gIJOfcJBqaPLXrmheTIxkY= - dependencies: - source-map "^0.6.1" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A= - -merge2@^1.2.3, merge2@^1.3.0: - version "1.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4= - -methods@~1.1.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -microevent.ts@~0.1.1: - version "0.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" - integrity sha1-cLCbg/Q99RctAgWmMCW84Pc1f6A= - -micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha1-cIWbyVyYQJUvNZoGij/En57PrCM= - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha1-iW1Rnf6dsl/OlM63pQCRm/iB6/k= - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha1-8IA1HIZbDcViqEYpZtqlNUPHik0= - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.51.0, "mime-db@>= 1.43.0 < 2": - version "1.51.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha1-2f9iRRhZsYNC2WCFDcPPt35j+ww= - -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.34" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha1-WnEvnsFQNRGpRYA2QPr+CdN5PCQ= - dependencies: - mime-db "1.51.0" - -mime@1.6.0, mime@^1.4.1: - version "1.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE= - -mime@^2.4.4, mime@^2.4.5: - version "2.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" - integrity sha1-oqaCqVzU0MsdYlfij4PafjWAA2c= - -mime@~2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" - integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs= - -min-document@^2.19.0: - version "2.19.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= - dependencies: - dom-walk "^0.1.0" - -mini-css-extract-plugin@1.3.5: - version "1.3.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.5.tgz#252166e78879c106e0130f229d44e0cbdfcebed3" - integrity sha1-JSFm54h5wQbgEw8inUTgy9/OvtM= - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - webpack-sources "^1.1.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha1-LhlN4ERibUoQ5/f7wAznPoPk1cc= - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM= - dependencies: - brace-expansion "^1.1.7" - -minimatch@~3.0.4: - version "3.0.8" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" - integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI= - -minimist@^1.2.6: - version "1.2.7" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" - integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== - -minipass-collect@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" - integrity sha1-IrgTv3Rdxu26JXa5QAIq1u3Ixhc= - dependencies: - minipass "^3.0.0" - -minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: - version "1.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" - integrity sha1-114AkdqsGw/9fp1BYp+v99DB8bY= - dependencies: - minipass "^3.1.0" - minipass-sized "^1.0.3" - minizlib "^2.0.0" - optionalDependencies: - encoding "^0.1.12" - -minipass-flush@^1.0.5: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" - integrity sha1-gucTXX6JpQ/+ZGEKeHlTxMTLs3M= - dependencies: - minipass "^3.0.0" - -minipass-json-stream@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" - integrity sha1-ftu5JYj7/C/x2y/BA5est7a0Sqc= - dependencies: - jsonparse "^1.3.1" - minipass "^3.0.0" - -minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: - version "1.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" - integrity sha1-aEcveXEcCEZXwGfFxq2Tzd6oIUw= - dependencies: - minipass "^3.0.0" - -minipass-sized@^1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" - integrity sha1-cO5afFBSBwr6z7wil36nne81O3A= - dependencies: - minipass "^3.0.0" - -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" - integrity sha1-O4FQqmiKcRoVIa9eh3nB07tPRe4= - dependencies: - yallist "^4.0.0" - -minizlib@^2.0.0, minizlib@^2.1.1: - version "2.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha1-6Q00Zrogm5MkUVCKEc49NjIUWTE= - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mississippi@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha1-6goykfl+C16HdrNj1fChLZTGcCI= - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha1-ESC0PcNZp4Xc5ltVuC4lfM9HlWY= - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5: - version "0.5.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8= - dependencies: - minimist "^1.2.5" - -mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha1-PrXtYmInVteaXw4qIh3+utdcL34= - -mkdirp@~0.5.1: - version "0.5.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" - integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== - dependencies: - minimist "^1.2.6" - -morgan@^1.10.0: - version "1.10.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" - integrity sha1-CRd4q8H8R801CYJGU9rh+qtrF9c= - dependencies: - basic-auth "~2.0.1" - debug "2.6.9" - depd "~2.0.0" - on-finished "~2.3.0" - on-headers "~1.0.2" - -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - -mrmime@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b" - integrity sha1-FNOH8FhaUjPSkbq6M5sGN1KiOYs= - -ms@2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo= - -ms@2.1.2: - version "2.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk= - -ms@2.1.3, ms@^2.0.0, ms@^2.1.1: - version "2.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha1-V0yBOM4dK1hh8LRFedut1gxmFbI= - -multicast-dns-service-types@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" - integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= - -multicast-dns@^6.0.1: - version "6.2.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" - integrity sha1-oOx72QVcQoL3kMPIL04o2zsxsik= - dependencies: - dns-packet "^1.3.1" - thunky "^1.0.2" - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha1-FjDEKyJR/4HiooPelqVJfqkuXg0= - -nan@^2.12.1: - version "2.15.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha1-PzSkc/8Y4VwbVia2KQO1rW5mX+4= - -nanoid@^3.1.23, nanoid@^3.1.30: - version "3.1.30" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" - integrity sha1-Y/k8xUjSoRPcXfvGO/oJ4rm2Q2I= - -nanoid@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" - integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk= - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -needle@^2.5.2: - version "2.9.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" - integrity sha1-ItHf++NJDCuD4wH3cJtnNs2PJoQ= - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - -needle@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-3.2.0.tgz#07d240ebcabfd65c76c03afae7f6defe6469df44" - integrity sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ== - dependencies: - debug "^3.2.6" - iconv-lite "^0.6.3" - sax "^1.2.4" - -negotiator@0.6.2: - version "0.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs= - -neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1, neo-async@^2.6.2: - version "2.6.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha1-tKr7k+OustgXTKU88WOrfXMIMF8= - -nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" - integrity sha1-D73PPhP+SZR4EoBST4uWsM3/nGE= - -next-tick@~1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= - -ng-packagr@^11.2.4: - version "11.2.4" - resolved "https://registry.yarnpkg.com/ng-packagr/-/ng-packagr-11.2.4.tgz#9deda83beb831bda7b753686d0f90e12a02dbb47" - integrity sha512-pAZYRWe4duLx6bXgfNKgT2XBHiepWz2sA+CaJ9UYEbLHE+QxYGtw/PJAC6o0zRDv1bBCkv5oquKTyTZtYjkAQQ== - dependencies: - "@rollup/plugin-commonjs" "^17.0.0" - "@rollup/plugin-json" "^4.1.0" - "@rollup/plugin-node-resolve" "^11.1.0" - ajv "^7.0.3" - ansi-colors "^4.1.1" - autoprefixer "^10.2.4" - browserslist "^4.16.1" - chokidar "^3.5.1" - commander "^7.0.0" - cssnano "^4.1.10" - glob "^7.1.6" - injection-js "^2.4.0" - less "^4.1.0" - node-sass-tilde-importer "^1.0.2" - ora "^5.1.0" - postcss "^8.2.4" - postcss-url "^10.1.1" - rimraf "^3.0.0" - rollup "^2.37.0" - rollup-plugin-sourcemaps "^0.6.3" - rxjs "^6.5.0" - sass "^1.32.5" - stylus "^0.54.8" - sync-rpc "^1.3.6" - terser "^5.5.1" - -ngx-mat-select-search@^3.3.3: - version "3.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ngx-mat-select-search/-/ngx-mat-select-search-3.3.3.tgz#b867e2c8add58a3bc99f2b1634bd7fd25af0a834" - integrity sha1-uGfiyK3VijvJnysWNL1/0lrwqDQ= - dependencies: - tslib "^1.9.0" - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y= - -no-case@^3.0.4: - version "3.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" - integrity sha1-02H9XJgA9VhVGoNp/A3NRmK2Ek0= - dependencies: - lower-case "^2.0.2" - tslib "^2.0.3" - -node-fetch@^2.6.1: - version "2.6.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" - integrity sha1-F1GnwBg06OFpd1hzLp77burfr4k= - dependencies: - whatwg-url "^5.0.0" - -node-forge@^0.10.0: - version "0.10.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" - integrity sha1-Mt6ir7Ppkm8C7lzoeUkCaRpna/M= - -node-gyp@^7.1.0: - version "7.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" - integrity sha1-IagQrrsYcSAlHDvOyXmvFYexiK4= - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.3" - nopt "^5.0.0" - npmlog "^4.1.2" - request "^2.88.2" - rimraf "^3.0.2" - semver "^7.3.2" - tar "^6.0.2" - which "^2.0.2" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - -node-libs-browser@^2.2.1: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha1-tk9RPRgzhiX5A0bSew0jXmMfZCU= - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - -node-releases@^1.1.61: - version "1.1.77" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" - integrity sha1-ULDP7ehV3TdOdYW/Io/zTlfBwy4= - -node-releases@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" - integrity sha1-PR05XyBPHy8ppUNYuftnh2WtL8U= - -node-releases@^2.0.6: - version "2.0.8" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.8.tgz#0f349cdc8fcfa39a92ac0be9bc48b7706292b9ae" - integrity sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A== - -node-sass-tilde-importer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/node-sass-tilde-importer/-/node-sass-tilde-importer-1.0.2.tgz#1a15105c153f648323b4347693fdb0f331bad1ce" - integrity sha512-Swcmr38Y7uB78itQeBm3mThjxBy9/Ah/ykPIaURY/L6Nec9AyRoL/jJ7ECfMR+oZeCTVQNxVMu/aHU+TLRVbdg== - dependencies: - find-parent-dir "^0.3.0" - -nopt@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha1-UwlCu1ilEvzK/lP+IQ8TolNV3Ig= - dependencies: - abbrev "1" - -normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg= - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU= - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - -normalize-url@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - -normalize-url@^6.0.1: - version "6.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" - integrity sha1-QNCIW1Nd7/4/MUe+yHfQX+TFZoo= - -npm-bundled@^1.1.1: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" - integrity sha1-lEx4eJvXOQNbcLqiylzDK42GC8E= - dependencies: - npm-normalize-package-bin "^1.0.1" - -npm-install-checks@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" - integrity sha1-o3+sx2Oi/eBJfvLG0Kx8P74A17Q= - dependencies: - semver "^7.1.1" - -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha1-bnmkHyP9I1wGIyGCKNp9nCO49uI= - -npm-package-arg@8.1.0: - version "8.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-package-arg/-/npm-package-arg-8.1.0.tgz#b5f6319418c3246a1c38e1a8fbaa06231bc5308f" - integrity sha1-tfYxlBjDJGocOOGo+6oGIxvFMI8= - dependencies: - hosted-git-info "^3.0.6" - semver "^7.0.0" - validate-npm-package-name "^3.0.0" - -npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.2: - version "8.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" - integrity sha1-M2my1f6P3GdLqn8XhlFN3BVGbkQ= - dependencies: - hosted-git-info "^4.0.1" - semver "^7.3.4" - validate-npm-package-name "^3.0.0" - -npm-packlist@^2.1.4: - version "2.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" - integrity sha1-B2uXKT+mIPYygzGGp6j2WqphSMg= - dependencies: - glob "^7.1.6" - ignore-walk "^3.0.3" - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" - -npm-pick-manifest@6.1.0: - version "6.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-pick-manifest/-/npm-pick-manifest-6.1.0.tgz#2befed87b0fce956790f62d32afb56d7539c022a" - integrity sha1-K+/th7D86VZ5D2LTKvtW11OcAio= - dependencies: - npm-install-checks "^4.0.0" - npm-package-arg "^8.0.0" - semver "^7.0.0" - -npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: - version "6.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" - integrity sha1-e1SEyiyQhWX0O38nZE82u4FvUUg= - dependencies: - npm-install-checks "^4.0.0" - npm-normalize-package-bin "^1.0.1" - npm-package-arg "^8.1.2" - semver "^7.3.4" - -npm-registry-fetch@^9.0.0: - version "9.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" - integrity sha1-hvP+tM4AMTvAuPH49p2q5vrOFmE= - dependencies: - "@npmcli/ci-detect" "^1.0.0" - lru-cache "^6.0.0" - make-fetch-happen "^8.0.9" - minipass "^3.1.3" - minipass-fetch "^1.3.0" - minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -npm-run-path@^4.0.0: - version "4.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha1-t+zR5e1T2o43pV4cImnguX7XSOo= - dependencies: - path-key "^3.0.0" - -npmlog@^4.1.2: - version "4.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha1-CKfyqL9zRgR3mp76StXMcXq7lUs= - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -npmlog@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" - integrity sha1-8GZ46A4pQZrWerlk4PpplZweuLA= - dependencies: - are-we-there-yet "^2.0.0" - console-control-strings "^1.1.0" - gauge "^3.0.0" - set-blocking "^2.0.0" - -nth-check@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - -nth-check@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" - integrity sha1-Lv4WL1w9oGoolZ+9PbddvuqfD8I= - dependencies: - boolbase "^1.0.0" - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU= - -object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1, object-assign@latest: - version "4.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.11.0, object-inspect@^1.6.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha1-biwSDoaP0f0Yy08YwxdB0NbndvA= - -object-inspect@^1.12.2: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - -object-is@^1.0.1: - version "1.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha1-ud7qpfx/GEag+uzc7sE45XePU6w= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha1-HEfyct8nfzsdrwYWd9nILiMixg4= - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0, object.assign@^4.1.2: - version "4.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha1-DtVKNC7Os3s4/3brgxoOeIy2OUA= - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.entries@^1.1.0: - version "1.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" - integrity sha1-4azdF8TeLNltWghIfPuduE2IGGE= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -"object.fromentries@^2.0.0 || ^1.0.0": - version "2.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" - integrity sha1-ezeyBRCcIedB5gVyf+iwrV+gglE= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.2: - version "2.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" - integrity sha1-siPPOOF/77l6Y8EMkd9yzLOG354= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -object.getownpropertydescriptors@^2.1.0: - version "2.1.5" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz#db5a9002489b64eef903df81d6623c07e5b4b4d3" - integrity sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw== - dependencies: - array.prototype.reduce "^1.0.5" - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -object.values@^1.1.0: - version "1.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" - integrity sha1-lZ9j486e8QhyAzMIITHkpFm3Fqw= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -obuf@^1.0.0, obuf@^1.1.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" - integrity sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4= - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8= - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4= - dependencies: - mimic-fn "^2.1.0" - -open@7.4.0: - version "7.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/open/-/open-7.4.0.tgz#ad95b98f871d9acb0ec8fecc557082cc9986626b" - integrity sha1-rZW5j4cdmssOyP7MVXCCzJmGYms= - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - -open@8.2.1: - version "8.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/open/-/open-8.2.1.tgz#82de42da0ccbf429bc12d099dad2e0975e14e8af" - integrity sha1-gt5C2gzL9Cm8EtCZ2tLgl14U6K8= - dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" - -open@^7.0.2, open@^7.0.3: - version "7.4.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha1-uBR+Jtzz5CYxbHMAif1x7dKcIyE= - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - -opencollective-postinstall@^2.0.3: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha1-eg//l49tv6TQBiOPusmO1BmMMlk= - -opener@^1.5.2: - version "1.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" - integrity sha1-XTfh81B3udysQwE3InGv3rKhNZg= - -opn@^5.5.0: - version "5.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" - integrity sha1-/HFk+rVtI1kExRw7J9pnWMo7m/w= - dependencies: - is-wsl "^1.1.0" - -optionator@^0.8.1: - version "0.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha1-hPodA2/p08fiHZmIS2ARZ+yPtJU= - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha1-TyNqY3Pa4FZqbUPhMmZ09QwpFJk= - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -ora@5.3.0: - version "5.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ora/-/ora-5.3.0.tgz#fb832899d3a1372fe71c8b2c534bbfe74961bb6f" - integrity sha1-+4MomdOhNy/nHIssU0u/50lhu28= - dependencies: - bl "^4.0.3" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - log-symbols "^4.0.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - -ora@^5.1.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" - integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== - dependencies: - bl "^4.1.0" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - is-unicode-supported "^0.1.0" - log-symbols "^4.1.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - -original@^1.0.0: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" - integrity sha1-5EKmHP/hxf0gpl8yYcJmY7MD8l8= - dependencies: - url-parse "^1.4.3" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - -os-name@4.0.1: - version "4.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/os-name/-/os-name-4.0.1.tgz#32cee7823de85a8897647ba4d76db46bf845e555" - integrity sha1-Ms7ngj3oWoiXZHuk1220a/hF5VU= - dependencies: - macos-release "^2.5.0" - windows-release "^4.0.0" - -os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -overlayscrollbars@^1.13.1: - version "1.13.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz#0b840a88737f43a946b9d87875a2f9e421d0338a" - integrity sha1-C4QKiHN/Q6lGudh4daL55CHQM4o= - -p-all@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-all/-/p-all-2.1.0.tgz#91419be56b7dee8fe4c5db875d55e0da084244a0" - integrity sha1-kUGb5Wt97o/kxduHXVXg2ghCRKA= - dependencies: - p-map "^2.0.0" - -p-event@^4.1.0: - version "4.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" - integrity sha1-r0sEnIrNka6BCD69Hm9criBEwbU= - dependencies: - p-timeout "^3.1.0" - -p-filter@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-filter/-/p-filter-2.1.0.tgz#1b1472562ae7a0f742f0f3d3d3718ea66ff9c09c" - integrity sha1-GxRyVirnoPdC8PPT03GOpm/5wJw= - dependencies: - p-map "^2.0.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE= - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2, p-limit@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha1-4drMvnjQ0TiMoYxk/qOOPlfjcGs= - dependencies: - yocto-queue "^0.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ= - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha1-o0KLtwiLOmApL2aRkni3wpetTwc= - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha1-g8gxXGeFAF470CGDlBHJ4RDm2DQ= - dependencies: - p-limit "^3.0.2" - -p-map@^2.0.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha1-MQko/u+cnsxltosXaTAYpmXOoXU= - -p-map@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" - integrity sha1-1wTZr4orpoTiYA2aIVmD1BQal50= - dependencies: - aggregate-error "^3.0.0" - -p-map@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha1-uy+Vpe2i7BaOySdOBqdHw+KQTSs= - dependencies: - aggregate-error "^3.0.0" - -p-retry@^3.0.1: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" - integrity sha1-MWtMiJPiyNwc+okfQGxLQivr8yg= - dependencies: - retry "^0.12.0" - -p-timeout@^3.1.0: - version "3.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" - integrity sha1-x+F6vJcdKnli74NiazXWNazyPf4= - dependencies: - p-finally "^1.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha1-yyhoVA4xPWHeWPr741zpAE1VQOY= - -pacote@11.2.4: - version "11.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pacote/-/pacote-11.2.4.tgz#dc7ca740a573ed86a3bf863511d22c1d413ec82f" - integrity sha1-3HynQKVz7Yajv4Y1EdIsHUE+yC8= - dependencies: - "@npmcli/git" "^2.0.1" - "@npmcli/installed-package-contents" "^1.0.5" - "@npmcli/promise-spawn" "^1.2.0" - "@npmcli/run-script" "^1.3.0" - cacache "^15.0.5" - chownr "^2.0.0" - fs-minipass "^2.1.0" - infer-owner "^1.0.4" - minipass "^3.1.3" - mkdirp "^1.0.3" - npm-package-arg "^8.0.1" - npm-packlist "^2.1.4" - npm-pick-manifest "^6.0.0" - npm-registry-fetch "^9.0.0" - promise-retry "^1.1.1" - read-package-json-fast "^1.1.3" - rimraf "^3.0.2" - ssri "^8.0.0" - tar "^6.1.0" - -pako@^0.2.5: - version "0.2.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" - integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU= - -pako@~1.0.2, pako@~1.0.5: - version "1.0.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha1-bJWZ00DVTf05RjgCUqNXBaa5kr8= - -parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha1-kEnKN9bLIYLDsdLHIL6U0UpYFPw= - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - -param-case@^3.0.3: - version "3.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" - integrity sha1-fRf+SqEr3jTUp32RrPtiGcqtAcU= - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI= - dependencies: - callsites "^3.0.0" - -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha1-OFCAo+wTy2KmLTlAnLPoiETNrtQ= - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-entities@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" - integrity sha1-U8brW5MUofTsmfoP33zgHs2gy+g= - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-json@^5.0.0: - version "5.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha1-x2/Gbe5UIxyWKyK8yKcs8vmXU80= - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parse-node-version@^1.0.0, parse-node-version@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" - integrity sha1-4rXb7eAOf6m8NjYH9TMn6LBzGJs= - -parse5-html-rewriting-stream@6.0.1: - version "6.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz#de1820559317ab4e451ea72dba05fddfd914480b" - integrity sha1-3hggVZMXq05FHqctugX939kUSAs= - dependencies: - parse5 "^6.0.1" - parse5-sax-parser "^6.0.1" - -parse5-htmlparser2-tree-adapter@^6.0.1: - version "6.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha1-LN+a2CMyEUA3DU2/XT6Sx8jdxuY= - dependencies: - parse5 "^6.0.1" - -parse5-sax-parser@^6.0.1: - version "6.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz#98b4d366b5b266a7cd90b4b58906667af882daba" - integrity sha1-mLTTZrWyZqfNkLS1iQZmeviC2ro= - dependencies: - parse5 "^6.0.1" - -parse5@^5.0.0: - version "5.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha1-9o5OW6GFKsLK3AD0VV//bCq7YXg= - -parse5@^6.0.0, parse5@^6.0.1: - version "6.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha1-4aHAhcVps9wIMhGE8Zo5zCf3wws= - -parseqs@0.0.6: - version "0.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parseqs/-/parseqs-0.0.6.tgz#8e4bb5a19d1cdc844a08ac974d34e273afa670d5" - integrity sha1-jku1oZ0c3IRKCKyXTTTic6+mcNU= - -parseuri@0.0.6: - version "0.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parseuri/-/parseuri-0.0.6.tgz#e1496e829e3ac2ff47f39a4dd044b32823c4a25a" - integrity sha1-4Ulugp46wv9H85pN0ESzKCPEolo= - -parseurl@~1.3.2, parseurl@~1.3.3: - version "1.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ= - -pascal-case@^3.1.2: - version "3.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" - integrity sha1-tI4O8rmOIF58Ha50fQsVCCN2YOs= - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-browserify@0.0.1: - version "0.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha1-5sTd1+06onxoogzE5Q4aTug7vEo= - -path-browserify@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha1-2YRUqcN1PVeQhg8W9ohnueRr4f0= - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha1-UTvb4tO5XXdi6METfvoZXGxhtbM= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.1, path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U= - -path-parse@^1.0.6, path-parse@^1.0.7: - version "1.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha1-+8EUtgykKzDZ2vWFjkvWi77bZzU= - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - -path-type@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha1-zvMdyOCho7sNEFwM2Xzzv0f0428= - dependencies: - pify "^3.0.0" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha1-hO0BwKe6OAr+CdkKjBgNzZ0DBDs= - -pause-stream@^0.0.11: - version "0.0.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= - dependencies: - through "~2.3" - -pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha1-3YIqoIh1gOUvGgOdw+2hCO+uMHU= - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -pdfmake@^0.2.4: - version "0.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pdfmake/-/pdfmake-0.2.4.tgz#7d58d64b59f8e9b9ed0b2494b17a9d94c575825b" - integrity sha1-fVjWS1n46bntCySUsXqdlMV1gls= - dependencies: - "@foliojs-fork/linebreak" "^1.1.1" - "@foliojs-fork/pdfkit" "^0.13.0" - iconv-lite "^0.6.3" - xmldoc "^1.1.2" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -picocolors@^0.2.1: - version "0.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" - integrity sha1-VwZw95NkaFHRuhNZlpYqutWHhZ8= - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha1-y1vcdP8/UYkiNur3nWi8RFZKuBw= - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0: - version "2.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI= - -picomatch@^2.2.2: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@^2.0.0, pify@^2.3.0: - version "2.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pify@^4.0.1: - version "4.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE= - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pirates@^4.0.0, pirates@^4.0.1: - version "4.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" - integrity sha1-B9+B5hAo5AJzXN1J23AeSIW05uY= - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM= - dependencies: - find-up "^3.0.0" - -pkg-dir@^4.1.0: - version "4.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM= - dependencies: - find-up "^4.0.0" - -pkg-dir@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha1-oC1q6+a6EzqSj3Suwguv3+a452A= - dependencies: - find-up "^5.0.0" - -pkg-up@3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha1-EA7CNcwVDk/UJRlBJZaihRKg3vU= - dependencies: - find-up "^3.0.0" - -png-js@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/png-js/-/png-js-1.0.0.tgz#e5484f1e8156996e383aceebb3789fd75df1874d" - integrity sha1-5UhPHoFWmW44Os7rs3if113xh00= - -pnp-webpack-plugin@1.6.4: - version "1.6.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" - integrity sha1-yXEaxNxIpoXauvyG+Lbdn434QUk= - dependencies: - ts-pnp "^1.1.6" - -polished@^4.0.5: - version "4.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/polished/-/polished-4.1.3.tgz#7a3abf2972364e7d97770b827eec9a9e64002cfc" - integrity sha1-ejq/KXI2Tn2XdwuCfuyanmQALPw= - dependencies: - "@babel/runtime" "^7.14.0" - -portfinder@^1.0.26: - version "1.0.28" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" - integrity sha1-Z8RiKFK9U3TdHdkA93n1NGL6x3g= - dependencies: - async "^2.6.2" - debug "^3.1.1" - mkdirp "^0.5.5" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss-calc@^7.0.1: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.5.tgz#f8a6e99f12e619c2ebc23cf6c486fdc15860933e" - integrity sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg== - dependencies: - postcss "^7.0.27" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.0.2" - -postcss-calc@^8.0.0: - version "8.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-calc/-/postcss-calc-8.0.0.tgz#a05b87aacd132740a5db09462a3612453e5df90a" - integrity sha1-oFuHqs0TJ0Cl2wlGKjYSRT5d+Qo= - dependencies: - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.0.2" - -postcss-colormin@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" - integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== - dependencies: - browserslist "^4.0.0" - color "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-colormin@^5.2.2: - version "5.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-colormin/-/postcss-colormin-5.2.2.tgz#019cd6912bef9e7e0924462c5e4ffae241e2f437" - integrity sha1-AZzWkSvvnn4JJEYsXk/64kHi9Dc= - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - colord "^2.9.1" - postcss-value-parser "^4.2.0" - -postcss-convert-values@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" - integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-convert-values@^5.0.2: - version "5.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz#879b849dc3677c7d6bc94b6a2c1a3f0808798059" - integrity sha1-h5uEncNnfH1ryUtqLBo/CAh5gFk= - dependencies: - postcss-value-parser "^4.1.0" - -postcss-discard-comments@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" - integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== - dependencies: - postcss "^7.0.0" - -postcss-discard-comments@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe" - integrity sha1-nq5LdHz3YNMfJEfCfwYZ1XGJAf4= - -postcss-discard-duplicates@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" - integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== - dependencies: - postcss "^7.0.0" - -postcss-discard-duplicates@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz#68f7cc6458fe6bab2e46c9f55ae52869f680e66d" - integrity sha1-aPfMZFj+a6suRsn1WuUoafaA5m0= - -postcss-discard-empty@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" - integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== - dependencies: - postcss "^7.0.0" - -postcss-discard-empty@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz#ee136c39e27d5d2ed4da0ee5ed02bc8a9f8bf6d8" - integrity sha1-7hNsOeJ9XS7U2g7l7QK8ip+L9tg= - -postcss-discard-overridden@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" - integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== - dependencies: - postcss "^7.0.0" - -postcss-discard-overridden@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz#454b41f707300b98109a75005ca4ab0ff2743ac6" - integrity sha1-RUtB9wcwC5gQmnUAXKSrD/J0OsY= - -postcss-flexbugs-fixes@^4.2.1: - version "4.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz#9218a65249f30897deab1033aced8578562a6690" - integrity sha1-khimUknzCJfeqxAzrO2FeFYqZpA= - dependencies: - postcss "^7.0.26" - -postcss-import@14.0.0: - version "14.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-import/-/postcss-import-14.0.0.tgz#3ed1dadac5a16650bde3f4cdea6633b9c3c78296" - integrity sha1-PtHa2sWhZlC94/TN6mYzucPHgpY= - dependencies: - postcss-value-parser "^4.0.0" - read-cache "^1.0.0" - resolve "^1.1.7" - -postcss-loader@4.2.0: - version "4.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-loader/-/postcss-loader-4.2.0.tgz#f6993ea3e0f46600fb3ee49bbd010448123a7db4" - integrity sha1-9pk+o+D0ZgD7PuSbvQEESBI6fbQ= - dependencies: - cosmiconfig "^7.0.0" - klona "^2.0.4" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - semver "^7.3.4" - -postcss-loader@^4.2.0: - version "4.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-loader/-/postcss-loader-4.3.0.tgz#2c4de9657cd4f07af5ab42bd60a673004da1b8cc" - integrity sha1-LE3pZXzU8Hr1q0K9YKZzAE2huMw= - dependencies: - cosmiconfig "^7.0.0" - klona "^2.0.4" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - semver "^7.3.4" - -postcss-merge-longhand@^4.0.11: - version "4.0.11" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" - integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== - dependencies: - css-color-names "0.0.4" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - stylehacks "^4.0.0" - -postcss-merge-longhand@^5.0.4: - version "5.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32" - integrity sha1-QfTzJwKC6hoUXs4Hi3Z58M7yHDI= - dependencies: - postcss-value-parser "^4.1.0" - stylehacks "^5.0.1" - -postcss-merge-rules@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" - integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - cssnano-util-same-parent "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - vendors "^1.0.0" - -postcss-merge-rules@^5.0.3: - version "5.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-merge-rules/-/postcss-merge-rules-5.0.3.tgz#b5cae31f53129812a77e3eb1eeee448f8cf1a1db" - integrity sha1-tcrjH1MSmBKnfj6x7u5Ej4zxods= - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - cssnano-utils "^2.0.1" - postcss-selector-parser "^6.0.5" - -postcss-minify-font-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" - integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-font-values@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz#a90cefbfdaa075bd3dbaa1b33588bb4dc268addf" - integrity sha1-qQzvv9qgdb09uqGzNYi7TcJord8= - dependencies: - postcss-value-parser "^4.1.0" - -postcss-minify-gradients@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" - integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - is-color-stop "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-gradients@^5.0.3: - version "5.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-minify-gradients/-/postcss-minify-gradients-5.0.3.tgz#f970a11cc71e08e9095e78ec3a6b34b91c19550e" - integrity sha1-+XChHMceCOkJXnjsOms0uRwZVQ4= - dependencies: - colord "^2.9.1" - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-minify-params@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" - integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== - dependencies: - alphanum-sort "^1.0.0" - browserslist "^4.0.0" - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - uniqs "^2.0.0" - -postcss-minify-params@^5.0.2: - version "5.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-minify-params/-/postcss-minify-params-5.0.2.tgz#1b644da903473fbbb18fbe07b8e239883684b85c" - integrity sha1-G2RNqQNHP7uxj74HuOI5iDaEuFw= - dependencies: - alphanum-sort "^1.0.2" - browserslist "^4.16.6" - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-minify-selectors@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" - integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== - dependencies: - alphanum-sort "^1.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -postcss-minify-selectors@^5.1.0: - version "5.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz#4385c845d3979ff160291774523ffa54eafd5a54" - integrity sha1-Q4XIRdOXn/FgKRd0Uj/6VOr9WlQ= - dependencies: - alphanum-sort "^1.0.2" - postcss-selector-parser "^6.0.5" - -postcss-modules-extract-imports@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" - integrity sha1-gYcZoa4doyX5gyRGsBE27rSTzX4= - dependencies: - postcss "^7.0.5" - -postcss-modules-extract-imports@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha1-zaHwR8CugMl9vijD52pDuIAldB0= - -postcss-modules-local-by-default@^3.0.2: - version "3.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" - integrity sha1-uxTgzHgnnVBNvcv9fgyiiZP/u7A= - dependencies: - icss-utils "^4.1.1" - postcss "^7.0.32" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - -postcss-modules-local-by-default@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" - integrity sha1-67tU+uFZjuz99pGgKz/zs5ClpRw= - dependencies: - icss-utils "^5.0.0" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - -postcss-modules-scope@^2.2.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" - integrity sha1-OFyuATzHdD9afXYC0Qc6iequYu4= - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - -postcss-modules-scope@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" - integrity sha1-nvMVFFbTu/oSDKRImN/Kby+gHwY= - dependencies: - postcss-selector-parser "^6.0.4" - -postcss-modules-values@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" - integrity sha1-W1AA1uuuKbQlUwG0o6VFdEI+fxA= - dependencies: - icss-utils "^4.0.0" - postcss "^7.0.6" - -postcss-modules-values@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" - integrity sha1-18Xn5ow7s8myfL9Iyguz/7RgLJw= - dependencies: - icss-utils "^5.0.0" - -postcss-normalize-charset@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" - integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== - dependencies: - postcss "^7.0.0" - -postcss-normalize-charset@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0" - integrity sha1-EhVZ0b68VayNJK839nvU2p79kdA= - -postcss-normalize-display-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" - integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-display-values@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz#62650b965981a955dffee83363453db82f6ad1fd" - integrity sha1-YmULllmBqVXf/ugzY0U9uC9q0f0= - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-normalize-positions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" - integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== - dependencies: - cssnano-util-get-arguments "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-positions@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz#868f6af1795fdfa86fbbe960dceb47e5f9492fe5" - integrity sha1-ho9q8Xlf36hvu+lg3OtH5flJL+U= - dependencies: - postcss-value-parser "^4.1.0" - -postcss-normalize-repeat-style@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" - integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-repeat-style@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz#cbc0de1383b57f5bb61ddd6a84653b5e8665b2b5" - integrity sha1-y8DeE4O1f1u2Hd1qhGU7XoZlsrU= - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-normalize-string@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" - integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== - dependencies: - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-string@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz#d9eafaa4df78c7a3b973ae346ef0e47c554985b0" - integrity sha1-2er6pN94x6O5c640bvDkfFVJhbA= - dependencies: - postcss-value-parser "^4.1.0" - -postcss-normalize-timing-functions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" - integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-timing-functions@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz#8ee41103b9130429c6cbba736932b75c5e2cb08c" - integrity sha1-juQRA7kTBCnGy7pzaTK3XF4ssIw= - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-normalize-unicode@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" - integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-unicode@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz#82d672d648a411814aa5bf3ae565379ccd9f5e37" - integrity sha1-gtZy1kikEYFKpb865WU3nM2fXjc= - dependencies: - browserslist "^4.16.0" - postcss-value-parser "^4.1.0" - -postcss-normalize-url@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" - integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^3.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-url@^5.0.4: - version "5.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-normalize-url/-/postcss-normalize-url-5.0.4.tgz#3b0322c425e31dd275174d0d5db0e466f50810fb" - integrity sha1-OwMixCXjHdJ1F00NXbDkZvUIEPs= - dependencies: - normalize-url "^6.0.1" - postcss-value-parser "^4.2.0" - -postcss-normalize-whitespace@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" - integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-whitespace@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz#b0b40b5bcac83585ff07ead2daf2dcfbeeef8e9a" - integrity sha1-sLQLW8rINYX/B+rS2vLc++7vjpo= - dependencies: - postcss-value-parser "^4.1.0" - -postcss-ordered-values@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" - integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== - dependencies: - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-ordered-values@^5.0.2: - version "5.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044" - integrity sha1-HzUUJpd74A4PdlsxZK11PayO0EQ= - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-reduce-initial@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" - integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - -postcss-reduce-initial@^5.0.2: - version "5.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz#fa424ce8aa88a89bc0b6d0f94871b24abe94c048" - integrity sha1-+kJM6KqIqJvAttD5SHGySr6UwEg= - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - -postcss-reduce-transforms@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" - integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== - dependencies: - cssnano-util-get-match "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-reduce-transforms@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz#93c12f6a159474aa711d5269923e2383cedcf640" - integrity sha1-k8EvahWUdKpxHVJpkj4jg87c9kA= - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-selector-parser@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" - integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== - dependencies: - dot-prop "^5.2.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: - version "6.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz#f023ed7a9ea736cd7ef70342996e8e78645a7914" - integrity sha1-8CPtep6nNs1+9wNCmW6OeGRaeRQ= - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-svgo@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e" - integrity sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - svgo "^1.0.0" - -postcss-svgo@^5.0.3: - version "5.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-svgo/-/postcss-svgo-5.0.3.tgz#d945185756e5dfaae07f9edb0d3cae7ff79f9b30" - integrity sha1-2UUYV1bl36rgf57bDTyuf/efmzA= - dependencies: - postcss-value-parser "^4.1.0" - svgo "^2.7.0" - -postcss-unique-selectors@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" - integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== - dependencies: - alphanum-sort "^1.0.0" - postcss "^7.0.0" - uniqs "^2.0.0" - -postcss-unique-selectors@^5.0.2: - version "5.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz#5d6893daf534ae52626708e0d62250890108c0c1" - integrity sha1-XWiT2vU0rlJiZwjg1iJQiQEIwME= - dependencies: - alphanum-sort "^1.0.2" - postcss-selector-parser "^6.0.5" - -postcss-url@^10.1.1: - version "10.1.3" - resolved "https://registry.yarnpkg.com/postcss-url/-/postcss-url-10.1.3.tgz#54120cc910309e2475ec05c2cfa8f8a2deafdf1e" - integrity sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw== - dependencies: - make-dir "~3.1.0" - mime "~2.5.2" - minimatch "~3.0.4" - xxhashjs "~0.2.2" - -postcss-value-parser@^3.0.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: - version "4.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" - integrity sha1-cjwJkgg2um0+WvAZ+SvAlxwC5RQ= - -postcss@8.2.15: - version "8.2.15" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss/-/postcss-8.2.15.tgz#9e66ccf07292817d226fc315cbbf9bc148fbca65" - integrity sha1-nmbM8HKSgX0ib8MVy7+bwUj7ymU= - dependencies: - colorette "^1.2.2" - nanoid "^3.1.23" - source-map "^0.6.1" - -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.36, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.39" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" - integrity sha1-liQ3XZZWMOLh8sAqk1yCpZy0gwk= - dependencies: - picocolors "^0.2.1" - source-map "^0.6.1" - -postcss@^8.1.4, postcss@^8.3.7: - version "8.4.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" - integrity sha1-uuZldk39TG/MJNwP3356oAzHf5U= - dependencies: - nanoid "^3.1.30" - picocolors "^1.0.0" - source-map-js "^1.0.1" - -postcss@^8.2.15, postcss@^8.2.4: - version "8.4.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" - integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== - dependencies: - nanoid "^3.3.4" - picocolors "^1.0.0" - source-map-js "^1.0.2" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha1-3rxkidem5rDnYRiIzsiAM30xY5Y= - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prettier@^2.2.1: - version "2.5.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha1-//dfqdUZxUzw/OMowQF9lFRrxWo= - -pretty-bytes@^5.3.0: - version "5.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" - integrity sha1-NWJW9kOAR3PIL2RyP+eMksYr6us= - -pretty-error@^2.1.1: - version "2.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" - integrity sha1-von4LYGxyG7I/fvDhQRYgnJ/k7Y= - dependencies: - lodash "^4.17.20" - renderkid "^2.0.4" - -pretty-hrtime@^1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" - integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= - -prismjs@^1.21.0, prismjs@~1.25.0: - version "1.25.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" - integrity sha1-b4It8b2tllc0sxCzFaIzFc+Zl1Y= - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha1-eCDZsWEgzFXKmud5JoCufbptf+I= - -process@^0.11.10: - version "0.11.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -progress@^2.0.0: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha1-foz42PW48jnBvGi+tOt4Vn1XLvg= - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= - -promise-retry@^1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" - integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= - dependencies: - err-code "^1.0.0" - retry "^0.10.0" - -promise-retry@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" - integrity sha1-/3R6E2IKtXumiPX8Z4VUEMNw2iI= - dependencies: - err-code "^2.0.2" - retry "^0.12.0" - -promise.allsettled@^1.0.0: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/promise.allsettled/-/promise.allsettled-1.0.5.tgz#2443f3d4b2aa8dfa560f6ac2aa6c4ea999d75f53" - integrity sha1-JEPz1LKqjfpWD2rCqmxOqZnXX1M= - dependencies: - array.prototype.map "^1.0.4" - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - iterate-value "^1.0.2" - -promise.prototype.finally@^3.1.0: - version "3.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/promise.prototype.finally/-/promise.prototype.finally-3.1.3.tgz#d3186e58fcf4df1682a150f934ccc27b7893389c" - integrity sha1-0xhuWPz03xaCoVD5NMzCe3iTOJw= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -prompts@2.4.0: - version "2.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" - integrity sha1-SqXeByOiMdHukSHED99mPfc/Ydc= - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -prompts@^2.4.0: - version "2.4.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha1-e1fnOzpIAprRDr1E90sBcipMsGk= - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -prop-types@^15.0.0, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2: - version "15.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/prop-types/-/prop-types-15.8.0.tgz#d237e624c45a9846e469f5f31117f970017ff588" - integrity sha1-0jfmJMRamEbkafXzERf5cAF/9Yg= - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -property-information@^5.0.0, property-information@^5.3.0: - version "5.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" - integrity sha1-YWdVRfsjAC8kXGVA7EYHfU2j7Wk= - dependencies: - xtend "^4.0.0" - -protractor@~7.0.0: - version "7.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/protractor/-/protractor-7.0.0.tgz#c3e263608bd72e2c2dc802b11a772711a4792d03" - integrity sha1-w+JjYIvXLiwtyAKxGncnEaR5LQM= - dependencies: - "@types/q" "^0.0.32" - "@types/selenium-webdriver" "^3.0.0" - blocking-proxy "^1.0.0" - browserstack "^1.5.1" - chalk "^1.1.3" - glob "^7.0.3" - jasmine "2.8.0" - jasminewd2 "^2.1.0" - q "1.4.1" - saucelabs "^1.5.0" - selenium-webdriver "3.6.0" - source-map-support "~0.4.0" - webdriver-js-extender "2.1.0" - webdriver-manager "^12.1.7" - yargs "^15.3.1" - -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha1-8Z/mnOqzEe65S0LnDowgcPm6ECU= - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -proxy-middleware@latest: - version "0.15.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/proxy-middleware/-/proxy-middleware-0.15.0.tgz#a3fdf1befb730f951965872ac2f6074c61477a56" - integrity sha1-o/3xvvtzD5UZZYcqwvYHTGFHelY= - -prr@~1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - -psl@^1.1.28: - version "1.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha1-kyb4vPsBOtzABf3/BWrM4CDlHCQ= - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha1-T8ydd6B+SLp1J+fL4N4z0HATMeA= - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pump@^2.0.0: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk= - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pump@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ= - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^1.3.3: - version "1.5.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4= - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - -punycode@1.3.2: - version "1.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.2.4: - version "1.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha1-tYsBCsQMIsVldhbI0sLALHv0eew= - -q@1.4.1: - version "1.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" - integrity sha1-VXBbzZPF82c1MMLCy8DCs63cKG4= - -q@^1.1.2, q@^1.4.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== - -qjobs@^1.2.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" - integrity sha1-xF6cYYAL0IfviNfiVkI73Unl0HE= - -qs@6.9.6: - version "6.9.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" - integrity sha1-Ju08gkOkMbKSSsqEzJBHHzXVoO4= - -qs@^6.10.0: - version "6.10.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/qs/-/qs-6.10.2.tgz#c1431bea37fc5b24c5bdbafa20f16bdf2a4b9ffe" - integrity sha1-wUMb6jf8WyTFvbr6IPFr3ypLn/4= - dependencies: - side-channel "^1.0.4" - -qs@~6.5.2: - version "6.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha1-yzroBuh0BERYTvFUzo7pjUA/PjY= - -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - -querystring@0.2.0: - version "0.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -querystring@^0.2.0: - version "0.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" - integrity sha1-QNd2FbsJ0WkCqFw+OKqLXtdhwt0= - -querystringify@^2.1.1: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha1-M0WUG0FTy50ILY7uTNogFqmu9/Y= - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha1-SSkii7xyTfrEPg77BYyve2z7YkM= - -quote-stream@^1.0.1: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/quote-stream/-/quote-stream-1.0.2.tgz#84963f8c9c26b942e153feeb53aae74652b7e0b2" - integrity sha1-hJY/jJwmuULhU/7rU6rnRlK34LI= - dependencies: - buffer-equal "0.0.1" - minimist "^1.1.3" - through2 "^2.0.0" - -ramda@^0.21.0: - version "0.21.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" - integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU= - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo= - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha1-ySGW/IarQr6YPxvzF3giSTHWFFg= - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@^1.2.1, range-parser@~1.2.1: - version "1.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE= - -raw-body@2.4.2: - version "2.4.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" - integrity sha1-uvPpwh7rztWd1lM6yHK3H3thyzI= - dependencies: - bytes "3.1.1" - http-errors "1.8.1" - iconv-lite "0.4.24" - unpipe "1.0.0" - -raw-loader@4.0.2, raw-loader@^4.0.2: - version "4.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6" - integrity sha1-GqxrfRrRUB5m79rBUixz5ZpYTrY= - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -react-colorful@^5.1.2: - version "5.5.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-colorful/-/react-colorful-5.5.1.tgz#29d9c4e496f2ca784dd2bb5053a3a4340cfaf784" - integrity sha1-KdnE5JbyynhN0rtQU6OkNAz694Q= - -react-dev-utils@^11.0.4: - version "11.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-dev-utils/-/react-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a" - integrity sha1-p8y2Alehyi4O/nqD445nANF6o3o= - dependencies: - "@babel/code-frame" "7.10.4" - address "1.1.2" - browserslist "4.14.2" - chalk "2.4.2" - cross-spawn "7.0.3" - detect-port-alt "1.1.6" - escape-string-regexp "2.0.0" - filesize "6.1.0" - find-up "4.1.0" - fork-ts-checker-webpack-plugin "4.1.6" - global-modules "2.0.0" - globby "11.0.1" - gzip-size "5.1.1" - immer "8.0.1" - is-root "2.1.0" - loader-utils "2.0.0" - open "^7.0.2" - pkg-up "3.1.0" - prompts "2.4.0" - react-error-overlay "^6.0.9" - recursive-readdir "2.2.2" - shell-quote "1.7.2" - strip-ansi "6.0.0" - text-table "0.2.0" - -react-dom@16.14.0: - version "16.14.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" - integrity sha1-etg47Cmnd/s8dcOhkPZhz5Kri4k= - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" - -react-dom@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - -react-draggable@^4.4.3: - version "4.4.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-draggable/-/react-draggable-4.4.4.tgz#5b26d9996be63d32d285a426f41055de87e59b2f" - integrity sha1-WybZmWvmPTLShaQm9BBV3oflmy8= - dependencies: - clsx "^1.1.1" - prop-types "^15.6.0" - -react-element-to-jsx-string@^14.3.4: - version "14.3.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-element-to-jsx-string/-/react-element-to-jsx-string-14.3.4.tgz#709125bc72f06800b68f9f4db485f2c7d31218a8" - integrity sha1-cJElvHLwaAC2j59NtIXyx9MSGKg= - dependencies: - "@base2/pretty-print-object" "1.0.1" - is-plain-object "5.0.0" - react-is "17.0.2" - -react-error-overlay@^6.0.9: - version "6.0.10" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6" - integrity sha1-D+JttPqF2du4YkcpWA6Q5xWaWaY= - -react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: - version "3.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" - integrity sha1-ZBqdqBtqYyDycOiXJPtFoLOeQ7s= - -react-helmet-async@^1.0.7: - version "1.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-helmet-async/-/react-helmet-async-1.2.2.tgz#38d58d32ebffbc01ba42b5ad9142f85722492389" - integrity sha1-ONWNMuv/vAG6QrWtkUL4VyJJI4k= - dependencies: - "@babel/runtime" "^7.12.5" - invariant "^2.2.4" - prop-types "^15.7.2" - react-fast-compare "^3.2.0" - shallowequal "^1.1.0" - -react-inspector@^5.1.0: - version "5.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-inspector/-/react-inspector-5.1.1.tgz#58476c78fde05d5055646ed8ec02030af42953c8" - integrity sha1-WEdseP3gXVBVZG7Y7AIDCvQpU8g= - dependencies: - "@babel/runtime" "^7.0.0" - is-dom "^1.0.0" - prop-types "^15.0.0" - -react-is@17.0.2, react-is@^17.0.2: - version "17.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha1-5pHUqOnHiTZWVVOas3J2Kw77VPA= - -react-is@^16.13.1, react-is@^16.7.0: - version "16.13.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha1-eJcppNw23imZ3BVt1sHZwYzqVqQ= - -react-popper-tooltip@^3.1.1: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz#329569eb7b287008f04fcbddb6370452ad3f9eac" - integrity sha1-MpVp63socAjwT8vdtjcEUq0/nqw= - dependencies: - "@babel/runtime" "^7.12.5" - "@popperjs/core" "^2.5.4" - react-popper "^2.2.4" - -react-popper@^2.2.4: - version "2.2.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-popper/-/react-popper-2.2.5.tgz#1214ef3cec86330a171671a4fbcbeeb65ee58e96" - integrity sha1-EhTvPOyGMwoXFnGk+8vutl7ljpY= - dependencies: - react-fast-compare "^3.0.1" - warning "^4.0.2" - -react-router-dom@^6.0.0: - version "6.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-router-dom/-/react-router-dom-6.2.1.tgz#32ec81829152fbb8a7b045bf593a22eadf019bec" - integrity sha1-MuyBgpFS+7insEW/WToi6t8Bm+w= - dependencies: - history "^5.2.0" - react-router "6.2.1" - -react-router@6.2.1, react-router@^6.0.0: - version "6.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-router/-/react-router-6.2.1.tgz#be2a97a6006ce1d9123c28934e604faef51448a3" - integrity sha1-viqXpgBs4dkSPCiTTmBPrvUUSKM= - dependencies: - history "^5.2.0" - -react-sizeme@^3.0.1: - version "3.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-sizeme/-/react-sizeme-3.0.2.tgz#4a2f167905ba8f8b8d932a9e35164e459f9020e4" - integrity sha1-Si8WeQW6j4uNkyqeNRZORZ+QIOQ= - dependencies: - element-resize-detector "^1.2.2" - invariant "^2.2.4" - shallowequal "^1.1.0" - throttle-debounce "^3.0.1" - -react-syntax-highlighter@^13.5.3: - version "13.5.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz#9712850f883a3e19eb858cf93fad7bb357eea9c6" - integrity sha1-lxKFD4g6PhnrhYz5P617s1fuqcY= - dependencies: - "@babel/runtime" "^7.3.1" - highlight.js "^10.1.1" - lowlight "^1.14.0" - prismjs "^1.21.0" - refractor "^3.1.0" - -react-textarea-autosize@^8.3.0: - version "8.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8" - integrity sha1-9wkTlFNp2kU/1VTBaPa6rNH6BNg= - dependencies: - "@babel/runtime" "^7.10.2" - use-composed-ref "^1.0.0" - use-latest "^1.0.0" - -react@16.14.0: - version "16.14.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" - integrity sha1-lNd23dCqo32j7aj8W2sYpMmjEU0= - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - -read-cache@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" - integrity sha1-5mTvMRYRZsl1HNvo28+GtftY93Q= - dependencies: - pify "^2.3.0" - -read-package-json-fast@^1.1.3: - version "1.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/read-package-json-fast/-/read-package-json-fast-1.2.2.tgz#fba77b0b0d66b1ab344e214cb0876577e749c423" - integrity sha1-+6d7Cw1msas0TiFMsIdld+dJxCM= - dependencies: - json-parse-even-better-errors "^2.3.0" - npm-normalize-package-bin "^1.0.1" - -read-package-json-fast@^2.0.1: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" - integrity sha1-MjylKWMNqCyzSzbMC5lmk8mMK4M= - dependencies: - json-parse-even-better-errors "^2.3.0" - npm-normalize-package-bin "^1.0.1" - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha1-86YTV1hFlzOuK5VjgFbhhU5+9Qc= - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha1-e/KVQ4yloz5WzTDgU7NO5yUMk8w= - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.3, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.0.6, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha1-M3u9o63AcGvT4CRCaihtS0sskZg= - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@^2.2.1: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha1-DodiKjMlqjPokihcr4tOhGUppSU= - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha1-dKNwvYVxFuJFspzJc0DNQxoCpsc= - dependencies: - picomatch "^2.2.1" - -recursive-readdir@2.2.2: - version "2.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" - integrity sha1-mUb7MnThYo3m42svZxSVO0hFCU8= - dependencies: - minimatch "3.0.4" - -reflect-metadata@^0.1.2: - version "0.1.13" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" - integrity sha1-Z648pXyXKiqhZCsQ/jY/4y1J3Ag= - -refractor@^3.1.0: - version "3.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/refractor/-/refractor-3.5.0.tgz#334586f352dda4beaf354099b48c2d18e0819aec" - integrity sha1-M0WG81LdpL6vNUCZtIwtGOCBmuw= - dependencies: - hastscript "^6.0.0" - parse-entities "^2.0.0" - prismjs "~1.25.0" - -regenerate-unicode-properties@^9.0.0: - version "9.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" - integrity sha1-VNCccRXh9T3CMUqXSzLBw0Tv4yY= - dependencies: - regenerate "^1.4.2" - -regenerate@^1.4.2: - version "1.4.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha1-uTRtiCfo9aMve6KWN9OYtpAUhIo= - -regenerator-runtime@0.13.7: - version "0.13.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" - integrity sha1-ysLazIoepnX+qrrriugziYrkb1U= - -regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: - version "0.13.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha1-iSV0Kpj/2QgUmI11Zq0wyjsmO1I= - -regenerator-transform@^0.14.2: - version "0.14.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" - integrity sha1-yY2hVGg2ccnE3LFuznNlF+G3/rQ= - dependencies: - "@babel/runtime" "^7.8.4" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw= - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regex-parser@^2.2.11: - version "2.2.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" - integrity sha1-OzfskEnhlHmAboeMq+fByoPM/lg= - -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: - version "1.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" - integrity sha1-fvNSro0VnnWMDq3Kb4/LTu8HviY= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" - -regexpp@^3.1.0: - version "3.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha1-BCWido2PI7rXDKS5BGH6LxIT4bI= - -regexpu-core@^4.7.1: - version "4.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" - integrity sha1-5WBbo2G2excYR4UBMnUC9EeamPA= - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^9.0.0" - regjsgen "^0.5.2" - regjsparser "^0.7.0" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" - -regjsgen@^0.5.2: - version "0.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" - integrity sha1-kv8pX7He7L9uzaslQ9IH6RqjNzM= - -regjsparser@^0.7.0: - version "0.7.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" - integrity sha1-prZntUyIXhi1JVTLSWDvcRh+mWg= - dependencies: - jsesc "~0.5.0" - -relateurl@^0.2.7: - version "0.2.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= - -remark-external-links@^8.0.0: - version "8.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/remark-external-links/-/remark-external-links-8.0.0.tgz#308de69482958b5d1cd3692bc9b725ce0240f345" - integrity sha1-MI3mlIKVi10c02krybclzgJA80U= - dependencies: - extend "^3.0.0" - is-absolute-url "^3.0.0" - mdast-util-definitions "^4.0.0" - space-separated-tokens "^1.0.0" - unist-util-visit "^2.0.0" - -remark-footnotes@2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f" - integrity sha1-kAHEwv/rulVpXS3YD/uLgvfmMD8= - -remark-mdx@1.6.22: - version "1.6.22" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/remark-mdx/-/remark-mdx-1.6.22.tgz#06a8dab07dcfdd57f3373af7f86bd0e992108bbd" - integrity sha1-BqjasH3P3VfzNzr3+GvQ6ZIQi70= - dependencies: - "@babel/core" "7.12.9" - "@babel/helper-plugin-utils" "7.10.4" - "@babel/plugin-proposal-object-rest-spread" "7.12.1" - "@babel/plugin-syntax-jsx" "7.12.1" - "@mdx-js/util" "1.6.22" - is-alphabetical "1.0.4" - remark-parse "8.0.3" - unified "9.2.0" - -remark-parse@8.0.3: - version "8.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/remark-parse/-/remark-parse-8.0.3.tgz#9c62aa3b35b79a486454c690472906075f40c7e1" - integrity sha1-nGKqOzW3mkhkVMaQRykGB19Ax+E= - dependencies: - ccount "^1.0.0" - collapse-white-space "^1.0.2" - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - is-word-character "^1.0.0" - markdown-escapes "^1.0.0" - parse-entities "^2.0.0" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - trim "0.0.1" - trim-trailing-lines "^1.0.0" - unherit "^1.0.4" - unist-util-remove-position "^2.0.0" - vfile-location "^3.0.0" - xtend "^4.0.1" - -remark-slug@^6.0.0: - version "6.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/remark-slug/-/remark-slug-6.1.0.tgz#0503268d5f0c4ecb1f33315c00465ccdd97923ce" - integrity sha1-BQMmjV8MTssfMzFcAEZczdl5I84= - dependencies: - github-slugger "^1.0.0" - mdast-util-to-string "^1.0.0" - unist-util-visit "^2.0.0" - -remark-squeeze-paragraphs@4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz#76eb0e085295131c84748c8e43810159c5653ead" - integrity sha1-dusOCFKVExyEdIyOQ4EBWcVlPq0= - dependencies: - mdast-squeeze-paragraphs "^4.0.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -renderkid@^2.0.4: - version "2.0.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/renderkid/-/renderkid-2.0.7.tgz#464f276a6bdcee606f4a15993f9b29fc74ca8609" - integrity sha1-Rk8namvc7mBvShWZP5sp/HTKhgk= - dependencies: - css-select "^4.1.3" - dom-converter "^0.2.0" - htmlparser2 "^6.1.0" - lodash "^4.17.21" - strip-ansi "^3.0.1" - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha1-vmgVIIR6tYx1aKx1+/rSjtQtOek= - -repeat-string@^1.5.4, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request@^2.87.0, request@^2.88.2: - version "2.88.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha1-1zyRhzHLWofaBH4gcjQUb2ZNErM= - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha1-iaf92TgmEmcxjq/hT5wy5ZjDaQk= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs= - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - dependencies: - resolve-from "^3.0.0" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY= - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha1-w1IlhD3493bfIcV1V7wIfp39/Gk= - -resolve-url-loader@4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz#d50d4ddc746bb10468443167acf800dcd6c3ad57" - integrity sha1-1Q1N3HRrsQRoRDFnrPgA3NbDrVc= - dependencies: - adjust-sourcemap-loader "^4.0.0" - convert-source-map "^1.7.0" - loader-utils "^2.0.0" - postcss "^7.0.35" - source-map "0.6.1" - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@1.1.7: - version "1.1.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - -resolve@1.19.0: - version "1.19.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" - integrity sha1-GvW/YwQJc0oGfK4pMYqsf6KaJnw= - dependencies: - is-core-module "^2.1.0" - path-parse "^1.0.6" - -resolve@^1.1.5, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.3.2, resolve@^1.3.3: - version "1.20.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha1-YpoBP7P3B1XW8LeTXMHCxTeLGXU= - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -resolve@^1.17.0: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha1-OfZ8VLOnpYzqUjbZXPADQjljH34= - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w= - -retry@^0.10.0: - version "0.10.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" - integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= - -retry@^0.12.0: - version "0.12.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - -reusify@^1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY= - -rfdc@^1.1.4: - version "1.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha1-0LfEQasnINBdxM8m4ByJYx2doIs= - -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w== - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg== - -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho= - dependencies: - glob "^7.1.3" - -rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.3: - version "2.7.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w= - dependencies: - glob "^7.1.3" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha1-ocGm9iR1FXe6XQeRTLyShQWFiQw= - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -rollup-plugin-sourcemaps@^0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz#bf93913ffe056e414419607f1d02780d7ece84ed" - integrity sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw== - dependencies: - "@rollup/pluginutils" "^3.0.9" - source-map-resolve "^0.6.0" - -rollup@2.38.4: - version "2.38.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/rollup/-/rollup-2.38.4.tgz#1b84ea8728c73b1a00a6a6e9c630ec8c3fe48cea" - integrity sha1-G4TqhyjHOxoApqbpxjDsjD/kjOo= - optionalDependencies: - fsevents "~2.3.1" - -rollup@^2.37.0: - version "2.79.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" - integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== - optionalDependencies: - fsevents "~2.3.2" - -rsvp@^4.8.4: - version "4.8.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha1-yPFVMR0Wf2jyHhaN9x7FsIMRNzQ= - -run-async@^2.4.0: - version "2.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha1-hEDsz5nqPnC9QJ1JqriOEMGJpFU= - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha1-ZtE2jae9+SHrnZW9GpIp5/IaQ+4= - dependencies: - queue-microtask "^1.2.2" - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -rxjs@6.6.3: - version "6.6.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" - integrity sha1-jKhGNcTaqQDA05Z6buesYCce5VI= - dependencies: - tslib "^1.9.0" - -rxjs@^6.5.0, rxjs@^6.5.3, rxjs@^6.5.5, rxjs@^6.6.0: - version "6.6.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha1-kKwBisq/SRv2UEQjXVhjxNq4BMk= - dependencies: - tslib "^1.9.0" - -safe-buffer@5.1.1: - version "5.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - integrity sha1-iTMSr2myEj3vcfV4iQAWce6yyFM= - -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha1-mR7GnSluAxN0fVm9/St0XDX4go0= - -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY= - -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-regex "^1.1.4" - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@^2.1.2, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo= - -sane@^4.0.3: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha1-7Ygf2SJzOmxGG8GJ3CtsAG8//e0= - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - -sass-loader@10.1.1: - version "10.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sass-loader/-/sass-loader-10.1.1.tgz#4ddd5a3d7638e7949065dd6e9c7c04037f7e663d" - integrity sha1-Td1aPXY455SQZd1unHwEA39+Zj0= - dependencies: - klona "^2.0.4" - loader-utils "^2.0.0" - neo-async "^2.6.2" - schema-utils "^3.0.0" - semver "^7.3.2" - -sass-loader@^10.0.1: - version "10.4.1" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-10.4.1.tgz#bea4e173ddf512c9d7f53e9ec686186146807cbf" - integrity sha512-aX/iJZTTpNUNx/OSYzo2KsjIUQHqvWsAhhUijFjAPdZTEhstjZI9zTNvkTTwsx+uNUJqUwOw5gacxQMx4hJxGQ== - dependencies: - klona "^2.0.4" - loader-utils "^2.0.0" - neo-async "^2.6.2" - schema-utils "^3.0.0" - semver "^7.3.2" - -sass-loader@^10.1.0: - version "10.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sass-loader/-/sass-loader-10.2.0.tgz#3d64c1590f911013b3fa48a0b22a83d5e1494716" - integrity sha1-PWTBWQ+REBOz+kigsiqD1eFJRxY= - dependencies: - klona "^2.0.4" - loader-utils "^2.0.0" - neo-async "^2.6.2" - schema-utils "^3.0.0" - semver "^7.3.2" - -sass@1.32.6: - version "1.32.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sass/-/sass-1.32.6.tgz#e3646c8325cd97ff75a8a15226007f3ccd221393" - integrity sha1-42RsgyXNl/91qKFSJgB/PM0iE5M= - dependencies: - chokidar ">=2.0.0 <4.0.0" - -sass@^1.32.5: - version "1.57.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.57.1.tgz#dfafd46eb3ab94817145e8825208ecf7281119b5" - integrity sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw== - dependencies: - chokidar ">=3.0.0 <4.0.0" - immutable "^4.0.0" - source-map-js ">=0.6.2 <2.0.0" - -sass@^1.32.8: - version "1.45.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sass/-/sass-1.45.1.tgz#fa03951f924d1ba5762949567eaf660e608a1ab0" - integrity sha1-+gOVH5JNG6V2KUlWfq9mDmCKGrA= - dependencies: - chokidar ">=3.0.0 <4.0.0" - immutable "^4.0.0" - source-map-js ">=0.6.2 <2.0.0" - -saucelabs@^1.5.0: - version "1.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" - integrity sha1-lAWnPDYNRJsjKDmRmobDltN5/Z0= - dependencies: - https-proxy-agent "^2.2.1" - -sax@>=0.6.0, sax@^1.2.1, sax@^1.2.4, sax@~1.2.4: - version "1.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha1-KBYjTiN4vdxOU1T6tcqold9xANk= - -scheduler@^0.19.1: - version "0.19.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha1-Tz4u0sGn1laB9MhU+oxaHMtA8ZY= - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -schema-utils@2.7.0: - version "2.7.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" - integrity sha1-FxUfdtjq5n+793lgwzxnatn078c= - dependencies: - "@types/json-schema" "^7.0.4" - ajv "^6.12.2" - ajv-keywords "^3.4.1" - -schema-utils@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" - integrity sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A= - dependencies: - ajv "^6.1.0" - ajv-errors "^1.0.0" - ajv-keywords "^3.1.0" - -schema-utils@^2.6.5, schema-utils@^2.7.0: - version "2.7.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" - integrity sha1-HKTzLRskxZDCA7jnpQvw6kzTlNc= - dependencies: - "@types/json-schema" "^7.0.5" - ajv "^6.12.4" - ajv-keywords "^3.5.2" - -schema-utils@^3.0.0: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" - integrity sha1-vHTEtraZXB2I92qLd76nIZ4MgoE= - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -scope-analyzer@^2.0.1: - version "2.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/scope-analyzer/-/scope-analyzer-2.1.2.tgz#b958162feb59823c2835c7b0229187a97c77e9cd" - integrity sha1-uVgWL+tZgjwoNcewIpGHqXx36c0= - dependencies: - array-from "^2.1.1" - dash-ast "^2.0.1" - es6-map "^0.1.5" - es6-set "^0.1.5" - es6-symbol "^3.1.1" - estree-is-function "^1.0.0" - get-assigned-identifiers "^1.1.0" - -select-hose@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" - integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= - -selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: - version "3.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" - integrity sha1-K6h6FmLAILiYjJga5iyyoBKY6vw= - dependencies: - jszip "^3.1.3" - rimraf "^2.5.4" - tmp "0.0.30" - xml2js "^0.4.17" - -selfsigned@^1.10.8: - version "1.10.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9" - integrity sha1-JJKc2Qb+D0S20B+yOZmnOVN6y+k= - dependencies: - node-forge "^0.10.0" - -semver-dsl@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/semver-dsl/-/semver-dsl-1.0.1.tgz#d3678de5555e8a61f629eed025366ae5f27340a0" - integrity sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA= - dependencies: - semver "^5.3.0" - -semver-intersect@1.4.0: - version "1.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/semver-intersect/-/semver-intersect-1.4.0.tgz#bdd9c06bedcdd2fedb8cd352c3c43ee8c61321f3" - integrity sha1-vdnAa+3N0v7bjNNSw8Q+6MYTIfM= - dependencies: - semver "^5.0.0" - -"semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: - version "5.7.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc= - -semver@7.0.0: - version "7.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha1-XzyjV2HkfgWyBsba/yz4FPAxa44= - -semver@7.3.4: - version "7.3.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha1-J6qn0uTKdkUvmNOt0JOnLJQ+3Jc= - dependencies: - lru-cache "^6.0.0" - -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0= - -semver@^7.0.0, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: - version "7.3.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc= - dependencies: - lru-cache "^6.0.0" - -send@0.17.2, send@latest: - version "0.17.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" - integrity sha1-kmYi92YBxBgIASyL8WiP45BveCA= - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "1.8.1" - mime "1.6.0" - ms "2.1.3" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha1-tSXhI4SJpez8Qq+sw/6Z5mb0sao= - dependencies: - randombytes "^2.1.0" - -serialize-javascript@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" - integrity sha1-eIbshIBJpGJGepfT2Rjrsqr5NPQ= - dependencies: - randombytes "^2.1.0" - -serve-favicon@^2.5.0: - version "2.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/serve-favicon/-/serve-favicon-2.5.0.tgz#935d240cdfe0f5805307fdfe967d88942a2cbcf0" - integrity sha1-k10kDN/g9YBTB/3+ln2IlCosvPA= - dependencies: - etag "~1.8.1" - fresh "0.5.2" - ms "2.1.1" - parseurl "~1.3.2" - safe-buffer "5.1.1" - -serve-index@^1.9.1: - version "1.9.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" - integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= - dependencies: - accepts "~1.3.4" - batch "0.6.1" - debug "2.6.9" - escape-html "~1.0.3" - http-errors "~1.6.2" - mime-types "~2.1.17" - parseurl "~1.3.2" - -serve-static@1.14.2: - version "1.14.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" - integrity sha1-ci1ilLHWJibUG0OgE+zkWY0pK/o= - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.2" - -set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-immediate-shim@~1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha1-oY1AUw5vB95CKMfe/kInr4ytAFs= - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY= - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha1-ZsmiSnP5/CjL5msJ/tPTPcrxtCQ= - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc= - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" - integrity sha1-jymBrZJTH1UDWwH7IwdppA4C76M= - dependencies: - kind-of "^6.0.2" - -shallow-copy@~0.0.1: - version "0.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/shallow-copy/-/shallow-copy-0.0.1.tgz#415f42702d73d810330292cc5ee86eae1a11a170" - integrity sha1-QV9CcC1z2BAzApLMXuhurhoRoXA= - -shallowequal@^1.1.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" - integrity sha1-GI1SHelbkIdAT9TctosT3wrk5/g= - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo= - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI= - -shell-quote@1.7.2: - version "1.7.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" - integrity sha1-Z6fQLHbJ2iT5nSCAj8re0ODgS+I= - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha1-785cj9wQTudRslxY1CkAEfpeos8= - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" - integrity sha1-JOYwxLDwP+pEaivSmeYrSmyo0K8= - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== - dependencies: - is-arrayish "^0.3.1" - -sirv@^1.0.7: - version "1.0.19" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49" - integrity sha1-HXOXmzjH/pH8uknIUoDaqcI2O0k= - dependencies: - "@polka/url" "^1.0.0-next.20" - mrmime "^1.0.0" - totalist "^1.0.0" - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha1-E01oEpd1ZDfMBcoBNw06elcQde0= - -slash@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q= - -slash@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ= - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha1-UA6N0P1VsFgVCGJVsxla3ypF/ms= - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -smart-buffer@^4.1.0: - version "4.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" - integrity sha1-bh1x+k8YwF99D/IW3RakgdDo2a4= - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha1-bBdfhv8UvbByRWPo88GwIaKGhTs= - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI= - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0= - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -socket.io-adapter@~1.1.0: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" - integrity sha1-qz8Nb2a4/H/KOVmrWZH4IiF4m+k= - -socket.io-client@2.4.0: - version "2.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/socket.io-client/-/socket.io-client-2.4.0.tgz#aafb5d594a3c55a34355562fc8aea22ed9119a35" - integrity sha1-qvtdWUo8VaNDVVYvyK6iLtkRmjU= - dependencies: - backo2 "1.0.2" - component-bind "1.0.0" - component-emitter "~1.3.0" - debug "~3.1.0" - engine.io-client "~3.5.0" - has-binary2 "~1.0.2" - indexof "0.0.1" - parseqs "0.0.6" - parseuri "0.0.6" - socket.io-parser "~3.3.0" - to-array "0.1.4" - -socket.io-parser@~3.3.0: - version "3.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6" - integrity sha1-74cgCdCtz3BPL76DAZGhR1KtULY= - dependencies: - component-emitter "~1.3.0" - debug "~3.1.0" - isarray "2.0.1" - -socket.io-parser@~3.4.0: - version "3.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/socket.io-parser/-/socket.io-parser-3.4.1.tgz#b06af838302975837eab2dc980037da24054d64a" - integrity sha1-sGr4ODApdYN+qy3JgAN9okBU1ko= - dependencies: - component-emitter "1.2.1" - debug "~4.1.0" - isarray "2.0.1" - -socket.io@^2.3.0: - version "2.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/socket.io/-/socket.io-2.4.1.tgz#95ad861c9a52369d7f1a68acf0d4a1b16da451d2" - integrity sha1-la2GHJpSNp1/Gmis8NShsW2kUdI= - dependencies: - debug "~4.1.0" - engine.io "~3.5.0" - has-binary2 "~1.0.2" - socket.io-adapter "~1.1.0" - socket.io-client "2.4.0" - socket.io-parser "~3.4.0" - -sockjs-client@^1.5.0: - version "1.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sockjs-client/-/sockjs-client-1.5.2.tgz#4bc48c2da9ce4769f19dc723396b50f5c12330a3" - integrity sha1-S8SMLanOR2nxnccjOWtQ9cEjMKM= - dependencies: - debug "^3.2.6" - eventsource "^1.0.7" - faye-websocket "^0.11.3" - inherits "^2.0.4" - json3 "^3.3.3" - url-parse "^1.5.3" - -sockjs@^0.3.21: - version "0.3.24" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" - integrity sha1-ybyJlfM6ERvqA5XsMKoyBr21zM4= - dependencies: - faye-websocket "^0.11.3" - uuid "^8.3.2" - websocket-driver "^0.7.4" - -socks-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" - integrity sha1-Ay+1gwSKKev/7C5qc/ygdh9IF34= - dependencies: - agent-base "^6.0.2" - debug "4" - socks "^2.3.3" - -socks@^2.3.3: - version "2.6.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" - integrity sha1-mJ5lNKB88zfesbHJSqpEKWUg0w4= - dependencies: - ip "^1.1.5" - smart-buffer "^4.1.0" - -source-list-map@^2.0.0, source-list-map@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha1-OZO9hzv8SEecyp6jpUeDXHwVSzQ= - -"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" - integrity sha1-oXQcEx48d9BIJSrfok4juQhnDK8= - -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - -source-map-loader@1.1.3: - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map-loader/-/source-map-loader-1.1.3.tgz#7dbc2fe7ea09d3e43c51fd9fc478b7f016c1f820" - integrity sha1-fbwv5+oJ0+Q8Uf2fxHi38BbB+CA= - dependencies: - abab "^2.0.5" - iconv-lite "^0.6.2" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - source-map "^0.6.1" - whatwg-mimetype "^2.3.0" - -source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: - version "0.5.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha1-GQhmvs51U+H48mei7oLGBrVQmho= - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-resolve@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" - integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - -source-map-support@0.5.19: - version "0.5.19" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha1-qYti+G3K9PZzmWSMCFKRq56P7WE= - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@^0.5.16, source-map-support@^0.5.17, source-map-support@^0.5.5, source-map-support@~0.5.12, source-map-support@~0.5.19, source-map-support@~0.5.20: - version "0.5.21" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha1-BP58f54e0tZiIzwoyys1ufY/bk8= - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@~0.4.0: - version "0.4.18" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8= - dependencies: - source-map "^0.5.6" - -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha1-CvZmBadFpaL5HPG7+KevvCg97FY= - -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: - version "0.6.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= - -source-map@0.7.3, source-map@^0.7.3, source-map@~0.7.2: - version "0.7.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha1-UwL4FpAxc1ImVECS5kmB91F1A4M= - -source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: - version "0.5.7" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@~0.1.30: - version "0.1.43" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" - integrity sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y= - dependencies: - amdefine ">=0.0.4" - -sourcemap-codec@^1.4.1, sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8: - version "1.4.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha1-6oBL2UhXQC5pktBaOO8a41qatMQ= - -space-separated-tokens@^1.0.0: - version "1.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" - integrity sha1-hfMsPRDZaCAH6RdBTdxcJtGqaJk= - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha1-3s6BrJweZxPl99G28X1Gj6U9iak= - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha1-PyjOGnegA3JoPq3kpDMYNSeiFj0= - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha1-z3D1BILu/cmOPOCmgz5KU87rpnk= - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" - integrity sha1-UMDYxAoU7Bv0Sbrmmg6kaFqdn5U= - -spdy-transport@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" - integrity sha1-ANSGOmQArXXfkzYaFghgXl3NzzE= - dependencies: - debug "^4.1.0" - detect-node "^2.0.4" - hpack.js "^2.1.6" - obuf "^1.1.2" - readable-stream "^3.0.6" - wbuf "^1.7.3" - -spdy@^4.0.2: - version "4.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" - integrity sha1-t09GYgOj7aRSwCSSuR+56EonZ3s= - dependencies: - debug "^4.1.0" - handle-thing "^2.0.0" - http-deceiver "^1.2.7" - select-hose "^2.0.0" - spdy-transport "^3.0.0" - -speed-measure-webpack-plugin@1.4.2: - version "1.4.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.4.2.tgz#1608e62d3bdb45f01810010e1b5bfedefedfa58f" - integrity sha1-FgjmLTvbRfAYEAEOG1v+3v7fpY8= - dependencies: - chalk "^4.1.0" - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha1-fLCd2jqGWFcFxks5pkZgOGguj+I= - dependencies: - extend-shallow "^3.0.0" - -split@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - integrity sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k= - dependencies: - through "2" - -sprintf-js@^1.1.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" - integrity sha1-2hdlJiv4wPVxdJ8q1sJjACB65nM= - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha1-+2YcC+8ps520B2nuOfpwCT1vaHc= - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -ssri@^6.0.1: - version "6.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" - integrity sha1-FXk5E08gRk5zAd26PpD/qPdyisU= - dependencies: - figgy-pudding "^3.5.1" - -ssri@^8.0.0, ssri@^8.0.1: - version "8.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha1-Y45OQ54v+9LNKJd21cpFfE9Roq8= - dependencies: - minipass "^3.1.1" - -stable@^0.1.8: - version "0.1.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88= - -state-toggle@^1.0.0: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" - integrity sha1-4SOxaojhQxObCcaFIiG8mBWRff4= - -static-eval@^2.0.5: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/static-eval/-/static-eval-2.1.0.tgz#a16dbe54522d7fa5ef1389129d813fd47b148014" - integrity sha1-oW2+VFItf6XvE4kSnYE/1HsUgBQ= - dependencies: - escodegen "^1.11.1" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -static-module@^3.0.2: - version "3.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/static-module/-/static-module-3.0.4.tgz#bfbd1d1c38dd1fbbf0bb4af0c1b3ae18a93a2b68" - integrity sha1-v70dHDjdH7vwu0rwwbOuGKk6K2g= - dependencies: - acorn-node "^1.3.0" - concat-stream "~1.6.0" - convert-source-map "^1.5.1" - duplexer2 "~0.1.4" - escodegen "^1.11.1" - has "^1.0.1" - magic-string "0.25.1" - merge-source-map "1.0.4" - object-inspect "^1.6.0" - readable-stream "~2.3.3" - scope-analyzer "^2.0.1" - shallow-copy "~0.0.1" - static-eval "^2.0.5" - through2 "~2.0.3" - -"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -store2@^2.12.0: - version "2.13.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/store2/-/store2-2.13.1.tgz#fae7b5bb9d35fc53dc61cd262df3abb2f6e59022" - integrity sha1-+ue1u501/FPcYc0mLfOrsvblkCI= - -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha1-h1IdOKRKp+6RzhzSpH3wy0ndZgs= - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-combiner@^0.2.2: - version "0.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" - integrity sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg= - dependencies: - duplexer "~0.1.1" - through "~2.3.4" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha1-6+J6DDibBPvMIzZClS4Qcxr6m64= - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha1-stJCRpKIpaJ+xP6JM6z2I95lFPw= - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha1-1wiCgVWasneEJCebCHfaPDktWj0= - -streamroller@^2.2.4: - version "2.2.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53" - integrity sha1-wZjO1C25QIamGTYIGHzoCl8rDlM= - dependencies: - date-format "^2.1.0" - debug "^4.1.1" - fs-extra "^8.1.0" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: - version "4.2.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA= - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha1-InZ74htirxCBV0MG9prFG2IgOWE= - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -"string.prototype.matchall@^4.0.0 || ^3.0.1": - version "4.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" - integrity sha1-Wrtdq8lMew6iOA9lumELOlRLFfo= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" - side-channel "^1.0.4" - -string.prototype.padend@^3.0.0: - version "3.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz#997a6de12c92c7cb34dc8a201a6c53d9bd88a5f1" - integrity sha1-mXpt4SySx8s03IogGmxT2b2IpfE= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -string.prototype.padstart@^3.0.0: - version "3.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string.prototype.padstart/-/string.prototype.padstart-3.1.3.tgz#4551d0117d9501692ec6000b15056ac3f816cfa5" - integrity sha1-RVHQEX2VAWkuxgALFQVqw/gWz6U= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha1-51rpDClCxjUEaGwYsoe0oLGkX4A= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha1-s2OZr0qymZtMnGSL16P7K7Jv7u0= - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string_decoder@^1.0.0, string_decoder@^1.1.1: - version "1.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4= - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha1-nPFhG6YmhdcDCunkujQUnDrwP8g= - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@6.0.0: - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI= - dependencies: - ansi-regex "^5.0.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4= - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk= - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0= - -strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY= - -style-loader@2.0.0, style-loader@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c" - integrity sha1-lmlgL9RpB0DqrsE3eZoDrdu8OTw= - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -style-loader@^1.3.0: - version "1.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" - integrity sha1-gotKOzt+eqWEfOe66eh0USEUJJ4= - dependencies: - loader-utils "^2.0.0" - schema-utils "^2.7.0" - -style-to-object@0.3.0, style-to-object@^0.3.0: - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" - integrity sha1-sbeQ0gWZHMeDgBlnIUl57hmnbkY= - dependencies: - inline-style-parser "0.1.1" - -stylehacks@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" - integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -stylehacks@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb" - integrity sha1-Mj7FVBmFIJhoBjiMf9rrw40sBvs= - dependencies: - browserslist "^4.16.0" - postcss-selector-parser "^6.0.4" - -stylus-loader@4.3.3: - version "4.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/stylus-loader/-/stylus-loader-4.3.3.tgz#381bb6341272ac50bcdfd0b877707eac99b6b757" - integrity sha1-OBu2NBJyrFC839C4d3B+rJm2t1c= - dependencies: - fast-glob "^3.2.4" - klona "^2.0.4" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - schema-utils "^3.0.0" - -stylus@0.54.8, stylus@^0.54.8: - version "0.54.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147" - integrity sha1-PaPmWWa8Vnp7BEv+DuzmU+CZ0Uc= - dependencies: - css-parse "~2.0.0" - debug "~3.1.0" - glob "^7.1.6" - mkdirp "~1.0.4" - safer-buffer "^2.1.2" - sax "~1.2.4" - semver "^6.3.0" - source-map "^0.7.3" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha1-4uaaRKyHcveKHsCzW2id9lMO/I8= - dependencies: - has-flag "^3.0.0" - -supports-color@^6.1.0: - version "6.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha1-B2Srxpxj1ayELdSGfo0CXogN+PM= - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha1-G33NyzK4E4gBs+R4umpRyqiWSNo= - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -svgo@^1.0.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" - integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== - dependencies: - chalk "^2.4.1" - coa "^2.0.2" - css-select "^2.0.0" - css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.37" - csso "^4.0.2" - js-yaml "^3.13.1" - mkdirp "~0.5.1" - object.values "^1.1.0" - sax "~1.2.4" - stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" - -svgo@^2.7.0: - version "2.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" - integrity sha1-T/gMzmcQ3CeV8MfHQQHmdkz8zSQ= - dependencies: - "@trysound/sax" "0.2.0" - commander "^7.2.0" - css-select "^4.1.3" - css-tree "^1.1.3" - csso "^4.2.0" - picocolors "^1.0.0" - stable "^0.1.8" - -symbol-observable@3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/symbol-observable/-/symbol-observable-3.0.0.tgz#eea8f6478c651018e059044268375c408c15c533" - integrity sha1-7qj2R4xlEBjgWQRCaDdcQIwVxTM= - -symbol.prototype.description@^1.0.0: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/symbol.prototype.description/-/symbol.prototype.description-1.0.5.tgz#d30e01263b6020fbbd2d2884a6276ce4d49ab568" - integrity sha1-0w4BJjtgIPu9LSiEpids5NSatWg= - dependencies: - call-bind "^1.0.2" - get-symbol-description "^1.0.0" - has-symbols "^1.0.2" - object.getownpropertydescriptors "^2.1.2" - -sync-rpc@^1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/sync-rpc/-/sync-rpc-1.3.6.tgz#b2e8b2550a12ccbc71df8644810529deb68665a7" - integrity sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw== - dependencies: - get-port "^3.1.0" - -synchronous-promise@^2.0.15: - version "2.0.15" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/synchronous-promise/-/synchronous-promise-2.0.15.tgz#07ca1822b9de0001f5ff73595f3d08c4f720eb8e" - integrity sha1-B8oYIrneAAH1/3NZXz0IxPcg644= - -table@^6.0.9: - version "6.7.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/table/-/table-6.7.5.tgz#f04478c351ef3d8c7904f0e8be90a1b62417d238" - integrity sha1-8ER4w1HvPYx5BPDovpChtiQX0jg= - dependencies: - ajv "^8.0.1" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - -tapable@^1.0.0, tapable@^1.1.3: - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" - integrity sha1-ofzMBrWNth/XpF2i2kT186Pme6I= - -tapable@^2.2.0: - version "2.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha1-GWenPvQGCoLxKrlq+G1S/bdu7KA= - -tar@^6.0.2, tar@^6.1.0: - version "6.1.11" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" - integrity sha1-Z2CjjwA6+hsv/Q/+npq70Oqz1iE= - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -telejson@^5.3.2, telejson@^5.3.3: - version "5.3.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/telejson/-/telejson-5.3.3.tgz#fa8ca84543e336576d8734123876a9f02bf41d2e" - integrity sha1-+oyoRUPjNldthzQSOHap8Cv0HS4= - dependencies: - "@types/is-function" "^1.0.0" - global "^4.4.0" - is-function "^1.0.2" - is-regex "^1.1.2" - is-symbol "^1.0.3" - isobject "^4.0.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - -terser-webpack-plugin@4.2.3, terser-webpack-plugin@^4.2.3: - version "4.2.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a" - integrity sha1-KNrvSoO9F8HbApcHCtwH/Iz8apo= - dependencies: - cacache "^15.0.5" - find-cache-dir "^3.3.1" - jest-worker "^26.5.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - source-map "^0.6.1" - terser "^5.3.4" - webpack-sources "^1.4.3" - -terser-webpack-plugin@^1.4.3: - version "1.4.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" - integrity sha1-oheu+uozDnNP+sthIOwfoxLWBAs= - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - -terser@5.5.1: - version "5.5.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289" - integrity sha1-VAyqJROdb0lv3qBW5BQoSIb7Iok= - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.19" - -terser@^4.1.2, terser@^4.6.3: - version "4.8.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha1-YwVjQ9fHC7KfOvZlhlpG/gOg3xc= - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -terser@^5.3.4: - version "5.10.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" - integrity sha1-uGOQgJwDiRBesKC2I5dWMJbdr8w= - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.20" - -terser@^5.5.1: - version "5.16.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.1.tgz#5af3bc3d0f24241c7fb2024199d5c461a1075880" - integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw== - dependencies: - "@jridgewell/source-map" "^0.3.2" - acorn "^8.5.0" - commander "^2.20.0" - source-map-support "~0.5.20" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha1-BKhphmHYBepvopO2y55jrARO8V4= - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-table@0.2.0, text-table@^0.2.0: - version "0.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -throttle-debounce@^3.0.1: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb" - integrity sha1-MvlNhN+olPeGyaHykOemRbahmrs= - -through2@^2.0.0, through2@~2.0.3: - version "2.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0= - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through@2, through@X.X.X, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.4: - version "2.3.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -thunky@^1.0.2: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" - integrity sha1-Wrr3FKlAXbBQRzK7zNLO3Z75U30= - -time-stamp@^1.0.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" - integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= - -timers-browserify@^2.0.4: - version "2.0.12" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" - integrity sha1-RKRcEfv0B/NPl7zNFXfGUjYbAO4= - dependencies: - setimmediate "^1.0.4" - -timsort@^0.3.0: - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - -tiny-inflate@^1.0.0, tiny-inflate@^1.0.2: - version "1.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4" - integrity sha1-EicVSUkToYBRZqr3yTRnkz7qJsQ= - -tmp@0.0.30: - version "0.0.30" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" - integrity sha1-ckGdSovn1s51FI/YsyTlk6cRwu0= - dependencies: - os-tmpdir "~1.0.1" - -tmp@0.2.1: - version "0.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha1-hFf8MDfc9HGcJRNnoa9lAO4czxQ= - dependencies: - rimraf "^3.0.0" - -tmp@^0.0.33: - version "0.0.33" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha1-bTQzWIl2jSGyvNoKonfO07G/rfk= - dependencies: - os-tmpdir "~1.0.2" - -tmpl@1.0.5: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha1-hoPguQK7nCDE9ybjwLafNlGMB8w= - -to-array@0.1.4: - version "0.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" - integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ= - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4= - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toggle-selection@^1.0.6: - version "1.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" - integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha1-O+NDIaiKgg7RvYDfqjPkefu43TU= - -totalist@^1.0.0: - version "1.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" - integrity sha1-pNZaPlRlF3AePlw3pHpwrJf+Vt8= - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha1-zZ+yoKodWhK0c72fuW+j3P9lreI= - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - -traverse@^0.6.6: - version "0.6.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" - integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= - -tree-kill@1.2.2: - version "1.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" - integrity sha1-TKCakJLIi3OnzcXooBtQeweQoMw= - -trim-trailing-lines@^1.0.0: - version "1.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz#bd4abbec7cc880462f10b2c8b5ce1d8d1ec7c2c0" - integrity sha1-vUq77HzIgEYvELLItc4djR7HwsA= - -trim@0.0.1: - version "0.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" - integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= - -trough@^1.0.0: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" - integrity sha1-uLY5zvrX0LsqvTfUM/+Ck++l9AY= - -ts-dedent@^2.0.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" - integrity sha1-OeS9KXzQNikq4jlOs0Er5j9WO7U= - -ts-loader@^8.0.14: - version "8.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ts-loader/-/ts-loader-8.3.0.tgz#83360496d6f8004fab35825279132c93412edf33" - integrity sha1-gzYEltb4AE+rNYJSeRMsk0Eu3zM= - dependencies: - chalk "^4.1.0" - enhanced-resolve "^4.0.0" - loader-utils "^2.0.0" - micromatch "^4.0.0" - semver "^7.3.4" - -ts-morph@^13.0.1: - version "13.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ts-morph/-/ts-morph-13.0.2.tgz#55546023493ef82389d9e4f28848a556c784bac4" - integrity sha1-VVRgI0k++COJ2eTyiEilVseEusQ= - dependencies: - "@ts-morph/common" "~0.12.2" - code-block-writer "^11.0.0" - -ts-node@~9.0.0: - version "9.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ts-node/-/ts-node-9.0.0.tgz#e7699d2a110cc8c0d3b831715e417688683460b3" - integrity sha1-52mdKhEMyMDTuDFxXkF2iGg0YLM= - dependencies: - arg "^4.1.0" - diff "^4.0.1" - make-error "^1.1.1" - source-map-support "^0.5.17" - yn "3.1.1" - -ts-pnp@^1.1.6: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" - integrity sha1-pQCtCEsHmPHDBxrzkeZZEshrypI= - -tsconfig-paths-webpack-plugin@^3.3.0: - version "3.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz#01aafff59130c04a8c4ebc96a3045c43c376449a" - integrity sha1-Aar/9ZEwwEqMTryWowRcQ8N2RJo= - dependencies: - chalk "^4.1.0" - enhanced-resolve "^5.7.0" - tsconfig-paths "^3.9.0" - -tsconfig-paths@^3.9.0: - version "3.12.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" - integrity sha1-GXaaym7o9qGjQeOMj6Rd2fsYiZs= - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - -tslib@2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" - integrity sha1-2mCGDxwuyqVwOrfTm8Bba/mIuXo= - -tslib@2.3.1, tslib@^2.0.0, tslib@^2.0.3, tslib@^2.2.0, tslib@^2.3.0: - version "2.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha1-6KM1rdXOrlGqJh0ypJAVjvBC7wE= - -tslib@^1.10.0, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.14.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha1-zy04vcNKE0vK8QkcQfZhni9nLQA= - -tslint@~6.1.0: - version "6.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904" - integrity sha1-XCOy7MwySH1VI706Rw6aoxeJ2QQ= - dependencies: - "@babel/code-frame" "^7.0.0" - builtin-modules "^1.1.1" - chalk "^2.3.0" - commander "^2.12.1" - diff "^4.0.1" - glob "^7.1.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - mkdirp "^0.5.3" - resolve "^1.3.2" - semver "^5.3.0" - tslib "^1.13.0" - tsutils "^2.29.0" - -tsutils@^2.29.0: - version "2.29.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" - integrity sha1-MrSIUBRnrL7dS4VJhnOggSrKC5k= - dependencies: - tslib "^1.8.1" - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha1-B7ggO/pwVsBlcFDjzNLDdzC6uPE= - dependencies: - prelude-ls "^1.2.1" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha1-G/IH9LKPkVg2ZstfvTJ4hzAc1fQ= - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha1-0mCiSwGYQ24TP6JqUkptZfo7Ljc= - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha1-jSojcNPfiG61yQraHFv2GIrPg4s= - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha1-CeJJ696FHTseSNJ8EFREZn8XuD0= - -type-is@~1.6.18: - version "1.6.18" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha1-TlUs0F3wlGfcvE73Od6J8s83wTE= - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -type@^1.0.1: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha1-hI3XaY2vo+VKbEeedZxLw/GIR6A= - -type@^2.5.0: - version "2.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d" - integrity sha1-Ci54wud5B7JSq+XymMGwHGPw2z0= - -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - is-typed-array "^1.1.9" - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha1-qX7nqf9CaRufeD/xvFES/j/KkIA= - dependencies: - is-typedarray "^1.0.0" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -typescript@4.1.5: - version "4.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/typescript/-/typescript-4.1.5.tgz#123a3b214aaff3be32926f0d8f1f6e704eb89a72" - integrity sha1-Ejo7IUqv874ykm8Njx9ucE64mnI= - -typescript@^4.0.3: - version "4.5.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" - integrity sha1-oX06AmO/XIcjucUvQ8UITt8Twug= - -typescript@~4.0.2: - version "4.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/typescript/-/typescript-4.0.8.tgz#5739105541db80a971fdbd0d56511d1a6f17d37f" - integrity sha1-VzkQVUHbgKlx/b0NVlEdGm8X038= - -ua-parser-js@0.7.22: - version "0.7.22" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ua-parser-js/-/ua-parser-js-0.7.22.tgz#960df60a5f911ea8f1c818f3747b99c6e177eae3" - integrity sha1-lg32Cl+RHqjxyBjzdHuZxuF36uM= - -uglify-js@^3.1.4: - version "3.14.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/uglify-js/-/uglify-js-3.14.5.tgz#cdabb7d4954231d80cb4a927654c4655e51f4859" - integrity sha1-zau31JVCMdgMtKknZUxGVeUfSFk= - -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha1-CF4hViXsMWJXTciFmr7nilmxRHE= - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - -unfetch@^4.2.0: - version "4.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" - integrity sha1-fiGw7302PY2a8PuSmlVV9u+Xo74= - -unherit@^1.0.4: - version "1.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" - integrity sha1-bJtQPytBsmIzDIDpHIYUq9qmnCI= - dependencies: - inherits "^2.0.0" - xtend "^4.0.0" - -unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" - integrity sha1-MBrNxSVjFnDTn2FG4Od/9rvevdw= - -unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" - integrity sha1-VP0W4OyxZ88Ezx91a9zJLrp5dsM= - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - -unicode-match-property-value-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" - integrity sha1-GgGqVyR8FMVouJd1pUk4eIGJpxQ= - -unicode-properties@^1.2.2: - version "1.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unicode-properties/-/unicode-properties-1.3.1.tgz#cc642b6314bde2c691d65dd94cece09ed84f1282" - integrity sha1-zGQrYxS94saR1l3ZTOzgnthPEoI= - dependencies: - base64-js "^1.3.0" - unicode-trie "^2.0.0" - -unicode-property-aliases-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" - integrity sha1-CjbLmlhcT2q9Ua0d7dsoXBZSl8g= - -unicode-trie@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unicode-trie/-/unicode-trie-2.0.0.tgz#8fd8845696e2e14a8b67d78fa9e0dd2cad62fec8" - integrity sha1-j9iEVpbi4UqLZ9ePqeDdLK1i/sg= - dependencies: - pako "^0.2.5" - tiny-inflate "^1.0.0" - -unified@9.2.0: - version "9.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unified/-/unified-9.2.0.tgz#67a62c627c40589edebbf60f53edfd4d822027f8" - integrity sha1-Z6YsYnxAWJ7eu/YPU+39TYIgJ/g= - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^2.0.0" - trough "^1.0.0" - vfile "^4.0.0" - -union-value@^1.0.0: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha1-C2/nuDWuzaYcbqTU8CwUIh4QmEc= - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA== - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha512-mZdDpf3vBV5Efh29kMw5tXoup/buMgxLzOt/XKFKcVmi+15ManNQWr6HfZ2aiZTYlYixbdNJ0KFmIZIv52tHSQ== - -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha1-HWl2k2mtoFgxA6HmrodoG1ZXMjA= - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha1-uqvOkQg/xk6UWw861hPiZPfNTmw= - dependencies: - imurmurhash "^0.1.4" - -unist-builder@2.0.3, unist-builder@^2.0.0: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" - integrity sha1-d2SHEbXYavCULzNDl6M8XpFRZDY= - -unist-util-generated@^1.0.0: - version "1.1.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" - integrity sha1-WrUfaJ4pkqRyvrGzXyzn/y8yTUs= - -unist-util-is@^4.0.0: - version "4.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" - integrity sha1-l25fRip6Xec9lLcGusG5BnG1d5c= - -unist-util-position@^3.0.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" - integrity sha1-HELuYwH41S9H0U9iu9t5ZXH6LUc= - -unist-util-remove-position@^2.0.0: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc" - integrity sha1-XRnKef26cSMBmZsrc1U8qPOzUsw= - dependencies: - unist-util-visit "^2.0.0" - -unist-util-remove@^2.0.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unist-util-remove/-/unist-util-remove-2.1.0.tgz#b0b4738aa7ee445c402fda9328d604a02d010588" - integrity sha1-sLRziqfuRFxAL9qTKNYEoC0BBYg= - dependencies: - unist-util-is "^4.0.0" - -unist-util-stringify-position@^2.0.0: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" - integrity sha1-zOO/oc34W6c3XR1bF73Eytqb2do= - dependencies: - "@types/unist" "^2.0.2" - -unist-util-visit-parents@^3.0.0: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" - integrity sha1-ZabOaY94prD1aqDojxOAGIbNrvY= - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^4.0.0" - -unist-util-visit@2.0.3, unist-util-visit@^2.0.0: - version "2.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c" - integrity sha1-w3A4kxRt9HIDu4qXla9H17lxIIw= - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^4.0.0" - unist-util-visit-parents "^3.0.0" - -universal-analytics@0.4.23: - version "0.4.23" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/universal-analytics/-/universal-analytics-0.4.23.tgz#d915e676850c25c4156762471bdd7cf2eaaca8ac" - integrity sha1-2RXmdoUMJcQVZ2JHG9188uqsqKw= - dependencies: - debug "^4.1.1" - request "^2.88.2" - uuid "^3.0.0" - -universalify@^0.1.0: - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY= - -universalify@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc= - -unix-crypt-td-js@^1.1.4: - version "1.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unix-crypt-td-js/-/unix-crypt-td-js-1.1.4.tgz#4912dfad1c8aeb7d20fa0a39e4c31918c1d5d5dd" - integrity sha1-SRLfrRyK630g+go55MMZGMHV1d0= - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg== - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.1.1: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha1-j2bbzVWog6za5ECK+LA1pQRMGJQ= - -update-browserslist-db@^1.0.9: - version "1.0.10" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" - integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha1-mxpSWVIlhZ5V9mnZKPiMbFfyp34= - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-loader@^4.1.1: - version "4.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" - integrity sha1-KFBekFyuFYzwfJLKYi1/I35wpOI= - dependencies: - loader-utils "^2.0.0" - mime-types "^2.1.27" - schema-utils "^3.0.0" - -url-parse@^1.4.3, url-parse@^1.5.3: - version "1.5.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/url-parse/-/url-parse-1.5.4.tgz#e4f645a7e2a0852cc8a66b14b292a3e9a11a97fd" - integrity sha1-5PZFp+KghSzIpmsUspKj6aEal/0= - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -url@^0.11.0: - version "0.11.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use-composed-ref@^1.0.0: - version "1.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849" - integrity sha1-m9y1zNiUKJEF2iMl4SEAefVr+Ek= - -use-isomorphic-layout-effect@^1.0.0: - version "1.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225" - integrity sha1-e7ZYkXDNKYehUgQvkIT57/t1wiU= - -use-latest@^1.0.0: - version "1.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232" - integrity sha1-pE9lcrgojgly7EEb3QhAraNm8jI= - dependencies: - use-isomorphic-layout-effect "^1.0.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8= - -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -util.promisify@1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - integrity sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA= - dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" - -util.promisify@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" - integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.2" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.0" - -util@0.10.3: - version "0.10.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -util@^0.11.0: - version "0.11.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha1-MjZzNyDsZLsn9uJvQhqqLhtYjWE= - dependencies: - inherits "2.0.3" - -utila@~0.4: - version "0.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid-browser@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/uuid-browser/-/uuid-browser-3.1.0.tgz#0f05a40aef74f9e5951e20efbf44b11871e56410" - integrity sha1-DwWkCu90+eWVHiDvv0SxGHHlZBA= - -uuid@8.3.2, uuid@^8.3.2: - version "8.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha1-gNW1ztJxu5r2xEXyGhoExgbO++I= - -uuid@^3.0.0, uuid@^3.3.2, uuid@^3.4.0: - version "3.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4= - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4= - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha1-/JH2uce6FchX9MssXe/uw51PQQo= - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -validate-npm-package-name@^3.0.0: - version "3.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" - integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= - dependencies: - builtins "^1.0.3" - -vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -vendors@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" - integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== - -verror@1.10.0: - version "1.10.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vfile-location@^3.0.0, vfile-location@^3.2.0: - version "3.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c" - integrity sha1-2OQfvL1AYGNmnr9sM9Vq6HIdDzw= - -vfile-message@^2.0.0: - version "2.0.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" - integrity sha1-W0O4gXHUCerlhHfRPyPdQdUsNxo= - dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position "^2.0.0" - -vfile@^4.0.0: - version "4.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" - integrity sha1-A/Hc4o/GJcYlvGUUNQ+9sA+p5iQ= - dependencies: - "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^2.0.0" - vfile-message "^2.0.0" - -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha1-eGQcSIuObKkadfUR56OzKobl3aA= - -void-elements@^2.0.0: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" - integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= - -walker@^1.0.7, walker@~1.0.5: - version "1.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha1-vUmNtHev5XPcBBhfAR06uKjXZT8= - dependencies: - makeerror "1.0.12" - -warning@^4.0.2: - version "4.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" - integrity sha1-Fungd+uKhtavfWSqHgX9hbRnjKM= - dependencies: - loose-envify "^1.0.0" - -watchpack-chokidar2@^2.0.1: - version "2.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" - integrity sha1-OFAAcu5uzmbzdpk2lQ6hdxvhyVc= - dependencies: - chokidar "^2.1.8" - -watchpack@^1.7.4: - version "1.7.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" - integrity sha1-EmfmxV4Lm1vkTCAjrtVDeiwmxFM= - dependencies: - graceful-fs "^4.1.2" - neo-async "^2.5.0" - optionalDependencies: - chokidar "^3.4.1" - watchpack-chokidar2 "^2.0.1" - -watchpack@^2.2.0: - version "2.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" - integrity sha1-QgDZRHtAEVbuyndn7mEPiAm8nSU= - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - -wbuf@^1.1.0, wbuf@^1.7.3: - version "1.7.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" - integrity sha1-wdjRSTFtPqhShIiVy2oL/oh7h98= - dependencies: - minimalistic-assert "^1.0.0" - -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - -web-namespaces@^1.0.0: - version "1.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" - integrity sha1-vJij3mDa3X+u/EA9EHbVKfXgMOw= - -webdriver-js-extender@2.1.0: - version "2.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz#57d7a93c00db4cc8d556e4d3db4b5db0a80c3bb7" - integrity sha1-V9epPADbTMjVVuTT20tdsKgMO7c= - dependencies: - "@types/selenium-webdriver" "^3.0.0" - selenium-webdriver "^3.0.1" - -webdriver-manager@^12.1.7: - version "12.1.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webdriver-manager/-/webdriver-manager-12.1.8.tgz#5e70e73eaaf53a0767d5745270addafbc5905fd4" - integrity sha1-XnDnPqr1Ogdn1XRScK3a+8WQX9Q= - dependencies: - adm-zip "^0.4.9" - chalk "^1.1.1" - del "^2.2.0" - glob "^7.0.3" - ini "^1.3.4" - minimist "^1.2.0" - q "^1.4.1" - request "^2.87.0" - rimraf "^2.5.2" - semver "^5.3.0" - xml2js "^0.4.17" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - -webpack-bundle-analyzer@^4.1.0: - version "4.5.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz#1b0eea2947e73528754a6f9af3e91b2b6e0f79d5" - integrity sha1-Gw7qKUfnNSh1Sm+a8+kbK24PedU= - dependencies: - acorn "^8.0.4" - acorn-walk "^8.0.0" - chalk "^4.1.0" - commander "^7.2.0" - gzip-size "^6.0.0" - lodash "^4.17.20" - opener "^1.5.2" - sirv "^1.0.7" - ws "^7.3.1" - -webpack-dev-middleware@3.7.2: - version "3.7.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" - integrity sha1-ABnD23FuP6XOy/ZPKriKdLqzMfM= - dependencies: - memory-fs "^0.4.1" - mime "^2.4.4" - mkdirp "^0.5.1" - range-parser "^1.2.1" - webpack-log "^2.0.0" - -webpack-dev-middleware@^3.7.2, webpack-dev-middleware@^3.7.3: - version "3.7.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" - integrity sha1-Bjk3KxQyYuK4SrldO5GnWXBhwsU= - dependencies: - memory-fs "^0.4.1" - mime "^2.4.4" - mkdirp "^0.5.1" - range-parser "^1.2.1" - webpack-log "^2.0.0" - -webpack-dev-server@3.11.2: - version "3.11.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708" - integrity sha1-aV687Xakkp8NXef9c/r+GF/jNwg= - dependencies: - ansi-html "0.0.7" - bonjour "^3.5.0" - chokidar "^2.1.8" - compression "^1.7.4" - connect-history-api-fallback "^1.6.0" - debug "^4.1.1" - del "^4.1.1" - express "^4.17.1" - html-entities "^1.3.1" - http-proxy-middleware "0.19.1" - import-local "^2.0.0" - internal-ip "^4.3.0" - ip "^1.1.5" - is-absolute-url "^3.0.3" - killable "^1.0.1" - loglevel "^1.6.8" - opn "^5.5.0" - p-retry "^3.0.1" - portfinder "^1.0.26" - schema-utils "^1.0.0" - selfsigned "^1.10.8" - semver "^6.3.0" - serve-index "^1.9.1" - sockjs "^0.3.21" - sockjs-client "^1.5.0" - spdy "^4.0.2" - strip-ansi "^3.0.1" - supports-color "^6.1.0" - url "^0.11.0" - webpack-dev-middleware "^3.7.2" - webpack-log "^2.0.0" - ws "^6.2.1" - yargs "^13.3.2" - -webpack-filter-warnings-plugin@^1.2.1: - version "1.2.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-filter-warnings-plugin/-/webpack-filter-warnings-plugin-1.2.1.tgz#dc61521cf4f9b4a336fbc89108a75ae1da951cdb" - integrity sha1-3GFSHPT5tKM2+8iRCKda4dqVHNs= - -webpack-hot-middleware@^2.25.1: - version "2.25.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-hot-middleware/-/webpack-hot-middleware-2.25.1.tgz#581f59edf0781743f4ca4c200fd32c9266c6cf7c" - integrity sha1-WB9Z7fB4F0P0ykwgD9MskmbGz3w= - dependencies: - ansi-html-community "0.0.8" - html-entities "^2.1.0" - querystring "^0.2.0" - strip-ansi "^6.0.0" - -webpack-log@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" - integrity sha1-W3ko4GN1k/EZ0y9iJ8HgrDHhtH8= - dependencies: - ansi-colors "^3.0.0" - uuid "^3.3.2" - -webpack-merge@5.7.3: - version "5.7.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-merge/-/webpack-merge-5.7.3.tgz#2a0754e1877a25a8bbab3d2475ca70a052708213" - integrity sha1-KgdU4Yd6Jai7qz0kdcpwoFJwghM= - dependencies: - clone-deep "^4.0.1" - wildcard "^2.0.0" - -webpack-sources@2.2.0: - version "2.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac" - integrity sha1-BYkm8549RDGTtsMVRyKYBv/QK6w= - dependencies: - source-list-map "^2.0.1" - source-map "^0.6.1" - -webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: - version "1.4.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha1-7t2OwLko+/HL/plOItLYkPMwqTM= - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack-subresource-integrity@1.5.2: - version "1.5.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-subresource-integrity/-/webpack-subresource-integrity-1.5.2.tgz#e40b6578d3072e2d24104975249c52c66e9a743e" - integrity sha1-5AtleNMHLi0kEEl1JJxSxm6adD4= - dependencies: - webpack-sources "^1.3.0" - -webpack-virtual-modules@^0.2.2: - version "0.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack-virtual-modules/-/webpack-virtual-modules-0.2.2.tgz#20863dc3cb6bb2104729fff951fbe14b18bd0299" - integrity sha1-IIY9w8trshBHKf/5UfvhSxi9Apk= - dependencies: - debug "^3.0.0" - -webpack@4: - version "4.46.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" - integrity sha1-v5tEBOogoHNgXgoBHRiNd8tq1UI= - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" - chrome-trace-event "^1.0.2" - enhanced-resolve "^4.5.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" - -webpack@4.44.2: - version "4.44.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/webpack/-/webpack-4.44.2.tgz#6bfe2b0af055c8b2d1e90ed2cd9363f841266b72" - integrity sha1-a/4rCvBVyLLR6Q7SzZNj+EEma3I= - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" - chrome-trace-event "^1.0.2" - enhanced-resolve "^4.3.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" - -websocket-driver@>=0.5.1, websocket-driver@^0.7.4: - version "0.7.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" - integrity sha1-ia1Slbv2S0gKvLox5JU6ynBvV2A= - dependencies: - http-parser-js ">=0.5.1" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.4" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" - integrity sha1-f4RzvIOd/YdgituV1+sHUhFXikI= - -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha1-PUseAxLSB5h5+Cav8Y2+7KWWD78= - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha1-E3V7yJsgmwSf5dhkMOIc9AqJqOY= - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" - -which@^1.2.1, which@^1.2.9, which@^1.3.1: - version "1.3.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo= - dependencies: - isexe "^2.0.0" - -which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE= - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.0, wide-align@^1.1.2: - version "1.1.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" - integrity sha1-3x1MIGhUNp7PPJpImPGyP72dFdM= - dependencies: - string-width "^1.0.2 || 2 || 3 || 4" - -widest-line@^3.1.0: - version "3.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" - integrity sha1-gpIzO79my0X/DeFgOxNreuFJbso= - dependencies: - string-width "^4.0.0" - -wildcard@^2.0.0: - version "2.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" - integrity sha1-p30g5SAMb6qsl55LOq3Hs91/j+w= - -windows-release@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/windows-release/-/windows-release-4.0.0.tgz#4725ec70217d1bf6e02c7772413b29cdde9ec377" - integrity sha1-RyXscCF9G/bgLHdyQTspzd6ew3c= - dependencies: - execa "^4.0.2" - -word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha1-YQY29rH3A4kb00dxzLF/uTtHB5w= - -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - -worker-farm@^1.7.0: - version "1.7.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha1-JqlMU5G7ypJhUgAvabhKS/dy5ag= - dependencies: - errno "~0.1.7" - -worker-plugin@5.0.0: - version "5.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/worker-plugin/-/worker-plugin-5.0.0.tgz#113b5fe1f4a5d6a957cecd29915bedafd70bb537" - integrity sha1-ETtf4fSl1qlXzs0pkVvtr9cLtTc= - dependencies: - loader-utils "^1.1.0" - -worker-rpc@^0.1.0: - version "0.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" - integrity sha1-y1Zb1tcHGo8WZgaGBR6WmtMvVNU= - dependencies: - microevent.ts "~0.1.1" - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha1-H9H2cjXVttD+54EFYAG/tpTAOwk= - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha1-6Tk7oHEC5skaOyIUePAlfNKFblM= - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM= - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha1-Vr1cWlxwSBzRnFcb05q5ZaXeVug= - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -ws@^6.2.1: - version "6.2.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" - integrity sha1-3Vzb1XqZeZFgl2UtePHMX66gwy4= - dependencies: - async-limiter "~1.0.0" - -ws@^7.3.1: - version "7.5.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" - integrity sha1-5Z/FCfsV3ftlSH7pdlxaUd7F/ns= - -ws@^8.2.3: - version "8.4.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ws/-/ws-8.4.0.tgz#f05e982a0a88c604080e8581576e2a063802bed6" - integrity sha1-8F6YKgqIxgQIDoWBV24qBjgCvtY= - -ws@~7.4.2: - version "7.4.6" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha1-VlTKjs3u5HwzqaS/bSjivimAN3w= - -xml2js@^0.4.17: - version "0.4.23" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha1-oMaVFnUkIesqx1juTUzPWIQ+rGY= - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha1-vpuuHIoEbnazESdyY0fQrXACvrM= - -xmldoc@^1.1.2: - version "1.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/xmldoc/-/xmldoc-1.1.2.tgz#6666e029fe25470d599cd30e23ff0d1ed50466d7" - integrity sha1-ZmbgKf4lRw1ZnNMOI/8NHtUEZtc= - dependencies: - sax "^1.2.1" - -xmlhttprequest-ssl@~1.6.2: - version "1.6.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz#03b713873b01659dfa2c1c5d056065b27ddc2de6" - integrity sha1-A7cThzsBZZ36LBxdBWBlsn3cLeY= - -xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: - version "4.0.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q= - -xxhashjs@~0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8" - integrity sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw== - dependencies: - cuint "^0.2.2" - -y18n@^4.0.0: - version "4.0.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha1-tfJZyCzW4zaSHv17/Yv1YN6e7t8= - -y18n@^5.0.5: - version "5.0.8" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU= - -yallist@^3.0.2: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha1-27fa+b/YusmrRev2ArjLrQ1dCP0= - -yallist@^4.0.0: - version "4.0.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI= - -yaml@^1.10.0, yaml@^1.7.2: - version "1.10.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha1-IwHF/78StGfejaIzOkWeKeeSDks= - -yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha1-Ew8JcC667vJlDVTObj5XBvek+zg= - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A= - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha1-LrfcOwKJcY/ClfNidThFxBoMlO4= - -yargs@^13.3.2: - version "13.3.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha1-rX/+/sGqWVZayRX4Lcyzipwxot0= - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yargs@^15.3.1: - version "15.4.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha1-DYehbeAa7p2L7Cv7909nhRcw9Pg= - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - -yargs@^16.2.0: - version "16.2.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha1-HIK/D2tqZur85+8w43b0mhJHf2Y= - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yeast@0.1.2: - version "0.1.2" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" - integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= - -yn@3.1.1: - version "3.1.1" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha1-HodAGgnXZ8HV6rJqbkwYUYLS61A= - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha1-ApTrPe4FAo0x7hpfosVWpqrxChs= - -zone.js@~0.10.3: - version "0.10.3" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/zone.js/-/zone.js-0.10.3.tgz#3e5e4da03c607c9dcd92e37dd35687a14a140c16" - integrity sha1-Pl5NoDxgfJ3NkuN901aHoUoUDBY= - -zwitch@^1.0.0: - version "1.0.5" - resolved "https://rt.adsw.io/artifactory/api/npm/arenadata-npm/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" - integrity sha1-0R1zgf/tFrdC9q97PyI9XNn+mSA= From cebf0c6ea9bb220ccf97112644e376ce8a50bd45 Mon Sep 17 00:00:00 2001 From: Aleksandr Alferov Date: Thu, 25 Jan 2024 15:29:11 +0300 Subject: [PATCH 056/151] Fix poetry.lock --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 07474b7e6d..043cf3cc23 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1742,4 +1742,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "f5e7cd4adf97e9545e5412f5485bbf6ca9c90bbe18aadf349171ea73205f684d" +content-hash = "fc1d113cdd9de022243712f1e04cbb2ec94de9bf6c587d366a5f373b2ee7f6d8" From 73d99e040dba6bdcad06041dca88f86fe5f352b2 Mon Sep 17 00:00:00 2001 From: Araslanov Egor Date: Thu, 25 Jan 2024 12:41:53 +0000 Subject: [PATCH 057/151] =?UTF-8?q?ADCM-5201=20Improve=20ADCM=20-=20Status?= =?UTF-8?q?Server=20(SS)=C2=A0=20interactions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed: 1. Status retrieval in API v2 gathers info from `api/v1/all/` per response instead of call for each entry 2. `load_mm_objects` (renamed) reworked to use new functions (topology and MM calculation) 3. Functions that update info in SS moved to `cm.services.status.notify` 4. `perform_host_to_cluster_map` now require passing status service as a dependency to avoid circular imports 5. Filtering by status reworked for cluster, service, host Added: 1. Information about components' aggregated status to SS's `api/v1/all/` endpoint 2. Service for interactions with SS, response validation and conversion with basic functionality 3. Cluster topology building and maintenance mode calculation functions to `core` and `services.cluster` --- go/adcm/status/status.go | 15 +- python/adcm/settings.py | 2 +- python/adcm/utils.py | 5 +- .../action/adcm_change_maintenance_mode.py | 4 +- python/api/component/views.py | 2 +- python/api/host/views.py | 16 +- python/api/service/views.py | 19 +- python/api/stack/views.py | 6 +- python/api/tests/test_api.py | 10 +- python/api/tests/test_bundle.py | 2 +- python/api_v2/cluster/filters.py | 31 ++- python/api_v2/cluster/serializers.py | 32 +-- python/api_v2/cluster/utils.py | 7 +- python/api_v2/cluster/views.py | 47 ++-- python/api_v2/component/serializers.py | 23 +- python/api_v2/component/views.py | 24 +- python/api_v2/filters.py | 34 +++ python/api_v2/host/serializers.py | 29 +-- python/api_v2/host/utils.py | 5 +- python/api_v2/host/views.py | 59 +++-- python/api_v2/imports/utils.py | 38 +-- python/api_v2/serializers.py | 81 ++++++ python/api_v2/service/filters.py | 12 +- python/api_v2/service/serializers.py | 16 +- python/api_v2/service/utils.py | 4 +- python/api_v2/service/views.py | 29 ++- python/api_v2/tests/test_cluster.py | 241 ++++++++++++++++-- python/api_v2/tests/test_import.py | 1 + python/api_v2/tests/test_service.py | 27 +- python/api_v2/views.py | 51 ++++ python/cm/api.py | 106 ++------ python/cm/job.py | 4 +- .../0091_migrate_adcm_logrotate_config.py | 2 +- python/cm/services/cluster.py | 104 +++++++- python/cm/services/status/__init__.py | 11 + python/cm/services/status/client.py | 112 ++++++++ python/cm/services/status/convert.py | 43 ++++ python/cm/services/status/notify.py | 109 ++++++++ python/cm/status_api.py | 25 -- python/cm/tests/test_cluster.py | 67 +++++ python/cm/tests/test_inventory/base.py | 2 +- .../test_inventory/test_before_upgrade.py | 2 +- .../tests/test_inventory/test_components.py | 2 - .../tests/test_inventory/test_group_config.py | 2 +- .../test_inventory/test_hc_acl_actions.py | 2 - .../tests/test_inventory/test_host_action.py | 2 +- .../cm/tests/test_inventory/test_imports.py | 2 +- .../test_inventory/test_maintenance_mode.py | 2 +- python/cm/tests/test_issue.py | 3 +- python/core/cluster/operations.py | 149 ++++++++++- python/core/cluster/types.py | 46 +++- python/core/tests/__init__.py | 11 + python/core/tests/test_cluster.py | 189 ++++++++++++++ python/core/types.py | 9 +- 54 files changed, 1491 insertions(+), 387 deletions(-) create mode 100644 python/api_v2/filters.py create mode 100644 python/api_v2/serializers.py create mode 100644 python/cm/services/status/__init__.py create mode 100644 python/cm/services/status/client.py create mode 100644 python/cm/services/status/convert.py create mode 100644 python/cm/services/status/notify.py create mode 100644 python/core/tests/__init__.py create mode 100644 python/core/tests/test_cluster.py diff --git a/go/adcm/status/status.go b/go/adcm/status/status.go index a450881369..c749280ac9 100644 --- a/go/adcm/status/status.go +++ b/go/adcm/status/status.go @@ -26,8 +26,9 @@ type hostCompStatus struct { } type serviceStatus struct { - Status int `json:"status"` - Details []hostCompStatus `json:"details"` + Status int `json:"status"` + Components map[int]Status `json:"components"` + Details []hostCompStatus `json:"details"` } type eventMessage struct { @@ -190,9 +191,15 @@ func getClusterServiceStatus(h Hub, clusterId int) (int, map[int]serviceStatus) result := 0 for _, serviceId := range servList { srvStatus, hcStatus := getServiceStatus(h, clusterId, serviceId) + componentStatusMap := make(map[int]Status) + for _, hcStatusEntry := range hcStatus { + status, _ := getComponentStatus(h, hcStatusEntry.Component) + componentStatusMap[hcStatusEntry.Component] = status + } services[serviceId] = serviceStatus{ - Status: srvStatus.Status, - Details: hcStatus, + Status: srvStatus.Status, + Components: componentStatusMap, + Details: hcStatus, } if srvStatus.Status != 0 { result = srvStatus.Status diff --git a/python/adcm/settings.py b/python/adcm/settings.py index 6fb15e3888..4f44afae93 100644 --- a/python/adcm/settings.py +++ b/python/adcm/settings.py @@ -319,7 +319,7 @@ EMPTY_REQUEST_STATUS_CODE = 32 VALUE_ERROR_STATUS_CODE = 8 EMPTY_STATUS_STATUS_CODE = 4 -STATUS_REQUEST_TIMEOUT = 0.01 +STATUS_REQUEST_TIMEOUT = 0.1 JOB_TYPE = "job" TASK_TYPE = "task" diff --git a/python/adcm/utils.py b/python/adcm/utils.py index bad20a3566..3b4e2d4f57 100644 --- a/python/adcm/utils.py +++ b/python/adcm/utils.py @@ -13,7 +13,7 @@ from typing import Any, Iterable from cm.adcm_config.ansible import ansible_decrypt -from cm.api import cancel_locking_tasks, delete_service, load_mm_objects +from cm.api import cancel_locking_tasks, delete_service from cm.errors import AdcmEx from cm.flag import update_flags from cm.issue import update_hierarchy_issues, update_issue_after_deleting @@ -35,6 +35,7 @@ ServiceComponent, TaskLog, ) +from cm.services.status.notify import reset_objects_in_mm from cm.status_api import send_object_update_event from django.conf import settings from rest_framework.response import Response @@ -88,7 +89,7 @@ def _update_mm_hierarchy_issues(obj: Host | ClusterObject | ServiceComponent) -> update_hierarchy_issues(obj.cluster) update_issue_after_deleting() update_flags() - load_mm_objects() + reset_objects_in_mm() def process_requires( diff --git a/python/ansible/plugins/action/adcm_change_maintenance_mode.py b/python/ansible/plugins/action/adcm_change_maintenance_mode.py index 2ba904c161..ddc6d6b528 100644 --- a/python/ansible/plugins/action/adcm_change_maintenance_mode.py +++ b/python/ansible/plugins/action/adcm_change_maintenance_mode.py @@ -52,9 +52,9 @@ import adcm.init_django # noqa: F401, isort:skip from cm.ansible_plugin import get_object_id_from_context -from cm.api import load_mm_objects from cm.issue import update_hierarchy_issues from cm.models import ClusterObject, Host, ServiceComponent +from cm.services.status.notify import reset_objects_in_mm from cm.status_api import send_object_update_event @@ -108,6 +108,6 @@ def run(self, tmp=None, task_vars=None): obj.save() send_object_update_event(object_=obj, changes={"maintenanceMode": obj.maintenance_mode}) update_hierarchy_issues(obj.cluster) - load_mm_objects() + reset_objects_in_mm() return {"failed": False, "changed": True} diff --git a/python/api/component/views.py b/python/api/component/views.py index 59c83636a1..a9d4e338a3 100644 --- a/python/api/component/views.py +++ b/python/api/component/views.py @@ -13,8 +13,8 @@ from adcm.permissions import check_custom_perm, get_object_for_user from adcm.utils import get_maintenance_mode_response from audit.utils import audit -from cm.api import update_mm_objects from cm.models import Cluster, ClusterObject, HostComponent, ServiceComponent +from cm.services.status.notify import update_mm_objects from cm.status_api import make_ui_component_status from guardian.mixins import PermissionListMixin from rbac.viewsets import DjangoOnlyObjectPermissions diff --git a/python/api/host/views.py b/python/api/host/views.py index afd2b44ab6..8d13967e02 100644 --- a/python/api/host/views.py +++ b/python/api/host/views.py @@ -19,13 +19,7 @@ ) from adcm.utils import get_maintenance_mode_response from audit.utils import audit -from cm.api import ( - add_host_to_cluster, - delete_host, - load_service_map, - remove_host_from_cluster, - update_mm_objects, -) +from cm.api import add_host_to_cluster, delete_host, remove_host_from_cluster from cm.errors import AdcmEx from cm.models import ( Cluster, @@ -36,6 +30,11 @@ HostProvider, ServiceComponent, ) +from cm.services.status.notify import ( + reset_hc_map, + reset_objects_in_mm, + update_mm_objects, +) from cm.status_api import make_ui_host_status from django_filters import rest_framework as drf_filters from guardian.mixins import PermissionListMixin @@ -257,7 +256,8 @@ def _update_host_object( raise AdcmEx("HOST_UPDATE_ERROR") serializer.save(**kwargs) - load_service_map() + reset_hc_map() + reset_objects_in_mm() return Response(self.get_serializer(self.get_object()).data, status=HTTP_200_OK) diff --git a/python/api/service/views.py b/python/api/service/views.py index b3b9fe0673..6ddd1088bb 100644 --- a/python/api/service/views.py +++ b/python/api/service/views.py @@ -13,8 +13,9 @@ from adcm.permissions import check_custom_perm, get_object_for_user from adcm.utils import delete_service_from_api, get_maintenance_mode_response from audit.utils import audit -from cm.api import get_import, unbind, update_mm_objects +from cm.api import get_import, unbind from cm.models import Cluster, ClusterBind, ClusterObject, HostComponent, Prototype +from cm.services.status.notify import update_mm_objects from cm.status_api import make_ui_service_status from guardian.mixins import PermissionListMixin from rbac.viewsets import DjangoOnlyObjectPermissions @@ -51,7 +52,7 @@ class ServiceListView(PermissionListMixin, PaginatedView): ordering_fields = ("id", "state", "prototype__display_name", "prototype__version_order") ordering = ["id"] - def get(self, request, *args, **kwargs): # noqa: ARG002 + def get(self, request, *_, **kwargs): # noqa: ARG002 queryset = self.get_queryset() if "cluster_id" in kwargs: cluster = get_object_for_user(request.user, "cm.view_cluster", Cluster, id=kwargs["cluster_id"]) @@ -60,7 +61,7 @@ def get(self, request, *args, **kwargs): # noqa: ARG002 return self.get_page(self.filter_queryset(queryset), request) @audit - def post(self, request, *args, **kwargs): # noqa: ARG001, ARG002 + def post(self, request, *args, **kwargs): # noqa: ARG002 serializer_class = self.serializer_class if "cluster_id" in kwargs: serializer_class = self.serializer_class_cluster @@ -96,7 +97,7 @@ def get_queryset(self, *args, **kwargs): return queryset @audit - def delete(self, request, *args, **kwargs): # noqa: ARG001, ARG002, ARG004 + def delete(self, request, *args, **kwargs): # noqa: ARG002 instance: ClusterObject = self.get_object() return delete_service_from_api(service=instance) @@ -132,7 +133,7 @@ class ServiceImportView(GenericUIView): ordering = ["id"] @staticmethod - def get(request, *args, **kwargs): # noqa: ARG001, ARG002, ARG004 + def get(request, *_, **kwargs): service = get_object_for_user(request.user, "cm.view_clusterobject", ClusterObject, id=kwargs["service_id"]) check_custom_perm(request.user, "view_import_of", "clusterobject", service, "view_clusterbind") cluster = service.cluster @@ -161,7 +162,7 @@ class ServiceBindView(GenericUIView): permission_classes = (permissions.IsAuthenticated,) ordering = ["id"] - def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 + def get(self, request, *args, **kwargs): # noqa: ARG002 service = get_object_for_user(request.user, "cm.view_clusterobject", ClusterObject, id=kwargs["service_id"]) check_custom_perm(request.user, "view_import_of", "clusterobject", service, "view_clusterbind") binds = self.get_queryset().filter(service=service) @@ -196,7 +197,7 @@ def get_obj(self, kwargs, bind_id): return service, check_obj(ClusterBind, {"cluster": cluster, "id": bind_id}) - def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 + def get(self, request, *args, **kwargs): # noqa: ARG002 service, bind = self.get_obj(kwargs, kwargs["bind_id"]) check_custom_perm(request.user, "view_import_of", "clusterobject", service, "view_clusterbind") serializer = self.get_serializer(bind) @@ -204,7 +205,7 @@ def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 return Response(serializer.data) @audit - def delete(self, request, *args, **kwargs): # noqa: ARG001, ARG002 + def delete(self, request, *args, **kwargs): # noqa: ARG002 service, bind = self.get_obj(kwargs, kwargs["bind_id"]) check_custom_perm(request.user, "change_import_of", "clusterobject", service) unbind(bind) @@ -218,7 +219,7 @@ class StatusList(GenericUIView): serializer_class = ServiceStatusSerializer ordering = ["id"] - def get(self, request, *args, **kwargs): # noqa: ARG001, ARG002 + def get(self, request, *args, **kwargs): # noqa: ARG002 service = get_object_for_user(request.user, "cm.view_clusterobject", ClusterObject, id=kwargs["service_id"]) if self._is_for_ui(): host_components = self.get_queryset().filter(service=service) diff --git a/python/api/stack/views.py b/python/api/stack/views.py index fbec4fe467..65f793aa38 100644 --- a/python/api/stack/views.py +++ b/python/api/stack/views.py @@ -13,7 +13,7 @@ from adcm.permissions import DjangoObjectPermissionsAudit, IsAuthenticatedAudit from audit.utils import audit -from cm.api import accept_license, get_license, load_service_map +from cm.api import accept_license, get_license from cm.bundle import delete_bundle, load_bundle, update_bundle, upload_file from cm.models import ( Action, @@ -24,6 +24,7 @@ PrototypeImport, Upgrade, ) +from cm.services.status.notify import reset_hc_map, reset_objects_in_mm from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt from rest_framework.authentication import SessionAuthentication, TokenAuthentication @@ -76,7 +77,8 @@ def load_servicemap_view(request: Request) -> HttpResponse: if request.method != "PUT": return HttpResponse(status=HTTP_405_METHOD_NOT_ALLOWED) - load_service_map() + reset_hc_map() + reset_objects_in_mm() return HttpResponse(status=HTTP_200_OK) diff --git a/python/api/tests/test_api.py b/python/api/tests/test_api.py index 272d1d887b..78edfcee0f 100755 --- a/python/api/tests/test_api.py +++ b/python/api/tests/test_api.py @@ -870,9 +870,9 @@ def setUp(self): state="installed", ) - @patch("cm.api.load_service_map") + @patch("cm.api.reset_hc_map") @patch("cm.api.update_hierarchy_issues") - def test_save_hc(self, mock_update_issues, mock_load_service_map): + def test_save_hc(self, mock_update_issues, mock_reset_hc_map): cluster_object = ClusterObject.objects.create(prototype=self.prototype, cluster=self.cluster) host = Host.objects.create(prototype=self.prototype, cluster=self.cluster) component = Prototype.objects.create( @@ -900,10 +900,10 @@ def test_save_hc(self, mock_update_issues, mock_load_service_map): self.assertListEqual(hc_list, [HostComponent.objects.first()]) mock_update_issues.assert_called() - mock_load_service_map.assert_called_once() + mock_reset_hc_map.assert_called_once() @patch("cm.api.CTX") - @patch("cm.api.load_service_map") + @patch("cm.services.status.notify.reset_hc_map") @patch("cm.api.update_hierarchy_issues") def test_save_hc__big_update__locked_hierarchy( self, @@ -960,7 +960,7 @@ def test_save_hc__big_update__locked_hierarchy( self.assertFalse(host_2.locked) self.assertTrue(host_3.locked) - @patch("cm.api.load_service_map") + @patch("cm.services.status.notify.reset_hc_map") @patch("cm.api.update_hierarchy_issues") def test_save_hc__big_update__unlocked_hierarchy(self, mock_update, mock_load): # noqa: ARG001, ARG002 """ diff --git a/python/api/tests/test_bundle.py b/python/api/tests/test_bundle.py index 8b3bee8c17..e3b340a6c2 100644 --- a/python/api/tests/test_bundle.py +++ b/python/api/tests/test_bundle.py @@ -151,7 +151,7 @@ def test_load_bundle_cluster_with_host_mm_has_ui_options_fail(self): self.assertEqual(response.data["code"], "INVALID_OBJECT_DEFINITION") def test_load_servicemap(self): - with patch("api.stack.views.load_service_map"): + with patch("cm.services.status.notify.reset_hc_map"): response: Response = self.client.put( path=reverse(viewname="v1:load-servicemap"), ) diff --git a/python/api_v2/cluster/filters.py b/python/api_v2/cluster/filters.py index 033c2e83bc..3ea9295368 100644 --- a/python/api_v2/cluster/filters.py +++ b/python/api_v2/cluster/filters.py @@ -11,7 +11,7 @@ # limitations under the License. from cm.models import ADCMEntityStatus, Cluster -from cm.status_api import get_cluster_status, get_host_status, get_service_status +from cm.services.status.client import retrieve_status_map from django.db.models import QuerySet from django_filters.rest_framework import ( CharFilter, @@ -20,6 +20,8 @@ OrderingFilter, ) +from api_v2.filters import filter_service_status + class ClusterFilter(FilterSet): status = ChoiceFilter(label="Cluster status", choices=ADCMEntityStatus.choices, method="filter_status") @@ -44,10 +46,16 @@ class Meta: @staticmethod def filter_status(queryset: QuerySet, _: str, value: str) -> QuerySet: + status_map = retrieve_status_map() + if value == ADCMEntityStatus.UP: - exclude_pks = {cluster.pk for cluster in queryset if get_cluster_status(cluster=cluster) != 0} + exclude_pks = { + cluster_id for cluster_id, status_info in status_map.clusters.items() if status_info.status != 0 + } else: - exclude_pks = {cluster.pk for cluster in queryset if get_cluster_status(cluster=cluster) == 0} + exclude_pks = { + cluster_id for cluster_id, status_info in status_map.clusters.items() if status_info.status == 0 + } return queryset.exclude(pk__in=exclude_pks) @@ -57,12 +65,14 @@ class ClusterHostFilter(FilterSet): @staticmethod def filter_status(queryset: QuerySet, _: str, value: str) -> QuerySet: + status_map = retrieve_status_map() + + hosts_up = {host_id for host_id, status_info in status_map.hosts.items() if status_info.status == 0} + if value == ADCMEntityStatus.UP: - exclude_pks = {host.pk for host in queryset if get_host_status(host=host) != 0} - else: - exclude_pks = {host.pk for host in queryset if get_host_status(host=host) == 0} + return queryset.filter(pk__in=hosts_up) - return queryset.exclude(pk__in=exclude_pks) + return queryset.exclude(pk__in=hosts_up) class ClusterServiceFilter(FilterSet): @@ -70,9 +80,4 @@ class ClusterServiceFilter(FilterSet): @staticmethod def filter_status(queryset: QuerySet, _: str, value: str) -> QuerySet: - if value == ADCMEntityStatus.UP: - exclude_pks = {service.pk for service in queryset if get_service_status(service=service) != 0} - else: - exclude_pks = {service.pk for service in queryset if get_service_status(service=service) == 0} - - return queryset.exclude(pk__in=exclude_pks) + return filter_service_status(queryset=queryset, value=value) diff --git a/python/api_v2/cluster/serializers.py b/python/api_v2/cluster/serializers.py index 81424b699a..cd319b673f 100644 --- a/python/api_v2/cluster/serializers.py +++ b/python/api_v2/cluster/serializers.py @@ -21,7 +21,6 @@ Prototype, ServiceComponent, ) -from cm.status_api import get_obj_status from cm.upgrade import get_upgrade from cm.validators import ClusterUniqueValidator, StartMidEndValidator from django.conf import settings @@ -36,10 +35,10 @@ from api_v2.concern.serializers import ConcernSerializer from api_v2.prototype.serializers import PrototypeRelatedSerializer from api_v2.prototype.utils import get_license_text +from api_v2.serializers import WithStatusSerializer -class ClusterSerializer(ModelSerializer): - status = SerializerMethodField() +class ClusterSerializer(WithStatusSerializer): prototype = PrototypeRelatedSerializer(read_only=True) concerns = ConcernSerializer(many=True, read_only=True) is_upgradable = SerializerMethodField() @@ -61,10 +60,6 @@ class Meta: "main_info", ] - @staticmethod - def get_status(cluster: Cluster) -> str: - return get_obj_status(obj=cluster) - @staticmethod def get_is_upgradable(cluster: Cluster) -> bool: return bool(get_upgrade(obj=cluster)) @@ -165,38 +160,21 @@ class Meta: extra_kwargs = {"id": {"read_only": True}} -class RelatedComponentStatusSerializer(ModelSerializer): - status = SerializerMethodField() - +class RelatedComponentStatusSerializer(WithStatusSerializer): class Meta: model = ServiceComponent fields = ["id", "name", "display_name", "status"] - @staticmethod - def get_status(instance: ServiceComponent) -> str: - return get_obj_status(obj=instance) - -class RelatedServicesStatusesSerializer(ModelSerializer): - status = SerializerMethodField() +class RelatedServicesStatusesSerializer(WithStatusSerializer): components = RelatedComponentStatusSerializer(many=True, source="servicecomponent_set") - @staticmethod - def get_status(instance: ClusterObject) -> str: - return get_obj_status(obj=instance) - class Meta: model = ClusterObject fields = ["id", "name", "display_name", "status", "components"] -class RelatedHostsStatusesSerializer(ModelSerializer): - status = SerializerMethodField() - - @staticmethod - def get_status(instance: ClusterObject) -> str: - return get_obj_status(obj=instance) - +class RelatedHostsStatusesSerializer(WithStatusSerializer): class Meta: model = Host fields = ["id", "name", "status"] diff --git a/python/api_v2/cluster/utils.py b/python/api_v2/cluster/utils.py index 42b2cc4f6e..5d37c0035e 100644 --- a/python/api_v2/cluster/utils.py +++ b/python/api_v2/cluster/utils.py @@ -14,7 +14,6 @@ from itertools import chain from typing import Literal -from cm.api import load_service_map from cm.api_context import CTX from cm.data_containers import ( ClusterData, @@ -45,6 +44,7 @@ Prototype, ServiceComponent, ) +from cm.services.status.notify import reset_hc_map, reset_objects_in_mm from cm.status_api import send_host_component_map_update_event from django.contrib.contenttypes.models import ContentType from django.db.models import QuerySet @@ -220,7 +220,7 @@ def _check_mapping_data(mapping_data: MappingData) -> None: hosts_mm_states_in_add_remove_groups = { diff.host.maintenance_mode for diff in mapping_data.mapping_difference["add"] - }.union({diff.host.maintenance_mode for diff in mapping_data.mapping_difference["remove"]}) + } | {diff.host.maintenance_mode for diff in mapping_data.mapping_difference["remove"]} if MaintenanceMode.ON.value in hosts_mm_states_in_add_remove_groups: raise AdcmEx("INVALID_HC_HOST_IN_MM") @@ -256,7 +256,8 @@ def _check_mapping_data(mapping_data: MappingData) -> None: @atomic def _save_mapping(mapping_data: MappingData) -> QuerySet[HostComponent]: - on_commit(func=load_service_map) + on_commit(func=reset_hc_map) + on_commit(func=reset_objects_in_mm) for removed_host in mapping_data.removed_hosts: remove_concern_from_object(object_=removed_host, concern=CTX.lock) diff --git a/python/api_v2/cluster/views.py b/python/api_v2/cluster/views.py index 24c9212021..654093b726 100644 --- a/python/api_v2/cluster/views.py +++ b/python/api_v2/cluster/views.py @@ -63,14 +63,10 @@ from api_v2.component.serializers import ComponentMappingSerializer from api_v2.config.utils import ConfigSchemaMixin from api_v2.host.serializers import HostMappingSerializer -from api_v2.views import CamelCaseModelViewSet +from api_v2.views import CamelCaseModelViewSet, ObjectWithStatusViewMixin -class ClusterViewSet( - PermissionListMixin, - ConfigSchemaMixin, - CamelCaseModelViewSet, -): +class ClusterViewSet(PermissionListMixin, ConfigSchemaMixin, CamelCaseModelViewSet, ObjectWithStatusViewMixin): queryset = ( Cluster.objects.prefetch_related("prototype", "concerns") .prefetch_related("clusterobject_set__prototype") @@ -79,6 +75,11 @@ class ClusterViewSet( permission_required = [VIEW_CLUSTER_PERM] filterset_class = ClusterFilter permission_classes = [ClusterPermissions] + retrieve_status_map_actions = ( + "services_statuses", + "hosts_statuses", + "list", + ) def get_serializer_class(self): match self.action: @@ -110,7 +111,9 @@ def create(self, request, *args, **kwargs): # noqa: ARG002 cluster = add_cluster(prototype=prototype, name=valid["name"], description=valid["description"]) - return Response(data=ClusterSerializer(cluster).data, status=HTTP_201_CREATED) + return Response( + data=ClusterSerializer(cluster, context=self.get_serializer_context()).data, status=HTTP_201_CREATED + ) @audit def update(self, request, *args, **kwargs): # noqa: ARG002 @@ -127,7 +130,9 @@ def update(self, request, *args, **kwargs): # noqa: ARG002 instance.save(update_fields=["name", "description"]) update_hierarchy_issues(obj=instance) - return Response(status=HTTP_200_OK, data=ClusterSerializer(instance).data) + return Response( + status=HTTP_200_OK, data=ClusterSerializer(instance, context=self.get_serializer_context()).data + ) @audit def destroy(self, request, *args, **kwargs): # noqa: ARG002 @@ -137,7 +142,7 @@ def destroy(self, request, *args, **kwargs): # noqa: ARG002 return Response(status=HTTP_204_NO_CONTENT) @action(methods=["get"], detail=True, url_path="service-prototypes") - def service_prototypes(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def service_prototypes(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 cluster = self.get_object() prototypes = Prototype.objects.filter(type=ObjectType.SERVICE, bundle=cluster.prototype.bundle).order_by( "display_name" @@ -147,7 +152,7 @@ def service_prototypes(self, request: Request, *args, **kwargs) -> Response: # return Response(data=serializer.data) @action(methods=["get"], detail=True, url_path="service-candidates") - def service_candidates(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def service_candidates(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 cluster = self.get_object() prototypes = ( Prototype.objects.filter(type=ObjectType.SERVICE, bundle=cluster.prototype.bundle) @@ -162,16 +167,18 @@ def service_candidates(self, request: Request, *args, **kwargs) -> Response: # methods=["get"], detail=True, url_path="statuses/services", - queryset=ClusterObject.objects.order_by("prototype__display_name"), + queryset=ClusterObject.objects.select_related("prototype").order_by("prototype__display_name"), permission_required=[VIEW_SERVICE_PERM], filterset_class=ClusterServiceFilter, ) - def services_statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def services_statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 cluster = get_object_for_user(user=request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=kwargs["pk"]) queryset = self.filter_queryset(queryset=self.get_queryset().filter(cluster=cluster)) return self.get_paginated_response( - data=RelatedServicesStatusesSerializer(instance=self.paginate_queryset(queryset=queryset), many=True).data + data=RelatedServicesStatusesSerializer( + instance=self.paginate_queryset(queryset=queryset), many=True, context=self.get_serializer_context() + ).data ) @action( @@ -182,12 +189,16 @@ def services_statuses(self, request: Request, *args, **kwargs) -> Response: # n permission_required=[VIEW_HOST_PERM], filterset_class=ClusterHostFilter, ) - def hosts_statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def hosts_statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 cluster = get_object_for_user(user=request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=kwargs["pk"]) queryset = self.filter_queryset(queryset=self.get_queryset().filter(cluster=cluster)) return self.get_paginated_response( - data=RelatedHostsStatusesSerializer(instance=self.paginate_queryset(queryset=queryset), many=True).data + data=RelatedHostsStatusesSerializer( + instance=self.paginate_queryset(queryset=queryset), + many=True, + context=self.get_serializer_context(), + ).data ) @audit @@ -197,7 +208,7 @@ def hosts_statuses(self, request: Request, *args, **kwargs) -> Response: # noqa pagination_class=None, filter_backends=[], ) - def mapping(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def mapping(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 cluster = self.get_object() if request.method == "GET": @@ -222,14 +233,14 @@ def mapping(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG00 return Response(data=self.get_serializer(instance=new_mapping, many=True).data, status=HTTP_201_CREATED) @action(methods=["get"], detail=True, url_path="mapping/hosts", url_name="mapping-hosts") - def mapping_hosts(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def mapping_hosts(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 cluster = self.get_object() serializer = self.get_serializer(instance=Host.objects.filter(cluster=cluster), many=True) return Response(status=HTTP_200_OK, data=serializer.data) @action(methods=["get"], detail=True, url_path="mapping/components", url_name="mapping-components") - def mapping_components(self, request: Request, *args, **kwargs): # noqa: ARG001, ARG002 + def mapping_components(self, request: Request, *args, **kwargs): # noqa: ARG002 cluster = self.get_object() serializer = self.get_serializer( instance=ServiceComponent.objects.filter(cluster=cluster).order_by("pk"), many=True diff --git a/python/api_v2/component/serializers.py b/python/api_v2/component/serializers.py index 482c28fc04..f30df5eea1 100644 --- a/python/api_v2/component/serializers.py +++ b/python/api_v2/component/serializers.py @@ -10,10 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. - from cm.adcm_config.config import get_main_info from cm.models import Host, HostComponent, MaintenanceMode, ServiceComponent -from cm.status_api import get_obj_status from rest_framework.serializers import ( CharField, ChoiceField, @@ -28,6 +26,7 @@ from api_v2.concern.serializers import ConcernSerializer from api_v2.host.serializers import HostShortSerializer from api_v2.prototype.serializers import PrototypeRelatedSerializer +from api_v2.serializers import WithStatusSerializer from api_v2.service.serializers import ServiceNameSerializer, ServiceRelatedSerializer @@ -59,8 +58,7 @@ def get_depend_on(instance: ServiceComponent) -> list[dict] | None: return None -class ComponentSerializer(ModelSerializer): - status = SerializerMethodField() +class ComponentSerializer(WithStatusSerializer): hosts = SerializerMethodField() prototype = PrototypeRelatedSerializer(read_only=True) cluster = ClusterRelatedSerializer(read_only=True) @@ -87,9 +85,6 @@ class Meta: "main_info", ] - def get_status(self, instance: ServiceComponent) -> str: - return get_obj_status(obj=instance) - def get_hosts(self, instance: ServiceComponent) -> HostShortSerializer: host_pks = set() for host_component in HostComponent.objects.filter(component=instance).select_related("host"): @@ -109,19 +104,14 @@ class Meta: fields = ["maintenance_mode"] -class RelatedHostComponentsStatusSerializer(ModelSerializer): +class RelatedHostComponentsStatusSerializer(WithStatusSerializer): id = IntegerField(source="host.id") name = CharField(source="host.name") - status = SerializerMethodField() class Meta: model = HostComponent fields = ["id", "name", "status"] - @staticmethod - def get_status(instance: HostComponent) -> str: - return get_obj_status(obj=instance) - class ComponentStatusSerializer(ModelSerializer): host_components = RelatedHostComponentsStatusSerializer(many=True, source="hostcomponent_set") @@ -131,9 +121,8 @@ class Meta: fields = ["host_components"] -class HostComponentSerializer(ModelSerializer): +class HostComponentSerializer(WithStatusSerializer): concerns = ConcernSerializer(read_only=True, many=True) - status = SerializerMethodField() cluster = ClusterRelatedSerializer(read_only=True) service = ServiceRelatedSerializer(read_only=True) prototype = PrototypeRelatedSerializer(read_only=True) @@ -153,10 +142,6 @@ class Meta: "prototype", ] - @staticmethod - def get_status(instance: ServiceComponent) -> str: - return get_obj_status(obj=instance) - class ComponentAuditSerializer(ModelSerializer): class Meta: diff --git a/python/api_v2/component/views.py b/python/api_v2/component/views.py index 718c6cc568..d66303937d 100644 --- a/python/api_v2/component/views.py +++ b/python/api_v2/component/views.py @@ -23,8 +23,8 @@ ) from adcm.utils import get_maintenance_mode_response from audit.utils import audit -from cm.api import update_mm_objects from cm.models import Cluster, ClusterObject, Host, ServiceComponent +from cm.services.status.notify import update_mm_objects from guardian.mixins import PermissionListMixin from rest_framework.decorators import action from rest_framework.mixins import ListModelMixin @@ -40,15 +40,21 @@ HostComponentSerializer, ) from api_v2.config.utils import ConfigSchemaMixin -from api_v2.views import CamelCaseGenericViewSet, CamelCaseReadOnlyModelViewSet +from api_v2.views import ( + CamelCaseGenericViewSet, + CamelCaseReadOnlyModelViewSet, + ObjectWithStatusViewMixin, +) -class ComponentViewSet(PermissionListMixin, ConfigSchemaMixin, CamelCaseReadOnlyModelViewSet): +class ComponentViewSet( + PermissionListMixin, ConfigSchemaMixin, CamelCaseReadOnlyModelViewSet, ObjectWithStatusViewMixin +): queryset = ServiceComponent.objects.select_related("cluster", "service").order_by("pk") - serializer_class = ComponentSerializer permission_classes = [DjangoModelPermissionsAudit] permission_required = [VIEW_COMPONENT_PERM] filterset_class = ComponentFilter + retrieve_status_map_actions = ("statuses", "list") audit_model_hint = ServiceComponent @@ -67,12 +73,12 @@ def get_serializer_class(self): case "maintenance_mode": return ComponentMaintenanceModeSerializer - return self.serializer_class + return ComponentSerializer @audit @update_mm_objects @action(methods=["post"], detail=True, url_path="maintenance-mode", permission_classes=[ChangeMMPermissions]) - def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 component = get_object_for_user( user=request.user, perms=VIEW_COMPONENT_PERM, klass=ServiceComponent, pk=kwargs["pk"] ) @@ -90,15 +96,15 @@ def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # no return response @action(methods=["get"], detail=True, url_path="statuses") - def statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 component = get_object_for_user( user=request.user, perms=VIEW_COMPONENT_PERM, klass=ServiceComponent, id=kwargs["pk"] ) - return Response(data=ComponentStatusSerializer(instance=component).data) + return Response(data=ComponentStatusSerializer(instance=component, context=self.get_serializer_context()).data) -class HostComponentViewSet(PermissionListMixin, ListModelMixin, CamelCaseGenericViewSet): +class HostComponentViewSet(PermissionListMixin, ListModelMixin, CamelCaseGenericViewSet, ObjectWithStatusViewMixin): queryset = ServiceComponent.objects.select_related("cluster", "service").order_by("prototype__name") serializer_class = HostComponentSerializer permission_classes = [DjangoModelPermissionsAudit] diff --git a/python/api_v2/filters.py b/python/api_v2/filters.py new file mode 100644 index 0000000000..d4c9823ae8 --- /dev/null +++ b/python/api_v2/filters.py @@ -0,0 +1,34 @@ +# Licensed 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. + +from itertools import chain + +from cm.models import ADCMEntityStatus +from cm.services.status.client import retrieve_status_map +from django.db.models import Q, QuerySet + + +def filter_service_status(queryset: QuerySet, value: str) -> QuerySet: + status_map = retrieve_status_map() + services_up = { + service_id + for service_id, service_info in chain.from_iterable( + cluster_info.services.items() for cluster_info in status_map.clusters.values() + ) + if service_info.status == 0 + } + service_up_condition = Q(pk__in=services_up) | Q(prototype__monitoring="passive") + + if value == ADCMEntityStatus.UP: + return queryset.filter(service_up_condition) + + return queryset.exclude(service_up_condition) diff --git a/python/api_v2/host/serializers.py b/python/api_v2/host/serializers.py index 4aa8b1c8f4..4e159f1bf4 100644 --- a/python/api_v2/host/serializers.py +++ b/python/api_v2/host/serializers.py @@ -12,8 +12,7 @@ from adcm import settings from adcm.serializers import EmptySerializer -from cm.models import Cluster, Host, HostProvider, MaintenanceMode, ServiceComponent -from cm.status_api import get_obj_status +from cm.models import Cluster, Host, HostComponent, HostProvider, MaintenanceMode, ServiceComponent from cm.validators import HostUniqueValidator, StartMidEndValidator from rest_framework.serializers import ( CharField, @@ -24,9 +23,9 @@ SerializerMethodField, ) -from api_v2.cluster.serializers import RelatedComponentStatusSerializer from api_v2.concern.serializers import ConcernSerializer from api_v2.prototype.serializers import PrototypeRelatedSerializer +from api_v2.serializers import WithStatusSerializer class HostProviderSerializer(ModelSerializer): @@ -47,8 +46,7 @@ class Meta: fields = ["id", "name", "display_name"] -class HostSerializer(ModelSerializer): - status = SerializerMethodField() +class HostSerializer(WithStatusSerializer): hostprovider = HostProviderSerializer(source="provider") prototype = PrototypeRelatedSerializer(read_only=True) concerns = ConcernSerializer(many=True) @@ -88,10 +86,6 @@ class Meta: "components", ] - @staticmethod - def get_status(host: Host) -> str: - return get_obj_status(obj=host) - @staticmethod def get_components(instance: Host) -> list[dict]: return HCComponentNameSerializer( @@ -179,18 +173,23 @@ class Meta: extra_kwargs = {"name": {"read_only": True}} +class RelatedHostComponentsStatusSerializer(WithStatusSerializer): + id = IntegerField(source="component.id") + name = CharField(source="component.name") + display_name = CharField(source="component.display_name") + + class Meta: + model = HostComponent + fields = ["id", "name", "display_name", "status"] + + class ClusterHostStatusSerializer(EmptySerializer): - host_components = SerializerMethodField() + host_components = RelatedHostComponentsStatusSerializer(many=True, source="hostcomponent_set") class Meta: model = Host fields = ["host_components"] - def get_host_components(self, instance: Host) -> list: - return RelatedComponentStatusSerializer( - instance=[hc.component for hc in instance.hostcomponent_set.select_related("component")], many=True - ).data - class HostAuditSerializer(ModelSerializer): class Meta: diff --git a/python/api_v2/host/utils.py b/python/api_v2/host/utils.py index b31154a439..576fe520b5 100644 --- a/python/api_v2/host/utils.py +++ b/python/api_v2/host/utils.py @@ -13,11 +13,12 @@ from adcm.permissions import check_custom_perm from adcm.utils import get_maintenance_mode_response from cm.adcm_config.config import init_object_config -from cm.api import check_license, load_service_map +from cm.api import check_license from cm.api_context import CTX from cm.issue import add_concern_to_object, update_hierarchy_issues from cm.logger import logger from cm.models import Cluster, Host, HostProvider, Prototype +from cm.services.status.notify import reset_hc_map from django.db.transaction import atomic from rbac.models import re_apply_object_policy from rest_framework.request import Request @@ -45,7 +46,7 @@ def add_new_host_and_map_it(provider: HostProvider, fqdn: str, cluster: Cluster if cluster: re_apply_object_policy(apply_object=cluster) - load_service_map() + reset_hc_map() logger.info("host #%s %s is added", host.pk, host.fqdn) if cluster: logger.info("host #%s %s is added to cluster #%s %s", host.pk, host.fqdn, cluster.pk, cluster.name) diff --git a/python/api_v2/host/views.py b/python/api_v2/host/views.py index a04f659993..d57ea3c4ff 100644 --- a/python/api_v2/host/views.py +++ b/python/api_v2/host/views.py @@ -27,6 +27,7 @@ from cm.errors import AdcmEx from cm.models import Cluster, GroupConfig, Host, HostProvider from cm.services.cluster import perform_host_to_cluster_map +from cm.services.status import notify from core.cluster.errors import ( HostAlreadyBoundError, HostBelongsToAnotherClusterError, @@ -62,10 +63,14 @@ HostUpdateSerializer, ) from api_v2.host.utils import add_new_host_and_map_it, maintenance_mode -from api_v2.views import CamelCaseModelViewSet, CamelCaseReadOnlyModelViewSet +from api_v2.views import ( + CamelCaseModelViewSet, + CamelCaseReadOnlyModelViewSet, + ObjectWithStatusViewMixin, +) -class HostViewSet(PermissionListMixin, ConfigSchemaMixin, CamelCaseModelViewSet): +class HostViewSet(PermissionListMixin, ConfigSchemaMixin, ObjectWithStatusViewMixin, CamelCaseModelViewSet): queryset = ( Host.objects.select_related("provider", "cluster", "cluster__prototype", "prototype") .prefetch_related("concerns", "hostcomponent_set") @@ -108,8 +113,7 @@ def create(self, request, *args, **kwargs): # noqa: ARG002 ) return Response( - data=HostSerializer(instance=host).data, - status=HTTP_201_CREATED, + data=HostSerializer(instance=host, context=self.get_serializer_context()).data, status=HTTP_201_CREATED ) @audit @@ -139,19 +143,27 @@ def update(self, request, *args, **kwargs): # noqa: ARG002 serializer.save() - return Response(status=HTTP_200_OK, data=HostSerializer(instance=instance).data) + return Response( + status=HTTP_200_OK, data=HostSerializer(instance=instance, context=self.get_serializer_context()).data + ) @audit @action(methods=["post"], detail=True, url_path="maintenance-mode", permission_classes=[ChangeMMPermissions]) - def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 return maintenance_mode(request=request, host=self.get_object()) -class HostClusterViewSet(PermissionListMixin, CamelCaseReadOnlyModelViewSet): +class HostClusterViewSet(PermissionListMixin, CamelCaseReadOnlyModelViewSet, ObjectWithStatusViewMixin): permission_required = [VIEW_HOST_PERM] permission_classes = [HostsClusterPermissions] + # have to define it here for `ObjectWithStatusViewMixin` to be able to determine model related to view + # don't use it directly, use `get_queryset` + queryset = Host.objects.select_related("cluster", "cluster__prototype", "provider", "prototype").prefetch_related( + "hostcomponent_set", "concerns" + ) filterset_class = HostClusterFilter audit_model_hint = Host + retrieve_status_map_actions = ("list", "statuses") def get_serializer_class(self): if self.action == "maintenance_mode": @@ -167,14 +179,15 @@ def get_queryset(self, *args, **kwargs): # noqa: ARG002 user=self.request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=self.kwargs["cluster_pk"] ) - return ( - Host.objects.filter(cluster=cluster) - .select_related("cluster", "cluster__prototype", "provider", "prototype") - .prefetch_related("hostcomponent_set", "concerns") - ) + by_cluster_qs = self.queryset.filter(cluster=cluster) + + if self.action == "statuses": + return by_cluster_qs.prefetch_related("hostcomponent_set__component__prototype") + + return by_cluster_qs @audit - def create(self, request, *_, **kwargs): # noqa: ARG002 + def create(self, request, *_, **kwargs): cluster = get_object_for_user( user=request.user, perms=VIEW_CLUSTER_PERM, klass=Cluster, id=kwargs["cluster_pk"] ) @@ -195,6 +208,7 @@ def create(self, request, *_, **kwargs): # noqa: ARG002 entry["host_id"] for entry in (serializer.validated_data if multiple_hosts else [serializer.validated_data]) ], + status_service=notify, ) except HostDoesNotExistError: raise AdcmEx("BAD_REQUEST", "At least one host does not exist.") from None @@ -205,15 +219,17 @@ def create(self, request, *_, **kwargs): # noqa: ARG002 qs_for_added_hosts = self.get_queryset().filter(id__in=added_hosts) + context = self.get_serializer_context() + if multiple_hosts: return Response( status=HTTP_201_CREATED, - data=HostSerializer(instance=qs_for_added_hosts, many=True).data, + data=HostSerializer(instance=qs_for_added_hosts, many=True, context=context).data, ) return Response( status=HTTP_201_CREATED, - data=HostSerializer(instance=qs_for_added_hosts.first()).data, + data=HostSerializer(instance=qs_for_added_hosts.first(), context=context).data, ) @audit @@ -226,17 +242,22 @@ def destroy(self, request, *args, **kwargs): # noqa: ARG002 @audit @action(methods=["post"], detail=True, url_path="maintenance-mode", permission_classes=[ChangeMMPermissions]) - def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 return maintenance_mode(request=request, host=self.get_object()) @action(methods=["get"], detail=True, url_path="statuses") - def statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 host = self.get_object() cluster = get_object_for_user(request.user, VIEW_CLUSTER_PERM, Cluster, id=kwargs["cluster_pk"]) if host.cluster != cluster: raise AdcmEx(code="FOREIGN_HOST", msg=f"Host #{host.id} doesn't belong to cluster #{cluster.id}") - return Response(data=ClusterHostStatusSerializer(instance=host).data) + return Response( + data=ClusterHostStatusSerializer( + instance=Host.objects.prefetch_related("hostcomponent_set__component__prototype").get(id=host.id), + context=self.get_serializer_context(), + ).data + ) class HostGroupConfigViewSet(PermissionListMixin, GetParentObjectMixin, CamelCaseReadOnlyModelViewSet): @@ -295,7 +316,7 @@ def create(self, request, *_, **__): return Response(status=HTTP_201_CREATED, data=HostGroupConfigSerializer(instance=host).data) @audit - def destroy(self, request, *_, **kwargs): # noqa: ARG001, ARG002 + def destroy(self, request, *_, **kwargs): # noqa: ARG002 group_config = self.get_group_for_change() host = group_config.hosts.filter(pk=kwargs["pk"]).first() diff --git a/python/api_v2/imports/utils.py b/python/api_v2/imports/utils.py index 29796b7082..3057462ad0 100644 --- a/python/api_v2/imports/utils.py +++ b/python/api_v2/imports/utils.py @@ -10,8 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from cm.api import DataForMultiBind, is_version_suitable -from cm.errors import AdcmEx, raise_adcm_ex +from cm.api import is_version_suitable +from cm.errors import raise_adcm_ex from cm.models import ( Cluster, ClusterBind, @@ -21,7 +21,8 @@ PrototypeExport, PrototypeImport, ) -from cm.status_api import get_obj_status +from cm.services.status.client import retrieve_status_map +from cm.services.status.convert import convert_to_entity_status from django.db.models import QuerySet from api_v2.imports.types import ( @@ -51,10 +52,6 @@ def _format_binds(binds: QuerySet[ClusterBind]) -> list[UIBind]: return binds_data -def _format_cluster(cluster: Cluster) -> UICluster: - return UICluster(id=cluster.pk, name=cluster.name, status=get_obj_status(obj=cluster), state=cluster.state) - - def _format_import_cluster(cluster: Cluster, prototype_import: PrototypeImport | None) -> UIImportCluster | None: if prototype_import is None: return None @@ -194,12 +191,22 @@ def get_imports(obj: Cluster | ClusterObject) -> list[UIObjectImport]: .order_by("pk") ) + status_map = retrieve_status_map() + for import_candidate in sorted(import_candidates, key=lambda candidate: candidate["obj"].name): + cluster_candidate = import_candidate["obj"] out_data.append( UIObjectImport( - cluster=_format_cluster(cluster=import_candidate["obj"]), + cluster=UICluster( + id=cluster_candidate.pk, + name=cluster_candidate.name, + status=convert_to_entity_status( + raw_status=status_map.get_for_cluster(cluster_id=cluster_candidate.pk) + ), + state=cluster_candidate.state, + ), import_cluster=_format_import_cluster( - cluster=import_candidate["obj"], prototype_import=import_candidate["prototype_import"] + cluster=cluster_candidate, prototype_import=import_candidate["prototype_import"] ), import_services=_format_import_services(service_candidates=import_candidate["services"]), binds=_format_binds(binds=binds.filter(source_cluster=import_candidate["obj"]).order_by("pk")), @@ -209,22 +216,19 @@ def get_imports(obj: Cluster | ClusterObject) -> list[UIObjectImport]: return out_data -def cook_data_for_multibind(validated_data: list, obj: Cluster | ClusterObject) -> list[DataForMultiBind]: +def cook_data_for_multibind(validated_data: list, obj: Cluster | ClusterObject) -> list: bind_data = [] for item in validated_data: if item["source"]["type"] == ObjectType.CLUSTER: export_obj = Cluster.objects.get(pk=item["source"]["id"]) - cluster_id: int = export_obj.pk - service_id: None = None + cluster_id = export_obj.pk + service_id = None elif item["source"]["type"] == ObjectType.SERVICE: export_obj = ClusterObject.objects.get(pk=item["source"]["id"]) - cluster_id: int = export_obj.cluster.pk - service_id: int = export_obj.pk - - else: - raise AdcmEx("INVALID_INPUT", "Incorrect type of `source`") + cluster_id = export_obj.cluster.pk + service_id = export_obj.pk proto_import = PrototypeImport.objects.filter(name=export_obj.prototype.name, prototype=obj.prototype).first() diff --git a/python/api_v2/serializers.py b/python/api_v2/serializers.py new file mode 100644 index 0000000000..d3a8270b2c --- /dev/null +++ b/python/api_v2/serializers.py @@ -0,0 +1,81 @@ +# Licensed 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. + +from typing import Callable, TypeVar + +from cm.models import ( + ADCMEntityStatus, + ADCMModel, + Cluster, + ClusterObject, + Host, + HostComponent, + ServiceComponent, +) +from cm.services.status.client import FullStatusMap +from cm.services.status.convert import ( + convert_to_component_status, + convert_to_entity_status, + convert_to_host_component_status, + convert_to_service_status, +) +from rest_framework.fields import SerializerMethodField +from rest_framework.serializers import ModelSerializer + +T = TypeVar("T") + + +_MODEL_RETRIEVAL_FUNC_MAP: dict[type[T], Callable[[FullStatusMap, T], ADCMEntityStatus]] = { + Cluster: lambda status_map, cluster: status_map.get_for_cluster(cluster_id=cluster.pk), + ClusterObject: lambda status_map, service: status_map.get_for_service( + cluster_id=service.cluster_id, service_id=service.pk + ), + ServiceComponent: lambda status_map, component: status_map.get_for_component( + cluster_id=component.cluster_id, service_id=component.service_id, component_id=component.pk + ), + Host: lambda status_map, host: status_map.get_for_host(host_id=host.pk), + HostComponent: lambda status_map, hc: status_map.get_for_host_component( + cluster_id=hc.cluster_id, service_id=hc.service_id, component_id=hc.component_id, host_id=hc.host_id + ), +} + + +class WithStatusSerializer(ModelSerializer): + status = SerializerMethodField() + + def get_status(self, instance: ADCMModel) -> ADCMEntityStatus: + status = self.context.get("status") + if status is None: + try: + status_map = self.context["status_map"] + except KeyError as err: + message = f"Can't detect status for {instance}, both `status` and `status_map` are absent in context" + raise KeyError(message) from err + + try: + status = _MODEL_RETRIEVAL_FUNC_MAP[instance.__class__](status_map, instance) + except KeyError as err: + message = f"Don't know how to retrieve status for {instance.__class__} from status map" + raise KeyError(message) from err + + if isinstance(instance, ClusterObject): + return convert_to_service_status(raw_status=status, monitoring=instance.monitoring) + + if isinstance(instance, ServiceComponent): + return convert_to_component_status(raw_status=status, monitoring=instance.monitoring) + + if isinstance(instance, HostComponent): + return convert_to_host_component_status( + raw_status=status, component_monitoring=instance.component.monitoring + ) + + return convert_to_entity_status(raw_status=status) diff --git a/python/api_v2/service/filters.py b/python/api_v2/service/filters.py index 509f5cd6e9..c72f2ec93f 100644 --- a/python/api_v2/service/filters.py +++ b/python/api_v2/service/filters.py @@ -11,7 +11,6 @@ # limitations under the License. from cm.models import ADCMEntityStatus, ClusterObject, ObjectType -from cm.status_api import get_service_status from django.db.models import QuerySet from django_filters.rest_framework import ( CharFilter, @@ -20,6 +19,8 @@ OrderingFilter, ) +from api_v2.filters import filter_service_status + class ServiceFilter(FilterSet): name = CharFilter(label="Service name", method="filter_name") @@ -35,13 +36,8 @@ class Meta: fields = ["name", "display_name", "status"] @staticmethod - def filter_status(queryset: QuerySet, name: str, value: str) -> QuerySet: # noqa: ARG001, ARG004 - if value == ADCMEntityStatus.UP: - exclude_pks = {service.pk for service in queryset if get_service_status(service=service) != 0} - else: - exclude_pks = {service.pk for service in queryset if get_service_status(service=service) == 0} - - return queryset.exclude(pk__in=exclude_pks) + def filter_status(queryset: QuerySet, _: str, value: str) -> QuerySet: + return filter_service_status(queryset=queryset, value=value) @staticmethod def filter_name(queryset: QuerySet, name: str, value: str) -> QuerySet: # noqa: ARG001, ARG004 diff --git a/python/api_v2/service/serializers.py b/python/api_v2/service/serializers.py index d2ab5f6a79..1a8ad61001 100644 --- a/python/api_v2/service/serializers.py +++ b/python/api_v2/service/serializers.py @@ -13,7 +13,6 @@ from adcm.serializers import EmptySerializer from cm.adcm_config.config import get_main_info from cm.models import ClusterObject, MaintenanceMode, ServiceComponent -from cm.status_api import get_obj_status from rest_framework.serializers import ( ChoiceField, IntegerField, @@ -24,12 +23,12 @@ from api_v2.cluster.serializers import ClusterRelatedSerializer from api_v2.concern.serializers import ConcernSerializer from api_v2.prototype.serializers import PrototypeRelatedSerializer +from api_v2.serializers import WithStatusSerializer -class ServiceRetrieveSerializer(ModelSerializer): +class ServiceRetrieveSerializer(WithStatusSerializer): prototype = PrototypeRelatedSerializer(read_only=True) cluster = ClusterRelatedSerializer(read_only=True) - status = SerializerMethodField() concerns = ConcernSerializer(read_only=True, many=True) main_info = SerializerMethodField() @@ -52,9 +51,6 @@ class Meta: "multi_state", ] - def get_status(self, instance: ClusterObject) -> str: - return get_obj_status(obj=instance) - def get_main_info(self, instance: ClusterObject) -> str | None: return get_main_info(obj=instance) @@ -85,13 +81,7 @@ class Meta: fields = ["id", "name", "display_name", "state", "prototype"] -class RelatedComponentsStatusesSerializer(ModelSerializer): - status = SerializerMethodField() - - @staticmethod - def get_status(instance: ClusterObject) -> str: - return get_obj_status(obj=instance) - +class RelatedComponentsStatusesSerializer(WithStatusSerializer): class Meta: model = ServiceComponent fields = ["id", "name", "display_name", "status"] diff --git a/python/api_v2/service/utils.py b/python/api_v2/service/utils.py index 15fd9ee8cc..976f70a1db 100644 --- a/python/api_v2/service/utils.py +++ b/python/api_v2/service/utils.py @@ -13,7 +13,6 @@ from typing import Literal from cm.adcm_config.config import get_prototype_config, process_file_type -from cm.api import load_service_map from cm.errors import AdcmEx from cm.issue import update_hierarchy_issues from cm.models import ( @@ -26,6 +25,7 @@ Prototype, ServiceComponent, ) +from cm.services.status.notify import reset_hc_map from django.db import connection, transaction from django.db.models import QuerySet from rbac.models import re_apply_object_policy @@ -53,7 +53,7 @@ def bulk_add_services_to_cluster(cluster: Cluster, prototypes: QuerySet[Prototyp update_hierarchy_issues(obj=cluster) re_apply_object_policy(apply_object=cluster) - load_service_map() + reset_hc_map() return services diff --git a/python/api_v2/service/views.py b/python/api_v2/service/views.py index 7a50a7542c..505ad2a617 100644 --- a/python/api_v2/service/views.py +++ b/python/api_v2/service/views.py @@ -20,8 +20,8 @@ ) from adcm.utils import delete_service_from_api, get_maintenance_mode_response from audit.utils import audit -from cm.api import update_mm_objects from cm.models import Cluster, ClusterObject +from cm.services.status.notify import update_mm_objects from django_filters.rest_framework.backends import DjangoFilterBackend from guardian.mixins import PermissionListMixin from rest_framework.decorators import action @@ -48,7 +48,7 @@ bulk_add_services_to_cluster, validate_service_prototypes, ) -from api_v2.views import CamelCaseGenericViewSet +from api_v2.views import CamelCaseGenericViewSet, ObjectWithStatusViewMixin class ServiceViewSet( @@ -59,14 +59,15 @@ class ServiceViewSet( ListModelMixin, RetrieveModelMixin, CamelCaseGenericViewSet, + ObjectWithStatusViewMixin, ): queryset = ClusterObject.objects.select_related("cluster").order_by("pk") - serializer_class = ServiceRetrieveSerializer filterset_class = ServiceFilter filter_backends = (DjangoFilterBackend,) permission_required = [VIEW_SERVICE_PERM] permission_classes = [ServicePermissions] audit_model_hint = ClusterObject + retrieve_status_map_actions = ("list", "statuses") def get_queryset(self, *args, **kwargs): cluster = get_object_for_user( @@ -82,7 +83,7 @@ def get_serializer_class(self): case "maintenance_mode": return ServiceMaintenanceModeSerializer - return self.serializer_class + return ServiceRetrieveSerializer @audit def create(self, request: Request, *args, **kwargs): # noqa: ARG002 @@ -92,9 +93,7 @@ def create(self, request: Request, *args, **kwargs): # noqa: ARG002 check_custom_perm(user=request.user, action_type=ADD_SERVICE_PERM, model=Cluster.__name__.lower(), obj=cluster) multiple_services = isinstance(request.data, list) - serializer = self.get_serializer( - data=request.data, many=multiple_services, context={"cluster": cluster, **self.get_serializer_context()} - ) + serializer = self.get_serializer(data=request.data, many=multiple_services, context={"cluster": cluster}) serializer.is_valid(raise_exception=True) service_prototypes, error = validate_service_prototypes( @@ -104,12 +103,18 @@ def create(self, request: Request, *args, **kwargs): # noqa: ARG002 raise error added_services = bulk_add_services_to_cluster(cluster=cluster, prototypes=service_prototypes) + context = self.get_serializer_context() + if multiple_services: return Response( - status=HTTP_201_CREATED, data=ServiceRetrieveSerializer(instance=added_services, many=True).data + status=HTTP_201_CREATED, + data=ServiceRetrieveSerializer(instance=added_services, many=True, context=context).data, ) - return Response(status=HTTP_201_CREATED, data=ServiceRetrieveSerializer(instance=added_services[0]).data) + return Response( + status=HTTP_201_CREATED, + data=ServiceRetrieveSerializer(instance=added_services[0], context=context).data, + ) @audit def destroy(self, request: Request, *args, **kwargs): # noqa: ARG002 @@ -119,7 +124,7 @@ def destroy(self, request: Request, *args, **kwargs): # noqa: ARG002 @audit @update_mm_objects @action(methods=["post"], detail=True, url_path="maintenance-mode", permission_classes=[ChangeMMPermissions]) - def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 service = get_object_for_user(user=request.user, perms=VIEW_SERVICE_PERM, klass=ClusterObject, pk=kwargs["pk"]) check_custom_perm( user=request.user, action_type=CHANGE_MM_PERM, model=service.__class__.__name__.lower(), obj=service @@ -135,7 +140,7 @@ def maintenance_mode(self, request: Request, *args, **kwargs) -> Response: # no return response @action(methods=["get"], detail=True, url_path="statuses") - def statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG001, ARG002 + def statuses(self, request: Request, *args, **kwargs) -> Response: # noqa: ARG002 service = get_object_for_user(user=request.user, perms=VIEW_SERVICE_PERM, klass=ClusterObject, id=kwargs["pk"]) - return Response(data=ServiceStatusSerializer(instance=service).data) + return Response(data=ServiceStatusSerializer(instance=service, context=self.get_serializer_context()).data) diff --git a/python/api_v2/tests/test_cluster.py b/python/api_v2/tests/test_cluster.py index 9325067eff..466c479dd1 100644 --- a/python/api_v2/tests/test_cluster.py +++ b/python/api_v2/tests/test_cluster.py @@ -9,19 +9,22 @@ # 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. - -from typing import Callable +from typing import Iterable from unittest.mock import patch +from cm.api import add_hc from cm.models import ( Action, ADCMEntityStatus, Cluster, ClusterObject, Host, + HostComponent, Prototype, ServiceComponent, ) +from cm.services.status.client import FullStatusMap +from cm.tests.utils import gen_component, gen_host, gen_service, generate_hierarchy from django.urls import reverse from guardian.models import GroupObjectPermission from rbac.models import User @@ -38,21 +41,15 @@ class TestCluster(BaseAPITestCase): - def get_cluster_status_mock(self) -> Callable: - def inner(cluster: Cluster) -> int: - if cluster.pk == self.cluster_1.pk: - return 0 - - return 32 - - return inner - def test_list_success(self): - response = self.client.get(path=reverse(viewname="v2:cluster-list")) + with patch("cm.services.status.client.api_request") as patched_request: + response = self.client.get(path=reverse(viewname="v2:cluster-list")) self.assertEqual(response.status_code, HTTP_200_OK) self.assertEqual(response.json()["count"], 2) + patched_request.assert_called_once() + def test_adcm_4539_ordering_success(self): cluster_3 = self.add_cluster(bundle=self.bundle_1, name="cluster_3", description="cluster_3") cluster_4 = self.add_cluster(bundle=self.bundle_2, name="cluster_4", description="cluster_3") @@ -66,13 +63,19 @@ def test_adcm_4539_ordering_success(self): self.assertListEqual([cluster["name"] for cluster in response.json()["results"]], cluster_list[::-1]) def test_retrieve_success(self): - response = self.client.get( - path=reverse(viewname="v2:cluster-detail", kwargs={"pk": self.cluster_1.pk}), - ) + with patch("api_v2.views.retrieve_status_map") as patched_retrieve, patch( + "api_v2.views.get_raw_status" + ) as patched_raw: + response = self.client.get( + path=reverse(viewname="v2:cluster-detail", kwargs={"pk": self.cluster_1.pk}), + ) self.assertEqual(response.status_code, HTTP_200_OK) self.assertEqual(response.json()["id"], self.cluster_1.pk) + patched_raw.assert_called_once() + patched_retrieve.assert_not_called() + def test_filter_by_name_success(self): response = self.client.get( path=reverse(viewname="v2:cluster-list"), @@ -92,7 +95,13 @@ def test_filter_by_wrong_name_success(self): self.assertEqual(response.json()["count"], 0) def test_filter_by_status_up_success(self): - with patch("api_v2.cluster.filters.get_cluster_status", new_callable=self.get_cluster_status_mock): + status_map = FullStatusMap( + clusters={ + str(self.cluster_1.pk): {"services": {}, "status": 0, "hosts": {}}, + str(self.cluster_2.pk): {"services": {}, "status": 16, "hosts": {}}, + } + ) + with patch("api_v2.cluster.filters.retrieve_status_map", return_value=status_map): response = self.client.get( path=reverse(viewname="v2:cluster-list"), data={"status": ADCMEntityStatus.UP}, @@ -103,7 +112,13 @@ def test_filter_by_status_up_success(self): self.assertEqual(response.json()["results"][0]["id"], self.cluster_1.pk) def test_filter_by_status_down_success(self): - with patch("api_v2.cluster.filters.get_cluster_status", new_callable=self.get_cluster_status_mock): + status_map = FullStatusMap( + clusters={ + str(self.cluster_1.pk): {"services": {}, "status": 0, "hosts": {}}, + str(self.cluster_2.pk): {"services": {}, "status": 16, "hosts": {}}, + } + ) + with patch("api_v2.cluster.filters.retrieve_status_map", return_value=status_map): response = self.client.get( path=reverse(viewname="v2:cluster-list"), data={"status": ADCMEntityStatus.DOWN}, @@ -598,3 +613,195 @@ def test_adcm_5051_post_change_mm_perm_wrong_object_fail(self): response = self.client.post(path=request, data={"maintenance_mode": "on"}) self.assertEqual(response.status_code, HTTP_404_NOT_FOUND) + + +class TestClusterStatuses(BaseAPITestCase): + @staticmethod + def set_hostcomponent(cluster: Cluster, entries: Iterable[tuple[Host, ServiceComponent]]) -> list[HostComponent]: + return add_hc( + cluster=cluster, + hc_in=[ + {"host_id": host.pk, "component_id": component.pk, "service_id": component.service_id} + for host, component in entries + ], + ) + + def setUp(self) -> None: + self.client.login(username="admin", password="admin") + + hierarchy_1 = generate_hierarchy() + self.cluster_1 = hierarchy_1["cluster"] + self.service_11 = hierarchy_1["service"] + self.component_111 = hierarchy_1["component"] + self.component_112 = gen_component(service=self.service_11) + self.service_12 = gen_service(cluster=self.cluster_1) + self.component_121 = gen_component(service=self.service_12) + self.component_122 = gen_component(service=self.service_12) + self.host_1 = hierarchy_1["host"] + self.host_2 = gen_host(provider=hierarchy_1["provider"], cluster=self.cluster_1) + self.set_hostcomponent( + cluster=self.cluster_1, + entries=[ + (self.host_1, self.component_111), + (self.host_1, self.component_112), + (self.host_1, self.component_121), + (self.host_2, self.component_122), + (self.host_2, self.component_112), + ], + ) + + hierarchy_2 = generate_hierarchy() + self.cluster_2 = hierarchy_2["cluster"] + self.service_21 = hierarchy_2["service"] + self.component_211 = hierarchy_2["component"] + self.host_3 = hierarchy_2["host"] + + self.status_map = FullStatusMap( + clusters={ + str(self.cluster_1.pk): { + "status": 0, + "hosts": {str(self.host_1.pk): {"status": 0}, str(self.host_2.pk): {"status": 16}}, + "services": { + str(self.service_11.pk): { + "status": 4, + "components": { + str(self.component_111.pk): {"status": 16}, + str(self.component_112.pk): {"status": 0}, + }, + "details": [ + {"host": self.host_1.pk, "component": self.component_111.pk, "status": 0}, + {"host": self.host_1.pk, "component": self.component_112.pk, "status": 16}, + {"host": self.host_2.pk, "component": self.component_112.pk, "status": 0}, + ], + }, + str(self.service_12.pk): { + "status": 0, + "components": { + str(self.component_121.pk): {"status": 0}, + str(self.component_122.pk): {"status": 2}, + }, + "details": [ + {"host": self.host_1.pk, "component": self.component_121.pk, "status": 0}, + {"host": self.host_2.pk, "component": self.component_122.pk, "status": 2}, + ], + }, + }, + }, + str(self.cluster_2.pk): {"status": 16, "hosts": {str(self.host_3.pk): {"status": 0}}, "services": {}}, + }, + hosts={ + str(self.host_1.pk): {"status": 0}, + str(self.host_2.pk): {"status": 16}, + str(self.host_3.pk): {"status": 0}, + }, + ) + + @staticmethod + def get_name_status_pairs(entries: list[dict]) -> set[tuple[int, str]]: + return {(entry["name"], entry["status"]) for entry in entries} + + def test_services_statuses_success(self) -> None: + with patch("api_v2.views.retrieve_status_map", return_value=self.status_map) as patched: + response = self.client.get( + path=reverse( + viewname="v2:cluster-services-statuses", + kwargs={"pk": self.cluster_1.pk}, + ), + ) + + patched.assert_called_once() + + self.assertEqual(response.status_code, HTTP_200_OK) + services = response.json()["results"] + self.assertEqual(len(services), 2) + self.assertSetEqual( + self.get_name_status_pairs(services), {(self.service_11.name, "down"), (self.service_12.name, "up")} + ) + service_1, service_2 = sorted(services, key=lambda i: i["id"]) + self.assertEqual(len(service_1["components"]), 2) + self.assertSetEqual( + self.get_name_status_pairs(service_1["components"]), + {(self.component_111.name, "down"), (self.component_112.name, "up")}, + ) + self.assertEqual(len(service_2["components"]), 2) + self.assertSetEqual( + self.get_name_status_pairs(service_2["components"]), + {(self.component_121.name, "up"), (self.component_122.name, "down")}, + ) + + def test_hosts_statuses_success(self) -> None: + with patch("api_v2.views.retrieve_status_map", return_value=self.status_map) as patched: + response = self.client.get( + path=reverse( + viewname="v2:cluster-hosts-statuses", + kwargs={"pk": self.cluster_1.pk}, + ), + ) + + patched.assert_called_once() + + self.assertEqual(response.status_code, HTTP_200_OK) + entries = response.json()["results"] + self.assertEqual(len(entries), 2) + self.assertSetEqual(self.get_name_status_pairs(entries), {(self.host_1.name, "up"), (self.host_2.name, "down")}) + + def test_components_of_service_statuses_success(self) -> None: + with patch("api_v2.views.retrieve_status_map", return_value=self.status_map) as patched: + response = self.client.get( + path=reverse( + viewname="v2:service-statuses", + kwargs={"cluster_pk": self.cluster_1.pk, "pk": self.service_11.pk}, + ), + ) + + patched.assert_called_once() + + self.assertEqual(response.status_code, HTTP_200_OK) + entries = response.json()["components"] + self.assertEqual(len(entries), 2) + self.assertSetEqual( + self.get_name_status_pairs(entries), + {(self.component_111.name, "down"), (self.component_112.name, "up")}, + ) + + def test_hc_statuses_of_component_success(self) -> None: + with patch("api_v2.views.retrieve_status_map", return_value=self.status_map) as patched: + response = self.client.get( + path=reverse( + viewname="v2:component-statuses", + kwargs={ + "cluster_pk": self.cluster_1.pk, + "service_pk": self.service_11.pk, + "pk": self.component_112.pk, + }, + ), + ) + + patched.assert_called_once() + + self.assertEqual(response.status_code, HTTP_200_OK) + entries = response.json()["hostComponents"] + self.assertEqual(len(entries), 2) + self.assertSetEqual( + self.get_name_status_pairs(entries), + {(self.host_1.name, "down"), (self.host_2.name, "up")}, + ) + + def test_hc_statuses_of_host_success(self) -> None: + with patch("api_v2.views.retrieve_status_map", return_value=self.status_map) as patched: + response = self.client.get( + path=reverse( + viewname="v2:host-cluster-statuses", + kwargs={"cluster_pk": self.cluster_1.pk, "pk": self.host_1.pk}, + ), + ) + + patched.assert_called_once() + + self.assertEqual(response.status_code, HTTP_200_OK) + entries = response.json()["hostComponents"] + self.assertEqual(len(entries), 3) + self.assertSetEqual( + self.get_name_status_pairs(entries), + {(self.component_111.name, "up"), (self.component_112.name, "down"), (self.component_121.name, "up")}, + ) diff --git a/python/api_v2/tests/test_import.py b/python/api_v2/tests/test_import.py index c5e248c9d4..bc4e856914 100644 --- a/python/api_v2/tests/test_import.py +++ b/python/api_v2/tests/test_import.py @@ -90,6 +90,7 @@ def test_service_imports_list_success(self): self.assertEqual(response.status_code, HTTP_200_OK) self.assertEqual(response.json()["count"], 1) + self.maxDiff = None self.assertDictEqual( response.json()["results"][0], { diff --git a/python/api_v2/tests/test_service.py b/python/api_v2/tests/test_service.py index 90f9d04edb..e5bbe8a5c0 100644 --- a/python/api_v2/tests/test_service.py +++ b/python/api_v2/tests/test_service.py @@ -10,7 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Callable, NamedTuple +from typing import NamedTuple from unittest.mock import patch from cm.job import ActionRunPayload, run_action @@ -28,6 +28,7 @@ ServiceComponent, TaskLog, ) +from cm.services.status.client import FullStatusMap from django.urls import reverse from rest_framework.status import ( HTTP_200_OK, @@ -52,15 +53,6 @@ def setUp(self) -> None: self.service_2 = self.add_services_to_cluster(service_names=["service_2"], cluster=self.cluster_1).get() self.action = Action.objects.filter(prototype=self.service_2.prototype).first() - def get_service_status_mock(self) -> Callable: - def inner(service: ClusterObject) -> int: - if service.pk == self.service_2.pk: - return 0 - - return 32 - - return inner - def test_list_success(self): response = self.client.get( path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), @@ -190,7 +182,20 @@ def test_filter_by_display_name_success(self): self.assertEqual(response.json()["count"], 1) def test_filter_by_status_success(self): - with patch("api_v2.service.filters.get_service_status", new_callable=self.get_service_status_mock): + status_map = FullStatusMap( + clusters={ + str(self.cluster_1.pk): { + "status": 16, + "hosts": {}, + "services": { + str(self.service_1.pk): {"status": 16, "components": {}, "details": []}, + str(self.service_2.pk): {"status": 0, "components": {}, "details": []}, + }, + } + } + ) + + with patch("api_v2.filters.retrieve_status_map", return_value=status_map): response = self.client.get( path=reverse(viewname="v2:service-list", kwargs={"cluster_pk": self.cluster_1.pk}), data={"status": ADCMEntityStatus.UP}, diff --git a/python/api_v2/views.py b/python/api_v2/views.py index e71391be79..81f3a40691 100644 --- a/python/api_v2/views.py +++ b/python/api_v2/views.py @@ -9,7 +9,11 @@ # 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. +from typing import Collection +from cm.models import Cluster, ClusterObject, Host, ServiceComponent +from cm.services.status.client import retrieve_status_map +from cm.status_api import get_raw_status from djangorestframework_camel_case.parser import ( CamelCaseFormParser, CamelCaseJSONParser, @@ -60,3 +64,50 @@ class CamelCaseModelViewSet( class CamelCaseReadOnlyModelViewSet(RetrieveModelMixin, ListModelMixin, CamelCaseGenericViewSet): pass + + +class ObjectWithStatusViewMixin(GenericViewSet): + retrieve_status_map_actions: Collection[str] = ("list",) + retrieve_single_status_actions: Collection[str] = ("retrieve", "update", "partial_update") + + def get_serializer_context(self) -> dict: + context = super().get_serializer_context() + + if self.action in self.retrieve_status_map_actions: + return {**context, "status_map": retrieve_status_map()} + + if self.action == "create": + return {**context, "status": 0} + + if self.action not in self.retrieve_single_status_actions: + return context + + try: + view_model = self.queryset.model + except AttributeError as err: + message = ( + f"{self.__class__} should have underlying model accessible via " + "`self.queryset.model` to determine how to retrieve status for object" + ) + raise AttributeError(message) from err + + url = None + try: + if view_model in (Cluster, Host): + url = f"{view_model.__name__.lower()}/{self.kwargs['pk']}/" + elif view_model == ClusterObject: + url = f"cluster/{self.kwargs['cluster_pk']}/service/{self.kwargs['pk']}/" + elif view_model == ServiceComponent: + url = ( + f"cluster/{self.kwargs['cluster_pk']}/service/{self.kwargs['service_pk']}" + f"/component/{self.kwargs['pk']}/" + ) + except KeyError as err: + message = f"Failed to detect Status Server URL for {view_model} from {self.kwargs=}" + raise RuntimeError(message) from err + + if not url: + message = f"Failed to detect Status Server URL for {view_model} from {self.kwargs=}" + raise RuntimeError(message) + + return {**context, "status": get_raw_status(url=url)} diff --git a/python/cm/api.py b/python/cm/api.py index 826a3665dd..89a89b267c 100644 --- a/python/cm/api.py +++ b/python/cm/api.py @@ -10,8 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from collections import defaultdict -from functools import partial, wraps +from functools import partial from typing import Literal, TypedDict import json @@ -56,15 +55,14 @@ HostProvider, MaintenanceMode, ObjectConfig, - ObjectType, Prototype, PrototypeExport, PrototypeImport, ServiceComponent, TaskLog, ) +from cm.services.status.notify import reset_hc_map, reset_objects_in_mm from cm.status_api import ( - api_request, send_config_creation_event, send_delete_service_event, send_host_component_map_update_event, @@ -100,84 +98,6 @@ def is_version_suitable(version: str, prototype_import: PrototypeImport) -> bool return True -def load_service_map() -> None: - comps = defaultdict(lambda: defaultdict(list)) - hosts = defaultdict(list) - hc_map = {} - services = defaultdict(list) - - passive = { - component_id: True - for component_id in ServiceComponent.objects.values_list("id", flat=True).filter( - prototype__monitoring="passive" - ) - } - - for cluster_id, service_id, component_id, host_id in ( - HostComponent.objects.values_list("cluster_id", "service_id", "component_id", "host_id") - .exclude(component_id__in=passive.keys()) - .order_by("id") - ): - key = f"{host_id}.{component_id}" - hc_map[key] = {"cluster": cluster_id, "service": service_id} - comps[str(cluster_id)][str(service_id)].append(key) - - for host_id, cluster_id in Host.objects.values_list("id", "cluster_id").filter(prototype__monitoring="active"): - hosts[cluster_id or 0].append(host_id) - - for service_id, cluster_id in ClusterObject.objects.values_list("id", "cluster_id").filter( - prototype__monitoring="active" - ): - services[cluster_id].append(service_id) - - data = { - "hostservice": hc_map, - "component": comps, - "service": services, - "host": hosts, - } - api_request(method="post", url="servicemap/", data=data) - - load_mm_objects() - - -def load_mm_objects(): - """send ids of all objects in mm to status server""" - clusters = Cluster.objects.filter(prototype__type=ObjectType.CLUSTER, prototype__allow_maintenance_mode=True) - - service_ids = set() - component_ids = set() - host_ids = [] - - for service in ClusterObject.objects.filter(cluster__in=clusters).prefetch_related("servicecomponent_set"): - if service.maintenance_mode == MaintenanceMode.ON: - service_ids.add(service.pk) - for component in service.servicecomponent_set.order_by("id"): - if component.maintenance_mode == MaintenanceMode.ON: - component_ids.add(component.pk) - - for host in Host.objects.filter(cluster__in=clusters): - if host.maintenance_mode == MaintenanceMode.ON: - host_ids.append(host.pk) - - data = { - "services": list(service_ids), - "components": list(component_ids), - "hosts": host_ids, - } - return api_request(method="post", url="object/mm/", data=data) - - -def update_mm_objects(func): - @wraps(func) - def wrapper(*args, **kwargs): - res = func(*args, **kwargs) - load_mm_objects() - return res - - return wrapper - - def add_cluster(prototype: Prototype, name: str, description: str = "") -> Cluster: if prototype.type != "cluster": raise_adcm_ex("OBJ_TYPE_ERROR", f"Prototype type should be cluster, not {prototype.type}") @@ -190,7 +110,7 @@ def add_cluster(prototype: Prototype, name: str, description: str = "") -> Clust cluster.save() update_hierarchy_issues(cluster) - load_service_map() + reset_hc_map() logger.info("cluster #%s %s is added", cluster.pk, cluster.name) return cluster @@ -217,7 +137,7 @@ def add_host(prototype: Prototype, provider: HostProvider, fqdn: str, descriptio update_hierarchy_issues(host.provider) re_apply_object_policy(provider) - load_service_map() + reset_hc_map() logger.info("host #%s %s is added", host.pk, host.fqdn) return host @@ -312,7 +232,8 @@ def delete_host(host: Host, cancel_tasks: bool = True) -> None: host_pk = host.pk host.delete() - load_service_map() + reset_hc_map() + reset_objects_in_mm() update_issue_after_deleting() logger.info("host #%s is deleted", host_pk) @@ -378,7 +299,7 @@ def delete_service(service: ClusterObject) -> None: update_issue_after_deleting() update_hierarchy_issues(service.cluster) re_apply_object_policy(service.cluster) - load_service_map() + reset_hc_map() on_commit(func=partial(send_delete_service_event, service_id=service_pk)) logger.info("service #%s is deleted", service_pk) @@ -400,7 +321,8 @@ def delete_cluster(cluster: Cluster) -> None: ) cluster.delete() update_issue_after_deleting() - load_service_map() + reset_hc_map() + reset_objects_in_mm() for task in tasks: task.cancel(obj_deletion=True) @@ -428,7 +350,8 @@ def remove_host_from_cluster(host: Host) -> Host: update_hierarchy_issues(obj=cluster) re_apply_object_policy(apply_object=cluster) - load_service_map() + reset_hc_map() + reset_objects_in_mm() return host @@ -464,7 +387,7 @@ def add_service_to_cluster(cluster: Cluster, proto: Prototype) -> ClusterObject: update_hierarchy_issues(obj=cluster) re_apply_object_policy(apply_object=cluster) - load_service_map() + reset_hc_map() logger.info( "service #%s %s is added to cluster #%s %s", service.pk, @@ -704,7 +627,8 @@ def save_hc( update_hierarchy_issues(provider) update_issue_after_deleting() - load_service_map() + reset_hc_map() + reset_objects_in_mm() for host_component_item in host_component_list: service_set.add(host_component_item.service) @@ -1088,7 +1012,7 @@ def add_host_to_cluster(cluster: Cluster, host: Host) -> Host: update_hierarchy_issues(host) re_apply_object_policy(cluster) - load_service_map() + reset_hc_map() logger.info("host #%s %s is added to cluster #%s %s", host.pk, host.fqdn, cluster.pk, cluster.name) return host diff --git a/python/cm/job.py b/python/cm/job.py index fcac6ac3e8..26b677529f 100644 --- a/python/cm/job.py +++ b/python/cm/job.py @@ -46,7 +46,6 @@ check_maintenance_mode, check_sub_key, get_hc, - load_mm_objects, make_host_comp_list, save_hc, ) @@ -92,6 +91,7 @@ Upgrade, get_object_cluster, ) +from cm.services.status.notify import reset_objects_in_mm from cm.status_api import ( send_object_update_event, send_prototype_and_state_update_event, @@ -872,7 +872,7 @@ def finish_task(task: TaskLog, job: JobLog | None, status: str) -> None: send_task_status_update_event(object_=task, status=status) try: - load_mm_objects() + reset_objects_in_mm() except Exception as error: # noqa: BLE001 logger.warning("Error loading mm objects on task finish") logger.exception(error) diff --git a/python/cm/migrations/0091_migrate_adcm_logrotate_config.py b/python/cm/migrations/0091_migrate_adcm_logrotate_config.py index 149f40b250..7a7b76ce6a 100644 --- a/python/cm/migrations/0091_migrate_adcm_logrotate_config.py +++ b/python/cm/migrations/0091_migrate_adcm_logrotate_config.py @@ -27,7 +27,7 @@ def migrate_logrotate_config(apps, schema_editor): adcm_configlog = ConfigLog.objects.get(obj_ref=adcm_object.config, id=adcm_object.config.current) - # pylint: disable=simplifiable-if-statement + if adcm_configlog.config.get("logrotate", {}).get("nginx_server", False): active_value = True else: diff --git a/python/cm/services/cluster.py b/python/cm/services/cluster.py index 7942df52b9..f6173f3296 100644 --- a/python/cm/services/cluster.py +++ b/python/cm/services/cluster.py @@ -10,19 +10,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Collection, Iterable +from collections import defaultdict +from typing import Collection, Generator, Iterable, Protocol -from core.cluster.operations import add_hosts_to_cluster -from core.cluster.types import HostClusterPair -from core.types import ClusterID, HostID +from core.cluster.operations import add_hosts_to_cluster, build_clusters_topology +from core.cluster.types import ( + ClusterTopology, + HostClusterPair, + HostComponentEntry, + MaintenanceModeOfObjects, + ObjectMaintenanceModeState, +) +from core.types import ClusterID, HostID, ShortObjectInfo from django.db.transaction import atomic from rbac.models import re_apply_object_policy -from cm.api import load_service_map -from cm.models import Cluster, Host +from cm.models import Cluster, ClusterObject, Host, HostComponent, ServiceComponent -class HostClusterDB: +class ClusterDB: __slots__ = () @staticmethod @@ -36,13 +42,91 @@ def get_host_cluster_pairs_for_hosts(hosts: Iterable[HostID]) -> Iterable[HostCl def set_cluster_id_for_hosts(cluster_id: ClusterID, hosts: Iterable[HostID]) -> None: Host.objects.filter(pk__in=hosts).update(cluster_id=cluster_id) + @staticmethod + def get_clusters_hosts(cluster_ids: Iterable[ClusterID]) -> dict[ClusterID, list[ShortObjectInfo]]: + query = Host.objects.filter(cluster_id__in=cluster_ids).values_list("id", "fqdn", "cluster_id") + + result = defaultdict(list) + for host_id, name, cluster_id in query: + result[cluster_id].append(ShortObjectInfo(id=host_id, name=name)) + + return result + + @staticmethod + def get_clusters_services_with_components( + cluster_ids: Iterable[ClusterID], + ) -> dict[ClusterID, list[tuple[ShortObjectInfo, Collection[ShortObjectInfo]]]]: + services = ( + ClusterObject.objects.select_related("prototype") + .prefetch_related("servicecomponent_set__prototype") + .filter(cluster_id__in=cluster_ids) + ) + + result = defaultdict(list) + for service in services: + result[service.cluster_id].append( + ( + ShortObjectInfo(id=service.pk, name=service.name), + tuple( + ShortObjectInfo(id=component.pk, name=component.name) + for component in service.servicecomponent_set.all() + ), + ) + ) + + return result + + @staticmethod + def get_host_component_entries(cluster_ids: Iterable[ClusterID]) -> dict[ClusterID, list[HostComponentEntry]]: + query = HostComponent.objects.filter(cluster_id__in=cluster_ids).values_list( + "host_id", "component_id", "cluster_id" + ) + + result = defaultdict(list) + for host_id, component_id, cluster_id in query: + result[cluster_id].append(HostComponentEntry(host_id=host_id, component_id=component_id)) + + return result + + +class _StatusServerService(Protocol): + def reset_hc_map(self) -> None: + ... -def perform_host_to_cluster_map(cluster_id: int, hosts: Collection[int]) -> Collection[int]: + +def perform_host_to_cluster_map( + cluster_id: int, hosts: Collection[int], status_service: _StatusServerService +) -> Collection[int]: with atomic(): - add_hosts_to_cluster(cluster_id=cluster_id, hosts=hosts, db=HostClusterDB) + add_hosts_to_cluster(cluster_id=cluster_id, hosts=hosts, db=ClusterDB) re_apply_object_policy(Cluster.objects.get(id=cluster_id)) - load_service_map() + status_service.reset_hc_map() return hosts + + +def retrieve_clusters_topology(cluster_ids: Iterable[ClusterID]) -> Generator[ClusterTopology, None, None]: + return build_clusters_topology(cluster_ids=cluster_ids, db=ClusterDB) + + +def retrieve_clusters_objects_maintenance_mode(cluster_ids: Iterable[ClusterID]) -> MaintenanceModeOfObjects: + return MaintenanceModeOfObjects( + hosts={ + host_id: ObjectMaintenanceModeState(mm) + for host_id, mm in Host.objects.values_list("id", "maintenance_mode").filter(cluster_id__in=cluster_ids) + }, + services={ + service_id: ObjectMaintenanceModeState(mm) + for service_id, mm in ClusterObject.objects.values_list("id", "_maintenance_mode").filter( + cluster_id__in=cluster_ids + ) + }, + components={ + component_id: ObjectMaintenanceModeState(mm) + for component_id, mm in ServiceComponent.objects.values_list("id", "_maintenance_mode").filter( + cluster_id__in=cluster_ids + ) + }, + ) diff --git a/python/cm/services/status/__init__.py b/python/cm/services/status/__init__.py new file mode 100644 index 0000000000..824dd6c8fe --- /dev/null +++ b/python/cm/services/status/__init__.py @@ -0,0 +1,11 @@ +# Licensed 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. diff --git a/python/cm/services/status/client.py b/python/cm/services/status/client.py new file mode 100644 index 0000000000..1e50964c37 --- /dev/null +++ b/python/cm/services/status/client.py @@ -0,0 +1,112 @@ +# Licensed 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. + +from contextlib import suppress +from typing import TypeAlias + +from pydantic import ( + BaseModel, + Field, + ValidationError, +) +from requests import JSONDecodeError + +from cm.status_api import api_request + +TypeIDPair: TypeAlias = tuple[str, int] +RawStatus: TypeAlias = int + +StringID: TypeAlias = str +IntegerID: TypeAlias = int + +# pylint: enable=invalid-name + + +class _StatusEntry(BaseModel): + status: RawStatus + + +class _HostComponentStatusEntry(_StatusEntry): + host: IntegerID + component: IntegerID + + +class _ServiceStatusEntry(_StatusEntry): + components: dict[StringID, _StatusEntry] + details: list[_HostComponentStatusEntry] + + +class _ClusterStatusEntry(_StatusEntry): + services: dict[StringID, _ServiceStatusEntry] + hosts: dict[StringID, _StatusEntry] + + +class FullStatusMap(BaseModel): + clusters: dict[StringID, _ClusterStatusEntry] = Field(default_factory=dict) + hosts: dict[StringID, _StatusEntry] = Field(default_factory=dict) + + def get_for_cluster(self, cluster_id: IntegerID) -> RawStatus | None: + with suppress(KeyError): + return self.clusters[str(cluster_id)].status + + return None + + def get_for_service(self, cluster_id: IntegerID, service_id: IntegerID) -> RawStatus | None: + with suppress(KeyError): + return self.clusters[str(cluster_id)].services[str(service_id)].status + + return None + + def get_for_component( + self, cluster_id: IntegerID, service_id: IntegerID, component_id: IntegerID + ) -> RawStatus | None: + with suppress(KeyError): + return self.clusters[str(cluster_id)].services[str(service_id)].components[str(component_id)].status + + return None + + def get_for_host(self, host_id: IntegerID) -> RawStatus | None: + with suppress(KeyError): + return self.hosts[str(host_id)].status + + return None + + def get_for_host_component( + self, cluster_id: IntegerID, service_id: IntegerID, component_id: IntegerID, host_id: IntegerID + ) -> RawStatus | None: + try: + components = self.clusters[str(cluster_id)].services[str(service_id)].details + except KeyError: + return None + + return next( + (entry.status for entry in components if entry.host == host_id and entry.component == component_id), None + ) + + +def retrieve_status_map() -> FullStatusMap: + response = api_request(method="get", url="all/") + if not response: + return FullStatusMap() + + try: + body = response.json() + except JSONDecodeError: + return FullStatusMap() + + if not isinstance(body, dict): + return FullStatusMap() + + try: + return FullStatusMap(**body) + except ValidationError: + return FullStatusMap() diff --git a/python/cm/services/status/convert.py b/python/cm/services/status/convert.py new file mode 100644 index 0000000000..bc052e8878 --- /dev/null +++ b/python/cm/services/status/convert.py @@ -0,0 +1,43 @@ +# Licensed 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. + +from typing import Literal, TypeAlias + +from cm.models import ADCMEntityStatus +from cm.services.status.client import RawStatus + +_MonitoringType: TypeAlias = Literal["active", "passive"] + + +def convert_to_entity_status(raw_status: RawStatus | None) -> ADCMEntityStatus: + return ADCMEntityStatus.UP if raw_status == 0 else ADCMEntityStatus.DOWN + + +def convert_to_service_status(raw_status: RawStatus | None, monitoring: _MonitoringType) -> ADCMEntityStatus: + return _convert_to_status_considering_monitoring(raw_status=raw_status, monitoring=monitoring) + + +def convert_to_component_status(raw_status: RawStatus | None, monitoring: _MonitoringType) -> ADCMEntityStatus: + return _convert_to_status_considering_monitoring(raw_status=raw_status, monitoring=monitoring) + + +def convert_to_host_component_status( + raw_status: RawStatus | None, component_monitoring: _MonitoringType +) -> ADCMEntityStatus: + return _convert_to_status_considering_monitoring(raw_status=raw_status, monitoring=component_monitoring) + + +def _convert_to_status_considering_monitoring(raw_status: RawStatus | None, monitoring: _MonitoringType): + if monitoring == "passive": + return ADCMEntityStatus.UP + + return convert_to_entity_status(raw_status=raw_status) diff --git a/python/cm/services/status/notify.py b/python/cm/services/status/notify.py new file mode 100644 index 0000000000..b14ddd78d7 --- /dev/null +++ b/python/cm/services/status/notify.py @@ -0,0 +1,109 @@ +# Licensed 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. + +from collections import defaultdict +from functools import wraps + +from core.cluster.operations import calculate_maintenance_mode_for_cluster_objects +from core.cluster.types import ObjectMaintenanceModeState +from requests import Response + +from cm.models import Cluster, ClusterObject, Host, HostComponent, ServiceComponent +from cm.services.cluster import ( + retrieve_clusters_objects_maintenance_mode, + retrieve_clusters_topology, +) +from cm.status_api import api_request + + +def reset_hc_map() -> None: + """Send request to SS with new HC map of all clusters""" + comps = defaultdict(lambda: defaultdict(list)) + hosts = defaultdict(list) + hc_map = {} + services = defaultdict(list) + + for cluster_id, service_id, component_id, host_id in ( + HostComponent.objects.values_list("cluster_id", "service_id", "component_id", "host_id") + .exclude( + component_id__in=ServiceComponent.objects.values_list("id", flat=True).filter( + prototype__monitoring="passive" + ) + ) + .order_by("id") + ): + key = f"{host_id}.{component_id}" + hc_map[key] = {"cluster": cluster_id, "service": service_id} + comps[str(cluster_id)][str(service_id)].append(key) + + for host_id, cluster_id in Host.objects.values_list("id", "cluster_id").filter(prototype__monitoring="active"): + hosts[cluster_id or 0].append(host_id) + + for service_id, cluster_id in ClusterObject.objects.values_list("id", "cluster_id").filter( + prototype__monitoring="active" + ): + services[cluster_id].append(service_id) + + data = { + "hostservice": hc_map, + "component": comps, + "service": services, + "host": hosts, + } + api_request(method="post", url="servicemap/", data=data) + + +def reset_objects_in_mm() -> Response | None: + """Send request to SS with all objects that are currently in MM""" + cluster_ids = set(Cluster.objects.values_list("id", flat=True).filter(prototype__allow_maintenance_mode=True)) + if not cluster_ids: + return None + + service_ids = set() + component_ids = set() + host_ids = set() + + mm_info = retrieve_clusters_objects_maintenance_mode(cluster_ids=cluster_ids) + + for topology in retrieve_clusters_topology(cluster_ids=cluster_ids): + cluster_objects_mm = calculate_maintenance_mode_for_cluster_objects( + topology=topology, own_maintenance_mode=mm_info + ) + service_ids |= { + entry_id for entry_id, mm in cluster_objects_mm.services.items() if mm == ObjectMaintenanceModeState.ON + } + component_ids |= { + entry_id for entry_id, mm in cluster_objects_mm.components.items() if mm == ObjectMaintenanceModeState.ON + } + host_ids |= { + entry_id for entry_id, mm in cluster_objects_mm.hosts.items() if mm == ObjectMaintenanceModeState.ON + } + + return api_request( + method="post", + url="object/mm/", + data={ + "services": list(service_ids), + "components": list(component_ids), + "hosts": list(host_ids), + }, + ) + + +def update_mm_objects(func): + @wraps(func) + def wrapper(*args, **kwargs): + res = func(*args, **kwargs) + reset_objects_in_mm() + return res + + return wrapper diff --git a/python/cm/status_api.py b/python/cm/status_api.py index f239323b3f..723940170a 100644 --- a/python/cm/status_api.py +++ b/python/cm/status_api.py @@ -23,7 +23,6 @@ from cm.logger import logger from cm.models import ( ADCMEntity, - ADCMEntityStatus, Cluster, ClusterObject, Host, @@ -191,30 +190,6 @@ def get_component_status(component: ServiceComponent) -> int: return get_status(obj=component, url=f"component/{component.id}/") -def get_obj_status(obj: Cluster | ClusterObject | Host | HostComponent | ServiceComponent) -> str: - match obj.__class__.__name__: - case Cluster.__name__: - url = f"cluster/{obj.pk}/" - case ClusterObject.__name__: - url = f"cluster/{obj.cluster.pk}/service/{obj.pk}/" - case Host.__name__: - url = f"host/{obj.pk}/" - case HostComponent.__name__: - url = f"host/{obj.host_id}/component/{obj.component_id}/" - obj = obj.component - case ServiceComponent.__name__: - url = f"component/{obj.pk}/" - case _: - raise ValueError("Wrong obj type") - - int_status = get_status(obj=obj, url=url) - - if int_status == 0: - return ADCMEntityStatus.UP - - return ADCMEntityStatus.DOWN - - def get_object_map(obj: ADCMEntity, url_type: str) -> dict | None: if url_type == "service": response = api_request(method="get", url=f"cluster/{obj.cluster.id}/service/{obj.id}/?view=interface") diff --git a/python/cm/tests/test_cluster.py b/python/cm/tests/test_cluster.py index 1c615c1d8b..64a962c883 100644 --- a/python/cm/tests/test_cluster.py +++ b/python/cm/tests/test_cluster.py @@ -13,10 +13,14 @@ import string from adcm.tests.base import APPLICATION_JSON, BaseTestCase +from core.cluster.types import ClusterTopology, ComponentTopology, ServiceTopology +from core.types import ShortObjectInfo from django.urls import reverse from rest_framework import status from cm.models import Bundle, Cluster, Prototype +from cm.services.cluster import retrieve_clusters_topology +from cm.tests.utils import gen_component, gen_host, gen_service, generate_hierarchy class TestCluster(BaseTestCase): @@ -149,3 +153,66 @@ def test_cluster_name_update_in_different_states(self): ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_retrieve_cluster_topology_success(self) -> None: + hierarchy = generate_hierarchy() + cluster = hierarchy["cluster"] + service_1 = hierarchy["service"] + component_11 = hierarchy["component"] + host_1 = hierarchy["host"] + host_2 = gen_host(provider=hierarchy["provider"]) + self.add_host_to_cluster(cluster_pk=cluster.pk, host_pk=host_2.pk) + gen_host(provider=hierarchy["provider"]) + service_2 = gen_service(cluster=cluster) + component_21 = gen_component(service=service_2) + component_22 = gen_component(service=service_2) + + component_12 = gen_component(service=service_1) + + lonely_service = gen_service(cluster=cluster) + + host_1_info = ShortObjectInfo(id=host_1.pk, name=host_1.fqdn) + + expected_topology = ClusterTopology( + cluster_id=cluster.pk, + services={ + lonely_service.pk: ServiceTopology( + info=ShortObjectInfo(id=lonely_service.pk, name=lonely_service.prototype.name), components={} + ), + service_1.pk: ServiceTopology( + info=ShortObjectInfo(id=service_1.pk, name=service_1.prototype.name), + components={ + component_11.pk: ComponentTopology( + info=ShortObjectInfo(id=component_11.pk, name=component_11.prototype.name), + hosts={host_1.pk: host_1_info}, + ), + component_12.pk: ComponentTopology( + info=ShortObjectInfo(id=component_12.pk, name=component_12.prototype.name), hosts={} + ), + }, + ), + service_2.pk: ServiceTopology( + info=ShortObjectInfo(id=service_2.pk, name=service_2.prototype.name), + components={ + component_21.pk: ComponentTopology( + info=ShortObjectInfo(id=component_21.pk, name=component_21.prototype.name), hosts={} + ), + component_22.pk: ComponentTopology( + info=ShortObjectInfo(id=component_22.pk, name=component_22.prototype.name), hosts={} + ), + }, + ), + }, + hosts={host_1.pk: host_1_info, host_2.pk: ShortObjectInfo(id=host_2.pk, name=host_2.fqdn)}, + ) + + with self.assertNumQueries(num=5): + actual_topology = next(retrieve_clusters_topology(cluster_ids=[cluster.pk])) + + self.assertEqual(actual_topology, expected_topology) + + second_cluster = generate_hierarchy()["cluster"] + with self.assertNumQueries(num=5): + result = tuple(retrieve_clusters_topology(cluster_ids=[cluster.pk, second_cluster.pk])) + + self.assertSetEqual({entry.cluster_id for entry in result}, {cluster.pk, second_cluster.pk}) diff --git a/python/cm/tests/test_inventory/base.py b/python/cm/tests/test_inventory/base.py index 36a36db281..3f47ff7919 100644 --- a/python/cm/tests/test_inventory/base.py +++ b/python/cm/tests/test_inventory/base.py @@ -61,7 +61,7 @@ class BaseInventoryTestCase(BusinessLogicMixin, BaseTestCase): def setUp(self): super().setUp() - self.maxDiff = None # pylint: disable=invalid-name + self.maxDiff = None self.bundles_dir = Path(__file__).parent.parent / "bundles" self.templates_dir = Path(__file__).parent.parent / "files" / "response_templates" diff --git a/python/cm/tests/test_inventory/test_before_upgrade.py b/python/cm/tests/test_inventory/test_before_upgrade.py index 00e7e0a2b8..f671c5b07d 100644 --- a/python/cm/tests/test_inventory/test_before_upgrade.py +++ b/python/cm/tests/test_inventory/test_before_upgrade.py @@ -19,7 +19,7 @@ from cm.upgrade import bundle_switch, update_before_upgrade -class TestBeforeUpgrade(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes +class TestBeforeUpgrade(BaseInventoryTestCase): def setUp(self) -> None: bundles_dir = Path(__file__).parent.parent / "bundles" self.templates_dir = Path(__file__).parent.parent / "files/response_templates" diff --git a/python/cm/tests/test_inventory/test_components.py b/python/cm/tests/test_inventory/test_components.py index a2597bcc3e..c3ea6d3415 100644 --- a/python/cm/tests/test_inventory/test_components.py +++ b/python/cm/tests/test_inventory/test_components.py @@ -10,8 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=attribute-defined-outside-init,too-many-locals - from cm.models import Action, ClusterObject, ServiceComponent from cm.tests.test_inventory.base import BaseInventoryTestCase diff --git a/python/cm/tests/test_inventory/test_group_config.py b/python/cm/tests/test_inventory/test_group_config.py index 0634650542..ffd6d0c5d5 100644 --- a/python/cm/tests/test_inventory/test_group_config.py +++ b/python/cm/tests/test_inventory/test_group_config.py @@ -27,7 +27,7 @@ from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets -class TestGroupConfigsInInventory(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes +class TestGroupConfigsInInventory(BaseInventoryTestCase): def setUp(self) -> None: super().setUp() diff --git a/python/cm/tests/test_inventory/test_hc_acl_actions.py b/python/cm/tests/test_inventory/test_hc_acl_actions.py index fc61b20223..2b5fa39fd6 100644 --- a/python/cm/tests/test_inventory/test_hc_acl_actions.py +++ b/python/cm/tests/test_inventory/test_hc_acl_actions.py @@ -10,8 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=too-many-instance-attributes - from cm.inventory import HcAclAction from cm.models import Action, ClusterObject, Host, HostComponent, ServiceComponent diff --git a/python/cm/tests/test_inventory/test_host_action.py b/python/cm/tests/test_inventory/test_host_action.py index 5a7c785685..75c5ffea0c 100644 --- a/python/cm/tests/test_inventory/test_host_action.py +++ b/python/cm/tests/test_inventory/test_host_action.py @@ -19,7 +19,7 @@ from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets -class TestHostAction(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes +class TestHostAction(BaseInventoryTestCase): def setUp(self) -> None: bundles_dir = Path(__file__).parent.parent / "bundles" self.templates_dir = Path(__file__).parent.parent / "files/response_templates" diff --git a/python/cm/tests/test_inventory/test_imports.py b/python/cm/tests/test_inventory/test_imports.py index 32692fee07..67f8c2ff75 100644 --- a/python/cm/tests/test_inventory/test_imports.py +++ b/python/cm/tests/test_inventory/test_imports.py @@ -24,7 +24,7 @@ from cm.tests.test_inventory.base import BaseInventoryTestCase, decrypt_secrets -class TestConfigAndImportsInInventory(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes +class TestConfigAndImportsInInventory(BaseInventoryTestCase): PARTIAL_CONFIG = { "boolean": True, "secrettext": "awe\nsopme\n\ttext\n", diff --git a/python/cm/tests/test_inventory/test_maintenance_mode.py b/python/cm/tests/test_inventory/test_maintenance_mode.py index 4808406e46..ace112fb27 100644 --- a/python/cm/tests/test_inventory/test_maintenance_mode.py +++ b/python/cm/tests/test_inventory/test_maintenance_mode.py @@ -29,7 +29,7 @@ from cm.tests.test_inventory.base import BaseInventoryTestCase -class TestMaintenanceMode(BaseInventoryTestCase): # pylint: disable=too-many-instance-attributes +class TestMaintenanceMode(BaseInventoryTestCase): def setUp(self) -> None: bundles_dir = Path(__file__).parent.parent / "bundles" self.templates_dir = Path(__file__).parent.parent / "files/response_templates" diff --git a/python/cm/tests/test_issue.py b/python/cm/tests/test_issue.py index 72e15787a1..129c732c03 100644 --- a/python/cm/tests/test_issue.py +++ b/python/cm/tests/test_issue.py @@ -36,6 +36,7 @@ PrototypeImport, ) from cm.services.cluster import perform_host_to_cluster_map +from cm.services.status import notify from cm.tests.utils import gen_service, generate_hierarchy mock_issue_check_map = { @@ -359,7 +360,7 @@ def test_map_host_to_cluster(self) -> None: ) with patch("cm.issue._issue_check_map", self.MOCK_ISSUE_CHECK_MAP_ALL_FALSE): - perform_host_to_cluster_map(self.cluster.id, [self.host.id]) + perform_host_to_cluster_map(self.cluster.id, [self.host.id], status_service=notify) self.host.refresh_from_db() concerns_after = self.host.concerns.all() diff --git a/python/core/cluster/operations.py b/python/core/cluster/operations.py index d2dbbe6635..3297d5275f 100644 --- a/python/core/cluster/operations.py +++ b/python/core/cluster/operations.py @@ -10,14 +10,157 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Any, Collection, Iterable, Protocol +from collections import defaultdict +from typing import Any, Collection, Generator, Iterable, Protocol from core.cluster.rules import ( check_all_hosts_exist, check_hosts_can_be_added_to_cluster, ) -from core.cluster.types import HostClusterPair -from core.types import ClusterID, HostID +from core.cluster.types import ( + ClusterTopology, + ComponentTopology, + HostClusterPair, + HostComponentEntry, + MaintenanceModeOfObjects, + ObjectMaintenanceModeState, + ServiceTopology, +) +from core.types import ClusterID, ComponentID, HostID, ShortObjectInfo + +# !===== Cluster Topology =====! + + +class ClusterTopologyDBProtocol(Protocol): + def get_clusters_hosts(self, cluster_ids: Iterable[ClusterID]) -> dict[ClusterID, Iterable[ShortObjectInfo]]: + """Get hosts that belongs to given clusters""" + + def get_clusters_services_with_components( + self, cluster_ids: Iterable[ClusterID] + ) -> dict[ClusterID, Iterable[tuple[ShortObjectInfo, Collection[ShortObjectInfo]]]]: + """ + Retrieve pairs of clusters' services and its components. + If service has no components, should return empty collection. + """ + + def get_host_component_entries( + self, cluster_ids: Iterable[ClusterID] + ) -> dict[ClusterID, Iterable[HostComponentEntry]]: + """Retrieve host-components entries of clusters""" + + +def build_clusters_topology( + cluster_ids: Iterable[ClusterID], db: ClusterTopologyDBProtocol +) -> Generator[ClusterTopology, None, None]: + hosts_in_clusters = { + cluster_id: {host.id: host for host in hosts} + for cluster_id, hosts in db.get_clusters_hosts(cluster_ids=cluster_ids).items() + } + services_in_clusters = db.get_clusters_services_with_components(cluster_ids=cluster_ids) + + hosts_on_components: dict[ClusterID, dict[ComponentID, set[HostID]]] = { + cluster_id: defaultdict(set) for cluster_id in cluster_ids + } + if hosts_in_clusters and services_in_clusters: + for cluster_id, entries in db.get_host_component_entries(cluster_ids=cluster_ids).items(): + for entry in entries: + hosts_on_components[cluster_id][entry.component_id].add(entry.host_id) + + return ( + ClusterTopology( + cluster_id=cluster_id, + hosts=hosts_in_clusters.get(cluster_id, {}), + services={ + service.id: ServiceTopology( + info=service, + components={ + component.id: ComponentTopology( + info=component, + hosts={ + host_id: hosts_in_clusters[cluster_id][host_id] + for host_id in hosts_on_components[cluster_id][component.id] + }, + ) + for component in components + }, + ) + for service, components in services_in_clusters.get(cluster_id, ()) + }, + ) + for cluster_id in cluster_ids + ) + + +def calculate_maintenance_mode_for_cluster_objects( + topology: ClusterTopology, own_maintenance_mode: MaintenanceModeOfObjects +) -> MaintenanceModeOfObjects: + cluster_objects_mm = MaintenanceModeOfObjects( + services={}, + components={}, + hosts={ + host_id: own_maintenance_mode.hosts.get(host_id, ObjectMaintenanceModeState.OFF) + for host_id in topology.hosts + }, + ) + + for service_id, service in topology.services.items(): + service_own_mm = own_maintenance_mode.services.get(service_id, ObjectMaintenanceModeState.OFF) + cluster_objects_mm.services[service_id] = calculate_maintenance_mode_for_service( + own_mm=service_own_mm, + service_components_own_mm=( + own_maintenance_mode.components.get(component_id, ObjectMaintenanceModeState.OFF) + for component_id in service.components + ), + service_hosts_mm=( + own_maintenance_mode.hosts.get(host_id, ObjectMaintenanceModeState.OFF) for host_id in service.host_ids + ), + ) + + for component_id, component in service.components.items(): + component_own_mm = own_maintenance_mode.components.get(component_id, ObjectMaintenanceModeState.OFF) + cluster_objects_mm.components[component_id] = calculate_maintenance_mode_for_component( + own_mm=component_own_mm, + service_mm=service_own_mm, + component_hosts_mm=( + own_maintenance_mode.hosts.get(host_id, ObjectMaintenanceModeState.OFF) + for host_id in component.hosts + ), + ) + + return cluster_objects_mm + + +def calculate_maintenance_mode_for_service( + own_mm: ObjectMaintenanceModeState, + service_components_own_mm: Iterable[ObjectMaintenanceModeState], + service_hosts_mm: Iterable[ObjectMaintenanceModeState], +) -> ObjectMaintenanceModeState: + # service has components and all components' maintenance mode is set to ON + if set(service_components_own_mm) == {ObjectMaintenanceModeState.ON}: + return ObjectMaintenanceModeState.ON + + # service has hosts and all hosts' maintenance mode is set to ON + if set(service_hosts_mm) == {ObjectMaintenanceModeState.ON}: + return ObjectMaintenanceModeState.ON + + return own_mm + + +def calculate_maintenance_mode_for_component( + own_mm: ObjectMaintenanceModeState, + service_mm: ObjectMaintenanceModeState, + component_hosts_mm: Iterable[ObjectMaintenanceModeState], +) -> ObjectMaintenanceModeState: + if service_mm == ObjectMaintenanceModeState.ON: + return ObjectMaintenanceModeState.ON + + if set(component_hosts_mm) == {ObjectMaintenanceModeState.ON}: + return ObjectMaintenanceModeState.ON + + return own_mm + + +# !===== Hosts In Cluster =====! class HostClusterDBProtocol(Protocol): diff --git a/python/core/cluster/types.py b/python/core/cluster/types.py index e8cf60d552..60155d5b5c 100644 --- a/python/core/cluster/types.py +++ b/python/core/cluster/types.py @@ -9,10 +9,50 @@ # 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. +from enum import Enum +from itertools import chain +from typing import Generator, NamedTuple -from typing import NamedTuple +from core.types import ClusterID, ComponentID, HostID, ServiceID, ShortObjectInfo class HostClusterPair(NamedTuple): - host_id: int - cluster_id: int | None + host_id: HostID + cluster_id: ClusterID | None + + +class HostComponentEntry(NamedTuple): + host_id: HostID + component_id: ComponentID + + +class ComponentTopology(NamedTuple): + info: ShortObjectInfo + hosts: dict[HostID, ShortObjectInfo] + + +class ServiceTopology(NamedTuple): + info: ShortObjectInfo + components: dict[ComponentID, ComponentTopology] + + @property + def host_ids(self) -> Generator[HostID, None, None]: + return chain.from_iterable(component.hosts for component in self.components.values()) + + +class ClusterTopology(NamedTuple): + cluster_id: ClusterID + services: dict[ServiceID, ServiceTopology] + hosts: dict[HostID, ShortObjectInfo] + + +class ObjectMaintenanceModeState(Enum): + ON = "on" + OFF = "off" + CHANGING = "changing" + + +class MaintenanceModeOfObjects(NamedTuple): + services: dict[ServiceID, ObjectMaintenanceModeState] + components: dict[ComponentID, ObjectMaintenanceModeState] + hosts: dict[HostID, ObjectMaintenanceModeState] diff --git a/python/core/tests/__init__.py b/python/core/tests/__init__.py new file mode 100644 index 0000000000..824dd6c8fe --- /dev/null +++ b/python/core/tests/__init__.py @@ -0,0 +1,11 @@ +# Licensed 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. diff --git a/python/core/tests/test_cluster.py b/python/core/tests/test_cluster.py new file mode 100644 index 0000000000..6ad2a95c63 --- /dev/null +++ b/python/core/tests/test_cluster.py @@ -0,0 +1,189 @@ +# Licensed 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. + +from unittest import TestCase + +from core.cluster.operations import ( + calculate_maintenance_mode_for_cluster_objects, + calculate_maintenance_mode_for_component, + calculate_maintenance_mode_for_service, +) +from core.cluster.types import ( + ClusterTopology, + ComponentTopology, + MaintenanceModeOfObjects, + ServiceTopology, +) +from core.cluster.types import ObjectMaintenanceModeState as MM # noqa: N814 +from core.types import ShortObjectInfo + + +class TestMaintenanceMode(TestCase): + def setUp(self) -> None: + super().setUp() + + self.maxDiff = None + + @staticmethod + def prepare_component_topology(component_id: int, name: str, *hosts: ShortObjectInfo): + return ComponentTopology(info=ShortObjectInfo(component_id, name), hosts={h.id: h for h in hosts}) + + def test_calculate_maintenance_mode_for_cluster_objects(self) -> None: + hosts = {i: ShortObjectInfo(i, f"host-{i}") for i in range(8)} + + maintenance_mode_info = MaintenanceModeOfObjects( + services={10: MM.OFF, 20: MM.ON, 30: MM.CHANGING, 40: MM.CHANGING, 50: MM.OFF, 60: MM.OFF, 70: MM.ON}, + components={ + 100: MM.OFF, + 101: MM.OFF, + 102: MM.ON, + 103: MM.CHANGING, + 200: MM.OFF, + 300: MM.ON, + 400: MM.OFF, + 401: MM.OFF, + 402: MM.ON, + 500: MM.OFF, + }, + hosts={ + hosts[0].id: MM.OFF, + hosts[1].id: MM.OFF, + hosts[2].id: MM.ON, + hosts[3].id: MM.ON, + hosts[4].id: MM.CHANGING, + hosts[5].id: MM.CHANGING, + hosts[6].id: MM.OFF, + hosts[7].id: MM.ON, + }, + ) + + result = calculate_maintenance_mode_for_cluster_objects( + topology=ClusterTopology( + cluster_id=400, + services={ + 10: ServiceTopology( + info=ShortObjectInfo(10, "components & hosts => OFF"), + components={ + 100: self.prepare_component_topology(100, "hosts => OFF", hosts[0], hosts[1]), + 101: self.prepare_component_topology(101, "hosts => ON [from hosts]", hosts[3]), + 102: self.prepare_component_topology(102, "hosts => ON [own]", hosts[4]), + 103: self.prepare_component_topology(103, "hosts => CHANGING [own]", hosts[0]), + }, + ), + 20: ServiceTopology( + info=ShortObjectInfo(20, "components & hosts => ON [own]"), + components={ + 200: self.prepare_component_topology( + 200, "hosts => ON [service]", hosts[0], hosts[1], hosts[4] + ) + }, + ), + 30: ServiceTopology( + info=ShortObjectInfo(30, "components & hosts => ON [components]"), + components={300: self.prepare_component_topology(300, "hosts => ON [own]", hosts[0])}, + ), + 40: ServiceTopology( + info=ShortObjectInfo(40, "components => CHANGING"), + components={ + 400: self.prepare_component_topology(400, "hosts => OFF", hosts[0]), + 401: self.prepare_component_topology(401, " => OFF"), + 402: self.prepare_component_topology(402, " => ON [own]"), + }, + ), + 50: ServiceTopology( + info=ShortObjectInfo(50, "components & hosts => ON [hosts]"), + components={500: self.prepare_component_topology(500, "hosts => ON [hosts]", hosts[2])}, + ), + 60: ServiceTopology(info=ShortObjectInfo(60, "=> OFF"), components={}), + 70: ServiceTopology(info=ShortObjectInfo(70, "=> ON"), components={}), + }, + hosts=hosts, + ), + own_maintenance_mode=maintenance_mode_info, + ) + self.assertEqual( + {"hosts": result.hosts, "services": result.services, "components": result.components}, + { + "hosts": maintenance_mode_info.hosts, + "services": {10: MM.OFF, 20: MM.ON, 30: MM.ON, 40: MM.CHANGING, 50: MM.ON, 60: MM.OFF, 70: MM.ON}, + "components": { + 100: MM.OFF, + 101: MM.ON, + 102: MM.ON, + 103: MM.CHANGING, + 200: MM.ON, + 300: MM.ON, + 400: MM.OFF, + 401: MM.OFF, + 402: MM.ON, + 500: MM.ON, + }, + }, + ) + + def test_calculate_maintenance_mode_for_service(self) -> None: + for (own_mm, service_components_own_mm, service_hosts_mm), expected_result in [ + # own + ((MM.OFF, (), ()), MM.OFF), + ((MM.ON, (), ()), MM.ON), + ((MM.CHANGING, (), ()), MM.CHANGING), + ((MM.ON, (MM.OFF,), (MM.OFF,)), MM.ON), + ((MM.CHANGING, (MM.OFF,), (MM.OFF,)), MM.CHANGING), + # components-related + ((MM.OFF, (MM.OFF, MM.CHANGING, MM.ON), ()), MM.OFF), + ((MM.OFF, (MM.ON, MM.ON), ()), MM.ON), + ((MM.OFF, (MM.OFF, MM.OFF), ()), MM.OFF), + ((MM.OFF, (MM.OFF, MM.ON), ()), MM.OFF), + # hosts-related + ((MM.OFF, (), (MM.OFF, MM.CHANGING, MM.ON)), MM.OFF), + ((MM.OFF, (), (MM.ON, MM.ON)), MM.ON), + ((MM.CHANGING, (), (MM.OFF, MM.OFF)), MM.CHANGING), + ((MM.OFF, (), (MM.OFF, MM.ON)), MM.OFF), + ]: + with self.subTest(f"{own_mm=} | {service_components_own_mm=} | {service_hosts_mm=} = {expected_result}"): + self.assertEqual( + calculate_maintenance_mode_for_service( + own_mm=own_mm, + service_components_own_mm=service_components_own_mm, + service_hosts_mm=service_hosts_mm, + ), + expected_result, + ) + + def test_calculate_maintenance_mode_for_component(self) -> None: + for (own_mm, service_mm, component_hosts_mm), expected_result in [ + # own + ((MM.OFF, MM.OFF, ()), MM.OFF), + ((MM.ON, MM.OFF, ()), MM.ON), + ((MM.ON, MM.OFF, (MM.ON, MM.OFF)), MM.ON), + ((MM.OFF, MM.CHANGING, (MM.OFF, MM.OFF)), MM.OFF), + ((MM.CHANGING, MM.OFF, (MM.OFF, MM.OFF)), MM.CHANGING), + # host-related + ((MM.OFF, MM.OFF, (MM.ON,)), MM.ON), + ((MM.CHANGING, MM.OFF, (MM.ON, MM.ON)), MM.ON), + ((MM.OFF, MM.OFF, (MM.OFF, MM.ON)), MM.OFF), + ((MM.OFF, MM.OFF, (MM.OFF, MM.OFF)), MM.OFF), + ((MM.OFF, MM.OFF, (MM.OFF, MM.CHANGING, MM.ON)), MM.OFF), + ((MM.CHANGING, MM.OFF, (MM.ON, MM.CHANGING, MM.OFF)), MM.CHANGING), + # service-related + ((MM.OFF, MM.ON, ()), MM.ON), + ((MM.ON, MM.ON, ()), MM.ON), + ((MM.CHANGING, MM.ON, ()), MM.ON), + ((MM.OFF, MM.ON, (MM.OFF, MM.OFF)), MM.ON), + ]: + with self.subTest(f"{own_mm=} | {service_mm=} | {component_hosts_mm=} = {expected_result}"): + self.assertEqual( + calculate_maintenance_mode_for_component( + own_mm=own_mm, service_mm=service_mm, component_hosts_mm=component_hosts_mm + ), + expected_result, + ) diff --git a/python/core/types.py b/python/core/types.py index 4b7046824e..2e5e94fb51 100644 --- a/python/core/types.py +++ b/python/core/types.py @@ -10,12 +10,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import TypeAlias +from typing import NamedTuple, TypeAlias ObjectID: TypeAlias = int ClusterID: TypeAlias = ObjectID +ServiceID: TypeAlias = ObjectID +ComponentID: TypeAlias = ObjectID HostID: TypeAlias = ObjectID class ADCMCoreError(Exception): ... + + +class ShortObjectInfo(NamedTuple): + id: int + name: str From 4cd7a80236af3643004006cdd889c70e1bb0e418 Mon Sep 17 00:00:00 2001 From: Vladimir Remizov Date: Fri, 26 Jan 2024 10:12:52 +0000 Subject: [PATCH 058/151] Update codeowners --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index 7071142002..4a3cd9fe18 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,4 @@ +/adcm-web/ @frontend /data/ @aas @d.skrynnik @aer /conf/ @aas @d.skrynnik @a.starovoitov @aer /go/ @aas @d.skrynnik @aer From effc6bce805f85616f08351fdb228de3a39b7501 Mon Sep 17 00:00:00 2001 From: Igor Kuzmin Date: Fri, 26 Jan 2024 11:14:13 +0000 Subject: [PATCH 059/151] feature/ADCM-5216 use single configurationSlice for all entities Task: https://tracker.yandex.ru/ADCM-5216 --- adcm-web/app/src/api/adcm/clusterConfigs.ts | 42 +-- .../src/api/adcm/clusterGroupConfigConfigs.ts | 45 +-- .../adcm/clusterServiceComponentsConfigs.ts | 48 ++-- .../adcm/clusterServiceGroupConfigConfigs.ts | 47 +-- .../src/api/adcm/clusterServicesConfigs.ts | 50 ++-- adcm-web/app/src/api/adcm/hostConfigs.ts | 42 +-- .../app/src/api/adcm/hostProviderConfigs.ts | 42 +-- .../adcm/hostProviderGroupConfigConfigs.ts | 45 +-- .../serviceComponentGroupConfigConfigs.ts | 51 ++-- adcm-web/app/src/api/adcm/settings.ts | 24 +- ...useHostProviderConfigGroupConfiguration.ts | 57 ++-- .../useHostProviderPrimaryConfiguration.ts | 42 +-- .../useSettingsConfiguration.ts | 40 +-- .../SettingsPage/useRequestAdcmSettings.ts | 2 +- .../useClusterConfigGroupConfiguration.ts | 51 ++-- .../useClusterPrimaryConfiguration.ts | 31 +- ...seServiceConfigGroupSingleConfiguration.ts | 61 ++-- .../useServicesPrimaryConfiguration.ts | 53 ++-- .../useComponentPrimaryConfiguration.ts | 61 ++-- ...erviceComponentConfigGroupConfiguration.ts | 69 +++-- .../useHostPrimaryConfiguration.ts | 44 +-- .../clusterConfigGroupConfigurationSlice.ts | 188 ------------ .../clusterConfigurationSlice.ts | 173 ----------- .../serviceConfigGroupConfigurationSlice.ts | 197 ------------- ...eComponentConfigGroupConfigurationSlice.ts | 211 -------------- .../serviceComponentConfigurationSlice.ts | 197 ------------- .../servicesConfigurationSlice.ts | 182 ------------ .../compareSlice.constants.ts | 87 ------ .../adcm/entityConfiguration/compareSlice.ts | 4 +- .../entityConfiguration/compareSlice.types.ts | 136 --------- .../configurationSlice.ts} | 106 +++---- .../entityConfiguration.constants.ts | 163 +++++++++++ .../entityConfiguration.types.ts | 270 ++++++++++++++++++ .../hostProviderConfigurationSlice.ts | 176 ------------ ...stProviderConfigGroupConfigurationSlice.ts | 185 ------------ .../settingsConfigurationSlice.ts | 162 ----------- adcm-web/app/src/store/store.ts | 22 +- 37 files changed, 1027 insertions(+), 2379 deletions(-) delete mode 100644 adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.constants.ts delete mode 100644 adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.types.ts rename adcm-web/app/src/store/adcm/{host/configuration/hostsConfigurationSlice.ts => entityConfiguration/configurationSlice.ts} (52%) create mode 100644 adcm-web/app/src/store/adcm/entityConfiguration/entityConfiguration.constants.ts create mode 100644 adcm-web/app/src/store/adcm/entityConfiguration/entityConfiguration.types.ts delete mode 100644 adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice.ts delete mode 100644 adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationSlice.ts diff --git a/adcm-web/app/src/api/adcm/clusterConfigs.ts b/adcm-web/app/src/api/adcm/clusterConfigs.ts index 6814891ad4..30c7330d44 100644 --- a/adcm-web/app/src/api/adcm/clusterConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterConfigs.ts @@ -8,43 +8,49 @@ import { ConfigurationAttributes, } from '@models/adcm'; -type GetConfigArgs = { +export interface GetClusterConfigsArgs { + clusterId: number; +} + +export interface GetClusterConfigArgs { clusterId: number; configId: number; -}; +} -type GetConfigSchemaArgs = { +interface GetClusterConfigSchemaArgs { clusterId: number; -}; +} + +export interface CreateClusterConfigArgs { + clusterId: number; + description?: string; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmClusterConfigsApi { - public static async getConfigs(clusterId: number) { + public static async getConfigs(args: GetClusterConfigsArgs) { const response = await httpClient.get>( - `/api/v2/clusters/${clusterId}/configs/?offset=0&limit=1000`, + `/api/v2/clusters/${args.clusterId}/configs/?offset=0&limit=1000`, ); return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetClusterConfigArgs) { const response = await httpClient.get(`/api/v2/clusters/${args.clusterId}/configs/${args.configId}/`); return response.data; } - public static async getConfigSchema(args: GetConfigSchemaArgs) { + public static async getConfigSchema(args: GetClusterConfigSchemaArgs) { const response = await httpClient.get(`/api/v2/clusters/${args.clusterId}/config-schema/`); return response.data; } - public static async createConfiguration( - clusterId: number, - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { - const response = await httpClient.post(`/api/v2/clusters/${clusterId}/configs/`, { - description, - adcmMeta: attributes, - config: configurationData, + public static async createConfiguration(args: CreateClusterConfigArgs) { + const response = await httpClient.post(`/api/v2/clusters/${args.clusterId}/configs/`, { + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, }); return response.data; } diff --git a/adcm-web/app/src/api/adcm/clusterGroupConfigConfigs.ts b/adcm-web/app/src/api/adcm/clusterGroupConfigConfigs.ts index 764a2a36f3..d1496b5e39 100644 --- a/adcm-web/app/src/api/adcm/clusterGroupConfigConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterGroupConfigConfigs.ts @@ -8,52 +8,59 @@ import { ConfigurationAttributes, } from '@models/adcm'; -type GetConfigArgs = { +export interface GetClusterGroupConfigsArgs { + clusterId: number; + configGroupId: number; +} + +export interface GetClusterGroupConfigArgs { clusterId: number; configGroupId: number; configId: number; -}; +} -type GetConfigSchemaArgs = { +interface GetClusterGroupConfigSchemaArgs { clusterId: number; configGroupId: number; -}; +} + +export interface CreateClusterGroupConfigArgs { + clusterId: number; + configGroupId: number; + description?: string; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmClusterGroupConfigsConfigsApi { - public static async getConfigs(clusterId: number, configGroupId: number) { + public static async getConfigs(args: GetClusterGroupConfigsArgs) { const response = await httpClient.get>( - `/api/v2/clusters/${clusterId}/config-groups/${configGroupId}/configs/?offset=0&limit=1000`, + `/api/v2/clusters/${args.clusterId}/config-groups/${args.configGroupId}/configs/?offset=0&limit=1000`, ); return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetClusterGroupConfigArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/config-groups/${args.configGroupId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(args: GetConfigSchemaArgs) { + public static async getConfigSchema(args: GetClusterGroupConfigSchemaArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/config-groups/${args.configGroupId}/config-schema/`, ); return response.data; } - public static async createConfiguration( - clusterId: number, - configGroupId: number, - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { + public static async createConfiguration(args: CreateClusterGroupConfigArgs) { const response = await httpClient.post( - `/api/v2/clusters/${clusterId}/config-groups/${configGroupId}/configs/`, + `/api/v2/clusters/${args.clusterId}/config-groups/${args.configGroupId}/configs/`, { - description, - adcmMeta: attributes, - config: configurationData, + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, }, ); return response.data; diff --git a/adcm-web/app/src/api/adcm/clusterServiceComponentsConfigs.ts b/adcm-web/app/src/api/adcm/clusterServiceComponentsConfigs.ts index 376db4ae90..3815771e72 100644 --- a/adcm-web/app/src/api/adcm/clusterServiceComponentsConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterServiceComponentsConfigs.ts @@ -8,55 +8,63 @@ import { ConfigurationAttributes, } from '@models/adcm'; -export type GetConfigArgs = { +export interface GetClusterServiceComponentConfigsArgs { + clusterId: number; + serviceId: number; + componentId: number; +} + +export interface GetClusterServiceComponentConfigArgs { clusterId: number; serviceId: number; componentId: number; configId: number; -}; +} -export type GetConfigSchemaArgs = { +interface GetClusterServiceComponentConfigSchemaArgs { clusterId: number; serviceId: number; componentId: number; -}; +} + +export interface CreateClusterServiceComponentConfigArgs { + clusterId: number; + serviceId: number; + componentId: number; + description?: string; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmClusterServiceComponentsConfigsApi { - public static async getConfigs(clusterId: number, serviceId: number, componentId: number) { + public static async getConfigs(args: GetClusterServiceComponentConfigsArgs) { const response = await httpClient.get>( - `/api/v2/clusters/${clusterId}/services/${serviceId}/components/${componentId}/configs/?offset=0&limit=1000`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/configs/?offset=0&limit=1000`, ); return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetClusterServiceComponentConfigArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(args: GetConfigSchemaArgs) { + public static async getConfigSchema(args: GetClusterServiceComponentConfigSchemaArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/config-schema/`, ); return response.data; } - public static async createConfiguration( - clusterId: number, - serviceId: number, - componentId: number, - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { + public static async createConfiguration(args: CreateClusterServiceComponentConfigArgs) { const response = await httpClient.post( - `/api/v2/clusters/${clusterId}/services/${serviceId}/components/${componentId}/configs/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/configs/`, { - description, - adcmMeta: attributes, - config: configurationData, + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, }, ); return response.data; diff --git a/adcm-web/app/src/api/adcm/clusterServiceGroupConfigConfigs.ts b/adcm-web/app/src/api/adcm/clusterServiceGroupConfigConfigs.ts index 44ea3434e8..3da247db54 100644 --- a/adcm-web/app/src/api/adcm/clusterServiceGroupConfigConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterServiceGroupConfigConfigs.ts @@ -8,55 +8,62 @@ import { ConfigurationAttributes, } from '@models/adcm'; -type GetConfigArgs = { +export interface GetClusterServiceGroupConfigsArgs { + clusterId: number; + serviceId: number; + configGroupId: number; +} +export interface GetClusterServiceGroupConfigArgs { clusterId: number; serviceId: number; configGroupId: number; configId: number; -}; +} -type GetConfigSchemaArgs = { +interface GetClusterServiceGroupConfigSchemaArgs { clusterId: number; serviceId: number; configGroupId: number; -}; +} + +export interface CreateClusterServiceGroupConfigArgs { + clusterId: number; + serviceId: number; + description?: string; + configGroupId: number; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmClusterServiceConfigGroupConfigsApi { - public static async getConfigs(clusterId: number, serviceId: number, configGroupId: number) { + public static async getConfigs(args: GetClusterServiceGroupConfigsArgs) { const response = await httpClient.get>( - `/api/v2/clusters/${clusterId}/services/${serviceId}/config-groups/${configGroupId}/configs/?offset=0&limit=1000`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/config-groups/${args.configGroupId}/configs/?offset=0&limit=1000`, ); return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetClusterServiceGroupConfigArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/config-groups/${args.configGroupId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(args: GetConfigSchemaArgs) { + public static async getConfigSchema(args: GetClusterServiceGroupConfigSchemaArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/config-groups/${args.configGroupId}/config-schema/`, ); return response.data; } - public static async createConfiguration( - clusterId: number, - serviceId: number, - configGroupId: number, - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { + public static async createConfiguration(args: CreateClusterServiceGroupConfigArgs) { const response = await httpClient.post( - `/api/v2/clusters/${clusterId}/services/${serviceId}/config-groups/${configGroupId}/configs/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/config-groups/${args.configGroupId}/configs/`, { - description, - adcmMeta: attributes, - config: configurationData, + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, }, ); return response.data; diff --git a/adcm-web/app/src/api/adcm/clusterServicesConfigs.ts b/adcm-web/app/src/api/adcm/clusterServicesConfigs.ts index 615281e223..f3b8d24099 100644 --- a/adcm-web/app/src/api/adcm/clusterServicesConfigs.ts +++ b/adcm-web/app/src/api/adcm/clusterServicesConfigs.ts @@ -8,51 +8,61 @@ import { ConfigurationAttributes, } from '@models/adcm'; -type GetConfigArgs = { +export interface GetClusterServiceConfigsArgs { + clusterId: number; + serviceId: number; +} + +export interface GetClusterServiceConfigArgs { clusterId: number; serviceId: number; configId: number; -}; +} -type GetConfigSchemaArgs = { +interface GetClusterServiceConfigSchemaArgs { clusterId: number; serviceId: number; -}; +} + +export interface CreateClusterServiceConfigArgs { + clusterId: number; + serviceId: number; + description?: string; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmClusterServicesConfigsApi { - public static async getConfigs(clusterId: number, serviceId: number) { + public static async getConfigs(args: GetClusterServiceConfigsArgs) { const response = await httpClient.get>( - `/api/v2/clusters/${clusterId}/services/${serviceId}/configs/?offset=0&limit=1000`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/configs/?offset=0&limit=1000`, ); return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetClusterServiceConfigArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/configs/${args.configId}`, ); return response.data; } - public static async getConfigSchema(args: GetConfigSchemaArgs) { + public static async getConfigSchema(args: GetClusterServiceConfigSchemaArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/config-schema/`, ); return response.data; } - public static async createConfiguration( - clusterId: number, - serviceId: number, - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { - const response = await httpClient.post(`/api/v2/clusters/${clusterId}/services/${serviceId}/configs/`, { - description, - adcmMeta: attributes, - config: configurationData, - }); + public static async createConfiguration(args: CreateClusterServiceConfigArgs) { + const response = await httpClient.post( + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/configs/`, + { + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, + }, + ); return response.data; } } diff --git a/adcm-web/app/src/api/adcm/hostConfigs.ts b/adcm-web/app/src/api/adcm/hostConfigs.ts index b5719444d9..ab62c816f0 100644 --- a/adcm-web/app/src/api/adcm/hostConfigs.ts +++ b/adcm-web/app/src/api/adcm/hostConfigs.ts @@ -8,43 +8,49 @@ import { ConfigurationAttributes, } from '@models/adcm'; -type GetConfigArgs = { +export interface GetHostConfigsArgs { + hostId: number; +} + +export interface GetHostConfigArgs { hostId: number; configId: number; -}; +} -type GetConfigSchemaArgs = { +interface GetHostConfigSchemaArgs { hostId: number; -}; +} + +export interface CreateHostConfigArgs { + hostId: number; + description?: string; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmHostConfigsApi { - public static async getConfigs(hostId: number) { + public static async getConfigs(args: GetHostConfigsArgs) { const response = await httpClient.get>( - `/api/v2/hosts/${hostId}/configs/?offset=0&limit=1000`, + `/api/v2/hosts/${args.hostId}/configs/?offset=0&limit=1000`, ); return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetHostConfigArgs) { const response = await httpClient.get(`/api/v2/hosts/${args.hostId}/configs/${args.configId}/`); return response.data; } - public static async getConfigSchema(args: GetConfigSchemaArgs) { + public static async getConfigSchema(args: GetHostConfigSchemaArgs) { const response = await httpClient.get(`/api/v2/hosts/${args.hostId}/config-schema/`); return response.data; } - public static async createConfiguration( - hostId: number, - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { - const response = await httpClient.post(`/api/v2/hosts/${hostId}/configs/`, { - description, - adcmMeta: attributes, - config: configurationData, + public static async createConfiguration(args: CreateHostConfigArgs) { + const response = await httpClient.post(`/api/v2/hosts/${args.hostId}/configs/`, { + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, }); return response.data; } diff --git a/adcm-web/app/src/api/adcm/hostProviderConfigs.ts b/adcm-web/app/src/api/adcm/hostProviderConfigs.ts index 79ffe0a8e2..56f6d629a4 100644 --- a/adcm-web/app/src/api/adcm/hostProviderConfigs.ts +++ b/adcm-web/app/src/api/adcm/hostProviderConfigs.ts @@ -8,47 +8,53 @@ import { ConfigurationAttributes, } from '@models/adcm'; -type GetConfigArgs = { +export interface GetHostProviderConfigsArgs { + hostProviderId: number; +} + +export interface GetHostProviderConfigArgs { hostProviderId: number; configId: number; -}; +} -type GetConfigSchemaArgs = { +interface GetHostProviderConfigSchemaArgs { hostProviderId: number; -}; +} + +export interface CreateHostProviderConfigArgs { + hostProviderId: number; + description?: string; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmHostProviderConfigsApi { - public static async getConfigs(hostProviderId: number) { + public static async getConfigs(args: GetHostProviderConfigsArgs) { const response = await httpClient.get>( - `/api/v2/hostproviders/${hostProviderId}/configs/?offset=0&limit=1000`, + `/api/v2/hostproviders/${args.hostProviderId}/configs/?offset=0&limit=1000`, ); return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetHostProviderConfigArgs) { const response = await httpClient.get( `/api/v2/hostproviders/${args.hostProviderId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(args: GetConfigSchemaArgs) { + public static async getConfigSchema(args: GetHostProviderConfigSchemaArgs) { const response = await httpClient.get( `/api/v2/hostproviders/${args.hostProviderId}/config-schema/`, ); return response.data; } - public static async createConfiguration( - hostProviderId: number, - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { - const response = await httpClient.post(`/api/v2/hostproviders/${hostProviderId}/configs/`, { - description, - adcmMeta: attributes, - config: configurationData, + public static async createConfiguration(args: CreateHostProviderConfigArgs) { + const response = await httpClient.post(`/api/v2/hostproviders/${args.hostProviderId}/configs/`, { + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, }); return response.data; } diff --git a/adcm-web/app/src/api/adcm/hostProviderGroupConfigConfigs.ts b/adcm-web/app/src/api/adcm/hostProviderGroupConfigConfigs.ts index 99cffec706..7a12437b27 100644 --- a/adcm-web/app/src/api/adcm/hostProviderGroupConfigConfigs.ts +++ b/adcm-web/app/src/api/adcm/hostProviderGroupConfigConfigs.ts @@ -8,52 +8,59 @@ import { ConfigurationAttributes, } from '@models/adcm'; -type GetConfigArgs = { +export interface GetHostProviderGroupConfigsArgs { + hostProviderId: number; + configGroupId: number; +} + +export interface GetHostProviderGroupConfigArgs { hostProviderId: number; configGroupId: number; configId: number; -}; +} -type GetConfigSchemaArgs = { +interface GetHostProviderGroupConfigSchemaArgs { hostProviderId: number; configGroupId: number; -}; +} + +export interface CreateHostProviderGroupConfigArgs { + hostProviderId: number; + configGroupId: number; + description?: string; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmHostProviderGroupConfigsConfigsApi { - public static async getConfigs(hostProviderId: number, configGroupId: number) { + public static async getConfigs(args: GetHostProviderGroupConfigsArgs) { const response = await httpClient.get>( - `/api/v2/hostproviders/${hostProviderId}/config-groups/${configGroupId}/configs/?offset=0&limit=1000`, + `/api/v2/hostproviders/${args.hostProviderId}/config-groups/${args.configGroupId}/configs/?offset=0&limit=1000`, ); return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetHostProviderGroupConfigArgs) { const response = await httpClient.get( `/api/v2/hostproviders/${args.hostProviderId}/config-groups/${args.configGroupId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(args: GetConfigSchemaArgs) { + public static async getConfigSchema(args: GetHostProviderGroupConfigSchemaArgs) { const response = await httpClient.get( `/api/v2/hostproviders/${args.hostProviderId}/config-groups/${args.configGroupId}/config-schema/`, ); return response.data; } - public static async createConfiguration( - hostProviderId: number, - configGroupId: number, - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { + public static async createConfiguration(args: CreateHostProviderGroupConfigArgs) { const response = await httpClient.post( - `/api/v2/hostproviders/${hostProviderId}/config-groups/${configGroupId}/configs/`, + `/api/v2/hostproviders/${args.hostProviderId}/config-groups/${args.configGroupId}/configs/`, { - description, - adcmMeta: attributes, - config: configurationData, + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, }, ); return response.data; diff --git a/adcm-web/app/src/api/adcm/serviceComponentGroupConfigConfigs.ts b/adcm-web/app/src/api/adcm/serviceComponentGroupConfigConfigs.ts index 8fdabc3737..a8bc542a29 100644 --- a/adcm-web/app/src/api/adcm/serviceComponentGroupConfigConfigs.ts +++ b/adcm-web/app/src/api/adcm/serviceComponentGroupConfigConfigs.ts @@ -8,58 +8,67 @@ import { ConfigurationAttributes, } from '@models/adcm'; -type GetConfigArgs = { +export interface GetClusterServiceComponentGroupConfigsArgs { + clusterId: number; + serviceId: number; + componentId: number; + configGroupId: number; +} + +export interface GetClusterServiceComponentGroupConfigArgs { clusterId: number; serviceId: number; componentId: number; configGroupId: number; configId: number; -}; +} -type GetConfigSchemaArgs = { +interface GetClusterServiceComponentGroupConfigSchemaArgs { clusterId: number; serviceId: number; componentId: number; configGroupId: number; -}; +} + +export interface CreateClusterServiceComponentGroupConfigArgs { + clusterId: number; + serviceId: number; + componentId: number; + configGroupId: number; + description?: string; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmClusterServiceComponentGroupConfigConfigsApi { - public static async getConfigs(clusterId: number, serviceId: number, componentId: number, configGroupId: number) { + public static async getConfigs(args: GetClusterServiceComponentGroupConfigsArgs) { const response = await httpClient.get>( - `/api/v2/clusters/${clusterId}/services/${serviceId}/components/${componentId}/config-groups/${configGroupId}/configs/?offset=0&limit=1000`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/config-groups/${args.configGroupId}/configs/?offset=0&limit=1000`, ); return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetClusterServiceComponentGroupConfigArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/config-groups/${args.configGroupId}/configs/${args.configId}/`, ); return response.data; } - public static async getConfigSchema(args: GetConfigSchemaArgs) { + public static async getConfigSchema(args: GetClusterServiceComponentGroupConfigSchemaArgs) { const response = await httpClient.get( `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/config-groups/${args.configGroupId}/config-schema/`, ); return response.data; } - public static async createConfiguration( - clusterId: number, - serviceId: number, - componentId: number, - configGroupId: number, - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { + public static async createConfiguration(args: CreateClusterServiceComponentGroupConfigArgs) { const response = await httpClient.post( - `/api/v2/clusters/${clusterId}/services/${serviceId}/components/${componentId}/config-groups/${configGroupId}/configs/`, + `/api/v2/clusters/${args.clusterId}/services/${args.serviceId}/components/${args.componentId}/config-groups/${args.configGroupId}/configs/`, { - description, - adcmMeta: attributes, - config: configurationData, + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, }, ); return response.data; diff --git a/adcm-web/app/src/api/adcm/settings.ts b/adcm-web/app/src/api/adcm/settings.ts index 8957542e40..0ab478f0a0 100644 --- a/adcm-web/app/src/api/adcm/settings.ts +++ b/adcm-web/app/src/api/adcm/settings.ts @@ -12,9 +12,15 @@ import { AdcmDynamicActionRunConfig, } from '@models/adcm'; -type GetConfigArgs = { +export interface GetSettingsConfigArgs { configId: number; -}; +} + +export interface CreateSettingsConfigArgs { + description?: string; + configurationData: ConfigurationData; + attributes: ConfigurationAttributes; +} export class AdcmSettingsApi { public static async getSettings() { @@ -27,7 +33,7 @@ export class AdcmSettingsApi { return response.data; } - public static async getConfig(args: GetConfigArgs) { + public static async getConfig(args: GetSettingsConfigArgs) { const response = await httpClient.get(`/api/v2/adcm/configs/${args.configId}/`); return response.data; } @@ -37,15 +43,11 @@ export class AdcmSettingsApi { return response.data; } - public static async createConfiguration( - configurationData: ConfigurationData, - attributes: ConfigurationAttributes, - description = '', - ) { + public static async createConfiguration(args: CreateSettingsConfigArgs) { const response = await httpClient.post('/api/v2/adcm/configs/', { - description, - adcmMeta: attributes, - config: configurationData, + description: args.description ?? '', + adcmMeta: args.attributes, + config: args.configurationData, }); return response.data; } diff --git a/adcm-web/app/src/components/pages/HostProviderPage/HostProviderConfigurationGroupSingle/HostProviderConfigGroupConfiguration/useHostProviderConfigGroupConfiguration.ts b/adcm-web/app/src/components/pages/HostProviderPage/HostProviderConfigurationGroupSingle/HostProviderConfigGroupConfiguration/useHostProviderConfigGroupConfiguration.ts index ab4d31f0f9..05fd20a41d 100644 --- a/adcm-web/app/src/components/pages/HostProviderPage/HostProviderConfigurationGroupSingle/HostProviderConfigGroupConfiguration/useHostProviderConfigGroupConfiguration.ts +++ b/adcm-web/app/src/components/pages/HostProviderPage/HostProviderConfigurationGroupSingle/HostProviderConfigGroupConfiguration/useHostProviderConfigGroupConfiguration.ts @@ -1,37 +1,38 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { - cleanupHostProviderConfigGroupConfiguration, - createWithUpdateHostProviderConfigGroupConfigurations, - getHostProviderConfigGroupConfiguration, - getHostProviderConfigGroupConfigurationsVersions, -} from '@store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; export const useHostProviderConfigGroupConfiguration = () => { const dispatch = useDispatch(); const hostProvider = useStore(({ adcm }) => adcm.hostProvider.hostProvider); const hostProviderConfigGroup = useStore((s) => s.adcm.hostProviderConfigGroup.hostProviderConfigGroup); - const configVersions = useStore(({ adcm }) => adcm.hostProviderConfigGroupConfiguration.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.hostProviderConfigGroupConfiguration.loadedConfiguration); - const isConfigurationLoading = useStore( - ({ adcm }) => adcm.hostProviderConfigGroupConfiguration.isConfigurationLoading, - ); - const isVersionsLoading = useStore(({ adcm }) => adcm.hostProviderConfigGroupConfiguration.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { if (hostProvider && hostProviderConfigGroup) { // load all configurations for current HostProvider dispatch( - getHostProviderConfigGroupConfigurationsVersions({ - hostProviderId: hostProvider.id, - configGroupId: hostProviderConfigGroup.id, + getConfigurationsVersions({ + entityType: 'host-provider-config-group', + args: { + hostProviderId: hostProvider.id, + configGroupId: hostProviderConfigGroup.id, + }, }), ); } return () => { - dispatch(cleanupHostProviderConfigGroupConfiguration()); + dispatch(cleanup()); }; }, [hostProvider, hostProviderConfigGroup, dispatch]); @@ -44,10 +45,13 @@ export const useHostProviderConfigGroupConfiguration = () => { if (hostProvider && hostProviderConfigGroup && selectedConfigId) { // load full config for selected configuration dispatch( - getHostProviderConfigGroupConfiguration({ - hostProviderId: hostProvider.id, - configGroupId: hostProviderConfigGroup.id, - configId: selectedConfigId, + getConfiguration({ + entityType: 'host-provider-config-group', + args: { + hostProviderId: hostProvider.id, + configGroupId: hostProviderConfigGroup.id, + configId: selectedConfigId, + }, }), ); } @@ -60,12 +64,15 @@ export const useHostProviderConfigGroupConfiguration = () => { if (hostProvider?.id && hostProviderConfigGroup?.id && selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateHostProviderConfigGroupConfigurations({ - configurationData, - attributes, - hostProviderId: hostProvider.id, - configGroupId: hostProviderConfigGroup.id, - description, + createWithUpdateConfigurations({ + entityType: 'host-provider-config-group', + args: { + configurationData, + attributes, + hostProviderId: hostProvider.id, + configGroupId: hostProviderConfigGroup.id, + description, + }, }), ) .unwrap() diff --git a/adcm-web/app/src/components/pages/HostProviderPage/HostProviderPrimaryConfiguration/useHostProviderPrimaryConfiguration.ts b/adcm-web/app/src/components/pages/HostProviderPage/HostProviderPrimaryConfiguration/useHostProviderPrimaryConfiguration.ts index 1a7d0807fb..17ae9fc73f 100644 --- a/adcm-web/app/src/components/pages/HostProviderPage/HostProviderPrimaryConfiguration/useHostProviderPrimaryConfiguration.ts +++ b/adcm-web/app/src/components/pages/HostProviderPage/HostProviderPrimaryConfiguration/useHostProviderPrimaryConfiguration.ts @@ -1,29 +1,29 @@ import { useDispatch, useStore } from '@hooks'; import { - cleanupHostProviderConfiguration, - createWithUpdateHostProviderConfigurations, - getHostProviderConfiguration, - getHostProviderConfigurationsVersions, -} from '@store/adcm/hostProvider/configuration/hostProviderConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; import { useCallback, useEffect } from 'react'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; export const useHostProviderPrimaryConfiguration = () => { const dispatch = useDispatch(); const hostProvider = useStore(({ adcm }) => adcm.hostProvider.hostProvider); - const configVersions = useStore(({ adcm }) => adcm.hostProviderConfiguration.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.hostProviderConfiguration.loadedConfiguration); - const isConfigurationLoading = useStore(({ adcm }) => adcm.hostProviderConfiguration.isConfigurationLoading); - const isVersionsLoading = useStore(({ adcm }) => adcm.hostProviderConfiguration.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { if (hostProvider) { // load all configurations for current HostProvider - dispatch(getHostProviderConfigurationsVersions({ hostProviderId: hostProvider.id })); + dispatch(getConfigurationsVersions({ entityType: 'host-provider', args: { hostProviderId: hostProvider.id } })); } return () => { - dispatch(cleanupHostProviderConfiguration()); + dispatch(cleanup()); }; }, [hostProvider, dispatch]); @@ -35,7 +35,12 @@ export const useHostProviderPrimaryConfiguration = () => { useEffect(() => { if (hostProvider && selectedConfigId) { // load full config for selected configuration - dispatch(getHostProviderConfiguration({ hostProviderId: hostProvider.id, configId: selectedConfigId })); + dispatch( + getConfiguration({ + entityType: 'host-provider', + args: { hostProviderId: hostProvider.id, configId: selectedConfigId }, + }), + ); } }, [dispatch, hostProvider, selectedConfigId]); @@ -46,11 +51,14 @@ export const useHostProviderPrimaryConfiguration = () => { if (hostProvider?.id && selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateHostProviderConfigurations({ - configurationData, - attributes, - hostProviderId: hostProvider.id, - description, + createWithUpdateConfigurations({ + entityType: 'host-provider', + args: { + configurationData, + attributes, + hostProviderId: hostProvider.id, + description, + }, }), ) .unwrap() diff --git a/adcm-web/app/src/components/pages/SettingsPage/SettingsConfiguration/useSettingsConfiguration.ts b/adcm-web/app/src/components/pages/SettingsPage/SettingsConfiguration/useSettingsConfiguration.ts index c8f20a8baa..a21f0d1823 100644 --- a/adcm-web/app/src/components/pages/SettingsPage/SettingsConfiguration/useSettingsConfiguration.ts +++ b/adcm-web/app/src/components/pages/SettingsPage/SettingsConfiguration/useSettingsConfiguration.ts @@ -2,24 +2,24 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; import { - cleanupSettings, - createWithUpdateSettingsConfiguration, - getSettingsConfiguration, - getSettingsConfigurationVersions, -} from '@store/adcm/settings/configuration/settingsConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; export const useSettingsConfiguration = () => { const dispatch = useDispatch(); - const configVersions = useStore(({ adcm }) => adcm.settingsConfigurations.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.settingsConfigurations.loadedConfiguration); - const isConfigurationLoading = useStore(({ adcm }) => adcm.settingsConfigurations.isConfigurationLoading); - const isVersionsLoading = useStore(({ adcm }) => adcm.settingsConfigurations.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { - dispatch(getSettingsConfigurationVersions()); + dispatch(getConfigurationsVersions({ entityType: 'settings', args: {} })); return () => { - dispatch(cleanupSettings()); + dispatch(cleanup()); }; }, [dispatch]); @@ -30,7 +30,12 @@ export const useSettingsConfiguration = () => { useEffect(() => { if (selectedConfigId) { - dispatch(getSettingsConfiguration(selectedConfigId)); + dispatch( + getConfiguration({ + entityType: 'settings', + args: { configId: selectedConfigId }, + }), + ); } }, [dispatch, selectedConfigId]); @@ -41,10 +46,13 @@ export const useSettingsConfiguration = () => { if (selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateSettingsConfiguration({ - configurationData, - attributes, - description, + createWithUpdateConfigurations({ + entityType: 'settings', + args: { + configurationData, + attributes, + description, + }, }), ) .unwrap() diff --git a/adcm-web/app/src/components/pages/SettingsPage/useRequestAdcmSettings.ts b/adcm-web/app/src/components/pages/SettingsPage/useRequestAdcmSettings.ts index 59316f4d97..aaf4713935 100644 --- a/adcm-web/app/src/components/pages/SettingsPage/useRequestAdcmSettings.ts +++ b/adcm-web/app/src/components/pages/SettingsPage/useRequestAdcmSettings.ts @@ -8,7 +8,7 @@ import { export const useRequestAdcmSettings = () => { const dispatch = useDispatch(); - const configVersions = useStore(({ adcm }) => adcm.settingsConfigurations.configVersions); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); useEffect(() => { dispatch(getAdcmSettings()); diff --git a/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterConfigGroupSingle/ClusterConfigGroupConfiguration/useClusterConfigGroupConfiguration.ts b/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterConfigGroupSingle/ClusterConfigGroupConfiguration/useClusterConfigGroupConfiguration.ts index abdeb29275..c37dce5569 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterConfigGroupSingle/ClusterConfigGroupConfiguration/useClusterConfigGroupConfiguration.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterConfigGroupSingle/ClusterConfigGroupConfiguration/useClusterConfigGroupConfiguration.ts @@ -2,31 +2,34 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; import { - cleanupClusterConfigGroupConfiguration, - createWithUpdateClusterConfigGroupConfigurations, - getClusterConfigGroupConfiguration, - getClusterConfigGroupConfigurationsVersions, -} from '@store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; export const useClusterConfigGroupConfiguration = () => { const dispatch = useDispatch(); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); const clusterConfigGroup = useStore((s) => s.adcm.clusterConfigGroup.clusterConfigGroup); - const configVersions = useStore(({ adcm }) => adcm.clusterConfigGroupConfiguration.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.clusterConfigGroupConfiguration.loadedConfiguration); - const isConfigurationLoading = useStore(({ adcm }) => adcm.clusterConfigGroupConfiguration.isConfigurationLoading); - const isVersionsLoading = useStore(({ adcm }) => adcm.clusterConfigGroupConfiguration.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { if (cluster && clusterConfigGroup) { // load all configurations for current Cluster dispatch( - getClusterConfigGroupConfigurationsVersions({ clusterId: cluster.id, configGroupId: clusterConfigGroup.id }), + getConfigurationsVersions({ + entityType: 'cluster-config-group', + args: { clusterId: cluster.id, configGroupId: clusterConfigGroup.id }, + }), ); } return () => { - dispatch(cleanupClusterConfigGroupConfiguration()); + dispatch(cleanup()); }; }, [cluster, clusterConfigGroup, dispatch]); @@ -39,10 +42,13 @@ export const useClusterConfigGroupConfiguration = () => { if (cluster && clusterConfigGroup && selectedConfigId) { // load full config for selected configuration dispatch( - getClusterConfigGroupConfiguration({ - clusterId: cluster.id, - configGroupId: clusterConfigGroup.id, - configId: selectedConfigId, + getConfiguration({ + entityType: 'cluster-config-group', + args: { + clusterId: cluster.id, + configGroupId: clusterConfigGroup.id, + configId: selectedConfigId, + }, }), ); } @@ -55,12 +61,15 @@ export const useClusterConfigGroupConfiguration = () => { if (cluster?.id && clusterConfigGroup?.id && selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateClusterConfigGroupConfigurations({ - configurationData, - attributes, - clusterId: cluster.id, - configGroupId: clusterConfigGroup.id, - description, + createWithUpdateConfigurations({ + entityType: 'cluster-config-group', + args: { + configurationData, + attributes, + clusterId: cluster.id, + configGroupId: clusterConfigGroup.id, + description, + }, }), ) .unwrap() diff --git a/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterPrimaryConfiguration/useClusterPrimaryConfiguration.ts b/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterPrimaryConfiguration/useClusterPrimaryConfiguration.ts index a49d2fa6a8..5d9502e272 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterPrimaryConfiguration/useClusterPrimaryConfiguration.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterConfiguration/ClusterPrimaryConfiguration/useClusterPrimaryConfiguration.ts @@ -1,29 +1,29 @@ import { useDispatch, useStore } from '@hooks'; import { - cleanupClusterConfiguration, - createWithUpdateClusterConfigurations, - getClusterConfiguration, - getClusterConfigurationsVersions, -} from '@store/adcm/cluster/configuration/clusterConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; import { useCallback, useEffect } from 'react'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; export const useClusterPrimaryConfiguration = () => { const dispatch = useDispatch(); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); - const configVersions = useStore(({ adcm }) => adcm.clusterConfiguration.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.clusterConfiguration.loadedConfiguration); - const isConfigurationLoading = useStore(({ adcm }) => adcm.clusterConfiguration.isConfigurationLoading); - const isVersionsLoading = useStore(({ adcm }) => adcm.clusterConfiguration.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { if (cluster) { // load all configurations for current Cluster - dispatch(getClusterConfigurationsVersions({ clusterId: cluster.id })); + dispatch(getConfigurationsVersions({ entityType: 'cluster', args: { clusterId: cluster.id } })); } return () => { - dispatch(cleanupClusterConfiguration()); + dispatch(cleanup()); }; }, [cluster, dispatch]); @@ -35,7 +35,9 @@ export const useClusterPrimaryConfiguration = () => { useEffect(() => { if (cluster && selectedConfigId) { // load full config for selected configuration - dispatch(getClusterConfiguration({ clusterId: cluster.id, configId: selectedConfigId })); + dispatch( + getConfiguration({ entityType: 'cluster', args: { clusterId: cluster.id, configId: selectedConfigId } }), + ); } }, [dispatch, cluster, selectedConfigId]); @@ -46,7 +48,10 @@ export const useClusterPrimaryConfiguration = () => { if (cluster?.id && selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateClusterConfigurations({ configurationData, attributes, clusterId: cluster.id, description }), + createWithUpdateConfigurations({ + entityType: 'cluster', + args: { configurationData, attributes, clusterId: cluster.id, description }, + }), ) .unwrap() .then(() => { diff --git a/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServiceConfigGroupSingle/ServiceConfigGroupSingleConfiguration/useServiceConfigGroupSingleConfiguration.ts b/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServiceConfigGroupSingle/ServiceConfigGroupSingleConfiguration/useServiceConfigGroupSingleConfiguration.ts index c5a0f4697c..6da36b0486 100644 --- a/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServiceConfigGroupSingle/ServiceConfigGroupSingleConfiguration/useServiceConfigGroupSingleConfiguration.ts +++ b/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServiceConfigGroupSingle/ServiceConfigGroupSingleConfiguration/useServiceConfigGroupSingleConfiguration.ts @@ -2,36 +2,39 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; import { - cleanupServiceConfigGroupConfiguration, - createWithUpdateServiceConfigGroupConfigurations, - getServiceConfigGroupConfiguration, - getServiceConfigGroupConfigurationsVersions, -} from '@store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; export const useServiceConfigGroupSingleConfiguration = () => { const dispatch = useDispatch(); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); const service = useStore(({ adcm }) => adcm.service.service); const serviceConfigGroup = useStore((s) => s.adcm.serviceConfigGroup.serviceConfigGroup); - const configVersions = useStore(({ adcm }) => adcm.serviceConfigGroupConfiguration.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.serviceConfigGroupConfiguration.loadedConfiguration); - const isConfigurationLoading = useStore(({ adcm }) => adcm.serviceConfigGroupConfiguration.isConfigurationLoading); - const isVersionsLoading = useStore(({ adcm }) => adcm.serviceConfigGroupConfiguration.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { if (cluster && service && serviceConfigGroup) { // load all configurations for current Cluster dispatch( - getServiceConfigGroupConfigurationsVersions({ - clusterId: cluster.id, - serviceId: service.id, - configGroupId: serviceConfigGroup.id, + getConfigurationsVersions({ + entityType: 'service-config-group', + args: { + clusterId: cluster.id, + serviceId: service.id, + configGroupId: serviceConfigGroup.id, + }, }), ); } return () => { - dispatch(cleanupServiceConfigGroupConfiguration()); + dispatch(cleanup()); }; }, [cluster, service, serviceConfigGroup, dispatch]); @@ -44,11 +47,14 @@ export const useServiceConfigGroupSingleConfiguration = () => { if (cluster && service && serviceConfigGroup && selectedConfigId) { // load full config for selected configuration dispatch( - getServiceConfigGroupConfiguration({ - clusterId: cluster.id, - serviceId: service.id, - configGroupId: serviceConfigGroup.id, - configId: selectedConfigId, + getConfiguration({ + entityType: 'service-config-group', + args: { + clusterId: cluster.id, + serviceId: service.id, + configGroupId: serviceConfigGroup.id, + configId: selectedConfigId, + }, }), ); } @@ -61,13 +67,16 @@ export const useServiceConfigGroupSingleConfiguration = () => { if (cluster && service && serviceConfigGroup && selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateServiceConfigGroupConfigurations({ - configurationData, - attributes, - clusterId: cluster.id, - serviceId: service.id, - configGroupId: serviceConfigGroup.id, - description, + createWithUpdateConfigurations({ + entityType: 'service-config-group', + args: { + configurationData, + attributes, + clusterId: cluster.id, + serviceId: service.id, + configGroupId: serviceConfigGroup.id, + description, + }, }), ) .unwrap() diff --git a/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServicePrimaryConfiguration/useServicesPrimaryConfiguration.ts b/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServicePrimaryConfiguration/useServicesPrimaryConfiguration.ts index 959a57c0d1..e8f3a81eb6 100644 --- a/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServicePrimaryConfiguration/useServicesPrimaryConfiguration.ts +++ b/adcm-web/app/src/components/pages/cluster/service/ServiceConfiguration/ServicePrimaryConfiguration/useServicesPrimaryConfiguration.ts @@ -1,29 +1,34 @@ import { useDispatch, useStore } from '@hooks'; import { - cleanupClusterServicesConfiguration, - createWithUpdateClusterServicesConfigurations, - getClusterServicesConfiguration, - getClusterServicesConfigurationsVersions, -} from '@store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; import { useCallback, useEffect } from 'react'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; export const useServicesPrimaryConfiguration = () => { const dispatch = useDispatch(); const service = useStore(({ adcm }) => adcm.service.service); - const configVersions = useStore(({ adcm }) => adcm.clusterServicesConfiguration.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.clusterServicesConfiguration.loadedConfiguration); - const isConfigurationLoading = useStore(({ adcm }) => adcm.clusterServicesConfiguration.isConfigurationLoading); - const isVersionsLoading = useStore(({ adcm }) => adcm.clusterServicesConfiguration.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { if (service) { // load all configurations for current HostProvider - dispatch(getClusterServicesConfigurationsVersions({ clusterId: service.cluster.id, serviceId: service.id })); + dispatch( + getConfigurationsVersions({ + entityType: 'service', + args: { clusterId: service.cluster.id, serviceId: service.id }, + }), + ); } return () => { - dispatch(cleanupClusterServicesConfiguration()); + dispatch(cleanup()); }; }, [service, dispatch]); @@ -36,10 +41,13 @@ export const useServicesPrimaryConfiguration = () => { if (service && selectedConfigId) { // load full config for selected configuration dispatch( - getClusterServicesConfiguration({ - clusterId: service.cluster.id, - serviceId: service.id, - configId: selectedConfigId, + getConfiguration({ + entityType: 'service', + args: { + clusterId: service.cluster.id, + serviceId: service.id, + configId: selectedConfigId, + }, }), ); } @@ -52,12 +60,15 @@ export const useServicesPrimaryConfiguration = () => { if (service?.id && selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateClusterServicesConfigurations({ - configurationData, - attributes, - clusterId: service.cluster.id, - serviceId: service.id, - description, + createWithUpdateConfigurations({ + entityType: 'service', + args: { + configurationData, + attributes, + clusterId: service.cluster.id, + serviceId: service.id, + description, + }, }), ) .unwrap() diff --git a/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/useComponentPrimaryConfiguration.ts b/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/useComponentPrimaryConfiguration.ts index 302a12741b..8e857c079f 100644 --- a/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/useComponentPrimaryConfiguration.ts +++ b/adcm-web/app/src/components/pages/cluster/service/component/ComponentPrimaryConfiguration/useComponentPrimaryConfiguration.ts @@ -2,11 +2,11 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; import { - cleanupServiceComponentConfiguration, - createWithUpdateServiceComponentConfigurations, - getServiceComponentConfiguration, - getServiceComponentConfigurationsVersions, -} from '@store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; import { useServiceComponentParams } from '@pages/cluster/service/component/useServiceComponentParams'; export const useComponentPrimaryConfiguration = () => { @@ -14,25 +14,28 @@ export const useComponentPrimaryConfiguration = () => { const { clusterId, serviceId, componentId } = useServiceComponentParams(); const component = useStore(({ adcm }) => adcm.serviceComponent.serviceComponent); - const configVersions = useStore(({ adcm }) => adcm.serviceComponentConfiguration.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.serviceComponentConfiguration.loadedConfiguration); - const isConfigurationLoading = useStore(({ adcm }) => adcm.serviceComponentConfiguration.isConfigurationLoading); - const isVersionsLoading = useStore(({ adcm }) => adcm.serviceComponentConfiguration.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { if (componentId) { // load all configurations for current component dispatch( - getServiceComponentConfigurationsVersions({ - clusterId: clusterId, - serviceId: serviceId, - componentId: componentId, + getConfigurationsVersions({ + entityType: 'service-component', + args: { + clusterId: clusterId, + serviceId: serviceId, + componentId: componentId, + }, }), ); } return () => { - dispatch(cleanupServiceComponentConfiguration()); + dispatch(cleanup()); }; }, [clusterId, componentId, dispatch, serviceId]); @@ -45,11 +48,14 @@ export const useComponentPrimaryConfiguration = () => { if (componentId && selectedConfigId) { // load full config for selected configuration dispatch( - getServiceComponentConfiguration({ - clusterId: clusterId, - serviceId: serviceId, - componentId: componentId, - configId: selectedConfigId, + getConfiguration({ + entityType: 'service-component', + args: { + clusterId: clusterId, + serviceId: serviceId, + componentId: componentId, + configId: selectedConfigId, + }, }), ); } @@ -62,13 +68,16 @@ export const useComponentPrimaryConfiguration = () => { if (componentId && selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateServiceComponentConfigurations({ - configurationData, - attributes, - clusterId: clusterId, - serviceId: serviceId, - componentId: componentId, - description, + createWithUpdateConfigurations({ + entityType: 'service-component', + args: { + configurationData, + attributes, + clusterId: clusterId, + serviceId: serviceId, + componentId: componentId, + description, + }, }), ) .unwrap() diff --git a/adcm-web/app/src/components/pages/cluster/service/component/ServiceComponentConfiguration/ServiceComponentConfigGroupSingle/ServiceComponentConfigGroupConfiguration/useServiceComponentConfigGroupConfiguration.ts b/adcm-web/app/src/components/pages/cluster/service/component/ServiceComponentConfiguration/ServiceComponentConfigGroupSingle/ServiceComponentConfigGroupConfiguration/useServiceComponentConfigGroupConfiguration.ts index 1d9fbd3899..0ed9e2e0e9 100644 --- a/adcm-web/app/src/components/pages/cluster/service/component/ServiceComponentConfiguration/ServiceComponentConfigGroupSingle/ServiceComponentConfigGroupConfiguration/useServiceComponentConfigGroupConfiguration.ts +++ b/adcm-web/app/src/components/pages/cluster/service/component/ServiceComponentConfiguration/ServiceComponentConfigGroupSingle/ServiceComponentConfigGroupConfiguration/useServiceComponentConfigGroupConfiguration.ts @@ -2,11 +2,11 @@ import { useDispatch, useStore } from '@hooks'; import { useCallback, useEffect } from 'react'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; import { - cleanupServiceComponentConfigGroupConfiguration, - createWithUpdateServiceComponentConfigGroupConfigurations, - getServiceComponentConfigGroupConfiguration, - getServiceComponentConfigGroupConfigurationsVersions, -} from '@store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; export const useServiceComponentConfigGroupConfiguration = () => { const dispatch = useDispatch(); @@ -16,28 +16,29 @@ export const useServiceComponentConfigGroupConfiguration = () => { const serviceComponentConfigGroup = useStore( (s) => s.adcm.serviceComponentConfigGroupSingle.serviceComponentConfigGroup, ); - const configVersions = useStore(({ adcm }) => adcm.serviceComponentConfigGroupConfiguration.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.serviceComponentConfigGroupConfiguration.loadedConfiguration); - const isConfigurationLoading = useStore( - ({ adcm }) => adcm.serviceComponentConfigGroupConfiguration.isConfigurationLoading, - ); - const isVersionsLoading = useStore(({ adcm }) => adcm.serviceComponentConfigGroupConfiguration.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { if (cluster && service && component && serviceComponentConfigGroup) { // load all configurations for current Cluster dispatch( - getServiceComponentConfigGroupConfigurationsVersions({ - clusterId: cluster.id, - serviceId: service.id, - componentId: component.id, - configGroupId: serviceComponentConfigGroup.id, + getConfigurationsVersions({ + entityType: 'service-component-config-group', + args: { + clusterId: cluster.id, + serviceId: service.id, + componentId: component.id, + configGroupId: serviceComponentConfigGroup.id, + }, }), ); } return () => { - dispatch(cleanupServiceComponentConfigGroupConfiguration()); + dispatch(cleanup()); }; }, [cluster, service, component, serviceComponentConfigGroup, dispatch]); @@ -50,12 +51,15 @@ export const useServiceComponentConfigGroupConfiguration = () => { if (cluster && service && component && serviceComponentConfigGroup && selectedConfigId) { // load full config for selected configuration dispatch( - getServiceComponentConfigGroupConfiguration({ - clusterId: cluster.id, - serviceId: service.id, - componentId: component.id, - configGroupId: serviceComponentConfigGroup.id, - configId: selectedConfigId, + getConfiguration({ + entityType: 'service-component-config-group', + args: { + clusterId: cluster.id, + serviceId: service.id, + componentId: component.id, + configGroupId: serviceComponentConfigGroup.id, + configId: selectedConfigId, + }, }), ); } @@ -68,14 +72,17 @@ export const useServiceComponentConfigGroupConfiguration = () => { if (cluster && service && component && serviceComponentConfigGroup && selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateServiceComponentConfigGroupConfigurations({ - configurationData, - attributes, - clusterId: cluster.id, - serviceId: service.id, - componentId: component.id, - configGroupId: serviceComponentConfigGroup.id, - description, + createWithUpdateConfigurations({ + entityType: 'service-component-config-group', + args: { + configurationData, + attributes, + clusterId: cluster.id, + serviceId: service.id, + componentId: component.id, + configGroupId: serviceComponentConfigGroup.id, + description, + }, }), ) .unwrap() diff --git a/adcm-web/app/src/components/pages/host/HostPrimaryConfiguration/useHostPrimaryConfiguration.ts b/adcm-web/app/src/components/pages/host/HostPrimaryConfiguration/useHostPrimaryConfiguration.ts index 2b26567d27..a46bc4203d 100644 --- a/adcm-web/app/src/components/pages/host/HostPrimaryConfiguration/useHostPrimaryConfiguration.ts +++ b/adcm-web/app/src/components/pages/host/HostPrimaryConfiguration/useHostPrimaryConfiguration.ts @@ -1,10 +1,10 @@ import { useDispatch, useStore } from '@hooks'; import { - cleanupHostsConfiguration, - createWithUpdateHostsConfigurations, - getHostsConfiguration, - getHostsConfigurationsVersions, -} from '@store/adcm/host/configuration/hostsConfigurationSlice'; + cleanup, + createWithUpdateConfigurations, + getConfiguration, + getConfigurationsVersions, +} from '@store/adcm/entityConfiguration/configurationSlice'; import { useCallback, useEffect } from 'react'; import { useConfigurations } from '@commonComponents/configuration/useConfigurations'; import { useParams } from 'react-router-dom'; @@ -13,17 +13,17 @@ export const useHostsPrimaryConfiguration = () => { const dispatch = useDispatch(); const { hostId: hostIdFromUrl } = useParams(); const hostId = Number(hostIdFromUrl); - const configVersions = useStore(({ adcm }) => adcm.hostsConfiguration.configVersions); - const loadedConfiguration = useStore(({ adcm }) => adcm.hostsConfiguration.loadedConfiguration); - const isConfigurationLoading = useStore(({ adcm }) => adcm.hostsConfiguration.isConfigurationLoading); - const isVersionsLoading = useStore(({ adcm }) => adcm.hostsConfiguration.isVersionsLoading); + const configVersions = useStore(({ adcm }) => adcm.entityConfiguration.configVersions); + const loadedConfiguration = useStore(({ adcm }) => adcm.entityConfiguration.loadedConfiguration); + const isConfigurationLoading = useStore(({ adcm }) => adcm.entityConfiguration.isConfigurationLoading); + const isVersionsLoading = useStore(({ adcm }) => adcm.entityConfiguration.isVersionsLoading); useEffect(() => { // load all configurations for current Host - dispatch(getHostsConfigurationsVersions(hostId)); + dispatch(getConfigurationsVersions({ entityType: 'host', args: { hostId } })); return () => { - dispatch(cleanupHostsConfiguration()); + dispatch(cleanup()); }; }, [hostId, dispatch]); @@ -36,9 +36,12 @@ export const useHostsPrimaryConfiguration = () => { if (selectedConfigId) { // load full config for selected configuration dispatch( - getHostsConfiguration({ - hostId, - configId: selectedConfigId, + getConfiguration({ + entityType: 'host', + args: { + hostId, + configId: selectedConfigId, + }, }), ); } @@ -51,11 +54,14 @@ export const useHostsPrimaryConfiguration = () => { if (selectedConfiguration) { const { configurationData, attributes } = selectedConfiguration; dispatch( - createWithUpdateHostsConfigurations({ - configurationData, - attributes, - hostId, - description, + createWithUpdateConfigurations({ + entityType: 'host', + args: { + configurationData, + attributes, + hostId, + description, + }, }), ) .unwrap() diff --git a/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice.ts deleted file mode 100644 index 6d13bfcfbd..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { AdcmClusterGroupConfigsConfigsApi, RequestError } from '@api'; -import { createAsyncThunk } from '@store/redux'; -import { - AdcmConfiguration, - ConfigurationData, - ConfigurationAttributes, - AdcmConfigShortView, -} from '@models/adcm/configuration'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; -import { executeWithMinDelay } from '@utils/requestUtils'; -import { defaultSpinnerDelay } from '@constants'; - -type AdcmClusterConfigGroupConfigurationState = { - isConfigurationLoading: boolean; - loadedConfiguration: AdcmConfiguration | null; - configVersions: AdcmConfigShortView[]; - isVersionsLoading: boolean; -}; - -type LoadClusterConfigGroupConfigurationPayload = { - clusterId: number; - configGroupId: number; - configId: number; -}; - -type SaveClusterConfigGroupConfigurationPayload = { - clusterId: number; - configGroupId: number; - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -}; - -const createClusterConfigGroupConfiguration = createAsyncThunk( - 'adcm/cluster/configGroup/configuration/createClusterConfigGroupConfiguration', - async ( - { - clusterId, - configGroupId, - configurationData, - attributes, - description, - }: SaveClusterConfigGroupConfigurationPayload, - thunkAPI, - ) => { - try { - const configuration = await AdcmClusterGroupConfigsConfigsApi.createConfiguration( - clusterId, - configGroupId, - configurationData, - attributes, - description, - ); - return configuration; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const createWithUpdateClusterConfigGroupConfigurations = createAsyncThunk( - 'adcm/cluster/configGroup/configuration/createAndUpdateClusterConfigGroupConfigurations', - async (arg: SaveClusterConfigGroupConfigurationPayload, thunkAPI) => { - await thunkAPI.dispatch(createClusterConfigGroupConfiguration(arg)).unwrap(); - await thunkAPI.dispatch( - getClusterConfigGroupConfigurationsVersions({ clusterId: arg.clusterId, configGroupId: arg.configGroupId }), - ); - }, -); - -const getClusterConfigGroupConfiguration = createAsyncThunk( - 'adcm/cluster/configGroup/configuration/getClusterConfigGroupConfiguration', - async (arg: LoadClusterConfigGroupConfigurationPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsConfigurationLoading(true)); - - try { - const [config, schema] = await Promise.all([ - AdcmClusterGroupConfigsConfigsApi.getConfig(arg), - AdcmClusterGroupConfigsConfigsApi.getConfigSchema(arg), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsConfigurationLoading(false)); - }, - }); - } - }, -); - -type GetClusterConfigGroupConfigurationsPayload = { - clusterId: number; - configGroupId: number; -}; - -const getClusterConfigGroupConfigurationsVersions = createAsyncThunk( - 'adcm/clusters/configuration/getClusterConfigGroupConfigurationsVersions', - async ({ clusterId, configGroupId }: GetClusterConfigGroupConfigurationsPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsVersionsLoading(true)); - - try { - return await AdcmClusterGroupConfigsConfigsApi.getConfigs(clusterId, configGroupId); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsVersionsLoading(false)); - }, - }); - } - }, -); - -const createInitialState = (): AdcmClusterConfigGroupConfigurationState => ({ - isVersionsLoading: false, - isConfigurationLoading: false, - loadedConfiguration: null, - configVersions: [], -}); - -const clusterConfigGroupConfigurationSlice = createSlice({ - name: 'adcm/cluster/configGroup/configuration', - initialState: createInitialState(), - reducers: { - cleanupClusterConfigGroupConfiguration() { - return createInitialState(); - }, - setIsConfigurationLoading(state, action) { - state.isConfigurationLoading = action.payload; - }, - setIsVersionsLoading(state, action) { - state.isVersionsLoading = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(getClusterConfigGroupConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.loadedConfiguration = { - configurationData, - attributes, - schema, - }; - - state.isConfigurationLoading = false; - }); - builder.addCase(getClusterConfigGroupConfiguration.rejected, (state) => { - state.loadedConfiguration = null; - }); - builder.addCase(getClusterConfigGroupConfigurationsVersions.fulfilled, (state, action) => { - state.configVersions = action.payload.results; - }); - builder.addCase(getClusterConfigGroupConfigurationsVersions.rejected, (state) => { - state.configVersions = []; - }); - }, -}); - -const { cleanupClusterConfigGroupConfiguration, setIsConfigurationLoading, setIsVersionsLoading } = - clusterConfigGroupConfigurationSlice.actions; -export { - getClusterConfigGroupConfiguration, - getClusterConfigGroupConfigurationsVersions, - cleanupClusterConfigGroupConfiguration, - createWithUpdateClusterConfigGroupConfigurations, -}; -export default clusterConfigGroupConfigurationSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationSlice.ts deleted file mode 100644 index f21c8ff33d..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/configuration/clusterConfigurationSlice.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { AdcmClusterConfigsApi, RequestError } from '@api'; -import { createAsyncThunk } from '@store/redux'; -import { - AdcmConfiguration, - ConfigurationData, - ConfigurationAttributes, - AdcmConfigShortView, -} from '@models/adcm/configuration'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; -import { executeWithMinDelay } from '@utils/requestUtils'; -import { defaultSpinnerDelay } from '@constants'; - -type AdcmClusterConfigurationState = { - isConfigurationLoading: boolean; - loadedConfiguration: AdcmConfiguration | null; - configVersions: AdcmConfigShortView[]; - isVersionsLoading: boolean; -}; - -type LoadClusterConfigurationPayload = { - clusterId: number; - configId: number; -}; - -type SaveClusterConfigurationPayload = { - clusterId: number; - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -}; - -const createClusterConfiguration = createAsyncThunk( - 'adcm/cluster/configuration/createClusterConfiguration', - async ({ clusterId, configurationData, attributes, description }: SaveClusterConfigurationPayload, thunkAPI) => { - try { - const configuration = await AdcmClusterConfigsApi.createConfiguration( - clusterId, - configurationData, - attributes, - description, - ); - return configuration; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const createWithUpdateClusterConfigurations = createAsyncThunk( - 'adcm/cluster/configuration/createAndUpdateClusterConfigurations', - async (arg: SaveClusterConfigurationPayload, thunkAPI) => { - await thunkAPI.dispatch(createClusterConfiguration(arg)).unwrap(); - await thunkAPI.dispatch(getClusterConfigurationsVersions({ clusterId: arg.clusterId })); - }, -); - -const getClusterConfiguration = createAsyncThunk( - 'adcm/cluster/configuration/getClusterConfiguration', - async (arg: LoadClusterConfigurationPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsConfigurationLoading(true)); - - try { - const [config, schema] = await Promise.all([ - AdcmClusterConfigsApi.getConfig(arg), - AdcmClusterConfigsApi.getConfigSchema(arg), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsConfigurationLoading(false)); - }, - }); - } - }, -); - -type GetClusterConfigurationsPayload = { - clusterId: number; -}; - -const getClusterConfigurationsVersions = createAsyncThunk( - 'adcm/clusters/configuration/getClusterConfigurationsVersions', - async ({ clusterId }: GetClusterConfigurationsPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsVersionsLoading(true)); - - try { - return await AdcmClusterConfigsApi.getConfigs(clusterId); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsVersionsLoading(false)); - }, - }); - } - }, -); - -const createInitialState = (): AdcmClusterConfigurationState => ({ - isVersionsLoading: false, - isConfigurationLoading: false, - loadedConfiguration: null, - configVersions: [], -}); - -const clusterConfigurationSlice = createSlice({ - name: 'adcm/cluster/configuration', - initialState: createInitialState(), - reducers: { - cleanupClusterConfiguration() { - return createInitialState(); - }, - setIsConfigurationLoading(state, action) { - state.isConfigurationLoading = action.payload; - }, - setIsVersionsLoading(state, action) { - state.isVersionsLoading = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(getClusterConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.loadedConfiguration = { - configurationData, - attributes, - schema, - }; - - state.isConfigurationLoading = false; - }); - builder.addCase(getClusterConfiguration.rejected, (state) => { - state.loadedConfiguration = null; - }); - builder.addCase(getClusterConfigurationsVersions.fulfilled, (state, action) => { - state.configVersions = action.payload.results; - }); - builder.addCase(getClusterConfigurationsVersions.rejected, (state) => { - state.configVersions = []; - }); - }, -}); - -const { cleanupClusterConfiguration, setIsConfigurationLoading, setIsVersionsLoading } = - clusterConfigurationSlice.actions; -export { - getClusterConfiguration, - getClusterConfigurationsVersions, - cleanupClusterConfiguration, - createWithUpdateClusterConfigurations, -}; -export default clusterConfigurationSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice.ts deleted file mode 100644 index baf7dfda40..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { AdcmClusterServiceConfigGroupConfigsApi, RequestError } from '@api'; -import { createAsyncThunk } from '@store/redux'; -import { - AdcmConfiguration, - ConfigurationData, - ConfigurationAttributes, - AdcmConfigShortView, -} from '@models/adcm/configuration'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; -import { executeWithMinDelay } from '@utils/requestUtils'; -import { defaultSpinnerDelay } from '@constants'; - -type AdcmServiceConfigGroupConfigurationState = { - isConfigurationLoading: boolean; - loadedConfiguration: AdcmConfiguration | null; - configVersions: AdcmConfigShortView[]; - isVersionsLoading: boolean; -}; - -type LoadServiceConfigGroupConfigurationPayload = { - clusterId: number; - serviceId: number; - configGroupId: number; - configId: number; -}; - -type SaveServiceConfigGroupConfigurationPayload = { - clusterId: number; - serviceId: number; - configGroupId: number; - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -}; - -const createServiceConfigGroupConfiguration = createAsyncThunk( - 'adcm/service/configGroup/configuration/createServiceConfigGroupConfiguration', - async ( - { - clusterId, - serviceId, - configGroupId, - configurationData, - attributes, - description, - }: SaveServiceConfigGroupConfigurationPayload, - thunkAPI, - ) => { - try { - const configuration = await AdcmClusterServiceConfigGroupConfigsApi.createConfiguration( - clusterId, - serviceId, - configGroupId, - configurationData, - attributes, - description, - ); - return configuration; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const createWithUpdateServiceConfigGroupConfigurations = createAsyncThunk( - 'adcm/service/configGroup/configuration/createAndUpdateServiceConfigGroupConfigurations', - async (arg: SaveServiceConfigGroupConfigurationPayload, thunkAPI) => { - await thunkAPI.dispatch(createServiceConfigGroupConfiguration(arg)).unwrap(); - await thunkAPI.dispatch( - getServiceConfigGroupConfigurationsVersions({ - clusterId: arg.clusterId, - serviceId: arg.serviceId, - configGroupId: arg.configGroupId, - }), - ); - }, -); - -const getServiceConfigGroupConfiguration = createAsyncThunk( - 'adcm/service/configGroup/configuration/getServiceConfigGroupConfiguration', - async (args: LoadServiceConfigGroupConfigurationPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsConfigurationLoading(true)); - - try { - const [config, schema] = await Promise.all([ - AdcmClusterServiceConfigGroupConfigsApi.getConfig(args), - AdcmClusterServiceConfigGroupConfigsApi.getConfigSchema(args), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsConfigurationLoading(false)); - }, - }); - } - }, -); - -type GetServiceConfigGroupConfigurationsPayload = { - clusterId: number; - serviceId: number; - configGroupId: number; -}; - -const getServiceConfigGroupConfigurationsVersions = createAsyncThunk( - 'adcm/clusters/configuration/getServiceConfigGroupConfigurationsVersions', - async ({ clusterId, serviceId, configGroupId }: GetServiceConfigGroupConfigurationsPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsVersionsLoading(true)); - - try { - return await AdcmClusterServiceConfigGroupConfigsApi.getConfigs(clusterId, serviceId, configGroupId); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsVersionsLoading(false)); - }, - }); - } - }, -); - -const createInitialState = (): AdcmServiceConfigGroupConfigurationState => ({ - isVersionsLoading: false, - isConfigurationLoading: false, - loadedConfiguration: null, - configVersions: [], -}); - -const serviceConfigGroupConfigurationSlice = createSlice({ - name: 'adcm/service/configGroup/configuration', - initialState: createInitialState(), - reducers: { - cleanupServiceConfigGroupConfiguration() { - return createInitialState(); - }, - setIsConfigurationLoading(state, action) { - state.isConfigurationLoading = action.payload; - }, - setIsVersionsLoading(state, action) { - state.isVersionsLoading = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(getServiceConfigGroupConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.loadedConfiguration = { - configurationData, - attributes, - schema, - }; - - state.isConfigurationLoading = false; - }); - builder.addCase(getServiceConfigGroupConfiguration.rejected, (state) => { - state.loadedConfiguration = null; - }); - builder.addCase(getServiceConfigGroupConfigurationsVersions.fulfilled, (state, action) => { - state.configVersions = action.payload.results; - }); - builder.addCase(getServiceConfigGroupConfigurationsVersions.rejected, (state) => { - state.configVersions = []; - }); - }, -}); - -const { cleanupServiceConfigGroupConfiguration, setIsConfigurationLoading, setIsVersionsLoading } = - serviceConfigGroupConfigurationSlice.actions; -export { - getServiceConfigGroupConfiguration, - getServiceConfigGroupConfigurationsVersions, - cleanupServiceConfigGroupConfiguration, - createWithUpdateServiceConfigGroupConfigurations, -}; -export default serviceConfigGroupConfigurationSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice.ts deleted file mode 100644 index 036ccc10f3..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { AdcmClusterServiceComponentGroupConfigConfigsApi, RequestError } from '@api'; -import { createAsyncThunk } from '@store/redux'; -import { - AdcmConfiguration, - ConfigurationData, - ConfigurationAttributes, - AdcmConfigShortView, -} from '@models/adcm/configuration'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; -import { executeWithMinDelay } from '@utils/requestUtils'; -import { defaultSpinnerDelay } from '@constants'; - -type AdcmServiceComponentConfigGroupConfigurationState = { - isConfigurationLoading: boolean; - loadedConfiguration: AdcmConfiguration | null; - configVersions: AdcmConfigShortView[]; - isVersionsLoading: boolean; -}; - -type LoadServiceComponentConfigGroupConfigurationPayload = { - clusterId: number; - serviceId: number; - componentId: number; - configGroupId: number; - configId: number; -}; - -type SaveServiceComponentConfigGroupConfigurationPayload = { - clusterId: number; - serviceId: number; - componentId: number; - configGroupId: number; - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -}; - -const createServiceComponentConfigGroupConfiguration = createAsyncThunk( - 'adcm/serviceComponent/configGroup/configuration/createServiceComponentConfigGroupConfiguration', - async ( - { - clusterId, - serviceId, - componentId, - configGroupId, - configurationData, - attributes, - description, - }: SaveServiceComponentConfigGroupConfigurationPayload, - thunkAPI, - ) => { - try { - const configuration = await AdcmClusterServiceComponentGroupConfigConfigsApi.createConfiguration( - clusterId, - serviceId, - componentId, - configGroupId, - configurationData, - attributes, - description, - ); - return configuration; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const createWithUpdateServiceComponentConfigGroupConfigurations = createAsyncThunk( - 'adcm/cluster/configGroup/configuration/createAndUpdateServiceComponentConfigGroupConfigurations', - async (arg: SaveServiceComponentConfigGroupConfigurationPayload, thunkAPI) => { - await thunkAPI.dispatch(createServiceComponentConfigGroupConfiguration(arg)).unwrap(); - await thunkAPI.dispatch( - getServiceComponentConfigGroupConfigurationsVersions({ - clusterId: arg.clusterId, - serviceId: arg.serviceId, - componentId: arg.componentId, - configGroupId: arg.configGroupId, - }), - ); - }, -); - -const getServiceComponentConfigGroupConfiguration = createAsyncThunk( - 'adcm/serviceComponent/configGroup/configuration/getServiceComponentConfigGroupConfiguration', - async (args: LoadServiceComponentConfigGroupConfigurationPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsConfigurationLoading(true)); - - try { - const [config, schema] = await Promise.all([ - AdcmClusterServiceComponentGroupConfigConfigsApi.getConfig(args), - AdcmClusterServiceComponentGroupConfigConfigsApi.getConfigSchema(args), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsConfigurationLoading(false)); - }, - }); - } - }, -); - -type GetServiceComponentConfigGroupConfigurationsPayload = { - clusterId: number; - serviceId: number; - componentId: number; - configGroupId: number; -}; - -const getServiceComponentConfigGroupConfigurationsVersions = createAsyncThunk( - 'adcm/serviceComponent/configuration/getServiceComponentConfigGroupConfigurationsVersions', - async ( - { clusterId, serviceId, componentId, configGroupId }: GetServiceComponentConfigGroupConfigurationsPayload, - thunkAPI, - ) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsVersionsLoading(true)); - - try { - return await AdcmClusterServiceComponentGroupConfigConfigsApi.getConfigs( - clusterId, - serviceId, - componentId, - configGroupId, - ); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsVersionsLoading(false)); - }, - }); - } - }, -); - -const createInitialState = (): AdcmServiceComponentConfigGroupConfigurationState => ({ - isVersionsLoading: false, - isConfigurationLoading: false, - loadedConfiguration: null, - configVersions: [], -}); - -const serviceComponentConfigGroupConfigurationSlice = createSlice({ - name: 'adcm/serviceComponent/configGroup/configuration', - initialState: createInitialState(), - reducers: { - cleanupServiceComponentConfigGroupConfiguration() { - return createInitialState(); - }, - setIsConfigurationLoading(state, action) { - state.isConfigurationLoading = action.payload; - }, - setIsVersionsLoading(state, action) { - state.isVersionsLoading = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(getServiceComponentConfigGroupConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.loadedConfiguration = { - configurationData, - attributes, - schema, - }; - - state.isConfigurationLoading = false; - }); - builder.addCase(getServiceComponentConfigGroupConfiguration.rejected, (state) => { - state.loadedConfiguration = null; - }); - builder.addCase(getServiceComponentConfigGroupConfigurationsVersions.fulfilled, (state, action) => { - state.configVersions = action.payload.results; - }); - builder.addCase(getServiceComponentConfigGroupConfigurationsVersions.rejected, (state) => { - state.configVersions = []; - }); - }, -}); - -const { cleanupServiceComponentConfigGroupConfiguration, setIsConfigurationLoading, setIsVersionsLoading } = - serviceComponentConfigGroupConfigurationSlice.actions; -export { - getServiceComponentConfigGroupConfiguration, - getServiceComponentConfigGroupConfigurationsVersions, - cleanupServiceComponentConfigGroupConfiguration, - createWithUpdateServiceComponentConfigGroupConfigurations, -}; -export default serviceComponentConfigGroupConfigurationSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice.ts deleted file mode 100644 index 6d119b92a7..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { AdcmClusterServiceComponentsConfigsApi, RequestError } from '@api'; -import { createAsyncThunk } from '@store/redux'; -import { - AdcmConfiguration, - ConfigurationData, - ConfigurationAttributes, - AdcmConfigShortView, -} from '@models/adcm/configuration'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; -import { executeWithMinDelay } from '@utils/requestUtils'; -import { defaultSpinnerDelay } from '@constants'; - -type AdcmServiceComponentConfigurationState = { - isConfigurationLoading: boolean; - loadedConfiguration: AdcmConfiguration | null; - configVersions: AdcmConfigShortView[]; - isVersionsLoading: boolean; -}; - -type LoadServiceComponentConfigurationPayload = { - clusterId: number; - serviceId: number; - componentId: number; - configId: number; -}; - -type SaveServiceComponentConfigurationPayload = { - clusterId: number; - serviceId: number; - componentId: number; - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -}; - -const createServiceComponentConfiguration = createAsyncThunk( - 'adcm/component/configuration/createServiceComponentConfiguration', - async ( - { - clusterId, - serviceId, - componentId, - configurationData, - attributes, - description, - }: SaveServiceComponentConfigurationPayload, - thunkAPI, - ) => { - try { - const configuration = await AdcmClusterServiceComponentsConfigsApi.createConfiguration( - clusterId, - serviceId, - componentId, - configurationData, - attributes, - description, - ); - return configuration; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const createWithUpdateServiceComponentConfigurations = createAsyncThunk( - 'adcm/component/configuration/createAndUpdateServiceComponentConfigurations', - async (arg: SaveServiceComponentConfigurationPayload, thunkAPI) => { - await thunkAPI.dispatch(createServiceComponentConfiguration(arg)).unwrap(); - await thunkAPI.dispatch( - getServiceComponentConfigurationsVersions({ - clusterId: arg.clusterId, - serviceId: arg.serviceId, - componentId: arg.componentId, - }), - ); - }, -); - -const getServiceComponentConfiguration = createAsyncThunk( - 'adcm/component/configuration/getServiceComponentConfiguration', - async (arg: LoadServiceComponentConfigurationPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsConfigurationLoading(true)); - - try { - const [config, schema] = await Promise.all([ - AdcmClusterServiceComponentsConfigsApi.getConfig(arg), - AdcmClusterServiceComponentsConfigsApi.getConfigSchema(arg), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsConfigurationLoading(false)); - }, - }); - } - }, -); - -type GetServiceComponentConfigurationsPayload = { - clusterId: number; - serviceId: number; - componentId: number; -}; - -const getServiceComponentConfigurationsVersions = createAsyncThunk( - 'adcm/component/configuration/getServiceComponentConfigurationsVersions', - async ({ clusterId, serviceId, componentId }: GetServiceComponentConfigurationsPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsVersionsLoading(true)); - - try { - return await AdcmClusterServiceComponentsConfigsApi.getConfigs(clusterId, serviceId, componentId); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsVersionsLoading(false)); - }, - }); - } - }, -); - -const createInitialState = (): AdcmServiceComponentConfigurationState => ({ - isVersionsLoading: false, - isConfigurationLoading: false, - loadedConfiguration: null, - configVersions: [], -}); - -const serviceComponentConfigurationSlice = createSlice({ - name: 'adcm/component/configuration', - initialState: createInitialState(), - reducers: { - cleanupServiceComponentConfiguration() { - return createInitialState(); - }, - setIsConfigurationLoading(state, action) { - state.isConfigurationLoading = action.payload; - }, - setIsVersionsLoading(state, action) { - state.isVersionsLoading = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(getServiceComponentConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.loadedConfiguration = { - configurationData, - attributes, - schema, - }; - - state.isConfigurationLoading = false; - }); - builder.addCase(getServiceComponentConfiguration.rejected, (state) => { - state.loadedConfiguration = null; - }); - builder.addCase(getServiceComponentConfigurationsVersions.fulfilled, (state, action) => { - state.configVersions = action.payload.results; - }); - builder.addCase(getServiceComponentConfigurationsVersions.rejected, (state) => { - state.configVersions = []; - }); - }, -}); - -const { cleanupServiceComponentConfiguration, setIsConfigurationLoading, setIsVersionsLoading } = - serviceComponentConfigurationSlice.actions; -export { - getServiceComponentConfiguration, - getServiceComponentConfigurationsVersions, - cleanupServiceComponentConfiguration, - createWithUpdateServiceComponentConfigurations, -}; -export default serviceComponentConfigurationSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts b/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts deleted file mode 100644 index 0576d3af89..0000000000 --- a/adcm-web/app/src/store/adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { AdcmClusterServicesConfigsApi, RequestError } from '@api'; -import { createAsyncThunk } from '@store/redux'; -import { - AdcmConfiguration, - ConfigurationData, - ConfigurationAttributes, - AdcmConfigShortView, -} from '@models/adcm/configuration'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; -import { executeWithMinDelay } from '@utils/requestUtils'; -import { defaultSpinnerDelay } from '@constants'; - -type AdcmClusterServicesConfigurationState = { - isConfigurationLoading: boolean; - loadedConfiguration: AdcmConfiguration | null; - configVersions: AdcmConfigShortView[]; - isVersionsLoading: boolean; -}; - -type LoadClusterServicesConfigurationPayload = { - clusterId: number; - serviceId: number; - configId: number; -}; - -type SaveClusterServicesConfigurationPayload = { - clusterId: number; - serviceId: number; - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -}; - -const createClusterServiceConfiguration = createAsyncThunk( - 'adcm/clusterServices/configuration/createClusterServiceConfiguration', - async ( - { clusterId, serviceId, configurationData, attributes, description }: SaveClusterServicesConfigurationPayload, - thunkAPI, - ) => { - try { - const configuration = await AdcmClusterServicesConfigsApi.createConfiguration( - clusterId, - serviceId, - configurationData, - attributes, - description, - ); - return configuration; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const createWithUpdateClusterServicesConfigurations = createAsyncThunk( - 'adcm/clusterServices/configuration/createWithUpdateClusterServicesConfigurations', - async (arg: SaveClusterServicesConfigurationPayload, thunkAPI) => { - await thunkAPI.dispatch(createClusterServiceConfiguration(arg)).unwrap(); - await thunkAPI.dispatch( - getClusterServicesConfigurationsVersions({ clusterId: arg.clusterId, serviceId: arg.serviceId }), - ); - }, -); - -const getClusterServicesConfiguration = createAsyncThunk( - 'adcm/clusterServices/configuration/getClusterServicesConfiguration', - async (arg: LoadClusterServicesConfigurationPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsConfigurationLoading(true)); - - try { - const [config, schema] = await Promise.all([ - AdcmClusterServicesConfigsApi.getConfig(arg), - AdcmClusterServicesConfigsApi.getConfigSchema(arg), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsConfigurationLoading(false)); - }, - }); - } - }, -); - -type GetClusterServicesConfigurationsPayload = { - clusterId: number; - serviceId: number; -}; - -const getClusterServicesConfigurationsVersions = createAsyncThunk( - 'adcm/clusterServices/configuration/getClusterServicesConfigurationsVersions', - async ({ clusterId, serviceId }: GetClusterServicesConfigurationsPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsVersionsLoading(true)); - - try { - return await AdcmClusterServicesConfigsApi.getConfigs(clusterId, serviceId); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsVersionsLoading(false)); - }, - }); - } - }, -); - -const createInitialState = (): AdcmClusterServicesConfigurationState => ({ - isVersionsLoading: false, - isConfigurationLoading: false, - loadedConfiguration: null, - configVersions: [], -}); - -const clusterServicesConfigurationSlice = createSlice({ - name: 'adcm/clusterServices/configuration', - initialState: createInitialState(), - reducers: { - cleanupClusterServicesConfiguration() { - return createInitialState(); - }, - setIsConfigurationLoading(state, action) { - state.isConfigurationLoading = action.payload; - }, - setIsVersionsLoading(state, action) { - state.isVersionsLoading = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(getClusterServicesConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.loadedConfiguration = { - configurationData, - attributes, - schema, - }; - - state.isConfigurationLoading = false; - }); - builder.addCase(getClusterServicesConfiguration.rejected, (state) => { - state.loadedConfiguration = null; - }); - builder.addCase(getClusterServicesConfigurationsVersions.fulfilled, (state, action) => { - state.configVersions = action.payload.results; - }); - builder.addCase(getClusterServicesConfigurationsVersions.rejected, (state) => { - state.configVersions = []; - }); - }, -}); - -const { cleanupClusterServicesConfiguration, setIsConfigurationLoading, setIsVersionsLoading } = - clusterServicesConfigurationSlice.actions; -export { - getClusterServicesConfiguration, - getClusterServicesConfigurationsVersions, - cleanupClusterServicesConfiguration, - createWithUpdateClusterServicesConfigurations, -}; -export default clusterServicesConfigurationSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.constants.ts b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.constants.ts deleted file mode 100644 index c24681d2f7..0000000000 --- a/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.constants.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - AdcmSettingsApi, - AdcmHostProviderConfigsApi, - AdcmHostProviderGroupConfigsConfigsApi, - AdcmClusterConfigsApi, - AdcmClusterGroupConfigsConfigsApi, - AdcmHostConfigsApi, - AdcmClusterServicesConfigsApi, - AdcmClusterServiceConfigGroupConfigsApi, - AdcmClusterServiceComponentsConfigsApi, - AdcmClusterServiceComponentGroupConfigConfigsApi, -} from '@api'; -import { - ApiRequestsDictionary, - LoadConfigurationArgs, - LoadSettingsConfigurationArgs, - LoadHostProviderConfigurationArgs, - LoadHostProviderGroupConfigurationArgs, - LoadClusterConfigurationArgs, - LoadClusterGroupConfigurationArgs, - LoadHostConfigurationArgs, - LoadServiceConfigurationArgs, - LoadServiceGroupConfigurationArgs, - LoadServiceComponentConfigurationArgs, - LoadServiceComponentGroupConfigurationArgs, -} from './compareSlice.types'; - -export const ApiRequests: ApiRequestsDictionary = { - settings: { - getConfig: (args: LoadConfigurationArgs) => AdcmSettingsApi.getConfig(args as LoadSettingsConfigurationArgs), - getConfigSchema: () => AdcmSettingsApi.getConfigSchema(), - }, - 'host-provider': { - getConfig: (args: LoadConfigurationArgs) => - AdcmHostProviderConfigsApi.getConfig(args as LoadHostProviderConfigurationArgs), - getConfigSchema: (args: LoadConfigurationArgs) => - AdcmHostProviderConfigsApi.getConfigSchema(args as LoadHostProviderConfigurationArgs), - }, - 'host-provider-config-group': { - getConfig: (args: LoadConfigurationArgs) => - AdcmHostProviderGroupConfigsConfigsApi.getConfig(args as LoadHostProviderGroupConfigurationArgs), - getConfigSchema: (args: LoadConfigurationArgs) => - AdcmHostProviderGroupConfigsConfigsApi.getConfigSchema(args as LoadHostProviderGroupConfigurationArgs), - }, - cluster: { - getConfig: (args: LoadConfigurationArgs) => AdcmClusterConfigsApi.getConfig(args as LoadClusterConfigurationArgs), - getConfigSchema: (args: LoadConfigurationArgs) => - AdcmClusterConfigsApi.getConfigSchema(args as LoadClusterConfigurationArgs), - }, - 'cluster-config-group': { - getConfig: (args: LoadConfigurationArgs) => - AdcmClusterGroupConfigsConfigsApi.getConfig(args as LoadClusterGroupConfigurationArgs), - getConfigSchema: (args: LoadConfigurationArgs) => - AdcmClusterGroupConfigsConfigsApi.getConfigSchema(args as LoadClusterGroupConfigurationArgs), - }, - host: { - getConfig: (args: LoadConfigurationArgs) => AdcmHostConfigsApi.getConfig(args as LoadHostConfigurationArgs), - getConfigSchema: (args: LoadConfigurationArgs) => - AdcmHostConfigsApi.getConfigSchema(args as LoadHostConfigurationArgs), - }, - service: { - getConfig: (args: LoadConfigurationArgs) => - AdcmClusterServicesConfigsApi.getConfig(args as LoadServiceConfigurationArgs), - getConfigSchema: (args: LoadConfigurationArgs) => - AdcmClusterServicesConfigsApi.getConfigSchema(args as LoadServiceConfigurationArgs), - }, - 'service-config-group': { - getConfig: (args: LoadConfigurationArgs) => - AdcmClusterServiceConfigGroupConfigsApi.getConfig(args as LoadServiceGroupConfigurationArgs), - getConfigSchema: (args: LoadConfigurationArgs) => - AdcmClusterServiceConfigGroupConfigsApi.getConfigSchema(args as LoadServiceGroupConfigurationArgs), - }, - 'service-component': { - getConfig: (args: LoadConfigurationArgs) => - AdcmClusterServiceComponentsConfigsApi.getConfig(args as LoadServiceComponentConfigurationArgs), - getConfigSchema: (args: LoadConfigurationArgs) => - AdcmClusterServiceComponentsConfigsApi.getConfigSchema(args as LoadServiceComponentConfigurationArgs), - }, - 'service-component-config-group': { - getConfig: (args: LoadConfigurationArgs) => - AdcmClusterServiceComponentGroupConfigConfigsApi.getConfig(args as LoadServiceComponentGroupConfigurationArgs), - getConfigSchema: (args: LoadConfigurationArgs) => - AdcmClusterServiceComponentGroupConfigConfigsApi.getConfigSchema( - args as LoadServiceComponentGroupConfigurationArgs, - ), - }, -}; diff --git a/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.ts b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.ts index 9b9a94c621..fde777fe58 100644 --- a/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.ts +++ b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.ts @@ -4,8 +4,8 @@ import { RequestError } from '@api'; import { showError } from '@store/notificationsSlice.ts'; import { getErrorMessage } from '@utils/httpResponseUtils.ts'; import { createSlice } from '@reduxjs/toolkit'; -import { LoadEntityConfigurationArgs } from './compareSlice.types'; -import { ApiRequests } from './compareSlice.constants'; +import { LoadEntityConfigurationArgs } from './entityConfiguration.types'; +import { ApiRequests } from './entityConfiguration.constants'; type AdcmEntityCompareConfigurationsState = { leftConfiguration: AdcmFullConfigurationInfo | null; diff --git a/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.types.ts b/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.types.ts deleted file mode 100644 index c508a5e40d..0000000000 --- a/adcm-web/app/src/store/adcm/entityConfiguration/compareSlice.types.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { AdcmConfig, SchemaDefinition } from '@models/adcm'; - -export type EntityType = - | 'settings' - | 'host-provider' - | 'host-provider-config-group' - | 'cluster' - | 'cluster-config-group' - | 'host' - | 'service' - | 'service-config-group' - | 'service-component' - | 'service-component-config-group'; - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface LoadConfigurationArgs {} - -/* Settings */ - -export interface LoadSettingsConfigurationArgs extends LoadConfigurationArgs { - configId: number; -} - -/* Host provider */ - -export interface LoadHostProviderConfigurationArgs extends LoadConfigurationArgs { - hostProviderId: number; - configId: number; -} - -export interface LoadHostProviderGroupConfigurationArgs extends LoadConfigurationArgs { - hostProviderId: number; - configGroupId: number; - configId: number; -} - -/* Cluster */ - -export interface LoadClusterConfigurationArgs extends LoadConfigurationArgs { - clusterId: number; - configId: number; -} - -export type LoadClusterGroupConfigurationArgs = { - clusterId: number; - configGroupId: number; - configId: number; -}; - -/* Host */ - -export type LoadHostConfigurationArgs = { - hostId: number; - configId: number; -}; - -/* Service */ - -export type LoadServiceConfigurationArgs = { - clusterId: number; - serviceId: number; - configId: number; -}; - -export type LoadServiceGroupConfigurationArgs = { - clusterId: number; - serviceId: number; - configGroupId: number; - configId: number; -}; - -/* Service component */ - -export type LoadServiceComponentConfigurationArgs = { - clusterId: number; - serviceId: number; - componentId: number; - configId: number; -}; - -export type LoadServiceComponentGroupConfigurationArgs = { - clusterId: number; - serviceId: number; - componentId: number; - configGroupId: number; - configId: number; -}; - -export type LoadEntityConfigurationArgs = - | { - entityType: 'settings'; - args: LoadSettingsConfigurationArgs; - } - | { - entityType: 'host-provider'; - args: LoadHostProviderConfigurationArgs; - } - | { - entityType: 'host-provider-config-group'; - args: LoadHostProviderGroupConfigurationArgs; - } - | { - entityType: 'cluster'; - args: LoadClusterConfigurationArgs; - } - | { - entityType: 'cluster-config-group'; - args: LoadClusterGroupConfigurationArgs; - } - | { - entityType: 'host'; - args: LoadHostConfigurationArgs; - } - | { - entityType: 'service'; - args: LoadServiceConfigurationArgs; - } - | { - entityType: 'service-config-group'; - args: LoadServiceGroupConfigurationArgs; - } - | { - entityType: 'service-component'; - args: LoadServiceComponentConfigurationArgs; - } - | { - entityType: 'service-component-config-group'; - args: LoadServiceComponentGroupConfigurationArgs; - }; - -export type ApiRequestsDictionary = { - [key in EntityType]: { - getConfig: (args: LoadConfigurationArgs) => Promise; - getConfigSchema: (args: LoadConfigurationArgs) => Promise; - }; -}; diff --git a/adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationSlice.ts b/adcm-web/app/src/store/adcm/entityConfiguration/configurationSlice.ts similarity index 52% rename from adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationSlice.ts rename to adcm-web/app/src/store/adcm/entityConfiguration/configurationSlice.ts index 6c70ae2081..c662415a0a 100644 --- a/adcm-web/app/src/store/adcm/host/configuration/hostsConfigurationSlice.ts +++ b/adcm-web/app/src/store/adcm/entityConfiguration/configurationSlice.ts @@ -1,47 +1,32 @@ import { createSlice } from '@reduxjs/toolkit'; -import { AdcmHostConfigsApi, RequestError } from '@api'; +import { RequestError } from '@api'; import { createAsyncThunk } from '@store/redux'; -import { - AdcmConfiguration, - ConfigurationData, - ConfigurationAttributes, - AdcmConfigShortView, -} from '@models/adcm/configuration'; +import { AdcmConfiguration, AdcmConfigShortView } from '@models/adcm/configuration'; import { showError } from '@store/notificationsSlice'; import { getErrorMessage } from '@utils/httpResponseUtils'; import { executeWithMinDelay } from '@utils/requestUtils'; import { defaultSpinnerDelay } from '@constants'; +import { ApiRequests } from './entityConfiguration.constants'; +import { + LoadEntityConfigurationVersionsArgs, + LoadEntityConfigurationArgs, + CreateEntityConfigurationArgs, +} from './entityConfiguration.types'; -interface AdcmHostConfigurationState { +type AdcmEntityConfigurationState = { isConfigurationLoading: boolean; loadedConfiguration: AdcmConfiguration | null; configVersions: AdcmConfigShortView[]; isVersionsLoading: boolean; -} - -interface LoadHostConfigurationPayload { - hostId: number; - configId: number; -} - -interface SaveHostConfigurationPayload { - hostId: number; - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -} +}; -const createHostConfiguration = createAsyncThunk( - 'adcm/host/configuration/createHostConfiguration', - async ({ hostId, configurationData, attributes, description }: SaveHostConfigurationPayload, thunkAPI) => { +const createConfiguration = createAsyncThunk( + 'adcm/entityConfiguration/createClusterConfiguration', + async ({ entityType, args }: CreateEntityConfigurationArgs, thunkAPI) => { try { - const configuration = await AdcmHostConfigsApi.createConfiguration( - hostId, - configurationData, - attributes, - description, - ); - return configuration; + const requests = ApiRequests[entityType]; + const config = await requests.createConfig(args); + return config; } catch (error) { thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); return thunkAPI.rejectWithValue(error); @@ -49,25 +34,23 @@ const createHostConfiguration = createAsyncThunk( }, ); -const createWithUpdateHostsConfigurations = createAsyncThunk( - 'adcm/host/configuration/createWithUpdateHostConfigurations', - async (arg: SaveHostConfigurationPayload, thunkAPI) => { - await thunkAPI.dispatch(createHostConfiguration(arg)).unwrap(); - await thunkAPI.dispatch(getHostsConfigurationsVersions(arg.hostId)); +const createWithUpdateConfigurations = createAsyncThunk( + 'adcm/entityConfiguration/createWithUpdateConfigurations', + async (args: CreateEntityConfigurationArgs, thunkAPI) => { + await thunkAPI.dispatch(createConfiguration(args)).unwrap(); + await thunkAPI.dispatch(getConfigurationsVersions(args)); }, ); -const getHostsConfiguration = createAsyncThunk( - 'adcm/host/configuration/getHostsConfiguration', - async (arg: LoadHostConfigurationPayload, thunkAPI) => { +const getConfiguration = createAsyncThunk( + 'adcm/entityConfiguration/getConfiguration', + async ({ entityType, args }: LoadEntityConfigurationArgs, thunkAPI) => { const startDate = new Date(); thunkAPI.dispatch(setIsConfigurationLoading(true)); try { - const [config, schema] = await Promise.all([ - AdcmHostConfigsApi.getConfig(arg), - AdcmHostConfigsApi.getConfigSchema(arg), - ]); + const requests = ApiRequests[entityType]; + const [config, schema] = await Promise.all([requests.getConfig(args), requests.getConfigSchema(args)]); return { config, schema }; } catch (error) { thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); @@ -84,14 +67,16 @@ const getHostsConfiguration = createAsyncThunk( }, ); -const getHostsConfigurationsVersions = createAsyncThunk( - 'adcm/host/configuration/getHostsConfigurationsVersions', - async (hostId: number, thunkAPI) => { +const getConfigurationsVersions = createAsyncThunk( + 'adcm/entityConfiguration/getConfigurationsVersions', + async ({ entityType, args }: LoadEntityConfigurationVersionsArgs, thunkAPI) => { const startDate = new Date(); thunkAPI.dispatch(setIsVersionsLoading(true)); try { - return await AdcmHostConfigsApi.getConfigs(hostId); + const requests = ApiRequests[entityType]; + const versions = await requests.getConfigVersions(args); + return versions; } catch (error) { thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); return thunkAPI.rejectWithValue(error); @@ -107,18 +92,18 @@ const getHostsConfigurationsVersions = createAsyncThunk( }, ); -const createInitialState = (): AdcmHostConfigurationState => ({ +const createInitialState = (): AdcmEntityConfigurationState => ({ isVersionsLoading: false, isConfigurationLoading: false, loadedConfiguration: null, configVersions: [], }); -const hostsConfigurationSlice = createSlice({ - name: 'adcm/host/configuration', +const entityConfigurationSlice = createSlice({ + name: 'adcm/entityConfiguration', initialState: createInitialState(), reducers: { - cleanupHostsConfiguration() { + cleanup() { return createInitialState(); }, setIsConfigurationLoading(state, action) { @@ -129,7 +114,7 @@ const hostsConfigurationSlice = createSlice({ }, }, extraReducers: (builder) => { - builder.addCase(getHostsConfiguration.fulfilled, (state, action) => { + builder.addCase(getConfiguration.fulfilled, (state, action) => { const { config: { config: configurationData, adcmMeta: attributes }, schema, @@ -146,23 +131,18 @@ const hostsConfigurationSlice = createSlice({ state.isConfigurationLoading = false; }); - builder.addCase(getHostsConfiguration.rejected, (state) => { + builder.addCase(getConfiguration.rejected, (state) => { state.loadedConfiguration = null; }); - builder.addCase(getHostsConfigurationsVersions.fulfilled, (state, action) => { + builder.addCase(getConfigurationsVersions.fulfilled, (state, action) => { state.configVersions = action.payload.results; }); - builder.addCase(getHostsConfigurationsVersions.rejected, (state) => { + builder.addCase(getConfigurationsVersions.rejected, (state) => { state.configVersions = []; }); }, }); -const { cleanupHostsConfiguration, setIsConfigurationLoading, setIsVersionsLoading } = hostsConfigurationSlice.actions; -export { - getHostsConfiguration, - getHostsConfigurationsVersions, - cleanupHostsConfiguration, - createWithUpdateHostsConfigurations, -}; -export default hostsConfigurationSlice.reducer; +const { cleanup, setIsConfigurationLoading, setIsVersionsLoading } = entityConfigurationSlice.actions; +export { getConfiguration, getConfigurationsVersions, cleanup, createWithUpdateConfigurations }; +export default entityConfigurationSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/entityConfiguration/entityConfiguration.constants.ts b/adcm-web/app/src/store/adcm/entityConfiguration/entityConfiguration.constants.ts new file mode 100644 index 0000000000..9e6218c3b5 --- /dev/null +++ b/adcm-web/app/src/store/adcm/entityConfiguration/entityConfiguration.constants.ts @@ -0,0 +1,163 @@ +import { + AdcmSettingsApi, + AdcmHostProviderConfigsApi, + AdcmHostProviderGroupConfigsConfigsApi, + AdcmClusterConfigsApi, + AdcmClusterGroupConfigsConfigsApi, + AdcmHostConfigsApi, + AdcmClusterServicesConfigsApi, + AdcmClusterServiceConfigGroupConfigsApi, + AdcmClusterServiceComponentsConfigsApi, + AdcmClusterServiceComponentGroupConfigConfigsApi, +} from '@api'; +import { + ApiRequestsDictionary, + LoadConfigurationArgs, + LoadConfigurationVersionsArgs, + SaveConfigurationArgs, + // Settings + LoadSettingsConfigurationArgs, + SaveSettingsConfigurationArgs, + // Host provider + LoadHostProviderConfigurationVersionsArgs, + LoadHostProviderConfigurationArgs, + SaveHostProviderConfigurationArgs, + // Host provider group + LoadHostProviderGroupConfigurationVersionsArgs, + LoadHostProviderGroupConfigurationArgs, + SaveHostProviderGroupConfigurationArgs, + // Cluster + LoadClusterConfigurationVersionsArgs, + LoadClusterConfigurationArgs, + SaveClusterConfigurationArgs, + // Cluster group + LoadClusterGroupConfigurationVersionsArgs, + LoadClusterGroupConfigurationArgs, + SaveClusterGroupConfigurationArgs, + // Host + LoadHostConfigurationVersionsArgs, + LoadHostConfigurationArgs, + SaveHostConfigurationArgs, + // Cluster service + LoadClusterServiceConfigurationVersionsArgs, + LoadClusterServiceConfigurationArgs, + SaveClusterServiceConfigurationArgs, + // Cluster service group + LoadClusterServiceGroupConfigurationVersionsArgs, + LoadClusterServiceGroupConfigurationArgs, + SaveClusterServiceGroupConfigurationArgs, + // Cluster service component + LoadClusterServiceComponentConfigurationVersionsArgs, + LoadClusterServiceComponentConfigurationArgs, + SaveClusterServiceComponentConfigurationArgs, + // Cluster service component group + LoadClusterServiceComponentGroupConfigurationVersionsArgs, + LoadClusterServiceComponentGroupConfigurationArgs, + SaveClusterServiceComponentGroupConfigurationArgs, +} from './entityConfiguration.types'; + +export const ApiRequests: ApiRequestsDictionary = { + settings: { + getConfigVersions: () => AdcmSettingsApi.getConfigs(), + getConfig: (args: LoadConfigurationArgs) => AdcmSettingsApi.getConfig(args as LoadSettingsConfigurationArgs), + getConfigSchema: () => AdcmSettingsApi.getConfigSchema(), + createConfig: (args: SaveConfigurationArgs) => + AdcmSettingsApi.createConfiguration(args as SaveSettingsConfigurationArgs), + }, + 'host-provider': { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => + AdcmHostProviderConfigsApi.getConfigs(args as LoadHostProviderConfigurationVersionsArgs), + getConfig: (args: LoadConfigurationArgs) => + AdcmHostProviderConfigsApi.getConfig(args as LoadHostProviderConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmHostProviderConfigsApi.getConfigSchema(args as LoadHostProviderConfigurationArgs), + createConfig: (args: SaveConfigurationArgs) => + AdcmHostProviderConfigsApi.createConfiguration(args as SaveHostProviderConfigurationArgs), + }, + 'host-provider-config-group': { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => + AdcmHostProviderGroupConfigsConfigsApi.getConfigs(args as LoadHostProviderGroupConfigurationVersionsArgs), + getConfig: (args: LoadConfigurationArgs) => + AdcmHostProviderGroupConfigsConfigsApi.getConfig(args as LoadHostProviderGroupConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmHostProviderGroupConfigsConfigsApi.getConfigSchema(args as LoadHostProviderGroupConfigurationArgs), + createConfig: (args: SaveConfigurationArgs) => + AdcmHostProviderGroupConfigsConfigsApi.createConfiguration(args as SaveHostProviderGroupConfigurationArgs), + }, + cluster: { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => + AdcmClusterConfigsApi.getConfigs(args as LoadClusterConfigurationVersionsArgs), + getConfig: (args: LoadConfigurationArgs) => AdcmClusterConfigsApi.getConfig(args as LoadClusterConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterConfigsApi.getConfigSchema(args as LoadClusterConfigurationArgs), + createConfig: (args: SaveConfigurationArgs) => + AdcmClusterConfigsApi.createConfiguration(args as SaveClusterConfigurationArgs), + }, + 'cluster-config-group': { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => + AdcmClusterGroupConfigsConfigsApi.getConfigs(args as LoadClusterGroupConfigurationVersionsArgs), + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterGroupConfigsConfigsApi.getConfig(args as LoadClusterGroupConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterGroupConfigsConfigsApi.getConfigSchema(args as LoadClusterGroupConfigurationArgs), + createConfig: (args: SaveConfigurationArgs) => + AdcmClusterGroupConfigsConfigsApi.createConfiguration(args as SaveClusterGroupConfigurationArgs), + }, + host: { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => + AdcmHostConfigsApi.getConfigs(args as LoadHostConfigurationVersionsArgs), + getConfig: (args: LoadConfigurationArgs) => AdcmHostConfigsApi.getConfig(args as LoadHostConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmHostConfigsApi.getConfigSchema(args as LoadHostConfigurationArgs), + createConfig: (args: SaveConfigurationArgs) => + AdcmHostConfigsApi.createConfiguration(args as SaveHostConfigurationArgs), + }, + service: { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => + AdcmClusterServicesConfigsApi.getConfigs(args as LoadClusterServiceConfigurationVersionsArgs), + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterServicesConfigsApi.getConfig(args as LoadClusterServiceConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterServicesConfigsApi.getConfigSchema(args as LoadClusterServiceConfigurationArgs), + createConfig: (args: SaveConfigurationArgs) => + AdcmClusterServicesConfigsApi.createConfiguration(args as SaveClusterServiceConfigurationArgs), + }, + 'service-config-group': { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => + AdcmClusterServiceConfigGroupConfigsApi.getConfigs(args as LoadClusterServiceGroupConfigurationVersionsArgs), + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterServiceConfigGroupConfigsApi.getConfig(args as LoadClusterServiceGroupConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterServiceConfigGroupConfigsApi.getConfigSchema(args as LoadClusterServiceGroupConfigurationArgs), + createConfig: (args: SaveConfigurationArgs) => + AdcmClusterServiceConfigGroupConfigsApi.createConfiguration(args as SaveClusterServiceGroupConfigurationArgs), + }, + 'service-component': { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => + AdcmClusterServiceComponentsConfigsApi.getConfigs(args as LoadClusterServiceComponentConfigurationVersionsArgs), + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterServiceComponentsConfigsApi.getConfig(args as LoadClusterServiceComponentConfigurationArgs), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterServiceComponentsConfigsApi.getConfigSchema(args as LoadClusterServiceComponentConfigurationArgs), + createConfig: (args: SaveConfigurationArgs) => + AdcmClusterServiceComponentsConfigsApi.createConfiguration(args as SaveClusterServiceComponentConfigurationArgs), + }, + 'service-component-config-group': { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => + AdcmClusterServiceComponentGroupConfigConfigsApi.getConfigs( + args as LoadClusterServiceComponentGroupConfigurationVersionsArgs, + ), + getConfig: (args: LoadConfigurationArgs) => + AdcmClusterServiceComponentGroupConfigConfigsApi.getConfig( + args as LoadClusterServiceComponentGroupConfigurationArgs, + ), + getConfigSchema: (args: LoadConfigurationArgs) => + AdcmClusterServiceComponentGroupConfigConfigsApi.getConfigSchema( + args as LoadClusterServiceComponentGroupConfigurationArgs, + ), + createConfig: (args: SaveConfigurationArgs) => + AdcmClusterServiceComponentGroupConfigConfigsApi.createConfiguration( + args as SaveClusterServiceComponentGroupConfigurationArgs, + ), + }, +}; diff --git a/adcm-web/app/src/store/adcm/entityConfiguration/entityConfiguration.types.ts b/adcm-web/app/src/store/adcm/entityConfiguration/entityConfiguration.types.ts new file mode 100644 index 0000000000..a5082e1701 --- /dev/null +++ b/adcm-web/app/src/store/adcm/entityConfiguration/entityConfiguration.types.ts @@ -0,0 +1,270 @@ +import { AdcmConfig, AdcmConfigShortView, Batch, SchemaDefinition } from '@models/adcm'; + +import { GetSettingsConfigArgs, CreateSettingsConfigArgs } from '@api/adcm/settings'; +import { GetClusterConfigsArgs, GetClusterConfigArgs, CreateClusterConfigArgs } from '@api/adcm/clusterConfigs'; +import { + GetClusterGroupConfigsArgs, + GetClusterGroupConfigArgs, + CreateClusterGroupConfigArgs, +} from '@api/adcm/clusterGroupConfigConfigs'; +import { + GetHostProviderConfigsArgs, + GetHostProviderConfigArgs, + CreateHostProviderConfigArgs, +} from '@api/adcm/hostProviderConfigs'; +import { + GetHostProviderGroupConfigsArgs, + GetHostProviderGroupConfigArgs, + CreateHostProviderGroupConfigArgs, +} from '@api/adcm/hostProviderGroupConfigConfigs'; +import { GetHostConfigsArgs, GetHostConfigArgs, CreateHostConfigArgs } from '@api/adcm/hostConfigs'; +import { + GetClusterServiceConfigsArgs, + GetClusterServiceConfigArgs, + CreateClusterServiceConfigArgs, +} from '@api/adcm/clusterServicesConfigs'; +import { + GetClusterServiceGroupConfigsArgs, + GetClusterServiceGroupConfigArgs, + CreateClusterServiceGroupConfigArgs, +} from '@api/adcm/clusterServiceGroupConfigConfigs'; +import { + GetClusterServiceComponentConfigsArgs, + GetClusterServiceComponentConfigArgs, + CreateClusterServiceComponentConfigArgs, +} from '@api/adcm/clusterServiceComponentsConfigs'; +import { + GetClusterServiceComponentGroupConfigsArgs, + GetClusterServiceComponentGroupConfigArgs, + CreateClusterServiceComponentGroupConfigArgs, +} from '@api/adcm/serviceComponentGroupConfigConfigs'; + +export type EntityType = + | 'settings' + | 'host-provider' + | 'host-provider-config-group' + | 'cluster' + | 'cluster-config-group' + | 'host' + | 'service' + | 'service-config-group' + | 'service-component' + | 'service-component-config-group'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface LoadConfigurationVersionsArgs {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface LoadConfigurationArgs {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SaveConfigurationArgs {} + +/* Settings */ +export interface LoadSettingsConfigurationArgs extends LoadConfigurationArgs, GetSettingsConfigArgs {} +export interface SaveSettingsConfigurationArgs extends SaveConfigurationArgs, CreateSettingsConfigArgs {} + +/* Host provider */ +// eslint-disable-next-line prettier/prettier +export interface LoadHostProviderConfigurationVersionsArgs extends LoadConfigurationVersionsArgs, GetHostProviderConfigsArgs {} +export interface LoadHostProviderConfigurationArgs extends LoadConfigurationArgs, GetHostProviderConfigArgs {} +export interface SaveHostProviderConfigurationArgs extends SaveConfigurationArgs, CreateHostProviderConfigArgs {} + +/* Host provider group */ +export interface LoadHostProviderGroupConfigurationVersionsArgs + extends LoadConfigurationVersionsArgs, + GetHostProviderGroupConfigsArgs {} +export interface LoadHostProviderGroupConfigurationArgs extends LoadConfigurationArgs, GetHostProviderGroupConfigArgs {} +export interface SaveHostProviderGroupConfigurationArgs + extends SaveConfigurationArgs, + CreateHostProviderGroupConfigArgs {} + +/* Cluster */ +export interface LoadClusterConfigurationVersionsArgs extends LoadConfigurationVersionsArgs, GetClusterConfigsArgs {} +export interface LoadClusterConfigurationArgs extends LoadConfigurationArgs, GetClusterConfigArgs {} +export interface SaveClusterConfigurationArgs extends SaveConfigurationArgs, CreateClusterConfigArgs {} + +/* Cluster group */ +export interface LoadClusterGroupConfigurationVersionsArgs + extends LoadConfigurationVersionsArgs, + GetClusterGroupConfigsArgs {} +export interface LoadClusterGroupConfigurationArgs extends LoadConfigurationArgs, GetClusterGroupConfigArgs {} +export interface SaveClusterGroupConfigurationArgs extends SaveConfigurationArgs, CreateClusterGroupConfigArgs {} + +/* Host */ +export interface LoadHostConfigurationVersionsArgs extends LoadConfigurationVersionsArgs, GetHostConfigsArgs {} +export interface LoadHostConfigurationArgs extends LoadConfigurationArgs, GetHostConfigArgs {} +export interface SaveHostConfigurationArgs extends SaveConfigurationArgs, CreateHostConfigArgs {} + +/* Cluster service */ +export interface LoadClusterServiceConfigurationVersionsArgs + extends LoadConfigurationVersionsArgs, + GetClusterServiceConfigsArgs {} +export interface LoadClusterServiceConfigurationArgs extends LoadConfigurationArgs, GetClusterServiceConfigArgs {} +export interface SaveClusterServiceConfigurationArgs extends SaveConfigurationArgs, CreateClusterServiceConfigArgs {} + +/* Cluster service group */ +export interface LoadClusterServiceGroupConfigurationVersionsArgs + extends LoadConfigurationVersionsArgs, + GetClusterServiceGroupConfigsArgs {} +export interface LoadClusterServiceGroupConfigurationArgs + extends LoadConfigurationArgs, + GetClusterServiceGroupConfigArgs {} +export interface SaveClusterServiceGroupConfigurationArgs + extends SaveConfigurationArgs, + CreateClusterServiceGroupConfigArgs {} + +/* Service component */ +export interface LoadClusterServiceComponentConfigurationVersionsArgs + extends LoadConfigurationVersionsArgs, + GetClusterServiceComponentConfigsArgs {} +export interface LoadClusterServiceComponentConfigurationArgs + extends LoadConfigurationArgs, + GetClusterServiceComponentConfigArgs {} +export interface SaveClusterServiceComponentConfigurationArgs + extends SaveConfigurationArgs, + CreateClusterServiceComponentConfigArgs {} + +/* Service component group */ +export interface LoadClusterServiceComponentGroupConfigurationVersionsArgs + extends LoadConfigurationVersionsArgs, + GetClusterServiceComponentGroupConfigsArgs {} +export interface LoadClusterServiceComponentGroupConfigurationArgs + extends LoadConfigurationArgs, + GetClusterServiceComponentGroupConfigArgs {} +export interface SaveClusterServiceComponentGroupConfigurationArgs + extends SaveConfigurationArgs, + CreateClusterServiceComponentGroupConfigArgs {} + +export type LoadEntityConfigurationVersionsArgs = + | { + entityType: 'settings'; + args: LoadConfigurationVersionsArgs; + } + | { + entityType: 'host-provider'; + args: LoadHostProviderConfigurationVersionsArgs; + } + | { + entityType: 'host-provider-config-group'; + args: LoadHostProviderGroupConfigurationVersionsArgs; + } + | { + entityType: 'cluster'; + args: LoadClusterConfigurationVersionsArgs; + } + | { + entityType: 'cluster-config-group'; + args: LoadClusterGroupConfigurationVersionsArgs; + } + | { + entityType: 'host'; + args: LoadHostConfigurationVersionsArgs; + } + | { + entityType: 'service'; + args: LoadClusterServiceConfigurationVersionsArgs; + } + | { + entityType: 'service-config-group'; + args: LoadClusterServiceGroupConfigurationVersionsArgs; + } + | { + entityType: 'service-component'; + args: LoadClusterServiceComponentConfigurationVersionsArgs; + } + | { + entityType: 'service-component-config-group'; + args: LoadClusterServiceComponentGroupConfigurationVersionsArgs; + }; + +export type LoadEntityConfigurationArgs = + | { + entityType: 'settings'; + args: LoadSettingsConfigurationArgs; + } + | { + entityType: 'host-provider'; + args: LoadHostProviderConfigurationArgs; + } + | { + entityType: 'host-provider-config-group'; + args: LoadHostProviderGroupConfigurationArgs; + } + | { + entityType: 'cluster'; + args: LoadClusterConfigurationArgs; + } + | { + entityType: 'cluster-config-group'; + args: LoadClusterGroupConfigurationArgs; + } + | { + entityType: 'host'; + args: LoadHostConfigurationArgs; + } + | { + entityType: 'service'; + args: LoadClusterServiceConfigurationArgs; + } + | { + entityType: 'service-config-group'; + args: LoadClusterServiceGroupConfigurationArgs; + } + | { + entityType: 'service-component'; + args: LoadClusterServiceComponentConfigurationArgs; + } + | { + entityType: 'service-component-config-group'; + args: LoadClusterServiceComponentGroupConfigurationArgs; + }; + +export type CreateEntityConfigurationArgs = + | { + entityType: 'settings'; + args: SaveSettingsConfigurationArgs; + } + | { + entityType: 'host-provider'; + args: SaveHostProviderConfigurationArgs; + } + | { + entityType: 'host-provider-config-group'; + args: SaveHostProviderGroupConfigurationArgs; + } + | { + entityType: 'cluster'; + args: SaveClusterConfigurationArgs; + } + | { + entityType: 'cluster-config-group'; + args: SaveClusterGroupConfigurationArgs; + } + | { + entityType: 'host'; + args: SaveHostConfigurationArgs; + } + | { + entityType: 'service'; + args: SaveClusterServiceConfigurationArgs; + } + | { + entityType: 'service-config-group'; + args: SaveClusterServiceGroupConfigurationArgs; + } + | { + entityType: 'service-component'; + args: SaveClusterServiceComponentConfigurationArgs; + } + | { + entityType: 'service-component-config-group'; + args: SaveClusterServiceComponentGroupConfigurationArgs; + }; + +export type ApiRequestsDictionary = { + [key in EntityType]: { + getConfigVersions: (args: LoadConfigurationVersionsArgs) => Promise>; + getConfig: (args: LoadConfigurationArgs) => Promise; + getConfigSchema: (args: LoadConfigurationArgs) => Promise; + createConfig: (args: SaveConfigurationArgs) => Promise; + }; +}; diff --git a/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationSlice.ts b/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationSlice.ts deleted file mode 100644 index 1d8c8630b7..0000000000 --- a/adcm-web/app/src/store/adcm/hostProvider/configuration/hostProviderConfigurationSlice.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { AdcmHostProviderConfigsApi, RequestError } from '@api'; -import { createAsyncThunk } from '@store/redux'; -import { - AdcmConfiguration, - ConfigurationData, - ConfigurationAttributes, - AdcmConfigShortView, -} from '@models/adcm/configuration'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; -import { executeWithMinDelay } from '@utils/requestUtils'; -import { defaultSpinnerDelay } from '@constants'; - -type AdcmHostProviderConfigurationState = { - isConfigurationLoading: boolean; - loadedConfiguration: AdcmConfiguration | null; - configVersions: AdcmConfigShortView[]; - isVersionsLoading: boolean; -}; - -type LoadHostProviderConfigurationPayload = { - hostProviderId: number; - configId: number; -}; - -type SaveHostProviderConfigurationPayload = { - hostProviderId: number; - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -}; - -const createHostProviderConfiguration = createAsyncThunk( - 'adcm/hostProvider/configuration/createHostProviderConfiguration', - async ( - { hostProviderId, configurationData, attributes, description }: SaveHostProviderConfigurationPayload, - thunkAPI, - ) => { - try { - const configuration = await AdcmHostProviderConfigsApi.createConfiguration( - hostProviderId, - configurationData, - attributes, - description, - ); - return configuration; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const createWithUpdateHostProviderConfigurations = createAsyncThunk( - 'adcm/hostProvider/configuration/createAndUpdateHostProviderConfigurations', - async (arg: SaveHostProviderConfigurationPayload, thunkAPI) => { - await thunkAPI.dispatch(createHostProviderConfiguration(arg)).unwrap(); - await thunkAPI.dispatch(getHostProviderConfigurationsVersions({ hostProviderId: arg.hostProviderId })); - }, -); - -const getHostProviderConfiguration = createAsyncThunk( - 'adcm/hostProvider/configuration/getHostProviderConfiguration', - async (arg: LoadHostProviderConfigurationPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsConfigurationLoading(true)); - - try { - const [config, schema] = await Promise.all([ - AdcmHostProviderConfigsApi.getConfig(arg), - AdcmHostProviderConfigsApi.getConfigSchema(arg), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsConfigurationLoading(false)); - }, - }); - } - }, -); - -type GetHostProviderConfigurationsPayload = { - hostProviderId: number; -}; - -const getHostProviderConfigurationsVersions = createAsyncThunk( - 'adcm/hostProvider/configuration/getHostProviderConfigurationsVersions', - async ({ hostProviderId }: GetHostProviderConfigurationsPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsVersionsLoading(true)); - - try { - return await AdcmHostProviderConfigsApi.getConfigs(hostProviderId); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsVersionsLoading(false)); - }, - }); - } - }, -); - -const createInitialState = (): AdcmHostProviderConfigurationState => ({ - isVersionsLoading: false, - isConfigurationLoading: false, - loadedConfiguration: null, - configVersions: [], -}); - -const hostProviderConfigurationSlice = createSlice({ - name: 'adcm/hostProvider/configuration', - initialState: createInitialState(), - reducers: { - cleanupHostProviderConfiguration() { - return createInitialState(); - }, - setIsConfigurationLoading(state, action) { - state.isConfigurationLoading = action.payload; - }, - setIsVersionsLoading(state, action) { - state.isVersionsLoading = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(getHostProviderConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.loadedConfiguration = { - configurationData, - attributes, - schema, - }; - - state.isConfigurationLoading = false; - }); - builder.addCase(getHostProviderConfiguration.rejected, (state) => { - state.loadedConfiguration = null; - }); - builder.addCase(getHostProviderConfigurationsVersions.fulfilled, (state, action) => { - state.configVersions = action.payload.results; - }); - builder.addCase(getHostProviderConfigurationsVersions.rejected, (state) => { - state.configVersions = []; - }); - }, -}); - -const { cleanupHostProviderConfiguration, setIsConfigurationLoading, setIsVersionsLoading } = - hostProviderConfigurationSlice.actions; -export { - getHostProviderConfiguration, - getHostProviderConfigurationsVersions, - cleanupHostProviderConfiguration, - createWithUpdateHostProviderConfigurations, -}; -export default hostProviderConfigurationSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice.ts b/adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice.ts deleted file mode 100644 index 4147722394..0000000000 --- a/adcm-web/app/src/store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { AdcmConfigShortView, AdcmConfiguration, ConfigurationAttributes, ConfigurationData } from '@models/adcm'; -import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; -import { AdcmHostProviderGroupConfigsConfigsApi, RequestError } from '@api'; -import { showError } from '@store/notificationsSlice.ts'; -import { getErrorMessage } from '@utils/httpResponseUtils.ts'; -import { executeWithMinDelay } from '@utils/requestUtils.ts'; -import { defaultSpinnerDelay } from '@constants'; - -type AdcmHostProviderConfigGroupConfigurationState = { - isConfigurationLoading: boolean; - loadedConfiguration: AdcmConfiguration | null; - configVersions: AdcmConfigShortView[]; - isVersionsLoading: boolean; -}; - -type LoadHostProviderConfigGroupConfigurationPayload = { - hostProviderId: number; - configGroupId: number; - configId: number; -}; - -type SaveHostProviderConfigGroupConfigurationPayload = { - hostProviderId: number; - configGroupId: number; - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -}; - -const createHostProviderConfigGroupConfiguration = createAsyncThunk( - 'adcm/hostProvider/configGroup/configuration/createHostProviderConfigGroupConfiguration', - async ( - { - hostProviderId, - configGroupId, - configurationData, - attributes, - description, - }: SaveHostProviderConfigGroupConfigurationPayload, - thunkAPI, - ) => { - try { - const configuration = await AdcmHostProviderGroupConfigsConfigsApi.createConfiguration( - hostProviderId, - configGroupId, - configurationData, - attributes, - description, - ); - return configuration; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const createWithUpdateHostProviderConfigGroupConfigurations = createAsyncThunk( - 'adcm/hostProvider/configGroup/configuration/createAndUpdateHostProviderConfigGroupConfigurations', - async (arg: SaveHostProviderConfigGroupConfigurationPayload, thunkAPI) => { - await thunkAPI.dispatch(createHostProviderConfigGroupConfiguration(arg)).unwrap(); - await thunkAPI.dispatch( - getHostProviderConfigGroupConfigurationsVersions({ - hostProviderId: arg.hostProviderId, - configGroupId: arg.configGroupId, - }), - ); - }, -); - -const getHostProviderConfigGroupConfiguration = createAsyncThunk( - 'adcm/hostProvider/configGroup/configuration/getHostProviderConfigGroupConfiguration', - async (arg: LoadHostProviderConfigGroupConfigurationPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsConfigurationLoading(true)); - - try { - const [config, schema] = await Promise.all([ - AdcmHostProviderGroupConfigsConfigsApi.getConfig(arg), - AdcmHostProviderGroupConfigsConfigsApi.getConfigSchema(arg), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsConfigurationLoading(false)); - }, - }); - } - }, -); - -type GetHostProviderConfigGroupConfigurationsPayload = { - hostProviderId: number; - configGroupId: number; -}; - -const getHostProviderConfigGroupConfigurationsVersions = createAsyncThunk( - 'adcm/hostProviders/configuration/getHostProviderConfigGroupConfigurationsVersions', - async ({ hostProviderId, configGroupId }: GetHostProviderConfigGroupConfigurationsPayload, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsVersionsLoading(true)); - - try { - return await AdcmHostProviderGroupConfigsConfigsApi.getConfigs(hostProviderId, configGroupId); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsVersionsLoading(false)); - }, - }); - } - }, -); - -const createInitialState = (): AdcmHostProviderConfigGroupConfigurationState => ({ - isVersionsLoading: false, - isConfigurationLoading: false, - loadedConfiguration: null, - configVersions: [], -}); - -const hostProviderConfigGroupConfigurationSlice = createSlice({ - name: 'adcm/hostProvider/configGroup/configuration', - initialState: createInitialState(), - reducers: { - cleanupHostProviderConfigGroupConfiguration() { - return createInitialState(); - }, - setIsConfigurationLoading(state, action) { - state.isConfigurationLoading = action.payload; - }, - setIsVersionsLoading(state, action) { - state.isVersionsLoading = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(getHostProviderConfigGroupConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.loadedConfiguration = { - configurationData, - attributes, - schema, - }; - - state.isConfigurationLoading = false; - }); - builder.addCase(getHostProviderConfigGroupConfiguration.rejected, (state) => { - state.loadedConfiguration = null; - }); - builder.addCase(getHostProviderConfigGroupConfigurationsVersions.fulfilled, (state, action) => { - state.configVersions = action.payload.results; - }); - builder.addCase(getHostProviderConfigGroupConfigurationsVersions.rejected, (state) => { - state.configVersions = []; - }); - }, -}); - -const { cleanupHostProviderConfigGroupConfiguration, setIsConfigurationLoading, setIsVersionsLoading } = - hostProviderConfigGroupConfigurationSlice.actions; -export { - getHostProviderConfigGroupConfiguration, - getHostProviderConfigGroupConfigurationsVersions, - cleanupHostProviderConfigGroupConfiguration, - createWithUpdateHostProviderConfigGroupConfigurations, -}; -export default hostProviderConfigGroupConfigurationSlice.reducer; diff --git a/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationSlice.ts b/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationSlice.ts deleted file mode 100644 index 40d104cfa9..0000000000 --- a/adcm-web/app/src/store/adcm/settings/configuration/settingsConfigurationSlice.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { AdcmSettingsApi, RequestError } from '@api'; -import { createAsyncThunk } from '@store/redux'; -import { - AdcmConfiguration, - ConfigurationData, - ConfigurationAttributes, - AdcmConfigShortView, -} from '@models/adcm/configuration'; -import { showError } from '@store/notificationsSlice'; -import { getErrorMessage } from '@utils/httpResponseUtils'; -import { executeWithMinDelay } from '@utils/requestUtils'; -import { defaultSpinnerDelay } from '@constants'; -import { checkSession } from '@store/authSlice'; - -type AdcmSettingsState = { - isConfigurationLoading: boolean; - loadedConfiguration: AdcmConfiguration | null; - configVersions: AdcmConfigShortView[]; - isVersionsLoading: boolean; -}; - -type SaveSettingsPayload = { - description?: string; - configurationData: ConfigurationData; - attributes: ConfigurationAttributes; -}; - -const createSettingsConfiguration = createAsyncThunk( - 'adcm/settings/configuration/createSettingsConfiguration', - async ({ configurationData, attributes, description }: SaveSettingsPayload, thunkAPI) => { - try { - const configuration = await AdcmSettingsApi.createConfiguration(configurationData, attributes, description); - return configuration; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } - }, -); - -const createWithUpdateSettingsConfiguration = createAsyncThunk( - 'adcm/settings/configuration/createWithUpdateSettingsConfiguration', - async (arg: SaveSettingsPayload, thunkAPI) => { - await thunkAPI.dispatch(createSettingsConfiguration(arg)).unwrap(); - // TODO: rework in future. We can save password [min,max] settings in adcm settings. And it should influence o user Create/Edit forms - // settings for this form we get from auth.profile. - // as fast fix: check session and update auth.profile - thunkAPI.dispatch(checkSession()); - thunkAPI.dispatch(getSettingsConfigurationVersions()); - }, -); - -const getSettingsConfiguration = createAsyncThunk( - 'adcm/settings/configuration/getSettings', - async (id: number, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsConfigurationLoading(true)); - - try { - const [config, schema] = await Promise.all([ - AdcmSettingsApi.getConfig({ configId: id }), - AdcmSettingsApi.getConfigSchema(), - ]); - return { config, schema }; - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsConfigurationLoading(false)); - }, - }); - } - }, -); - -const getSettingsConfigurationVersions = createAsyncThunk( - 'adcm/settings/configuration/getSettingsConfigurationVersions', - async (arg, thunkAPI) => { - const startDate = new Date(); - thunkAPI.dispatch(setIsVersionsLoading(true)); - - try { - return await AdcmSettingsApi.getConfigs(); - } catch (error) { - thunkAPI.dispatch(showError({ message: getErrorMessage(error as RequestError) })); - return thunkAPI.rejectWithValue(error); - } finally { - executeWithMinDelay({ - startDate, - delay: defaultSpinnerDelay, - callback: () => { - thunkAPI.dispatch(setIsVersionsLoading(false)); - }, - }); - } - }, -); - -const createInitialState = (): AdcmSettingsState => ({ - isVersionsLoading: false, - isConfigurationLoading: false, - loadedConfiguration: null, - configVersions: [], -}); - -const SettingsConfigurationsSlice = createSlice({ - name: 'adcm/settings/configuration', - initialState: createInitialState(), - reducers: { - cleanupSettings() { - return createInitialState(); - }, - setIsConfigurationLoading(state, action) { - state.isConfigurationLoading = action.payload; - }, - setIsVersionsLoading(state, action) { - state.isVersionsLoading = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(getSettingsConfiguration.fulfilled, (state, action) => { - const { - config: { config: configurationData, adcmMeta: attributes }, - schema, - } = action.payload; - // https://github.com/microsoft/TypeScript/issues/34933 - // cast to any to avoid compiler warning - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - state.loadedConfiguration = { - configurationData, - attributes, - schema, - }; - - state.isConfigurationLoading = false; - }); - builder.addCase(getSettingsConfiguration.rejected, (state) => { - state.loadedConfiguration = null; - }); - builder.addCase(getSettingsConfigurationVersions.fulfilled, (state, action) => { - state.configVersions = action.payload.results; - }); - builder.addCase(getSettingsConfigurationVersions.rejected, (state) => { - state.configVersions = []; - }); - }, -}); - -const { cleanupSettings, setIsConfigurationLoading, setIsVersionsLoading } = SettingsConfigurationsSlice.actions; -export { - getSettingsConfiguration, - getSettingsConfigurationVersions, - cleanupSettings, - createWithUpdateSettingsConfiguration, -}; -export default SettingsConfigurationsSlice.reducer; diff --git a/adcm-web/app/src/store/store.ts b/adcm-web/app/src/store/store.ts index bab5f56260..e48bd00328 100644 --- a/adcm-web/app/src/store/store.ts +++ b/adcm-web/app/src/store/store.ts @@ -10,13 +10,10 @@ import clusterHostsActionsSlice from '@store/adcm/cluster/hosts/hostsActionsSlic import clusterHostsDynamicActionsSlice from '@store/adcm/cluster/hosts/hostsDynamicActionsSlice'; import hostComponentsDynamicActionsSlice from '@store/adcm/cluster/hosts/host/hostComponentsDynamicActionsSlice'; import clustersTableSlice from '@store/adcm/clusters/clustersTableSlice'; -import clusterConfigurationSlice from '@store/adcm/cluster/configuration/clusterConfigurationSlice'; import clusterConfigGroupsSlice from '@store/adcm/cluster/configGroups/clusterConfigGroupsSlice'; import clusterConfigGroupsTableSlice from '@store/adcm/cluster/configGroups/clusterConfigGroupsTableSlice'; import clusterConfigGroupActionsSlice from '@store/adcm/cluster/configGroups/clusterConfigGroupActionsSlice'; import clusterConfigGroupSlice from '@store/adcm/cluster/configGroupSingle/clusterConfigGroup'; -import clusterConfigGroupConfigurationSlice from '@store/adcm/cluster/configGroupSingle/configuration/clusterConfigGroupConfigurationSlice'; -import hostProviderConfigurationSlice from '@store/adcm/hostProvider/configuration/hostProviderConfigurationSlice'; import hostProviderConfigGroupsSlice from '@store/adcm/hostProvider/configurationGroups/hostProviderConfigGroupsSlice'; import hostProviderConfigGroupsTableSlice from '@store/adcm/hostProvider/configurationGroups/hostProviderConfigGroupsTableSlice'; import bundlesSlice from '@store/adcm/bundles/bundlesSlice'; @@ -74,7 +71,6 @@ import serviceComponentConfigGroupsSlice from './adcm/cluster/services/serviceCo import serviceComponentConfigGroupsTableSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configGroups/serviceComponentConfigGroupsTableSlice'; import serviceComponentConfigGroupsActionsSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configGroups/serviceComponentConfigGroupsActionsSlice'; import serviceComponentConfigGroupSingleSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupSingleSlice'; -import serviceComponentConfigGroupConfigurationSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configGroupSingle/serviceComponentConfigGroupConfigurationSlice'; import clustersActionsSlice from './adcm/clusters/clustersActionsSlice'; import clusterHostSlice from './adcm/cluster/hosts/host/clusterHostSlice'; @@ -87,24 +83,19 @@ import hostProvidersActionsSlice from './adcm/hostProviders/hostProvidersActions import hostProvidersDynamicActionsSlice from './adcm/hostProviders/hostProvidersDynamicActionsSlice'; import hostProviderUpgradesSlice from './adcm/hostProviders/hostProviderUpgradesSlice'; import serviceComponentsDynamicActionsSlice from './adcm/cluster/services/serviceComponents/serviceComponentsDynamicActionsSlice'; -import serviceComponentConfigurationSlice from './adcm/cluster/services/serviceComponents/serviceComponent/configuration/serviceComponentConfigurationSlice'; import hostSlice from './adcm/host/hostSlice'; -import clusterServicesConfigurationSlice from './adcm/cluster/services/servicesPrymaryConfiguration/servicesConfigurationSlice.ts'; -import hostsConfigurationSlice from './adcm/host/configuration/hostsConfigurationSlice.ts'; import serviceConfigGroupsSlice from './adcm/cluster/services/configGroups/serviceConfigGroupsSlice.ts'; import serviceConfigGroupsTableSlice from './adcm/cluster/services/configGroups/serviceConfigGroupsTableSlice.ts'; import serviceConfigGroupsActionsSlice from './adcm/cluster/services/configGroups/serviceConfigGroupsActionsSlice.ts'; import serviceConfigGroupSlice from './adcm/cluster/services/configGroupSingle/configGroupSingle.ts'; -import serviceConfigGroupConfigurationSlice from './adcm/cluster/services/configGroupSingle/configuration/serviceConfigGroupConfigurationSlice'; -import settingsConfigurationsSlice from './adcm/settings/configuration/settingsConfigurationSlice.ts'; import hostProviderConfigGroupActionsSlice from '@store/adcm/hostProvider/configurationGroups/hostProviderConfigGroupActionsSlice'; import hostProviderConfigGroupSlice from '@store/adcm/hostProvider/configurationGroupSingle/hostProviderConfigGroupSlice'; -import hostProviderConfigGroupConfigurationSlice from '@store/adcm/hostProvider/configurationGroupSingle/configuration/hostProviderConfigGroupConfigurationSlice'; import bellSlice from '@store/adcm/bell/bellSlice'; import adcmSettingsSlice from '@store/adcm/settings/settingsSlice'; import adcmSettingsDynamicActionsSlice from '@store/adcm/settings/settingsDynamicActionsSlice'; import bundlesActionsSlice from './adcm/bundles/bundlesActionsSlice.ts'; +import adcmEntityConfigurationSlice from '@store/adcm/entityConfiguration/configurationSlice.ts'; import adcmEntityConfigurationCompareSlice from '@store/adcm/entityConfiguration/compareSlice.ts'; const rootReducer = combineReducers({ @@ -124,13 +115,10 @@ const rootReducer = combineReducers({ hostComponentsDynamicActions: hostComponentsDynamicActionsSlice, clusterHostsTable: clusterHostsTableSlice, clusterMapping: clusterMappingSlice, - clusterConfiguration: clusterConfigurationSlice, clusterConfigGroups: clusterConfigGroupsSlice, clusterConfigGroupsTable: clusterConfigGroupsTableSlice, clusterConfigGroupActions: clusterConfigGroupActionsSlice, clusterConfigGroup: clusterConfigGroupSlice, - clusterConfigGroupConfiguration: clusterConfigGroupConfigurationSlice, - clusterServicesConfiguration: clusterServicesConfigurationSlice, bundle: bundleSlice, bundles: bundlesSlice, bundlesActions: bundlesActionsSlice, @@ -139,12 +127,10 @@ const rootReducer = combineReducers({ hostComponents: hostComponentsSlice, hostComponentsTable: hostComponentsTableSlice, hostProvider: hostProviderSlice, - hostProviderConfiguration: hostProviderConfigurationSlice, hostProviderConfigGroupActions: hostProviderConfigGroupActionsSlice, hostProviderConfigGroups: hostProviderConfigGroupsSlice, hostProviderConfigGroupsTable: hostProviderConfigGroupsTableSlice, hostProviderConfigGroup: hostProviderConfigGroupSlice, - hostProviderConfigGroupConfiguration: hostProviderConfigGroupConfigurationSlice, hostProviders: hostProvidersSlice, hostProvidersActions: hostProvidersActionsSlice, hostProvidersTable: hostProvidersTableSlice, @@ -156,7 +142,6 @@ const rootReducer = combineReducers({ host: hostSlice, hostsTable: hostsTableSlice, hostsActions: hostsActionsSlice, - hostsConfiguration: hostsConfigurationSlice, service: serviceSlice, services: servicesSlice, servicesTable: servicesTableSlice, @@ -166,14 +151,11 @@ const rootReducer = combineReducers({ serviceConfigGroupsTable: serviceConfigGroupsTableSlice, serviceConfigGroupsActions: serviceConfigGroupsActionsSlice, serviceConfigGroup: serviceConfigGroupSlice, - serviceConfigGroupConfiguration: serviceConfigGroupConfigurationSlice, serviceComponents: serviceComponentsSlice, - serviceComponentConfiguration: serviceComponentConfigurationSlice, serviceComponentConfigGroups: serviceComponentConfigGroupsSlice, serviceComponentConfigGroupsTable: serviceComponentConfigGroupsTableSlice, serviceComponentConfigGroupsActions: serviceComponentConfigGroupsActionsSlice, serviceComponentConfigGroupSingle: serviceComponentConfigGroupSingleSlice, - serviceComponentConfigGroupConfiguration: serviceComponentConfigGroupConfigurationSlice, serviceComponentsTable: serviceComponentsTableSlice, serviceComponentsActions: serviceComponentsActionsSlice, serviceComponentsDynamicActions: serviceComponentsDynamicActionsSlice, @@ -208,10 +190,10 @@ const rootReducer = combineReducers({ roles: rolesSlice, rolesTable: rolesTableSlice, rolesActions: rolesActionsSlice, - settingsConfigurations: settingsConfigurationsSlice, adcmSettings: adcmSettingsSlice, adcmSettingsDynamicActions: adcmSettingsDynamicActionsSlice, entityConfigurationCompare: adcmEntityConfigurationCompareSlice, + entityConfiguration: adcmEntityConfigurationSlice, }), }); From ce8aaea600c1f296766f488866752b93e6a3dee1 Mon Sep 17 00:00:00 2001 From: Daniil Skrynnik Date: Fri, 26 Jan 2024 13:02:24 +0000 Subject: [PATCH 060/151] Ldap/audit fixes --- python/adcm/utils.py | 1 + python/rbac/ldap.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/python/adcm/utils.py b/python/adcm/utils.py index 3b4e2d4f57..5bd3e7090f 100644 --- a/python/adcm/utils.py +++ b/python/adcm/utils.py @@ -132,6 +132,7 @@ def get_obj_type(obj_type: str) -> str: "cluster object": "service", "service component": "component", "host provider": "provider", + "host": "host", } return object_names_to_object_types[obj_type] diff --git a/python/rbac/ldap.py b/python/rbac/ldap.py index 23b4564903..a5c89a1151 100644 --- a/python/rbac/ldap.py +++ b/python/rbac/ldap.py @@ -235,6 +235,8 @@ def _get_local_groups_by_username(username: str) -> list[Group]: user = User.objects.get(username__iexact=username, type=OriginType.LDAP) return [g.group for g in user.groups.order_by("id") if g.group.type == OriginType.LOCAL] + return [] + def get_user_model(self) -> type[User]: return User @@ -310,6 +312,8 @@ def _get_ldap_group_dn(group_name: str, ldap_groups: list) -> str: with suppress(IndexError): return [i for i in ldap_groups if i[0] == group_name][0][1] + return "" + @staticmethod def _get_rbac_group(group: Group | DjangoGroup, ldap_group_dn: str) -> Group: """ From 719c5717e1665f3c820c1f0ca52881d874374f39 Mon Sep 17 00:00:00 2001 From: Igor Kuzmin Date: Mon, 29 Jan 2024 08:52:09 +0000 Subject: [PATCH 061/151] feature/ADCM-5190 redesign cluster mappings page, get rid of tabs Task: https://tracker.yandex.ru/ADCM-5190 --- adcm-web/app/src/App.tsx | 8 +- .../DynamicActionHostMapping.tsx | 36 +-- .../ClusterMapping/ClusterMapping.module.scss | 4 - .../cluster/ClusterMapping/ClusterMapping.tsx | 75 +++++- .../ClusterMapping/ClusterMapping.types.ts | 21 +- .../ClusterMapping/ClusterMapping.utils.ts | 6 +- .../ClusterMappingToolbar.module.scss | 15 +- .../ClusterMappingToolbar.tsx | 104 +++++++- .../ComponentContainer/ComponentContainer.tsx | 11 +- .../ComponentsMapping.module.scss | 26 +- .../ComponentsMapping/ComponentsMapping.tsx | 222 ++++++------------ .../HostContainer/HostContainer.tsx | 12 +- .../HostsMapping/HostsMapping.module.scss | 17 +- .../HostsMapping/HostsMapping.tsx | 64 ++--- .../ClusterMapping/useClusterMapping.ts | 71 +++--- .../uikit/Switch/Switch.module.scss | 4 +- .../app/src/models/adcm/clusterMapping.ts | 6 + adcm-web/app/src/models/adcm/service.ts | 2 + adcm-web/app/src/models/loadState.ts | 2 + adcm-web/app/src/routes/routes.ts | 18 +- .../adcm/cluster/mapping/mappingSlice.ts | 73 +++--- .../clusters/clustersDynamicActionsSlice.ts | 19 +- 22 files changed, 401 insertions(+), 415 deletions(-) diff --git a/adcm-web/app/src/App.tsx b/adcm-web/app/src/App.tsx index efced8681f..0df9293d9c 100644 --- a/adcm-web/app/src/App.tsx +++ b/adcm-web/app/src/App.tsx @@ -26,8 +26,6 @@ import { ClusterImportsCluster, ClusterImportsService, ClusterMapping, - ClusterHostsMapping, - ClusterComponentsMapping, ClusterOverview, ClusterServices, } from '@pages/cluster'; @@ -145,11 +143,7 @@ function App() { element={} /> - }> - } /> - } /> - } /> - + } /> }> } /> = ({ }, [clusterId, dispatch]); const { - dialog: { hosts, components, localMapping, loadState }, + dialog: { hosts, components, mapping, loadState }, } = useStore(({ adcm }) => adcm.clustersDynamicActions); const notAddedServicesDictionary = useStore(({ adcm }) => adcm.clusterMapping.relatedData.notAddedServicesDictionary); - const handleSetMapping = useCallback( - (newMapping: AdcmMapping[]) => { - dispatch(setLocalMapping(newMapping)); - }, - [dispatch], - ); - const { - hostComponentMapping, + localMapping, servicesMapping, - servicesMappingFilter, - handleServicesMappingFilterChange, + mappingFilter, + handleMappingFilterChange, mappingValidation, handleMap, handleUnmap, - } = useClusterMapping(localMapping, hosts, components, notAddedServicesDictionary, true, handleSetMapping); + handleReset, + } = useClusterMapping(mapping, hosts, components, notAddedServicesDictionary, true); const isServicesMappingEmpty = servicesMapping.length === 0; const handleSubmit = () => { - onSubmit({ hostComponentMap: hostComponentMapping }); + onSubmit({ hostComponentMap: localMapping }); }; const getMapRules = (service: AdcmMappingComponentService, component: AdcmMappingComponent) => { @@ -66,11 +60,7 @@ const DynamicActionHostMapping: React.FC = ({ }; const handleFilterChange = (event: React.ChangeEvent) => { - handleServicesMappingFilterChange({ hostName: event.target.value }); - }; - - const handleRevertMappingChanges = () => { - dispatch(revertChanges()); + handleMappingFilterChange({ hostName: event.target.value }); }; return ( @@ -78,7 +68,7 @@ const DynamicActionHostMapping: React.FC = ({ - @@ -113,7 +103,7 @@ const DynamicActionHostMapping: React.FC = ({ { const dispatch = useDispatch(); @@ -13,6 +21,8 @@ const ClusterMapping: React.FC = () => { const { clusterId: clusterIdFromUrl } = useParams(); const clusterId = Number(clusterIdFromUrl); + const [isHostsPreviewMode, setIsHostsPreviewMode] = useState(false); + useEffect(() => { if (!Number.isNaN(clusterId)) { dispatch(getMappings({ clusterId })); @@ -36,13 +46,58 @@ const ClusterMapping: React.FC = () => { } }, [cluster, dispatch]); + const { mapping, hosts, components, loading, saving } = useStore(({ adcm }) => adcm.clusterMapping); + const notAddedServicesDictionary = useStore(({ adcm }) => adcm.clusterMapping.relatedData.notAddedServicesDictionary); + + const { + localMapping, + mappingFilter, + servicesMapping, + hostsMapping, + mappingValidation, + isMappingChanged, + handleMap, + handleUnmap, + handleMappingFilterChange, + handleReset, + } = useClusterMapping(mapping, hosts, components, notAddedServicesDictionary, loading.state === 'completed'); + + const handleSave = () => { + dispatch(saveMapping({ clusterId, mapping: localMapping })); + }; + return (
      - - Components - Hosts view - - + + {isHostsPreviewMode ? ( + + ) : ( + + )}
      ); }; diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.types.ts b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.types.ts index dfe3837e62..16f00a07de 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.types.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.types.ts @@ -3,27 +3,21 @@ import { AdcmMappingComponent, AdcmMappingComponentService, AdcmServicePrototype, + HostId, + ComponentId, + ServiceId, + ServicePrototypeId, } from '@models/adcm'; export type ValidationError = { isValid: false; errors: string[] }; export type ValidationSuccess = { isValid: true }; export type ValidationResult = ValidationError | ValidationSuccess; -export type HostId = AdcmHostShortView['id']; -export type ComponentId = AdcmMappingComponent['id']; -export type ServiceId = AdcmMappingComponentService['id']; -export type ServicePrototypeId = AdcmServicePrototype['id']; - export type HostsDictionary = Record; export type ComponentHostsDictionary = Record; export type ComponentsDictionary = Record; export type ServicesDictionary = Record; -export type HostMappingFilter = { - componentDisplayName: string; - isHideEmptyHosts: boolean; -}; - export type HostMapping = { host: AdcmHostShortView; components: AdcmMappingComponent[]; @@ -40,9 +34,10 @@ export type ComponentMappingValidation = { isValid: boolean; }; -export type ServiceMappingFilter = { +export type MappingFilter = { hostName: string; - isHideEmptyComponents: boolean; + componentDisplayName: string; + isHideEmpty: boolean; }; export type ServiceMapping = { @@ -55,8 +50,6 @@ export type ComponentMapping = { hosts: AdcmHostShortView[]; }; -export type MappingState = 'no-changes' | 'editing' | 'saved'; - export type ComponentValidateResult = { constraintsValidationResult: ValidationResult; requireValidationResults: ValidationResult; diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.ts b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.ts index c8ff9b3c8f..066d957683 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMapping.utils.ts @@ -5,16 +5,16 @@ import { AdcmMapping, AdcmMappingComponentService, AdcmDependOnService, + ComponentId, + HostId, + ServiceId, } from '@models/adcm'; import { HostMapping, ServiceMapping, ComponentMapping, ValidationResult, - ComponentId, - ServiceId, ComponentMappingValidation, - HostId, HostsDictionary, MappingValidation, ValidateCache, diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMappingToolbar/ClusterMappingToolbar.module.scss b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMappingToolbar/ClusterMappingToolbar.module.scss index a4bf015582..9e4882246f 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMappingToolbar/ClusterMappingToolbar.module.scss +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMappingToolbar/ClusterMappingToolbar.module.scss @@ -9,7 +9,16 @@ } .clusterMappingToolbar { - border-radius: 12px; - background: var(--cluster-mapping-toolbar-background); - padding: 8px; + gap: 40px; + margin-bottom: 24px; + + &__inputAndSwitches { + width: 100%; + gap: 20px; + display: flex; + } + + &__searchInput { + flex: 1; + } } diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMappingToolbar/ClusterMappingToolbar.tsx b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMappingToolbar/ClusterMappingToolbar.tsx index 226b52318b..b8b53b7b61 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMappingToolbar/ClusterMappingToolbar.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ClusterMappingToolbar/ClusterMappingToolbar.tsx @@ -1,16 +1,106 @@ import React from 'react'; +import { Button, ButtonGroup, Panel, SearchInput, Switch } from '@uikit'; +import { MappingFilter } from '../ClusterMapping.types'; +import { ActionState } from '@models/loadState'; import s from './ClusterMappingToolbar.module.scss'; -import cn from 'classnames'; -export interface ClusterMappingToolbarProps extends React.PropsWithChildren { - className?: string; +export interface ClusterMappingToolbarProps { + isHostsPreviewMode: boolean; + filter: MappingFilter; + savingState: ActionState; + hasSaveError: boolean; + isValid: boolean; + isMappingChanged: boolean; + onHostsPreviewModeChange: (isHostsPreviewMode: boolean) => void; + onFilterChange: (filter: Partial) => void; + onReset: () => void; + onSave: () => void; } -const ClusterMappingToolbar = ({ className = '', children }: ClusterMappingToolbarProps) => { +const ClusterMappingToolbar = ({ + isHostsPreviewMode, + filter, + savingState, + hasSaveError, + isValid, + isMappingChanged, + onHostsPreviewModeChange, + onFilterChange, + onReset, + onSave, +}: ClusterMappingToolbarProps) => { + const handleFilterHostsChange = (event: React.ChangeEvent) => { + onFilterChange({ + componentDisplayName: '', + hostName: event.target.value, + }); + }; + + const handleFilterComponentsChange = (event: React.ChangeEvent) => { + onFilterChange({ + componentDisplayName: event.target.value, + hostName: '', + }); + }; + + const handleHideEmptyChange = (event: React.ChangeEvent) => { + onFilterChange({ isHideEmpty: event.target.checked }); + }; + + const handleHostsPreviewModeChange = (event: React.ChangeEvent) => { + onHostsPreviewModeChange(event.target.checked); + }; + + const isSavingInProgress = savingState === 'in-progress'; + const isButtonsDisabledByState = isSavingInProgress || !isMappingChanged; + return ( -
      - {children} -
      + +
      + {isHostsPreviewMode ? ( + + ) : ( + + )} + + + +
      + + + + +
      ); }; diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentContainer/ComponentContainer.tsx b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentContainer/ComponentContainer.tsx index 5d64fd99e8..7fd82a4978 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentContainer/ComponentContainer.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentContainer/ComponentContainer.tsx @@ -9,21 +9,20 @@ import { AdcmHostShortView, AdcmMaintenanceMode, AdcmMappingComponent, - AdcmServicePrototype, } from '@models/adcm'; -import { ComponentMapping, ComponentMappingValidation, ServiceMappingFilter } from '../../ClusterMapping.types'; +import { ComponentMapping, ComponentMappingValidation, MappingFilter } from '../../ClusterMapping.types'; import { getConstraintsLimit, isComponentDependOnNotAddedServices } from '../../ClusterMapping.utils'; import s from './ComponentContainer.module.scss'; import cn from 'classnames'; import { useDispatch } from '@hooks'; -import { openRequiredServicesDialog } from '@store/adcm/cluster/mapping/mappingSlice'; +import { NotAddedServicesDictionary, openRequiredServicesDialog } from '@store/adcm/cluster/mapping/mappingSlice'; export interface ComponentContainerProps { componentMapping: ComponentMapping; componentMappingValidation: ComponentMappingValidation; - filter: ServiceMappingFilter; + filter: MappingFilter; allHosts: AdcmHostShortView[]; - notAddedServicesDictionary: Record; + notAddedServicesDictionary: NotAddedServicesDictionary; onMap: (hosts: AdcmHostShortView[], component: AdcmMappingComponent) => void; onUnmap: (hostId: number, componentId: number) => void; allowActions?: AdcmHostComponentMapRuleAction[]; @@ -106,7 +105,7 @@ const ComponentContainer = ({ const limit = getConstraintsLimit(component.constraints); - if (visibleHosts.length === 0 && filter.isHideEmptyComponents) { + if (visibleHosts.length === 0 && filter.isHideEmpty) { return null; } diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.module.scss b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.module.scss index 091a2bd8f2..07bd860beb 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.module.scss +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.module.scss @@ -16,31 +16,9 @@ } } -.componentsMapping { - &__toolbar { - margin-bottom: 24px; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 20px; - } - - &__toolbarButtonsAndSwitch { - display: flex; - justify-content: space-between; - } - &__toolbarButtons { - display: flex; - justify-content: flex-end; - - & > *:not(:last-child) { - margin-right: 12px; - } - } - - &__content { +.componentsMapping { display: grid; grid-template-columns: 4fr 1fr; gap: 20px; - } -} +} \ No newline at end of file diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.tsx b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.tsx index 77f78191b4..0a3719010d 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/ComponentsMapping/ComponentsMapping.tsx @@ -1,67 +1,38 @@ -import { useCallback, useEffect, useMemo } from 'react'; -import { AnchorBar, AnchorBarItem, AnchorList, Button, MarkerIcon, SearchInput, Switch, Text } from '@uikit'; -import { useClusterMapping } from '../useClusterMapping'; +import { useMemo } from 'react'; +import { AnchorBar, AnchorBarItem, AnchorList, MarkerIcon, Text } from '@uikit'; import ComponentContainer from './ComponentContainer/ComponentContainer'; -import ClusterMappingToolbar from '../ClusterMappingToolbar/ClusterMappingToolbar'; -import s from './ComponentsMapping.module.scss'; -import cn from 'classnames'; import { Link, useParams } from 'react-router-dom'; -import { setLocalMapping, saveMapping, revertChanges } from '@store/adcm/cluster/mapping/mappingSlice'; -import { useDispatch, useStore } from '@hooks'; -import { setBreadcrumbs } from '@store/adcm/breadcrumbs/breadcrumbsSlice'; import RequiredServicesDialog from '@pages/cluster/ClusterMapping/ComponentsMapping/RequiredServicesDialog/RequiredServicesDialog'; -import { AdcmEntitySystemState, AdcmMaintenanceMode, AdcmMapping } from '@models/adcm'; +import { AdcmEntitySystemState, AdcmHostShortView, AdcmMaintenanceMode, AdcmMappingComponent } from '@models/adcm'; +import { MappingFilter, MappingValidation, ServiceMapping } from '../ClusterMapping.types'; +import s from './ComponentsMapping.module.scss'; +import cn from 'classnames'; +import { NotAddedServicesDictionary } from '@store/adcm/cluster/mapping/mappingSlice'; const buildServiceAnchorId = (id: number) => `anchor_${id}`; -const ComponentsMapping = () => { - const dispatch = useDispatch(); - +export interface ComponentsMappingProps { + hosts: AdcmHostShortView[]; + servicesMapping: ServiceMapping[]; + mappingValidation: MappingValidation; + mappingFilter: MappingFilter; + notAddedServicesDictionary: NotAddedServicesDictionary; + onMap: (hosts: AdcmHostShortView[], component: AdcmMappingComponent) => void; + onUnmap: (hostId: number, componentId: number) => void; +} + +const ComponentsMapping = ({ + hosts, + servicesMapping, + mappingValidation, + mappingFilter, + notAddedServicesDictionary, + onMap, + onUnmap, +}: ComponentsMappingProps) => { const { clusterId: clusterIdFromUrl } = useParams(); const clusterId = Number(clusterIdFromUrl); - const cluster = useStore(({ adcm }) => adcm.cluster.cluster); - - useEffect(() => { - if (cluster) { - dispatch( - setBreadcrumbs([ - { href: '/clusters', label: 'Clusters' }, - { href: `/clusters/${cluster.id}`, label: cluster.name }, - { label: 'Mapping' }, - { label: 'Components' }, - ]), - ); - } - }, [cluster, dispatch]); - - const handleSetMapping = useCallback( - (newMapping: AdcmMapping[]) => { - dispatch(setLocalMapping(newMapping)); - }, - [dispatch], - ); - - const { - hosts, - components, - localMapping, - isLoaded, - hasSaveError, - state: mappingState, - } = useStore(({ adcm }) => adcm.clusterMapping); - const notAddedServicesDictionary = useStore(({ adcm }) => adcm.clusterMapping.relatedData.notAddedServicesDictionary); - - const { - hostComponentMapping, - servicesMapping, - servicesMappingFilter, - handleServicesMappingFilterChange, - mappingValidation, - handleMap, - handleUnmap, - } = useClusterMapping(localMapping, hosts, components, notAddedServicesDictionary, isLoaded, handleSetMapping); - const anchorItems: AnchorBarItem[] = useMemo( () => servicesMapping.map((m) => ({ @@ -71,102 +42,59 @@ const ComponentsMapping = () => { [servicesMapping], ); - const handleFilterChange = (event: React.ChangeEvent) => { - handleServicesMappingFilterChange({ hostName: event.target.value }); - }; - - const handleHideEmptyComponentsChange = (event: React.ChangeEvent) => { - handleServicesMappingFilterChange({ isHideEmptyComponents: event.target.checked }); - }; - - const handleSave = () => { - dispatch(saveMapping({ clusterId, mapping: hostComponentMapping })); - }; - - const handleRevert = () => { - dispatch(revertChanges()); - }; - - const isButtonsDisabledByState = mappingState === 'saving' || mappingState === 'no-changes'; - return (
      - - -
      - -
      - - -
      -
      -
      -
      -
      - {servicesMapping.map(({ service, componentsMapping }) => { - const isServiceValid = componentsMapping.every( - (cm) => mappingValidation.byComponents[cm.component.id].isValid, - ); - const titleClassName = cn(s.serviceMapping__title, { - [s['serviceMapping__title_error']]: !isServiceValid, - }); - - const markerType = isServiceValid ? 'check' : 'alert'; - - return ( -
      - - {service.displayName} - - - {componentsMapping.map((componentMapping) => { - const isEditableComponent = - componentMapping.component.service.state === AdcmEntitySystemState.Created && - componentMapping.component.maintenanceMode !== AdcmMaintenanceMode.On; - - return ( - - ); - })} -
      - ); - })} - {servicesMapping.length === 0 && ( -
      - Add services on the{' '} - - services page - +
      + {servicesMapping.map(({ service, componentsMapping }) => { + const isServiceValid = componentsMapping.every( + (cm) => mappingValidation.byComponents[cm.component.id].isValid, + ); + const titleClassName = cn(s.serviceMapping__title, { + [s['serviceMapping__title_error']]: !isServiceValid, + }); + + const markerType = isServiceValid ? 'check' : 'alert'; + + return ( +
      + + {service.displayName} + + + {componentsMapping.map((componentMapping) => { + const isEditableComponent = + componentMapping.component.service.state === AdcmEntitySystemState.Created && + componentMapping.component.maintenanceMode !== AdcmMaintenanceMode.On; + + return ( + + ); + })}
      - )} -
      - - - + ); + })} + {servicesMapping.length === 0 && ( +
      + Add services on the{' '} + + services page + +
      + )}
      + + +
      diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostContainer/HostContainer.tsx b/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostContainer/HostContainer.tsx index 953ef21e50..fee78c3328 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostContainer/HostContainer.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostContainer/HostContainer.tsx @@ -1,16 +1,18 @@ import { useMemo } from 'react'; import { Tags } from '@uikit'; import MappingItemTag from '../../MappingItemTag/MappingItemTag'; -import { MappingValidation, HostMapping, HostMappingFilter } from '../../ClusterMapping.types'; +import { MappingValidation, HostMapping, MappingFilter } from '../../ClusterMapping.types'; import s from './HostContainer.module.scss'; +import cn from 'classnames'; export interface HostContainerProps { hostMapping: HostMapping; mappingValidation: MappingValidation; - filter: HostMappingFilter; + filter: MappingFilter; + className?: string; } -const HostContainer = ({ hostMapping, mappingValidation, filter }: HostContainerProps) => { +const HostContainer = ({ hostMapping, mappingValidation, filter, className }: HostContainerProps) => { const { host, components } = hostMapping; const visibleHostComponents = useMemo( @@ -21,13 +23,13 @@ const HostContainer = ({ hostMapping, mappingValidation, filter }: HostContainer [components, filter.componentDisplayName], ); - if (visibleHostComponents.length === 0 && filter.isHideEmptyHosts) { + if (visibleHostComponents.length === 0 && filter.isHideEmpty) { return null; } return ( <> -
      +
      {host.name} {components.length} diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.module.scss b/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.module.scss index fc45e927b6..dbf2542b7f 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.module.scss +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.module.scss @@ -1,14 +1,9 @@ .hostsMapping { - &__toolbar { - margin-bottom: 24px; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 20px; - } + display: grid; + grid-template-columns: 4fr 1fr; + gap: 20px; +} - &__content { - display: grid; - grid-template-columns: 4fr 1fr; - gap: 20px; - } +.hostContainer { + grid-column: 1; } \ No newline at end of file diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.tsx b/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.tsx index 5403d21c6c..bec1ebf56e 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.tsx +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/HostsMapping/HostsMapping.tsx @@ -1,33 +1,18 @@ -import { useClusterMapping } from '../useClusterMapping'; import HostContainer from './HostContainer/HostContainer'; -import ClusterMappingToolbar from '../ClusterMappingToolbar/ClusterMappingToolbar'; -import s from './HostsMapping.module.scss'; -import { SearchInput, Switch } from '@uikit'; import { useDispatch, useStore } from '@hooks'; import { useEffect } from 'react'; import { setBreadcrumbs } from '@store/adcm/breadcrumbs/breadcrumbsSlice'; +import { HostMapping, MappingFilter, MappingValidation } from '../ClusterMapping.types'; +import s from './HostsMapping.module.scss'; -const HostsMapping = () => { - const dispatch = useDispatch(); - - const { hosts, components, localMapping, isLoaded } = useStore(({ adcm }) => adcm.clusterMapping); - const notAddedServicesDictionary = useStore(({ adcm }) => adcm.clusterMapping.relatedData.notAddedServicesDictionary); - - const { hostsMapping, hostsMappingFilter, handleHostsMappingFilterChange, mappingValidation } = useClusterMapping( - localMapping, - hosts, - components, - notAddedServicesDictionary, - isLoaded, - ); - - const handleFilterChange = (event: React.ChangeEvent) => { - handleHostsMappingFilterChange({ componentDisplayName: event.target.value }); - }; +export interface HostsMappingProps { + hostsMapping: HostMapping[]; + mappingValidation: MappingValidation; + mappingFilter: MappingFilter; +} - const handleHideEmptyHostsChange = (event: React.ChangeEvent) => { - handleHostsMappingFilterChange({ isHideEmptyHosts: event.target.checked }); - }; +const HostsMapping = ({ hostsMapping, mappingValidation, mappingFilter }: HostsMappingProps) => { + const dispatch = useDispatch(); const cluster = useStore(({ adcm }) => adcm.cluster.cluster); useEffect(() => { @@ -45,30 +30,15 @@ const HostsMapping = () => { return (
      - - - ( + - -
      -
      - {hostsMapping.map((hostMapping) => ( - - ))} -
      -
      + ))}
      ); }; diff --git a/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts b/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts index 7fd8f00cfd..afd2114d1d 100644 --- a/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts +++ b/adcm-web/app/src/components/pages/cluster/ClusterMapping/useClusterMapping.ts @@ -1,5 +1,5 @@ -import { useCallback, useMemo, useState } from 'react'; -import { AdcmMappingComponent, AdcmHostShortView, AdcmMapping, AdcmServicePrototype } from '@models/adcm'; +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { AdcmMappingComponent, AdcmHostShortView, AdcmMapping } from '@models/adcm'; import { arrayToHash } from '@utils/arrayUtils'; import { getComponentsMapping, @@ -9,43 +9,48 @@ import { validate, } from './ClusterMapping.utils'; import { - HostMappingFilter, + MappingFilter, HostMapping, ComponentMapping, - ServiceMappingFilter, ServiceMapping, HostsDictionary, ComponentsDictionary, } from './ClusterMapping.types'; +import { NotAddedServicesDictionary } from '@store/adcm/cluster/mapping/mappingSlice'; export const useClusterMapping = ( mapping: AdcmMapping[], hosts: AdcmHostShortView[], components: AdcmMappingComponent[], - notAddedServicesDictionary: Record, + notAddedServicesDictionary: NotAddedServicesDictionary, isLoaded: boolean, - handleSetMapping?: (newMapping: AdcmMapping[]) => void, ) => { const hostsDictionary: HostsDictionary = useMemo(() => arrayToHash(hosts, (h) => h.id), [hosts]); const componentsDictionary: ComponentsDictionary = useMemo(() => arrayToHash(components, (c) => c.id), [components]); - const [hostsMappingFilter, setHostsMappingFilter] = useState({ + const [localMapping, setLocalMapping] = useState(mapping); + const [isMappingChanged, setIsMappingChanged] = useState(false); + + const [mappingFilter, setMappingFilter] = useState({ componentDisplayName: '', - isHideEmptyHosts: false, - }); - const [servicesMappingFilter, setServicesMappingFilter] = useState({ hostName: '', - isHideEmptyComponents: false, + isHideEmpty: false, }); + useEffect(() => { + if (isLoaded) { + setLocalMapping(mapping); + } + }, [isLoaded, mapping]); + const componentsMapping: ComponentMapping[] = useMemo( - () => (isLoaded ? getComponentsMapping(mapping, components, hostsDictionary) : []), - [components, hostsDictionary, isLoaded, mapping], + () => (isLoaded ? getComponentsMapping(localMapping, components, hostsDictionary) : []), + [components, hostsDictionary, isLoaded, localMapping], ); const hostsMapping: HostMapping[] = useMemo( - () => (isLoaded ? getHostsMapping(mapping, hosts, componentsDictionary) : []), - [isLoaded, mapping, hosts, componentsDictionary], + () => (isLoaded ? getHostsMapping(localMapping, hosts, componentsDictionary) : []), + [hosts, componentsDictionary, isLoaded, localMapping], ); const servicesMapping: ServiceMapping[] = useMemo( @@ -69,45 +74,45 @@ export const useClusterMapping = ( const handleMap = useCallback( (hosts: AdcmHostShortView[], component: AdcmMappingComponent) => { const newLocalMapping = mapHostsToComponent(servicesMapping, hosts, component); - handleSetMapping?.(newLocalMapping); + setLocalMapping(newLocalMapping); + setIsMappingChanged(true); }, - [servicesMapping, handleSetMapping], + [servicesMapping], ); const handleUnmap = useCallback( (hostId: number, componentId: number) => { - const newMapping = mapping.filter((m) => !(m.hostId === hostId && m.componentId === componentId)); - handleSetMapping?.(newMapping); + const newMapping = localMapping.filter((m) => !(m.hostId === hostId && m.componentId === componentId)); + setLocalMapping(newMapping); + setIsMappingChanged(true); }, - [mapping, handleSetMapping], + [localMapping], ); - const handleServicesMappingFilterChange = (changes: Partial) => { - setServicesMappingFilter({ - ...servicesMappingFilter, + const handleMappingFilterChange = (changes: Partial) => { + setMappingFilter({ + ...mappingFilter, ...changes, }); }; - const handleHostsMappingFilterChange = (changes: Partial) => { - setHostsMappingFilter({ - ...hostsMappingFilter, - ...changes, - }); + const handleReset = () => { + setLocalMapping(mapping); + setIsMappingChanged(false); }; return { - hostComponentMapping: mapping, hosts, hostsMapping, - hostsMappingFilter, - handleHostsMappingFilterChange, + localMapping, + isMappingChanged, + mappingFilter, + handleMappingFilterChange, components, servicesMapping, - servicesMappingFilter, - handleServicesMappingFilterChange, mappingValidation, handleMap, handleUnmap, + handleReset, }; }; diff --git a/adcm-web/app/src/components/uikit/Switch/Switch.module.scss b/adcm-web/app/src/components/uikit/Switch/Switch.module.scss index b06fd05da8..d7a4c29ce9 100644 --- a/adcm-web/app/src/components/uikit/Switch/Switch.module.scss +++ b/adcm-web/app/src/components/uikit/Switch/Switch.module.scss @@ -48,6 +48,7 @@ --switch-button-width: 16px; --switch-button-height: 16px; --switch-button-padding: 2px; + --switch-gap: 16px; } .switch_small { @@ -56,6 +57,7 @@ --switch-button-width: 10px; --switch-button-height: 10px; --switch-button-padding: 1px; + --switch-gap: 8px; } .switch_green { @@ -71,7 +73,7 @@ .switch { display: inline-flex; align-items: center; - gap: 16px; + gap: var(--switch-gap); font-weight: 500; } diff --git a/adcm-web/app/src/models/adcm/clusterMapping.ts b/adcm-web/app/src/models/adcm/clusterMapping.ts index ced5bc72ae..566a692ca7 100644 --- a/adcm-web/app/src/models/adcm/clusterMapping.ts +++ b/adcm-web/app/src/models/adcm/clusterMapping.ts @@ -7,6 +7,8 @@ export interface AdcmMapping { componentId: number; } +export type HostId = AdcmHostShortView['id']; + export interface AdcmHostShortView { id: number; name: string; @@ -29,6 +31,8 @@ export interface AdcmComponentDependency { export type AdcmComponentConstraint = number | string; +export type ServiceId = AdcmMappingComponentService['id']; + export interface AdcmMappingComponentService { id: number; name: string; @@ -37,6 +41,8 @@ export interface AdcmMappingComponentService { prototype: AdcmPrototypeShortView; } +export type ComponentId = AdcmMappingComponent['id']; + export interface AdcmMappingComponent { id: number; name: string; diff --git a/adcm-web/app/src/models/adcm/service.ts b/adcm-web/app/src/models/adcm/service.ts index 23929ccca2..9e22d2936f 100644 --- a/adcm-web/app/src/models/adcm/service.ts +++ b/adcm-web/app/src/models/adcm/service.ts @@ -37,6 +37,8 @@ export interface AdcmService { }; } +export type ServicePrototypeId = AdcmServicePrototype['id']; + export interface AdcmServicePrototype { id: number; name: string; diff --git a/adcm-web/app/src/models/loadState.ts b/adcm-web/app/src/models/loadState.ts index e524b19211..9955297053 100644 --- a/adcm-web/app/src/models/loadState.ts +++ b/adcm-web/app/src/models/loadState.ts @@ -3,3 +3,5 @@ export enum LoadState { Loading = 'loading', Loaded = 'loaded', } + +export type ActionState = 'not-started' | 'in-progress' | 'completed'; diff --git a/adcm-web/app/src/routes/routes.ts b/adcm-web/app/src/routes/routes.ts index b05bcaab09..0a9e5503ab 100644 --- a/adcm-web/app/src/routes/routes.ts +++ b/adcm-web/app/src/routes/routes.ts @@ -255,23 +255,7 @@ const routes: RoutesConfigs = { }, ], }, - '/clusters/:clusterId/mapping/hosts': { - pageTitle: 'Clusters', - breadcrumbs: [ - { - href: '/clusters', - label: 'Clusters', - }, - { - href: '/clusters/:clusterId', - label: ':clusterId', - }, - { - label: 'Mapping', - }, - ], - }, - '/clusters/:clusterId/mapping/components': { + '/clusters/:clusterId/mapping': { pageTitle: 'Clusters', breadcrumbs: [ { diff --git a/adcm-web/app/src/store/adcm/cluster/mapping/mappingSlice.ts b/adcm-web/app/src/store/adcm/cluster/mapping/mappingSlice.ts index ffd50345a9..b596370225 100644 --- a/adcm-web/app/src/store/adcm/cluster/mapping/mappingSlice.ts +++ b/adcm-web/app/src/store/adcm/cluster/mapping/mappingSlice.ts @@ -1,13 +1,20 @@ -import { PayloadAction, createSlice } from '@reduxjs/toolkit'; +import { createSlice } from '@reduxjs/toolkit'; import { RequestError, AdcmClusterMappingApi } from '@api'; import { createAsyncThunk } from '@store/redux'; import { showError, showInfo } from '@store/notificationsSlice'; -import { AdcmMappingComponent, AdcmHostShortView, AdcmMapping, AdcmError, AdcmServicePrototype } from '@models/adcm'; -import { ServiceId } from '@pages/cluster/ClusterMapping/ClusterMapping.types'; +import { + AdcmMappingComponent, + AdcmHostShortView, + AdcmMapping, + AdcmError, + AdcmServicePrototype, + ServiceId, +} from '@models/adcm'; import { AdcmClusterServicesApi } from '@api/adcm/clusterServices'; import { arrayToHash } from '@utils/arrayUtils'; +import { ActionState } from '@models/loadState'; -type MappingState = 'no-changes' | 'editing' | 'saving'; +export type NotAddedServicesDictionary = Record; type GetClusterMappingArg = { clusterId: number; @@ -20,15 +27,17 @@ type SaveClusterMappingArg = { type AdcmClusterMappingsState = { mapping: AdcmMapping[]; - state: MappingState; - localMapping: AdcmMapping[]; hosts: AdcmHostShortView[]; components: AdcmMappingComponent[]; - isLoading: boolean; - isLoaded: boolean; - hasSaveError: boolean; + loading: { + state: ActionState; + }; + saving: { + state: ActionState; + hasError: boolean; + }; relatedData: { - notAddedServicesDictionary: Record; + notAddedServicesDictionary: NotAddedServicesDictionary; }; requiredServicesDialog: { component: AdcmMappingComponent | null; @@ -109,13 +118,15 @@ const getNotAddedServices = createAsyncThunk( const createInitialState = (): AdcmClusterMappingsState => ({ mapping: [], - state: 'no-changes', - localMapping: [], hosts: [], components: [], - isLoading: false, - isLoaded: false, - hasSaveError: false, + loading: { + state: 'not-started', + }, + saving: { + state: 'not-started', + hasError: false, + }, relatedData: { notAddedServicesDictionary: {}, }, @@ -128,14 +139,6 @@ const mappingSlice = createSlice({ name: 'adcm/cluster/mapping', initialState: createInitialState(), reducers: { - setLocalMapping(state, action: PayloadAction) { - state.localMapping = action.payload; - state.state = 'editing'; - }, - revertChanges(state) { - state.localMapping = state.mapping; - state.state = 'no-changes'; - }, cleanupMappings() { return createInitialState(); }, @@ -148,19 +151,16 @@ const mappingSlice = createSlice({ }, extraReducers: (builder) => { builder.addCase(getMappings.pending, (state) => { - state.isLoading = true; + state.loading.state = 'in-progress'; }); builder.addCase(getMappings.fulfilled, (state) => { - state.isLoading = false; - state.isLoaded = true; + state.loading.state = 'completed'; }); builder.addCase(getMappings.rejected, (state) => { - state.isLoading = false; - state.isLoaded = true; + state.loading.state = 'completed'; }); builder.addCase(loadMapping.fulfilled, (state, action) => { state.mapping = action.payload; - state.localMapping = action.payload; }); builder.addCase(loadMappingHosts.fulfilled, (state, action) => { state.hosts = action.payload; @@ -169,16 +169,14 @@ const mappingSlice = createSlice({ state.components = action.payload; }); builder.addCase(saveMapping.pending, (state) => { - state.state = 'saving'; + state.saving.state = 'in-progress'; }); builder.addCase(saveMapping.fulfilled, (state) => { - state.hasSaveError = false; - state.state = 'no-changes'; - state.mapping = state.localMapping; + state.saving.state = 'completed'; }); builder.addCase(saveMapping.rejected, (state) => { - state.hasSaveError = true; - state.state = 'editing'; + state.saving.state = 'completed'; + state.saving.hasError = true; }); builder.addCase(getNotAddedServices.fulfilled, (state, action) => { state.relatedData.notAddedServicesDictionary = arrayToHash(action.payload, (s) => s.id); @@ -189,13 +187,10 @@ const mappingSlice = createSlice({ }, }); -const { setLocalMapping, revertChanges, cleanupMappings, openRequiredServicesDialog, closeRequiredServicesDialog } = - mappingSlice.actions; +const { cleanupMappings, openRequiredServicesDialog, closeRequiredServicesDialog } = mappingSlice.actions; export { getMappings, saveMapping, - setLocalMapping, - revertChanges, cleanupMappings, getNotAddedServices, openRequiredServicesDialog, diff --git a/adcm-web/app/src/store/adcm/clusters/clustersDynamicActionsSlice.ts b/adcm-web/app/src/store/adcm/clusters/clustersDynamicActionsSlice.ts index 5b03a3b933..6c814f270d 100644 --- a/adcm-web/app/src/store/adcm/clusters/clustersDynamicActionsSlice.ts +++ b/adcm-web/app/src/store/adcm/clusters/clustersDynamicActionsSlice.ts @@ -1,5 +1,5 @@ -import { PayloadAction, createSlice } from '@reduxjs/toolkit'; -import { AdcmCluster, AdcmHostShortView, AdcmMapping, AdcmMappingComponent, AdcmServicePrototype } from '@models/adcm'; +import { createSlice } from '@reduxjs/toolkit'; +import { AdcmCluster, AdcmHostShortView, AdcmMapping, AdcmMappingComponent } from '@models/adcm'; import { createAsyncThunk } from '@store/redux'; import { AdcmClusterMappingApi, AdcmClustersApi, RequestError } from '@api'; import { fulfilledFilter } from '@utils/promiseUtils'; @@ -10,6 +10,7 @@ import { ActionStatuses } from '@constants'; import { LoadState } from '@models/loadState'; import { AdcmClusterServicesApi } from '@api/adcm/clusterServices'; import { arrayToHash } from '@utils/arrayUtils'; +import { NotAddedServicesDictionary } from '../cluster/mapping/mappingSlice'; type GetClusterMappingArg = { clusterId: number; @@ -117,10 +118,9 @@ type AdcmClustersDynamicActionsState = { actionDetails: AdcmDynamicActionDetails | null; cluster: AdcmCluster | null; mapping: AdcmMapping[]; - localMapping: AdcmMapping[]; hosts: AdcmHostShortView[]; components: AdcmMappingComponent[]; - notAddedServicesDictionary: Record; + notAddedServicesDictionary: NotAddedServicesDictionary; loadState: LoadState; }; clusterDynamicActions: Record; @@ -131,7 +131,6 @@ const createInitialState = (): AdcmClustersDynamicActionsState => ({ actionDetails: null, cluster: null, mapping: [], - localMapping: [], hosts: [], components: [], notAddedServicesDictionary: {}, @@ -144,12 +143,6 @@ const clustersDynamicActionsSlice = createSlice({ name: 'adcm/clustersDynamicActions', initialState: createInitialState(), reducers: { - setLocalMapping(state, action: PayloadAction) { - state.dialog.localMapping = action.payload; - }, - revertChanges(state) { - state.dialog.localMapping = state.dialog.mapping; - }, cleanupClusterDynamicActions() { return createInitialState(); }, @@ -161,7 +154,6 @@ const clustersDynamicActionsSlice = createSlice({ }, extraReducers: (builder) => { builder.addCase(loadMappings.fulfilled, (state, action) => { - state.dialog.localMapping = action.payload.mapping; state.dialog.mapping = action.payload.mapping; state.dialog.hosts = action.payload.hosts; state.dialog.components = action.payload.components; @@ -192,8 +184,7 @@ const clustersDynamicActionsSlice = createSlice({ }, }); -export const { setLocalMapping, revertChanges, cleanupClusterDynamicActions, closeClusterDynamicActionDialog } = - clustersDynamicActionsSlice.actions; +export const { cleanupClusterDynamicActions, closeClusterDynamicActionDialog } = clustersDynamicActionsSlice.actions; export { loadClustersDynamicActions, openClusterDynamicActionDialog, getMappings, runClusterDynamicAction }; export default clustersDynamicActionsSlice.reducer; From 1047b66e61018fb64246b2d3195c296b41bff8fe Mon Sep 17 00:00:00 2001 From: Igor Kuzmin Date: Mon, 29 Jan 2024 08:52:47 +0000 Subject: [PATCH 062/151] feature/ADCM-5231 + loaded data validator for usePersistSettings hook task: https://tracker.yandex.ru/ADCM-5231 --- adcm-web/app/src/hooks/usePersistSettings.ts | 41 ++++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/adcm-web/app/src/hooks/usePersistSettings.ts b/adcm-web/app/src/hooks/usePersistSettings.ts index f207a81409..78a4423e3c 100644 --- a/adcm-web/app/src/hooks/usePersistSettings.ts +++ b/adcm-web/app/src/hooks/usePersistSettings.ts @@ -8,10 +8,37 @@ type UsePersistSettingsProps = { settings: T; isReadyToLoad: boolean; onSettingsLoaded: (settings: T) => void; + loadedDataValidator?: (loadedData: T, data: T) => boolean; }; const getTableSettingKey = (userName: string, tableKey: string) => `${userName}_${tableKey}`; +const defaultLoadedDataValidator = (loadedData: unknown, data: unknown) => { + const dataType = typeof data; + const loadedDataType = typeof loadedData; + if (dataType !== loadedDataType) { + return false; + } + + // check 1st level keys similarity + if (loadedData && loadedDataType === 'object' && data && dataType === 'object') { + const loadedDataKeys = new Set(Object.keys(loadedData)); + const dataKeys = Object.keys(data); + + if (loadedDataKeys.size === dataKeys.length) { + for (const key of dataKeys) { + if (!loadedDataKeys.has(key)) { + return false; + } + } + + return true; + } + } + + return false; +}; + const mergePaginationParams = (perPage: number | undefined, paginationParams: PaginationParams): PaginationParams => { return perPage === undefined ? paginationParams @@ -32,12 +59,18 @@ export const usePersistSettings = (props: UsePersistSettingsProps, deps: u }); useEffect(() => { - if (props.isReadyToLoad && dataFromLocalStorage && !isLoaded) { - props.onSettingsLoaded(dataFromLocalStorage); - setIsLoaded(true); + if (props.isReadyToLoad && !isLoaded) { + const loadedDataValidator = props.loadedDataValidator ?? defaultLoadedDataValidator; + const isValid = loadedDataValidator(dataFromLocalStorage as T, props.settings); + const validData = isValid ? dataFromLocalStorage : props.settings; + + if (validData) { + props.onSettingsLoaded(validData); + setIsLoaded(true); + } } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.isReadyToLoad, dataFromLocalStorage, isLoaded]); + }, [props.isReadyToLoad, props.loadedDataValidator, dataFromLocalStorage, isLoaded]); useEffect(() => { if (isLoaded) { From 96586daa0729173775126298cdcb9b3ee47e347b Mon Sep 17 00:00:00 2001 From: Daniil Skrynnik Date: Tue, 30 Jan 2024 07:36:28 +0000 Subject: [PATCH 063/151] ADCM-5223: Rework generate config.json file --- python/cm/job.py | 238 ++---------------- python/cm/services/job/__init__.py | 12 + python/cm/services/job/config.py | 194 ++++++++++++++ python/cm/services/job/types.py | 124 +++++++++ python/cm/services/job/utils.py | 124 +++++++++ python/cm/services/types.py | 17 ++ .../action_configs/cluster.json.j2 | 4 +- .../action_configs/cluster_on_host.json.j2 | 4 +- .../action_configs/component.json.j2 | 4 +- .../action_configs/component_on_host.json.j2 | 4 +- .../action_configs/host.json.j2 | 4 +- .../action_configs/hostprovider.json.j2 | 4 +- .../action_configs/service.json.j2 | 4 +- .../action_configs/service_on_host.json.j2 | 4 +- .../test_inventory/test_action_config.py | 45 ++-- .../cm/tests/test_inventory/test_inventory.py | 4 +- python/cm/tests/test_job.py | 155 ++++++------ python/core/types.py | 2 + python/task_runner.py | 3 +- 19 files changed, 626 insertions(+), 324 deletions(-) create mode 100644 python/cm/services/job/__init__.py create mode 100644 python/cm/services/job/config.py create mode 100644 python/cm/services/job/types.py create mode 100644 python/cm/services/job/utils.py create mode 100644 python/cm/services/types.py diff --git a/python/cm/job.py b/python/cm/job.py index 26b677529f..5591a27662 100644 --- a/python/cm/job.py +++ b/python/cm/job.py @@ -15,7 +15,7 @@ from dataclasses import dataclass, field from functools import partial from pathlib import Path -from typing import Any, Literal +from typing import Any import copy import json import subprocess @@ -29,7 +29,6 @@ AuditLogOperationType, ) from django.conf import settings -from django.db.models import JSONField from django.db.transaction import atomic, on_commit from django.utils import timezone from rbac.roles import re_apply_policy_for_jobs @@ -51,12 +50,7 @@ ) from cm.errors import AdcmEx, raise_adcm_ex from cm.hierarchy import Tree -from cm.inventory import ( - HcAclAction, - get_obj_config, - prepare_job_inventory, - process_config_and_attr, -) +from cm.inventory import HcAclAction, prepare_job_inventory, process_config_and_attr from cm.issue import ( check_bound_components, check_component_constraint, @@ -83,7 +77,6 @@ JobStatus, LogStorage, MaintenanceMode, - ObjectType, Prototype, ServiceComponent, SubAction, @@ -91,6 +84,8 @@ Upgrade, get_object_cluster, ) +from cm.services.job.config import get_job_config +from cm.services.job.utils import JobScope, get_selector from cm.services.status.notify import reset_objects_in_mm from cm.status_api import ( send_object_update_event, @@ -436,30 +431,6 @@ def check_cluster(cluster_id: int) -> Cluster: return Cluster.obj.get(id=cluster_id) -def get_bundle_root(action: Action) -> str: - if action.prototype.type == "adcm": - return str(Path(settings.BASE_DIR, "conf")) - - return str(settings.BUNDLE_DIR) - - -def cook_script(action: Action, sub_action: SubAction | None): - prefix = action.prototype.bundle.hash - script = action.script - - if sub_action: - script = sub_action.script - - if script[0:2] == "./": - script = Path(action.prototype.path, script[2:]) - - return str(Path(get_bundle_root(action), prefix, script)) - - -def get_adcm_config(): - return get_obj_config(ADCM.obj.get()) - - def get_actual_hc(cluster: Cluster): new_hc = [] for hostcomponent in HostComponent.objects.filter(cluster=cluster): @@ -482,188 +453,30 @@ def get_old_hc(saved_hostcomponent: list[dict]): return old_hostcomponent -def re_prepare_job(task: TaskLog, job: JobLog): - conf = None - hosts = None - delta = {} - if task.config: - conf = task.config - - if task.hosts: - hosts = task.hosts - - action = task.action - obj = task.task_object - cluster = get_object_cluster(obj) - sub_action = None - if job.sub_action_id: - sub_action = job.sub_action - - if action.hostcomponentmap: - new_hc = get_actual_hc(cluster) - old_hc = get_old_hc(task.hostcomponentmap) - delta = cook_delta(cluster, new_hc, action.hostcomponentmap, old_hc) - - prepare_job(action, sub_action, job.pk, obj, conf, delta, hosts, task.verbose) - - -def prepare_job( - action: Action, - sub_action: SubAction, - job_id: int, - obj: ADCM | Cluster | ClusterObject | ServiceComponent | HostProvider | Host, - conf: JSONField | None, - delta: dict, - hosts: JSONField | None, - verbose: bool, -): - write_job_config(job_id=job_id, config=prepare_job_config(action, sub_action, job_id, obj, conf, verbose)) - prepare_job_inventory(obj, job_id, action, delta, hosts) - prepare_ansible_config(job_id, action, sub_action) - - -def get_selector( - obj: ADCM | Cluster | ClusterObject | ServiceComponent | HostProvider | Host, action: Action -) -> dict[str | ObjectType, dict[Literal["id", "name"], int | str]]: - selector = {obj.prototype.type: {"id": obj.pk, "name": obj.display_name}} - - if obj.prototype.type == ObjectType.SERVICE: - selector[ObjectType.CLUSTER] = {"id": obj.cluster.pk, "name": obj.cluster.display_name} - elif obj.prototype.type == ObjectType.COMPONENT: - selector[ObjectType.SERVICE] = {"id": obj.service.pk, "name": obj.service.display_name} - selector[ObjectType.CLUSTER] = {"id": obj.cluster.pk, "name": obj.cluster.display_name} - elif obj.prototype.type == ObjectType.HOST: - if action.host_action: - cluster = obj.cluster - selector[ObjectType.CLUSTER] = {"id": cluster.pk, "name": cluster.display_name} - if action.prototype.type == ObjectType.SERVICE: - service = ClusterObject.objects.get(prototype=action.prototype, cluster=cluster) - selector[ObjectType.SERVICE] = {"id": service.pk, "name": service.display_name} - elif action.prototype.type == ObjectType.COMPONENT: - service = ClusterObject.objects.get(prototype=action.prototype.parent, cluster=cluster) - selector[ObjectType.SERVICE] = {"id": service.pk, "name": service.display_name} - component = ServiceComponent.objects.get(prototype=action.prototype, cluster=cluster, service=service) - selector[ObjectType.COMPONENT] = { - "id": component.pk, - "name": component.display_name, - } - else: - selector[ObjectType.PROVIDER] = { - "id": obj.provider.pk, - "name": obj.provider.display_name, - } - - return selector +def re_prepare_job(job_scope: JobScope) -> None: + cluster = get_object_cluster(obj=job_scope.object) + delta = {} + if job_scope.action.hostcomponentmap: + delta = cook_delta( + cluster=cluster, + new_hc=get_actual_hc(cluster=cluster), + action_hc=job_scope.action.hostcomponentmap, + old=get_old_hc(saved_hostcomponent=job_scope.task.hostcomponentmap), + ) -def prepare_context( - action: Action, - obj: ADCM | Cluster | ClusterObject | ServiceComponent | HostProvider | Host, -) -> dict: - selector = get_selector(obj, action) - context = {f"{k}_id": v["id"] for k, v in selector.items()} - context["type"] = obj.prototype.type - - if obj.prototype.type == ObjectType.HOST and action.host_action: - context["type"] = action.prototype.type - - return context - - -def prepare_job_config( - action: Action, - sub_action: SubAction | None, - job_id: int, - obj: ADCM | Cluster | ClusterObject | ServiceComponent | HostProvider | Host, - conf: dict | JSONField | None, - verbose: bool, -) -> dict: - job_conf = { - "adcm": {"config": get_adcm_config()}, - "context": prepare_context(action, obj), - "env": { - "run_dir": str(settings.RUN_DIR), - "log_dir": str(settings.LOG_DIR), - "tmp_dir": str(settings.RUN_DIR / f"{job_id}" / "tmp"), - "stack_dir": str(Path(get_bundle_root(action), action.prototype.bundle.hash)), - "status_api_token": str(settings.STATUS_SECRET_KEY), - }, - "job": { - "id": job_id, - "action": action.name, - "job_name": action.name, - "command": action.name, - "script": action.script, - "verbose": verbose, - "playbook": cook_script(action, sub_action), - }, - } - - if action.params: - job_conf["job"]["params"] = action.params - - if sub_action: - job_conf["job"]["script"] = sub_action.script - job_conf["job"]["job_name"] = sub_action.name - job_conf["job"]["command"] = sub_action.name - if sub_action.params: - job_conf["job"]["params"] = sub_action.params - - cluster = get_object_cluster(obj) - if cluster: - job_conf["job"]["cluster_id"] = cluster.pk - - if action.prototype.type == "service": - if action.host_action: - service = ClusterObject.obj.get(prototype=action.prototype, cluster=cluster) - job_conf["job"]["hostgroup"] = service.name - job_conf["job"]["service_id"] = service.pk - job_conf["job"]["service_type_id"] = service.prototype.pk - else: - job_conf["job"]["hostgroup"] = obj.prototype.name - job_conf["job"]["service_id"] = obj.pk - job_conf["job"]["service_type_id"] = obj.prototype.pk - elif action.prototype.type == "component": - if action.host_action: - service = ClusterObject.obj.get(prototype=action.prototype.parent, cluster=cluster) - comp = ServiceComponent.obj.get(prototype=action.prototype, cluster=cluster, service=service) - job_conf["job"]["hostgroup"] = f"{service.name}.{comp.name}" - job_conf["job"]["service_id"] = service.pk - job_conf["job"]["component_id"] = comp.pk - job_conf["job"]["component_type_id"] = comp.prototype.pk - else: - job_conf["job"]["hostgroup"] = f"{obj.service.prototype.name}.{obj.prototype.name}" - job_conf["job"]["service_id"] = obj.service.pk - job_conf["job"]["component_id"] = obj.pk - job_conf["job"]["component_type_id"] = obj.prototype.pk - elif action.prototype.type == "cluster": - job_conf["job"]["hostgroup"] = "CLUSTER" - elif action.prototype.type == "host": - job_conf["job"]["hostgroup"] = "HOST" - job_conf["job"]["hostname"] = obj.fqdn - job_conf["job"]["host_id"] = obj.pk - job_conf["job"]["host_type_id"] = obj.prototype.pk - job_conf["job"]["provider_id"] = obj.provider.pk - elif action.prototype.type == "provider": - job_conf["job"]["hostgroup"] = "PROVIDER" - job_conf["job"]["provider_id"] = obj.pk - elif action.prototype.type == "adcm": - job_conf["job"]["hostgroup"] = "127.0.0.1" - else: - raise AdcmEx("NOT_IMPLEMENTED", f'unknown prototype type "{action.prototype.type}"') - - if conf: - job_conf["job"]["config"] = conf + prepare_job(job_scope=job_scope, delta=delta) - return job_conf +def prepare_job(job_scope: JobScope, delta: dict): + config_path = Path(settings.RUN_DIR, str(job_scope.job_id), "config.json") + with config_path.open(mode="w", encoding=settings.ENCODING_UTF_8) as config_file: + json.dump(obj=get_job_config(job_scope=job_scope), fp=config_file, sort_keys=True, separators=(",", ":")) -def write_job_config(job_id: int, config: dict) -> None: - with (settings.RUN_DIR / f"{job_id}" / "config.json").open( - mode="w", - encoding=settings.ENCODING_UTF_8, - ) as file_descriptor: - json.dump(config, file_descriptor, sort_keys=True, separators=(",", ":")) + prepare_job_inventory( + obj=job_scope.object, job_id=job_scope.job_id, action=job_scope.action, delta=delta, action_host=job_scope.hosts + ) + prepare_ansible_config(job_id=job_scope.job_id, action=job_scope.action, sub_action=job_scope.sub_action) def create_task( @@ -676,6 +489,7 @@ def create_task( verbose: bool, post_upgrade_hc: list[dict], ) -> TaskLog: + selector = get_selector(obj=obj, action=action) task = TaskLog.objects.create( action=action, task_object=obj, @@ -686,7 +500,7 @@ def create_task( post_upgrade_hc_map=post_upgrade_hc, verbose=verbose, status=JobStatus.CREATED, - selector=get_selector(obj, action), + selector=selector, ) if action.type == ActionType.JOB.value: @@ -701,7 +515,7 @@ def create_task( sub_action=sub_action, log_files=action.log_files, status=JobStatus.CREATED, - selector=get_selector(obj, action), + selector=selector, ) log_type = sub_action.script_type if sub_action else action.script_type LogStorage.objects.create(job=job, name=log_type, type="stdout", format="txt") diff --git a/python/cm/services/job/__init__.py b/python/cm/services/job/__init__.py new file mode 100644 index 0000000000..f3e59d81d8 --- /dev/null +++ b/python/cm/services/job/__init__.py @@ -0,0 +1,12 @@ +# Licensed 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. + diff --git a/python/cm/services/job/config.py b/python/cm/services/job/config.py new file mode 100644 index 0000000000..65ee6a9ef1 --- /dev/null +++ b/python/cm/services/job/config.py @@ -0,0 +1,194 @@ +# Licensed 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. + +from pathlib import Path +from typing import Any + +from django.conf import settings + +from cm.inventory import get_obj_config +from cm.models import ( + ADCM, + Action, + Cluster, + ClusterObject, + Host, + HostProvider, + ObjectType, + ServiceComponent, + get_object_cluster, +) +from cm.services.job.types import ( + ADCMActionType, + ClusterActionType, + ComponentActionType, + HostActionType, + HostProviderActionType, + JobConfig, + JobData, + JobEnv, + Selector, + ServiceActionType, +) +from cm.services.job.utils import JobScope, get_bundle_root, get_script_path, get_selector + +IMPLEMENTED_ACTION_PROTO_TYPES = ( + ObjectType.ADCM, + ObjectType.CLUSTER, + ObjectType.SERVICE, + ObjectType.COMPONENT, + ObjectType.PROVIDER, + ObjectType.HOST, +) +ADCM_HOSTGROUP = "127.0.0.1" + + +def get_job_config(job_scope: JobScope) -> dict[str, Any]: + if (action_proto_type := job_scope.action.prototype.type) not in IMPLEMENTED_ACTION_PROTO_TYPES: + raise NotImplementedError(f'Job Config can\'t be generated for action of "{action_proto_type}" object') + + return JobConfig( + adcm={"config": get_obj_config(obj=ADCM.objects.get())}, + context=get_context( + action=job_scope.action, + object_type=job_scope.object.prototype.type, + selector=get_selector(obj=job_scope.object, action=job_scope.action), + ), + env=JobEnv( + run_dir=str(settings.RUN_DIR), + log_dir=str(settings.LOG_DIR), + tmp_dir=str(Path(settings.RUN_DIR, f"{job_scope.job_id}", "tmp")), + stack_dir=str(Path(get_bundle_root(action=job_scope.action), job_scope.action.prototype.bundle.hash)), + status_api_token=str(settings.STATUS_SECRET_KEY), + ), + job=_get_job_data(job_scope=job_scope), + ).dict(exclude_unset=True) + + +def get_context(action: Action, object_type: str, selector: Selector) -> dict[str, int | str]: + context = {f"{k}_id": v["id"] for k, v in selector.items()} + context["type"] = object_type + + if object_type == ObjectType.HOST and action.host_action: + context["type"] = action.prototype.type + + return context + + +def _get_job_data(job_scope: JobScope) -> JobData: + cluster = get_object_cluster(obj=job_scope.object) + + job_data = JobData( + id=job_scope.job_id, + action=job_scope.action.name, + job_name=job_scope.action.name, + command=job_scope.action.name, + script=job_scope.action.script, + verbose=job_scope.task.verbose, + playbook=get_script_path(action=job_scope.action, sub_action=job_scope.sub_action), + action_type_specification=_get_action_type_specific_data( + cluster=cluster, obj=job_scope.object, action=job_scope.action + ), + ) + + if job_scope.action.params: + job_data.params = job_scope.action.params + + if job_scope.sub_action: + job_data.script = job_scope.sub_action.script + job_data.job_name = job_scope.sub_action.name + job_data.command = job_scope.sub_action.name + if job_scope.sub_action.params: + job_data.params = job_scope.sub_action.params + + if cluster is not None: + job_data.cluster_id = cluster.pk + + if job_scope.config: + job_data.config = job_scope.config + + return job_data + + +def _get_action_type_specific_data( + cluster: Cluster, obj: ClusterObject | ServiceComponent | HostProvider | Host, action: Action +) -> ( + ClusterActionType + | ServiceActionType + | ComponentActionType + | HostProviderActionType + | HostActionType + | ADCMActionType +): + match action.prototype.type: + case ObjectType.SERVICE: + if action.host_action: + service = ClusterObject.objects.get(prototype=action.prototype, cluster=cluster) + + return ServiceActionType( + action_proto_type="service", + hostgroup=service.name, + service_id=service.pk, + service_type_id=service.prototype_id, + ) + + return ServiceActionType( + action_proto_type="service", + hostgroup=obj.prototype.name, + service_id=obj.pk, + service_type_id=obj.prototype_id, + ) + + case ObjectType.COMPONENT: + if action.host_action: + service = ClusterObject.objects.get(prototype=action.prototype.parent, cluster=cluster) + comp = ServiceComponent.objects.get(prototype=action.prototype, cluster=cluster, service=service) + + return ComponentActionType( + action_proto_type="component", + hostgroup=f"{service.name}.{comp.name}", + service_id=service.pk, + component_id=comp.pk, + component_type_id=comp.prototype_id, + ) + + return ComponentActionType( + action_proto_type="component", + hostgroup=f"{obj.service.prototype.name}.{obj.prototype.name}", + service_id=obj.service_id, + component_id=obj.pk, + component_type_id=obj.prototype_id, + ) + + case ObjectType.CLUSTER: + return ClusterActionType(action_proto_type="cluster", hostgroup=ObjectType.CLUSTER.name) + + case ObjectType.HOST: + obj: Host + return HostActionType( + action_proto_type="host", + hostgroup=ObjectType.HOST.name, + hostname=obj.fqdn, + host_id=obj.pk, + host_type_id=obj.prototype_id, + provider_id=obj.provider_id, + ) + + case ObjectType.PROVIDER: + return HostProviderActionType( + action_proto_type="provider", + hostgroup=ObjectType.PROVIDER.name, + provider_id=obj.pk, + ) + + case ObjectType.ADCM: + return ADCMActionType(action_proto_type="adcm", hostgroup=ADCM_HOSTGROUP) diff --git a/python/cm/services/job/types.py b/python/cm/services/job/types.py new file mode 100644 index 0000000000..cd2ce648ca --- /dev/null +++ b/python/cm/services/job/types.py @@ -0,0 +1,124 @@ +# Licensed 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. + +from typing import Any, Literal, Optional, TypeAlias, Union + +from core.types import ClusterID, ComponentID, HostID, HostProviderID, ObjectID, PrototypeID, ServiceID +from pydantic import BaseModel, Field, Json + +Selector: TypeAlias = dict[str, dict[Literal["id", "name"], int | str]] + + +class ObjectWithHostGroup(BaseModel): + hostgroup: str + + +class ServiceActionType(ObjectWithHostGroup): + action_proto_type: Literal["service"] + service_id: ServiceID + service_type_id: PrototypeID + + +class ComponentActionType(ObjectWithHostGroup): + action_proto_type: Literal["component"] + service_id: ServiceID + component_id: ComponentID + component_type_id: PrototypeID + + +class ClusterActionType(ObjectWithHostGroup): + action_proto_type: Literal["cluster"] + + +class HostActionType(ObjectWithHostGroup): + action_proto_type: Literal["host"] + hostname: str + host_id: HostID + host_type_id: PrototypeID + provider_id: HostProviderID + + +class HostProviderActionType(ObjectWithHostGroup): + action_proto_type: Literal["provider"] + provider_id: HostProviderID + + +class ADCMActionType(ObjectWithHostGroup): + action_proto_type: Literal["adcm"] + + +class JobEnv(BaseModel): + run_dir: str + log_dir: str + tmp_dir: str + stack_dir: str + status_api_token: str + + +class JobData(BaseModel): + id: ObjectID + action: str + job_name: str + command: str + script: str + verbose: bool + playbook: str + config: Optional[Json] + params: Optional[Json] + cluster_id: Optional[ClusterID] + action_type_specification: ( + ClusterActionType + | ServiceActionType + | ComponentActionType + | HostProviderActionType + | HostActionType + | ADCMActionType + ) = Field(..., discriminator="action_proto_type") + + def dict( + self, + *, + include: Optional[Union["AbstractSetIntStr", "MappingIntStrAny"]] = None, # noqa: F821 + exclude: Optional[Union["AbstractSetIntStr", "MappingIntStrAny"]] = None, # noqa: F821 + by_alias: bool = False, + skip_defaults: Optional[bool] = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + ) -> dict[str, Any]: + result: dict[str, Any] = super().dict( + include=include, + exclude=exclude, + by_alias=by_alias, + skip_defaults=skip_defaults, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + for key, value in result.pop("action_type_specification").items(): + # Merge `action_type_specification` fields into root dict, + # exclude discriminator field. + # See https://docs.pydantic.dev/1.10/usage/types/#discriminated-unions-aka-tagged-unions + if key == "action_proto_type": + continue + + result[key] = value + + return result + + +class JobConfig(BaseModel): + adcm: dict[Literal["config"], dict[str, Any]] + context: dict[str, Any] + env: JobEnv + job: JobData diff --git a/python/cm/services/job/utils.py b/python/cm/services/job/utils.py new file mode 100644 index 0000000000..71b46db3d7 --- /dev/null +++ b/python/cm/services/job/utils.py @@ -0,0 +1,124 @@ +# Licensed 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. + +from dataclasses import dataclass +from pathlib import Path + +from core.types import ObjectID +from django.conf import settings +from django.utils.functional import cached_property +from pydantic import Json + +from cm.models import ( + Action, + ClusterObject, + JobLog, + ObjectType, + ServiceComponent, + SubAction, + TaskLog, +) +from cm.services.job.types import Selector +from cm.services.types import ADCMEntityType + + +@dataclass +class JobScope: + job_id: ObjectID + + @cached_property + def object(self) -> ADCMEntityType: + return self.task.task_object + + @cached_property + def task(self) -> TaskLog: + return ( + TaskLog.objects.prefetch_related("task_object", "task_object__prototype") + .select_related("action", "action__prototype", "action__prototype__bundle") + .get(pk=self.job.task_id) + ) + + @cached_property + def job(self) -> JobLog: + return JobLog.objects.get(pk=self.job_id) + + @cached_property + def hosts(self) -> Json: + return self.task.hosts or None + + @cached_property + def config(self) -> Json: + return self.task.config or None + + @cached_property + def action(self) -> Action | None: + return self.task.action + + @cached_property + def sub_action(self) -> SubAction | None: + return self.job.sub_action + + +def get_selector(obj: ADCMEntityType, action: Action) -> Selector: + selector: Selector = {obj.prototype.type: {"id": obj.pk, "name": obj.display_name}} + + match obj.prototype.type: + case ObjectType.SERVICE: + selector[ObjectType.CLUSTER.value] = {"id": obj.cluster.pk, "name": obj.cluster.display_name} + + case ObjectType.COMPONENT: + selector[ObjectType.SERVICE.value] = {"id": obj.service.pk, "name": obj.service.display_name} + selector[ObjectType.CLUSTER.value] = {"id": obj.cluster.pk, "name": obj.cluster.display_name} + + case ObjectType.HOST: + if action.host_action: + if obj.cluster_id is None: + raise ValueError(f'Host "{obj.fqdn}" is not bound to any cluster') + + cluster = obj.cluster + selector[ObjectType.CLUSTER.value] = {"id": cluster.pk, "name": cluster.display_name} + + if action.prototype.type == ObjectType.SERVICE: + service = ClusterObject.objects.get(prototype=action.prototype, cluster=cluster) + selector[ObjectType.SERVICE.value] = {"id": service.pk, "name": service.display_name} + + elif action.prototype.type == ObjectType.COMPONENT: + service = ClusterObject.objects.get(prototype=action.prototype.parent, cluster=cluster) + selector[ObjectType.SERVICE.value] = {"id": service.pk, "name": service.display_name} + component = ServiceComponent.objects.get( + prototype=action.prototype, cluster=cluster, service=service + ) + selector[ObjectType.COMPONENT.value] = {"id": component.pk, "name": component.display_name} + + else: + selector[ObjectType.PROVIDER.value] = {"id": obj.provider.pk, "name": obj.provider.display_name} + + return selector + + +def get_script_path(action: Action, sub_action: SubAction | None) -> str: + script = action.script + if sub_action: + script = sub_action.script + + relative_path_part = "./" + if script.startswith(relative_path_part): + script = Path(action.prototype.path, script.lstrip(relative_path_part)) + + return str(Path(get_bundle_root(action=action), action.prototype.bundle.hash, script)) + + +def get_bundle_root(action: Action) -> str: + if action.prototype.type == "adcm": + return str(Path(settings.BASE_DIR, "conf")) + + return str(settings.BUNDLE_DIR) diff --git a/python/cm/services/types.py b/python/cm/services/types.py new file mode 100644 index 0000000000..3199c69a63 --- /dev/null +++ b/python/cm/services/types.py @@ -0,0 +1,17 @@ +# Licensed 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. + +from typing import TypeAlias + +from cm.models import ADCM, Cluster, ClusterObject, Host, HostProvider, ServiceComponent + +ADCMEntityType: TypeAlias = ADCM | Cluster | ClusterObject | ServiceComponent | HostProvider | Host diff --git a/python/cm/tests/files/response_templates/action_configs/cluster.json.j2 b/python/cm/tests/files/response_templates/action_configs/cluster.json.j2 index be4110b3ad..50acdc22ed 100644 --- a/python/cm/tests/files/response_templates/action_configs/cluster.json.j2 +++ b/python/cm/tests/files/response_templates/action_configs/cluster.json.j2 @@ -43,12 +43,12 @@ "env": { "run_dir": "{{ datadir }}/run", "log_dir": "{{ datadir }}/log", - "tmp_dir": "{{ datadir }}/run/1/tmp", + "tmp_dir": "{{ datadir }}/run/{{ job_id }}/tmp", "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", "status_api_token": "{{ token }}" }, "job": { - "id": 1, + "id": {{ job_id }}, "action": "with_config", "job_name": "with_config", "command": "with_config", diff --git a/python/cm/tests/files/response_templates/action_configs/cluster_on_host.json.j2 b/python/cm/tests/files/response_templates/action_configs/cluster_on_host.json.j2 index 45643630e4..5c4cdb4f3c 100644 --- a/python/cm/tests/files/response_templates/action_configs/cluster_on_host.json.j2 +++ b/python/cm/tests/files/response_templates/action_configs/cluster_on_host.json.j2 @@ -44,12 +44,12 @@ "env": { "run_dir": "{{ datadir }}/run", "log_dir": "{{ datadir }}/log", - "tmp_dir": "{{ datadir }}/run/100/tmp", + "tmp_dir": "{{ datadir }}/run/{{ job_id }}/tmp", "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", "status_api_token": "{{ token }}" }, "job": { - "id": 100, + "id": {{ job_id }}, "action": "with_config_on_host", "job_name": "with_config_on_host", "command": "with_config_on_host", diff --git a/python/cm/tests/files/response_templates/action_configs/component.json.j2 b/python/cm/tests/files/response_templates/action_configs/component.json.j2 index d289c4a087..a666700591 100644 --- a/python/cm/tests/files/response_templates/action_configs/component.json.j2 +++ b/python/cm/tests/files/response_templates/action_configs/component.json.j2 @@ -45,12 +45,12 @@ "env": { "run_dir": "{{ datadir }}/run", "log_dir": "{{ datadir }}/log", - "tmp_dir": "{{ datadir }}/run/1/tmp", + "tmp_dir": "{{ datadir }}/run/{{ job_id }}/tmp", "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", "status_api_token": "{{ token }}" }, "job": { - "id": 1, + "id": {{ job_id }}, "action": "with_config", "job_name": "with_config", "command": "with_config", diff --git a/python/cm/tests/files/response_templates/action_configs/component_on_host.json.j2 b/python/cm/tests/files/response_templates/action_configs/component_on_host.json.j2 index 27d577f4a9..73a5a486e8 100644 --- a/python/cm/tests/files/response_templates/action_configs/component_on_host.json.j2 +++ b/python/cm/tests/files/response_templates/action_configs/component_on_host.json.j2 @@ -46,12 +46,12 @@ "env": { "run_dir": "{{ datadir }}/run", "log_dir": "{{ datadir }}/log", - "tmp_dir": "{{ datadir }}/run/100/tmp", + "tmp_dir": "{{ datadir }}/run/{{ job_id }}/tmp", "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", "status_api_token": "{{ token }}" }, "job": { - "id": 100, + "id": {{ job_id }}, "action": "with_config_on_host", "job_name": "with_config_on_host", "command": "with_config_on_host", diff --git a/python/cm/tests/files/response_templates/action_configs/host.json.j2 b/python/cm/tests/files/response_templates/action_configs/host.json.j2 index d1bb37a557..07045dfde5 100644 --- a/python/cm/tests/files/response_templates/action_configs/host.json.j2 +++ b/python/cm/tests/files/response_templates/action_configs/host.json.j2 @@ -44,12 +44,12 @@ "env": { "run_dir": "{{ datadir }}/run", "log_dir": "{{ datadir }}/log", - "tmp_dir": "{{ datadir }}/run/1/tmp", + "tmp_dir": "{{ datadir }}/run/{{ job_id }}/tmp", "stack_dir": "{{ stackdir }}/data/bundle/{{ hostprovider_bundle.hash }}", "status_api_token": "{{ token }}" }, "job": { - "id": 1, + "id": {{ job_id }}, "action": "with_config", "job_name": "with_config", "command": "with_config", diff --git a/python/cm/tests/files/response_templates/action_configs/hostprovider.json.j2 b/python/cm/tests/files/response_templates/action_configs/hostprovider.json.j2 index 809ab856ae..142b5bfcdd 100644 --- a/python/cm/tests/files/response_templates/action_configs/hostprovider.json.j2 +++ b/python/cm/tests/files/response_templates/action_configs/hostprovider.json.j2 @@ -43,12 +43,12 @@ "env": { "run_dir": "{{ datadir }}/run", "log_dir": "{{ datadir }}/log", - "tmp_dir": "{{ datadir }}/run/1/tmp", + "tmp_dir": "{{ datadir }}/run/{{ job_id }}/tmp", "stack_dir": "{{ stackdir }}/data/bundle/{{ hostprovider_bundle.hash }}", "status_api_token": "{{ token }}" }, "job": { - "id": 1, + "id": {{ job_id }}, "action": "with_config", "job_name": "with_config", "command": "with_config", diff --git a/python/cm/tests/files/response_templates/action_configs/service.json.j2 b/python/cm/tests/files/response_templates/action_configs/service.json.j2 index 612f19ee18..07b70804a8 100644 --- a/python/cm/tests/files/response_templates/action_configs/service.json.j2 +++ b/python/cm/tests/files/response_templates/action_configs/service.json.j2 @@ -44,12 +44,12 @@ "env": { "run_dir": "{{ datadir }}/run", "log_dir": "{{ datadir }}/log", - "tmp_dir": "{{ datadir }}/run/1/tmp", + "tmp_dir": "{{ datadir }}/run/{{ job_id }}/tmp", "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", "status_api_token": "{{ token }}" }, "job": { - "id": 1, + "id": {{ job_id }}, "action": "with_config", "job_name": "with_config", "command": "with_config", diff --git a/python/cm/tests/files/response_templates/action_configs/service_on_host.json.j2 b/python/cm/tests/files/response_templates/action_configs/service_on_host.json.j2 index e3fc7ec5e7..a876a10034 100644 --- a/python/cm/tests/files/response_templates/action_configs/service_on_host.json.j2 +++ b/python/cm/tests/files/response_templates/action_configs/service_on_host.json.j2 @@ -45,12 +45,12 @@ "env": { "run_dir": "{{ datadir }}/run", "log_dir": "{{ datadir }}/log", - "tmp_dir": "{{ datadir }}/run/100/tmp", + "tmp_dir": "{{ datadir }}/run/{{ job_id }}/tmp", "stack_dir": "{{ stackdir }}/data/bundle/{{ cluster_bundle.hash }}", "status_api_token": "{{ token }}" }, "job": { - "id": 100, + "id": {{ job_id }}, "action": "with_config_on_host", "job_name": "with_config_on_host", "command": "with_config_on_host", diff --git a/python/cm/tests/test_inventory/test_action_config.py b/python/cm/tests/test_inventory/test_action_config.py index 96d16a981c..33cfe6a4f7 100644 --- a/python/cm/tests/test_inventory/test_action_config.py +++ b/python/cm/tests/test_inventory/test_action_config.py @@ -10,9 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. from django.conf import settings +from django.utils import timezone -from cm.job import prepare_job_config -from cm.models import Action, ServiceComponent +from cm.models import Action, JobLog, ServiceComponent, TaskLog +from cm.services.job.config import get_job_config +from cm.services.job.utils import JobScope from cm.tests.test_inventory.base import BaseInventoryTestCase @@ -97,15 +99,22 @@ def test_action_config(self) -> None: (self.hostprovider, self.FULL_CONFIG, "hostprovider"), (self.host_1, self.CONFIG_WITH_NONES, "host"), ): + action = Action.objects.filter(prototype=object_.prototype, name="with_config").first() + task = TaskLog.objects.create( + task_object=object_, + action=action, + config=config, + start_date=timezone.now(), + finish_date=timezone.now(), + ) + job = JobLog.objects.create(task=task, action=action, start_date=timezone.now(), finish_date=timezone.now()) + with self.subTest(f"Own Action for {object_.__class__.__name__}"): expected_data = self.render_json_template( - file=self.templates_dir / "action_configs" / f"{type_name}.json.j2", context=self.context - ) - - action = Action.objects.filter(prototype=object_.prototype, name="with_config").first() - job_config = prepare_job_config( - action=action, sub_action=None, job_id=1, obj=object_, conf=config, verbose=False + file=self.templates_dir / "action_configs" / f"{type_name}.json.j2", + context={**self.context, "job_id": job.pk}, ) + job_config = get_job_config(job_scope=JobScope(job_id=job.pk)) self.assertDictEqual(job_config, expected_data) @@ -114,14 +123,22 @@ def test_action_config(self) -> None: (self.service, self.CONFIG_WITH_NONES, "service"), (self.component, None, "component"), ): + action = Action.objects.filter(prototype=object_.prototype, name="with_config_on_host").first() + task = TaskLog.objects.create( + task_object=self.host_1, + action=action, + config=config, + start_date=timezone.now(), + finish_date=timezone.now(), + verbose=True, + ) + job = JobLog.objects.create(task=task, action=action, start_date=timezone.now(), finish_date=timezone.now()) + with self.subTest(f"Host Action for {object_.__class__.__name__}"): expected_data = self.render_json_template( - file=self.templates_dir / "action_configs" / f"{type_name}_on_host.json.j2", context=self.context - ) - - action = Action.objects.filter(prototype=object_.prototype, name="with_config_on_host").first() - job_config = prepare_job_config( - action=action, sub_action=action, job_id=100, obj=self.host_1, conf=config, verbose=True + file=self.templates_dir / "action_configs" / f"{type_name}_on_host.json.j2", + context={**self.context, "job_id": job.pk}, ) + job_config = get_job_config(job_scope=JobScope(job_id=job.pk)) self.assertDictEqual(job_config, expected_data) diff --git a/python/cm/tests/test_inventory/test_inventory.py b/python/cm/tests/test_inventory/test_inventory.py index 26106e6a53..36a55dac20 100644 --- a/python/cm/tests/test_inventory/test_inventory.py +++ b/python/cm/tests/test_inventory/test_inventory.py @@ -51,6 +51,7 @@ ServiceComponent, TaskLog, ) +from cm.services.job.utils import JobScope from cm.tests.utils import ( gen_bundle, gen_cluster, @@ -556,10 +557,9 @@ def get_inventory_data(self, data: dict, kwargs: dict) -> dict: ) self.assertEqual(response.status_code, HTTP_201_CREATED) - task = TaskLog.objects.last() job = JobLog.objects.last() - re_prepare_job(task=task, job=job) + re_prepare_job(job_scope=JobScope(job_id=job.pk)) inventory_file = settings.RUN_DIR / str(job.pk) / "inventory.json" with Path(inventory_file).open(encoding=settings.ENCODING_UTF_8) as f: diff --git a/python/cm/tests/test_job.py b/python/cm/tests/test_job.py index d35d8f872f..471d91da6a 100644 --- a/python/cm/tests/test_job.py +++ b/python/cm/tests/test_job.py @@ -12,7 +12,7 @@ from pathlib import Path from signal import SIGTERM -from unittest.mock import Mock, patch +from unittest.mock import Mock, mock_open, patch from urllib.parse import urljoin from adcm.tests.base import APPLICATION_JSON, BaseTestCase @@ -28,18 +28,12 @@ from cm.job import ( check_cluster, check_service_task, - cook_script, - get_adcm_config, - get_bundle_root, get_state, - prepare_context, prepare_job, - prepare_job_config, re_prepare_job, restore_hc, set_action_state, set_job_start_status, - write_job_config, ) from cm.models import ( ADCM, @@ -56,6 +50,11 @@ SubAction, TaskLog, ) +from cm.services.job.config import ( + get_context, + get_job_config, +) +from cm.services.job.utils import JobScope, get_bundle_root, get_script_path, get_selector from cm.tests.utils import ( gen_action, gen_bundle, @@ -70,6 +69,7 @@ class TestJob(BaseTestCase): def setUp(self): super().setUp() + self.maxDiff = None # pylint: disable=invalid-name self.test_files_dir = self.base_dir / "python" / "cm" / "tests" / "files" self.multijob_bundle = "multijob_cluster.tar" self.multijob_cluster_name = "multijob_cluster" @@ -305,34 +305,31 @@ def test_check_cluster(self, mock_err): self.assertEqual(mock_err.call_count, 0) @patch("cm.job.prepare_ansible_config") - @patch("cm.job.prepare_job_config") + @patch("cm.job.get_job_config") @patch("cm.job.prepare_job_inventory") - @patch("cm.job.write_job_config") - def test_prepare_job( - self, mock_write_job_config, mock_prepare_job_inventory, mock_prepare_job_config, mock_prepare_ansible_config - ): + def test_prepare_job(self, mock_prepare_job_inventory, mock_get_job_config, mock_prepare_ansible_config): bundle = Bundle.objects.create() prototype = Prototype.objects.create(bundle=bundle) cluster = Cluster.objects.create(prototype=prototype) action = Action.objects.create(prototype=prototype) - job = JobLog.objects.create(action=action, start_date=timezone.now(), finish_date=timezone.now()) - - prepare_job(action, None, job.id, cluster, "", {}, None, False) - - mock_prepare_job_inventory.assert_called_once_with(cluster, job.id, action, {}, None) - mock_prepare_job_config.assert_called_once_with(action, None, job.id, cluster, "", False) - mock_prepare_ansible_config.assert_called_once_with(job.id, action, None) - mock_write_job_config.assert_called() - - @patch("cm.job.get_obj_config") - def test_get_adcm_config(self, mock_get_obj_config): - adcm = ADCM.objects.first() - mock_get_obj_config.return_value = {} + task = TaskLog.objects.create( + task_object=cluster, + action=action, + start_date=timezone.now(), + finish_date=timezone.now(), + ) + job = JobLog.objects.create(action=action, start_date=timezone.now(), finish_date=timezone.now(), task=task) + job_scope = JobScope(job_id=job.pk) - conf = get_adcm_config() + mocked_open = mock_open() + with patch.object(Path, "open", mocked_open), patch("cm.job.json.dump"): + prepare_job(job_scope=job_scope, delta={}) - self.assertEqual(conf, {}) - mock_get_obj_config.assert_called_once_with(adcm) + mock_prepare_job_inventory.assert_called_once_with( + obj=cluster, job_id=job.id, action=action, delta={}, action_host=None + ) + mock_get_job_config.assert_called_once_with(job_scope=job_scope) + mock_prepare_ansible_config.assert_called_once_with(job_id=job.id, action=action, sub_action=None) def test_prepare_context(self): bundle = Bundle.objects.create() @@ -340,14 +337,18 @@ def test_prepare_context(self): action1 = Action.objects.create(prototype=proto1) add_cluster(proto1, "Garbage") cluster = add_cluster(proto1, "Ontario") - context = prepare_context(action1, cluster) + context = get_context( + action=action1, object_type=cluster.prototype.type, selector=get_selector(obj=cluster, action=action1) + ) self.assertDictEqual(context, {"type": "cluster", "cluster_id": cluster.id}) proto2 = Prototype.objects.create(bundle=bundle, type="service") action2 = Action.objects.create(prototype=proto2) service = add_service_to_cluster(cluster, proto2) - context = prepare_context(action2, service) + context = get_context( + action=action2, object_type=service.prototype.type, selector=get_selector(obj=service, action=action2) + ) self.assertDictEqual(context, {"type": "service", "service_id": service.id, "cluster_id": cluster.id}) @@ -366,7 +367,7 @@ def test_get_bundle_root(self): self.assertEqual(path, test_path) - @patch("cm.job.get_bundle_root") + @patch("cm.services.job.utils.get_bundle_root") def test_cook_script(self, mock_get_bundle_root): bundle = Bundle.objects.create(hash="6525d392dc9d1fb3273fb4244e393672579d75f3") prototype = Prototype.objects.create(bundle=bundle) @@ -397,26 +398,22 @@ def test_cook_script(self, mock_get_bundle_root): action.script = script action.save() - path = cook_script(action, data_sub_action) + path = get_script_path(action, data_sub_action) self.assertEqual(path, test_path) - mock_get_bundle_root.assert_called_once_with(action) + mock_get_bundle_root.assert_called_once_with(action=action) mock_get_bundle_root.reset_mock() - @patch("cm.job.cook_script") - @patch("cm.job.get_bundle_root") - @patch("cm.job.prepare_context") - @patch("cm.job.get_adcm_config") - @patch("json.dump") - @patch("pathlib.Path.open") + @patch("cm.services.job.config.get_script_path") + @patch("cm.services.job.config.get_bundle_root") + @patch("cm.services.job.config.get_context") + @patch("cm.services.job.config.get_obj_config") def test_prepare_job_config( self, - mock_open, - mock_dump, - mock_get_adcm_config, - mock_prepare_context, + mock_get_obj_config, + mock_get_context, mock_get_bundle_root, - mock_cook_script, + mock_get_script_path, ): bundle = Bundle.objects.create() proto1 = Prototype.objects.create(bundle=bundle, type="cluster") @@ -425,30 +422,23 @@ def test_prepare_job_config( service = add_service_to_cluster(cluster, proto2) cluster_action = Action.objects.create(prototype=proto1) service_action = Action.objects.create(prototype=proto2) - proto3 = Prototype.objects.create(bundle=bundle, type="adcm") - adcm_action = Action.objects.create(prototype=proto3) - adcm = ADCM.objects.create(prototype=proto3) - - file_mock = Mock() - file_mock.__enter__ = Mock(return_value=(Mock(), None)) - file_mock.__exit__ = Mock(return_value=None) - mock_open.return_value = file_mock - mock_get_adcm_config.return_value = {} - mock_prepare_context.return_value = {"type": "cluster", "cluster_id": 1} + adcm_prototype = Prototype.objects.get(type="adcm") + adcm_action = Action.objects.create(prototype=adcm_prototype) + adcm = ADCM.objects.get() + + mock_get_obj_config.return_value = {} + mock_get_context.return_value = {"type": "cluster", "cluster_id": 1} mock_get_bundle_root.return_value = str(settings.BUNDLE_DIR) - mock_cook_script.return_value = str( + mock_get_script_path.return_value = str( Path(settings.BUNDLE_DIR, cluster_action.prototype.bundle.hash, cluster_action.script), ) - job = JobLog.objects.create(action=cluster_action, start_date=timezone.now(), finish_date=timezone.now()) - - conf = "test" proto4 = Prototype.objects.create(bundle=bundle, type="provider") provider_action = Action.objects.create(prototype=proto4) - provider = HostProvider(prototype=proto4) + provider = HostProvider.objects.create(prototype=proto4, name="hostprovider") proto5 = Prototype.objects.create(bundle=bundle, type="host") host_action = Action.objects.create(prototype=proto5) - host = Host(prototype=proto5, provider=provider) + host = Host.objects.create(prototype=proto5, provider=provider) data = [ ("service", service, service_action), @@ -459,19 +449,23 @@ def test_prepare_job_config( ] for prototype_type, obj, action in data: - with self.subTest(provider_type=prototype_type, obj=obj): - config = prepare_job_config(action, None, job.pk, obj, conf, False) - write_job_config(job_id=job.pk, config=config) + task = TaskLog.objects.create( + task_object=obj, action=action, start_date=timezone.now(), finish_date=timezone.now(), config="test" + ) + job = JobLog.objects.create(action=action, start_date=timezone.now(), finish_date=timezone.now(), task=task) + + with self.subTest(prototype_type=prototype_type, obj=obj): + actual_job_config = get_job_config(job_scope=JobScope(job_id=job.pk)) job_config = { "adcm": {"config": {}}, "context": {"type": "cluster", "cluster_id": 1}, "env": { - "run_dir": mock_dump.call_args[0][0]["env"]["run_dir"], - "log_dir": mock_dump.call_args[0][0]["env"]["log_dir"], + "run_dir": str(settings.RUN_DIR), + "log_dir": str(settings.LOG_DIR), "tmp_dir": str(Path(settings.RUN_DIR, f"{job.id}", "tmp")), - "stack_dir": mock_dump.call_args[0][0]["env"]["stack_dir"], - "status_api_token": mock_dump.call_args[0][0]["env"]["status_api_token"], + "stack_dir": str(Path(settings.BUNDLE_DIR, action.prototype.bundle.hash)), + "status_api_token": str(settings.STATUS_SECRET_KEY), }, "job": { "id": job.pk, @@ -480,7 +474,7 @@ def test_prepare_job_config( "command": "", "script": "", "verbose": False, - "playbook": mock_dump.call_args[0][0]["job"]["playbook"], + "playbook": str(settings.BUNDLE_DIR), "config": "test", }, } @@ -512,13 +506,13 @@ def test_prepare_job_config( elif prototype_type == "adcm": job_config["job"]["hostgroup"] = "127.0.0.1" - mock_dump.assert_called_with( - job_config, file_mock.__enter__.return_value, separators=(",", ":"), sort_keys=True + self.assertDictEqual(job_config, actual_job_config) + mock_get_obj_config.assert_called() + mock_get_context.assert_called_with( + action=action, object_type=obj.prototype.type, selector=get_selector(obj=obj, action=action) ) - mock_get_adcm_config.assert_called() - mock_prepare_context.assert_called_with(action, obj) - mock_get_bundle_root.assert_called_with(action) - mock_cook_script.assert_called_with(action, None) + mock_get_bundle_root.assert_called_with(action=action) + mock_get_script_path.assert_called_with(action=action, sub_action=None) @patch("cm.job.cook_delta") @patch("cm.job.get_old_hc") @@ -571,12 +565,15 @@ def test_re_prepare_job(self, mock_prepare_job, mock_get_actual_hc, mock_get_old finish_date=timezone.now(), ) - re_prepare_job(task, job) + job_scope = JobScope(job_id=job.pk) + re_prepare_job(job_scope=job_scope) - mock_get_actual_hc.assert_called_once_with(cluster) - mock_get_old_hc.assert_called_once_with(task.hostcomponentmap) - mock_cook_delta.assert_called_once_with(cluster, new_hc, action.hostcomponentmap, old_hc) - mock_prepare_job.assert_called_once_with(action, sub_action, job.id, cluster, task.config, delta, None, False) + mock_get_actual_hc.assert_called_once_with(cluster=cluster) + mock_get_old_hc.assert_called_once_with(saved_hostcomponent=task.hostcomponentmap) + mock_cook_delta.assert_called_once_with( + cluster=cluster, new_hc=new_hc, action_hc=action.hostcomponentmap, old=old_hc + ) + mock_prepare_job.assert_called_once_with(job_scope=job_scope, delta=delta) def test_job_termination_allowed_action_termination_allowed(self): self.init_adcm() diff --git a/python/core/types.py b/python/core/types.py index 2e5e94fb51..0b2b3fe429 100644 --- a/python/core/types.py +++ b/python/core/types.py @@ -17,6 +17,8 @@ ServiceID: TypeAlias = ObjectID ComponentID: TypeAlias = ObjectID HostID: TypeAlias = ObjectID +PrototypeID: TypeAlias = ObjectID +HostProviderID: TypeAlias = ObjectID class ADCMCoreError(Exception): diff --git a/python/task_runner.py b/python/task_runner.py index 34871abd27..c063881c61 100755 --- a/python/task_runner.py +++ b/python/task_runner.py @@ -24,6 +24,7 @@ from cm.job import finish_task, re_prepare_job from cm.logger import logger from cm.models import JobLog, JobStatus, LogStorage, TaskLog +from cm.services.job import JobScope from cm.status_api import send_task_status_update_event from cm.utils import get_env_with_venv_path from django.conf import settings @@ -140,7 +141,7 @@ def run_task(task_id: int, args: str | None = None) -> None: continue task.refresh_from_db() - re_prepare_job(task, job) + re_prepare_job(job_scope=JobScope(job_id=job.pk)) res = run_job(task.id, job.id, err_file) set_log_body(job) From e3b40995d71be732af8a483860c4b3672e113034 Mon Sep 17 00:00:00 2001 From: Vladislav Paskov Date: Wed, 31 Jan 2024 10:41:57 +0000 Subject: [PATCH 064/151] ADCM-5193: [UI] Expanded table row variant https://tracker.yandex.ru/ADCM-5193 --- .../AccessManagerPoliciesTable.module.scss | 62 +---------------- .../AccessManagerPoliciesTable.tsx | 13 ++-- .../AccessManagerRolesTable.module.scss | 68 ++----------------- .../AccessManagerRolesTable.tsx | 12 ++-- .../JobPageChildJobsTable.tsx | 4 -- .../AuditOperationsTable.module.scss | 42 ------------ .../AuditOperationsTable.tsx | 13 +--- .../components/uikit/Table/Table.module.scss | 64 +++++++++++++++++ .../Table/TableCell/TableBigTextCell.tsx | 18 +++++ .../Table/TableCell/TableCell.module.scss | 6 ++ .../uikit/Table/TableRow/ExpandableRow.tsx | 6 +- adcm-web/app/src/components/uikit/index.ts | 2 + 12 files changed, 111 insertions(+), 199 deletions(-) delete mode 100644 adcm-web/app/src/components/pages/audit/AuditOperationsPage/AuditOperationsTable/AuditOperationsTable.module.scss create mode 100644 adcm-web/app/src/components/uikit/Table/TableCell/TableBigTextCell.tsx diff --git a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.module.scss b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.module.scss index 2b50527de5..aaefbca0fa 100644 --- a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.module.scss +++ b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.module.scss @@ -1,61 +1,3 @@ -:global { - body.theme-dark { - --policy-row-color: var(--color-xwhite-off); - --table-expandable-row-background: var(--table-tr-background-primary); - } - - body.theme-light { - --policy-row-color: var(--color-xdark); - --table-expandable-row-background: var(--color-xgray-alt); - } -} - -.policiesTable { - table { - table-layout: fixed; - width: 100%; - - td { - div { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - } - } - - &__policyRow { - &.expandedRow { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - - td { - color: var(--policy-row-color); - font-weight: 500; - - &:first-child { - border-bottom-left-radius: 0; - } - - &:last-child { - border-bottom-right-radius: 0; - } - } - } - } - - &__expandedRow { - position: relative; - top: -12px; - - border-top-right-radius: 0; - border-top-left-radius: 0; - border-spacing: 0; - - td { - border-top-right-radius: 0 !important; - border-top-left-radius: 0 !important; - box-shadow: inset 0 0 0 2px var(--table-tr-border, transparent); - } - } +.tablePolicies > table { + table-layout: fixed; } diff --git a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.tsx b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.tsx index 4b5403f719..c0d75fa246 100644 --- a/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.tsx +++ b/adcm-web/app/src/components/pages/AccessManagerPage/AccessManagerPoliciesPage/AccessManagerPoliciesTable/AccessManagerPoliciesTable.tsx @@ -1,16 +1,15 @@ import React, { useState } from 'react'; import { useDispatch, useStore } from '@hooks'; -import { Button, ExpandableRowComponent, IconButton, Table, TableCell } from '@uikit'; +import { Button, ExpandableRowComponent, IconButton, Table, TableCell, TableBigTextCell } from '@uikit'; import { columns } from './AccessManagerPoliciesTable.constants'; import { orElseGet } from '@utils/checkUtils'; import { openDeleteDialog, openPoliciesEditDialog } from '@store/adcm/policies/policiesActionsSlice'; import { setSortParams } from '@store/adcm/policies/policiesTableSlice'; import { SortParams } from '@uikit/types/list.types'; import { AdcmPolicy } from '@models/adcm'; -import cn from 'classnames'; -import s from './AccessManagerPoliciesTable.module.scss'; import AccessManagerPoliciesTableExpandedContent from './AccessManagerPoliciesTableExpandedContent/AccessManagerPoliciesTableExpandedContent'; import { isShowSpinner } from '@uikit/Table/Table.utils'; +import s from './AccessManagerPoliciesTable.module.scss'; const AccessManagerPoliciesTable: React.FC = () => { const dispatch = useDispatch(); @@ -47,7 +46,7 @@ const AccessManagerPoliciesTable: React.FC = () => { isLoading={isLoading} sortParams={sortParams} onSorting={handleSorting} - className={s.policiesTable} + className={s.tablePolicies} > {policies.map((policy) => { return ( @@ -56,14 +55,12 @@ const AccessManagerPoliciesTable: React.FC = () => { colSpan={columns.length} isExpanded={expandableRows[policy.id] || false} expandedContent={} - className={cn(s.policiesTable__policyRow, { [s.expandedRow]: expandableRows[policy.id] })} - expandedClassName={s.policiesTable__expandedRow} > {policy.name} {orElseGet(policy.description)} {orElseGet(policy.role?.displayName)} - {policy.groups.map((group) => group.displayName).join(', ')} - {policy.objects.map((object) => object.displayName).join(', ')} + group.displayName).join(', ')} /> + object.displayName).join(', ')} />

      Wj!f5&YuZ>t20( zlPM(EPMxhj8K2z!LS!Ox3-|&%Wb95bzlCyS4Zpj$T7tD!g3MwGa*T?Jh^zt@?_=rPe4b>upic5d+z zs$Dc1h)3wD@p%Al*h`P2XTk{ENe2W|T1$4wk6h3Vz}{jbo2bsz)7j?PH=h&~AvGV> zW1fN-Rll!Co2vnjJ6V~2NAw%>H!fQ~&zZ<|v7K4K=wrMX=?H%QAn)gPlYCg}b3U)< z?++F6AI{zMdIw|sNk(8GvsFX?hboi7CapS~yFzs{B^WXVh77E43FuRbuz5W|Y%UD* zHR?Xw@OaNd-moCU8+BN~q7DmK6yAl_?_@xg#FQwMikY-0?GZ(vFVaY*)45Gl2UJxi znT!_!f}(H5B~_M7Tb$_eNCF37{?2f)9ld5QM3@z^QBRx`(^fquoIW5K_z?mpOG zRaO@_7Jpj#>B)W{rN3NvfedB#&n}ce; zT3x;n1&Ot;!F4UXvAmi4<@&!Y|GJ9b)~WA4^Oo~Cvir54`|S)?aHv0<`L_>1j`i5( z>+rMqE2s|`gB2T6zcS1ct~eUK2OTf|po6_%fR$JvzgdUSst#^O1+s?~C_z!L^{ zB%D$maIs=L7`+<#q0`B29+KrlgSpLGjYSbGL=G=DQ$;i}(cNldX*=L1CS#kWm0;S! zXHyia0f#^x%H)(zt8=xSDMwrZN}aSvQ(OQpzddp-NFz>-5i&zL4w#nQSPM-Ay_zKI z;k2Oy1YS%8rWOq~r0H_T6-?LSp-Nh>HbRA%`qCTgN9Cm4%WL_hR;h$basTx$mXl0H z*1VjHImoe@d^jJ~ggzsQ0_TtDv6L?A(QIV-WI#A1D7+HY&6Fwy7^$cy2O#}`2|YhFASw_Wfk1OBi}WnYW~FL6jiOkHR&69Ny!|&t?vF5$2(i4`Q87Ibz&M{H z4*4pR#m2Cn4t#XL-RJKN%X?WHTkuTpQ`^!SFdI*K> z^n7?IpdEr|of3SYm<&C1)2gGK3NbCRh(~Q9%kQ_WT-Lp57&-EZB(9ZZ&$jNgw|1x` zT*o0@Z(P+94Mnyq825&c=f~EA^1@WNUTlTRR@BXVGUbMG{HSVm(xFsHc7-?Y?DmXs zF&&BVl0+s|@^JGrF|x!INexD{+rZbIy8Q1>P{%c;a=K=X%}9_ajq%U5`Y1@mjUHkVq^ntcjd10@oTR@;tY=aA4JMR0qwtd*G>g z8qLM#Cz=m8T}@BZBl?*{dX=Lz!4xDi(`eXiTMC8M*r=NQ#(hM$MfFcc*2AFudtmK{ zGSW8U#$DjYIq67fS{PUP_#1yNpY}+hN8Y2oN}4C76AtDu*>x$s3P zP8{G^K)}pUr@KkcyAW9tf7;8^jshOii@Zs(TL43W@Q#OgfTu_ar#R#S!+Vtck{XW% z0T39 zoOgZPyQQKQ*E~(zS4b4%F&0Exd>nOD(ymI*?gpeJc=#W}QmTDq;{3sIsO#^}ZOs4P z{KkA&+5HDImoUZ9!-n9JGq`;Vbl<=3mU9dLPX4#>J?P0le=ap$4x?cml4@AAk-cVr zmU#*DYvi=nkbyqXTXhH2P>^Ma(}0Md2aJZID2EjTdWfiz3uKt?$Y0J>&wC?n2Yn_-N*Y+^zlo7cQ^e6 zqIvF(%b#EnQz5ISiaKZpefA;p_}}Y^WWBU0s7H0;%^`0!>lmCVd~c_v^6o0T-Q>aQftlrLNl_EVFk*bkN9(nNdr-}qcz%P$`f ztv43$+?qV$TlLOc)wx2DyO$LtFSPBukK$$KBd$cPyP-z-pOqRvc{Fhm(D^O0N7Gav z@eRErA=r{3*pfbo%YBfE_L-1-3CH4Q+%(rXq+=I{I24I643|zM{3%y>fMYRaa-5t|SGCM*jHL=6X*IQO+M&m!88tk7vc<7(dztyTg5~-#|9acFxUn{y3iiSi({lTFl;4iG zBAIG5V)^t4e&@<>FFpo2H@{Xt@aW>*Kb?qM#Z+94=pq{St@6Z2$)QQ~XT4Gj5VB41 zahvof@JgEC?KU9|-h}3k2E=Sd$5V!gt{0_eAgv!+V6PLjpp<}a_Xwz2!9huW_>-Oo zoC0uf7$-ZI#voT{&eV;*TWkhgUpDY2%lclIbf-PDx!WUPz)PXE3oXWX*Q*IV`w=cewKXlp`ulF`9jX^t7%2UBZ zP=}md-~Fq0K=)GJk8)iu8?8)isAPC}U#lwZQ)OiQWu%}MdTTGZhg1%M%MdEs1qO;> z@HogpDA4q300C56E?29ylS%6t;w=@6nT~hUXy>-8ZWq6uj^S1&!=i0fmuLffM;&#} zI79%~;I8XZke(A2Bp73V%R1}c8?ri{>h4A+L#y79(Ak_#@mlt_;6(h`YVqXjPI}W; zQo2hLBW|51L4=emshnpfq~a#S7MHggdOo3*CI9uSb9bKYvTnh>TQ5}@W{Kf~<;4q)_*4m0LBG{gD->^B04q|UdQ^_Sm+1IZR8tg6RM5ZKTOsdw14h76k~ZR{zQ?21 zqE;qGHtZT3*I9C~vvH6Ti(?^PjT+v>z+xD8EG`68A(LEXN5qZ8)~oi9jFvB5txT|p zJKB{ZVD1dC9(T1d8L(+}sh>KTyzca=6|WXh#Z#VustUZ9Upa7c_L*SOGgHkix8vPs z58<-FpIknDn-T3CIMQw(ovCX0*=KQgPYsO3PtY?!){}`&_sTpU(LoeF7~BalIyRuA z-ZTS&P*^w4s2IC~AyM&dK|b8}9tgba!YutJ<*|d`W zaLDi{ms05uE5A_PsIGnYe`YxTh>K&1L-DS~Pk$Qh%6X`Lk~1PkPUN@rRzm$CapK5b zGD0vY#ff(Y@&m{tdOVI2j#rX$S(gi;Tsr0U55guJ@Ot9$KtKuw8Br2q!+tq<07##! zj!Wi<7Qtif(*fU;o4PcnN&tZAIxY}n3epiF1GEW%55P)b<`sI)Jm$YGw^p3q=mwJV zdH>!CmPVB(Lg8^jh4%8XgvtH%H>wQ zhJt4bsibMPqE;5gqR77`xE(&mu}tfpat2iz8+B=tOX~dZU4q&czDhX583Pg-cWj6v z-|=I6DDY=P6N%W&((zWfEX9SSHqpxcg)SzuCEu)b!IQbQ#VY{z0W$5&mVC#wxQ3Pj87iDyceO$tYJ83 z!fIH{L6EB4rYn{ng6Wj;Z?rCiSszIczg+Z>13H!;u_8F{1) zxw0_*>5(@1JmNqbJbu-S;_p3QU{0-;-f%ByiD8~ti07CG$>&%-89wI%i-^;L$tR)4 zlavW{{8Pwh6uS7;FG{@kh9dLg)#4l9mbLLI-((KpXPMUrY;*#AZW@1&`7qK^@YBSQ zaRJ_o$OryK8#kV$&u24}b=(fz7?7{GMGK~voxoi!s*3Eiu*#&BXhxG|R_OY4L!9f; zXUEe_7XLEyUL+ykgOD_|M{PgH5WXcCwG2I;XR=`tyB)lWnMo<*=J&p$Q-}`IEV%*I8pzpNjBhJ3=b{mSQX{?AE zL+lg=xD*-27X&}y*UGx2g~f89T?i0wE+}axxo8ywQRX$gC+3gjijp7*Q6-Wqd8yy{ z2>Gx2$ogW*vo?D{9*X#=hZ#4=VHeMjtyd@aj_Ji$#uhDEaId+~dgC9Ef6Qy|D!y&* zj{Mu`7+xZ4>`Ai5f@F2zy3_JvVG5r3bcSb)%V*4LJ?-A|6%kt0%_}t|ek$dz1zfAZumw)d;K^TOw zTA8%>EKE?G{%-MWNFl$w`(4`K`ft$RL|-SyhQ9uFn^$A>`&Ik(%MyLvAaP!hzTWhIp8db?deL6rEdBc;8uoI{(d+rq^%A|dxk4zej>J7I z(og~YZ7*x9%fexlhrlHdII0|FB2Q5sDv#6t6L6?{ROecBt{r(*C>w+v%ASye{Ruh0 z2iHB()}A1quH=BQB&Pz-fzJ=AF5DBm1B}(aVU$>)ln;?>mi6@0MRtIY?p;lIT&p@u zBWBg%{cATWwisOH+7S^jLux+)GWXp5%Kh*75hyu)b_K`B1DnIcaA){^uXmV^b9Ik5 zieA@guctF_D1;96a&E8cU6b6pB)Pee8d|d{D^w(z$SVn|n`1(bJX&W+>bH;3uhkq< z%~?}*ra;bjU-|?Th9$q~W=><5AaPoM<5Y@Pf)9V>SAOB(#xK9`HM!&)KKQFg&`9^S zPVcXYMmzxYx<%IsG3!*b3GAGNI=!&R!?K)Dl6Z0!N&`V)TmxRf1BTg~4VyE=PF)a- zk|v%-nok3;o@wmft>Sk)|4sb!>h6o*ikAYr4>Q)_`L7(tFFUf=_e}PX8}Odv>z29K z?!~3!3;UvDb5_{8wZt-Q_iCKTA#qJsby-#s$E~TluIe0#j=aIJC?b;tO0qsM1W_JH zjwqHo6K-I$v6pN4{rg>d|!8mC3 zesTfNlgCGk{V7=c{Rje4m~=KbVZ ze~Mmv$n^#K{sH=|FCo_h@~lzxOHgBYx_1gx!9l-R*R(aVm_xx}C?qSyVMaa%`w=)NB+>#;W-b=jgN$F61uYa3c|OVv6rT@!1ZLQxXa`9h8fK`pQaOY+j>;=e znBkyB9G$*VQ6g=1Z61yeAo#l-zHMtzvKAKC3$<>*Mcp zQRjW=^Z#Rb-?9CP=WH(E;rrW{zYAw8`TOhavjI70gD<&{SCu94u0d?b#~va_1GU06 zhZ(2ns7V%_=8=M9odJNz|7W|D&Zrji?@h;76uf%P;rE!I0VsX!(yQKUD*)i>_*m)^z(mk$0njc~~Fmb>@ z9hj1K4HGc2Fq*lzHvHSh_R1ovr1Q+Bx8wZktX8le%ZX~#aIHW77 zb2O_W`gZTuRnEg{<1196iV13=FZ9$BMfW8D*pg5j6!(KZ=j?Il&LGFa zJNYNxX}{;4MjakfF2_L%hgB%;nGa~sXp5=`2$4Z8GMC;|eAP`sP&&jRZnaEvCyaF9 z$Z4Blw=Z`lpXVa6Eh8wQR;#|n$$RR_|Khw*SAyid{Np{N8X02v!7TV>&8C6AzM06`7vFuPi zwc!X_UYZ$>+tA_IOM;JqKN2L4=daW|-0N3eVDPIpJ1KP`Wsdj6hIwEs=pUGI3MrOCc%R%vRSGPcBwEkPDDI zy>R&q@xwns{HovRNw#MVu5`q)KM|)85OE3t5yw?F96MwDlg~V|zmfkcuk0)xDl}+S!qf&4?n=QqnJkXrc<+e!Gb%(sJkG36*-ZfX74Gy76 za+)~;WPuH?xp3%ZZ=88j!F?sOaq9Sd&Kql3y>1~tCupivYu08mzKyCKv6f8pdN`p5bx}+d+xEI4=P3Rca>j+xyL(a)YHGUa+cXn5Zk%&_i<3r025`Q^!mxWAesj2E+AIvh=%m1IVyR$Tme`bX%G^Yy(CJi)Q?`6k)IL?l zqM|Fw(7X0Q?7*q1XpIF&HH1cd$2PGy)lb|yH#k&3evy2AATv`>d%o$7e>^=^O-tY4 zIJXk{joW|soyT9YbNlDsaqQ+uxqn^zaChnm(<&~XsV8R5Xg#A3eV<>)j}ia%+x8p- zM=m)tOmt7L_bV)B1(OjR$z*a|?8urfn~bb^JX(Y`OokyRD8f3z7=;a1mOZ*A3LZq< zH`AdHv0YWr0fU~7EBbwb{&q-x3!XeW2jn3g-Z@f+?6-@zZ`2Y?i_@W-g3Ct+5wp`M zdT)%KX-?zEJ{M}Wnn7dsz@!$OUA8%IA%9CA=J&}wrqEWe5eP*?JHdb+3TV%9BstfiS|;C0`6MfpHZVYy|FU7Y#o?lZ5=pS=Fo z#oC1%Z>-rdpNpK`h|bGvY#)`(ONd_Y(0KxzHA$Xt4*gj#PXVk&Ffc`MdeXGEnHnVq zqAA)62VDe!bn-)o6+jAwq1d?qi(7HNSla9BOm|w5c@%vvv)a2@k7%R~WL%;i+mn zsC#HZa$ex~6^{2xVA>XE9Mjfl)MnGZXrq@;luC!r)TXB8xZKRfr>l{r=|d_$t{3Ku zW-_E)W$I$NX1usOne)n%#mVE7QNQ~TC#&gBrc&&qJw7k|1eu2oyDy&1i-+tN9`$=U zV#RiNr1Lzv^ssyCivq)*=H1A}iFmXr#+g9JsdLhn2DFH2{K1X$51-$-9lr>_bNAKc zzd-$E^52FUZ4&+3LnvWqZsJ4t$DkOJkTNXVDvn>QIQ?IWLvjf8@I4v)BMK@3-A$P2 zUI~^$coU(tDtMAfk7q}ebWxJTR8o>+TQc^DZdKnBIB8gsywp}ZKT1K;PFLGaA-vOt zg-80CuyyeF^9RpPM5p7`&0E8Fo?PG9{dJ=jEH9Qrh3dqTic<@>oox90zlA^h((~8t zJ}yh8rH%4rcW~I&4?RPUjjx~*`eaWk!jWA71i%pA7In_&=y2iFeo=@q%puW~KBP|3 zoo;>IIlFad2l)2{8Nc46bT`x?Whs$zW-}}Z;R*<`hPHFLay-UU$<-kq&_2Vzbm=O= z*?ney-2b_9;co-sdSWh;RI1kG$!<(ZHq+C?WnM1S7INyZ%)D}EO7N}-p31?Kxo9fn z_sF%eRjql%NUrJd96ZZR&|WGF{q(2Oisbk-3jI!FD?ohGRwKYg_GlyuhnWnAnFvTW z(G>Sch}{kv9vYN-5y&QLn=J7ISvD8jl(Hyvnk>~V!HG(TbgfYByn?0#kNC!5j~~E( zOdfws4;+8V!>4*T^p0)h4!?ByZ_}b`26=rxuUAT_-qSJ)NK!l= z*BO!d9?K)8%&gEtcL94v`7q#^lO`m?Lb@2RbVYOJCOv~Sdce15roS!?Itt|_G zx$?5Zxf@?R`J(m4M?NB?+r94;=2o-S6=5&Oo1o|Wb@W^TZQKf34@vZ!J+Ef^{Af)} z+1&3>JI?0gy^|`?agotXs7g{HkLO2ZAt*^*NhTG=6XMjE`DpDtGtGJI;$6zC_Om@@k6wqi;SPaqq66mQoB*G;cXWwckg8~2`9@hjBd#rOEam6=p&bGhPT zdJGdTPsKY^Jh%G@lk4|~bxIgds8do7Z~nv*dK>?Pr7;n52q%RZcM0@XW!^pgOEOa>-}fk|QDHAaAj z>7dVN74%4-%Nqk-7n8EAuKGkalS!^xw11I0T8_HVC5PMSiWJk>mfLHK^7k2@tltc3 zqWc~~0W$cKBg1wGC^h;S+_V7vP1OiMj=(>Vj`$;vMpLBR=lOOd(o)nxrdeCXE>{j^ zn8<3_W92}rz>yXjR+Xqmx-HX2EZDigOl3b&by7n@1fAz|@g_QEUfIq>{nv$>h&cr#`9V}vjNkd93RmC=9yR1(PE$2;X8A97su zj*=lmSW)y$Ul6KBKnrQ1(0WkUgF!v0S0Z7iTv%lhs|E&!X|Uw~ zLP18;g=lMlegDb)?5 zg`9rPf1=~{s@?*QMApKF9u6C_Y#8B~pei1ZqO3_GagRmf97{;Vf*8ey5s8p^hg(%O zO;n_TkMW3t9p(=;?HuU%`Kt`wqkAt9?|A{+n{Q~+VzC%Th4y{;eKxc8Kb zPpJQ`+^kK_7;dq+@v-1!Bjw?C9|be^8**XsMDb(S(tRTKEbZt%*_`Yn-hAeb&iRpa z?48Y=M=gJ=bgU?mqFRM2=;cHITA(xi}y3 zb)E4dBZedrlnz8PQlh}R7+bxzamCWubH5!&3L+xRLXRuOv1-_J@7M0#_`rWH9xMF( z`$4an$vywTM?cD3yb^~3oWGa8jqh3v|7X65MOd^o}6eo4*F6qm1`jkrC`js4xIKR@5-lz+ft zbT!U~%!h-sA@+Z|7YBv#kv5mWFm6c@IW!Oi*8nra!1Ir6Hju`sC9g|v(PBG%x_j@v zcwYUdSG`@`eN63>m9?Ah_YrgX8)VKq+pPwc6gcL@LGttaUtSx3p~FDc17ojZ3#tDU(?(qR2u?|Nf;Ul2|6R7fyQ`A z9AlcICqm+s9liunOtc@1<*TMqGitSU6w-qj zg+d7Ng?>KY2=rCe-RBE=AsS<#tsD&yvbnuD{UMi=tQa-tPH8Jb<}Ma4is71pJ&+B>pX-DzybrzSg5 zIjni{I>XDFJira}@X4)W<-*w$(M)f7wYvWH8SLHt?#$cPs_TajWuj|a*H?;XPWH{+ zzq0La^zyTekGY$i;J?ySY~om8_N_u?+8UCYLDq_@5=EV|QqW0B1)X$OV3@q3{hLkL z%mSomSgHjaa+AeX?uXmWCOI5hq2>S~C6mdmCOlrRXH{XZtjpPrK6Y+)ztg1s$IS41 z@Z>+NCk`DbOf@Ffqf+{Y>GgAmRti(K)f+mK+s$I?Xw_P3CBoH(Y#ZMy5mzczH06Uz zWMzKh2GifG&umPZYW!eGSJIQ&Xf7nu@p5oZNJS4ngj8~V&y(}p4_nVa4fQ72jvVx; za8R^#!GOA`7>)}fWr2=|0KHxUT&vFbsnn~7S5>dN&I&rq3S#Q{x}`KvC#y(4kZn8;*s@MeBkJ78tcb)4xD=6=I`4M#p5gh; zxj2`AcmXp5H^&SWY+mTJZZ*?(dY;8+@BN2+PksRZ6uC2UI$wPLfvd4^6q`h2DRP~^ z8ec~4kNO_euYdVN$hiEy-i+u#fc!x-xTgDcUH7B78DC2vJ&{1BNxo)v!HOpsKe^(9 zIwJ}m?Ds$5|w*SFVbVOvDI=!RbxotQt`iC2ZV7>%?J zWrF!+h})2AiTLdFgt=w)=I1|G8cZgA+#ybEwdUV+&&BewKfa}M!%a6edUxJ(GtK)s zI5`wV2~X-#O<1*V zFq>{DaxoA{GStDLvgZtx0yHZ_TryGD*U4%XB4HHtc!EJT*_Y)~sLvL|)+*BUppc2I z5|6<{>|*Ch+Pn^5$N84*9$0hKwtg)ZET=dHxtn1(ti=N9ip=IF@&&T@|7PxBbng6e z;7GvvVKov@Z|A3T8jh16a?^S3n0Wqd{iW9(6pkE`&Y!K_LVjAu=Jb+;U+HNbTst&% zP};qp{Iq^8++o)7S0r>xuPaK@nn0eKII05pN6wlTe6Z+;w$01A!Ke|FC-5$IAUWOp z?e?P(QeV0Jzc}(Z##Bl>tV7Du&Axx*-pB9Vu-yjRTLnh}qc=PIFNWUUi-elchdT}M z<0e!KAnXsqPhgsQ6Oh(a{9Z4#z}xVE1PQ3uB2gV8wn!w7A`wYgRWwbGMH#;=czw2e zJ!*}k1Pmj3i9NGCHf!2mybsRyh%JlE-B(?1A(&637W``)4{S`UJ*zsGQ@oW8{24W) z1d@hVbm6(@ANV@QYuQ$!(0CAyY)p@i{cXKjk03a)fGD|nejPg2iIH(3Y5(X;f=7f- z1TqD5{1K%!cUsl2JYF6h5r18C0?5DY`;XpxYVGLSse6w;026>`cmD`NhVixGNB8&E zy*}UCP!WWzlXX}pWSI!A8~oVsM-0oZIrV&%teKICRD3c+jz?l5{p8jWPn>JpRz6DC z%;>(a9pV7bN8nnIkRxj+J@y#*Z^#1L{Wy7;W8`7h?>%~N|C=8jd!8pC-nr@W5AeT| z=g~==_crKNg?I;Cpb!)ULc)+j&u9CckjkS4&Kg;6W}oA%Kq9HC$t0Bn@yQ^R=gTCb ztK@76$^(^220;OHFZAhLQ3txZ(uwzl@!bwT)n?mM!{l88w6eGZ|ua^>jLwN{9LgrL$5rCdNc@ z4Qd1)!6R6iw2(|O(eSDy%c6&gsjC7v%yc+0{*?(1yX*8Cr+scX9xxivt2Fc`{lFzb zwjRDEI>S3daGZ|c2fRIR`t(ID!%9V1INGHzHX(&yP2DxVb(7v+w+N9 z&Gkc;Wh$_)A@2PF{vjQcG(Q z??0>fhMF*j-D~f?V@2{SuAUsW=1w;HHXkm;P7UU@Wc4@Ew|dbkKs|toT!3AR!{5bW{NgF_AL7%ZL%-p-BLyd7 zpvHto4$}Y~&G$W@Ko67KLR^EyTWx`L@h%eNyE)zM=G!$w0CLLEy*=c5x%j zK9q?rT{}s5u5)cB{_aHAk;)vB;y_DGozXI~i}o z=p>@hs`D7RbNjMSKUJtlkeuO^RF_Z~p%$&~QbHf4aKxB{i z7y_&=Y(^4n;QRSnHk$^%7>yMAlc~A6mF&^} zf)QBgbkEErfFbDlU;H+ML({!}hAFZB>|C{39_cLNFB2c^5M86!ku}<7K812<8oj?a z(SQxwfW%Q9_G=w1QytPpb?}1gKn_%=jy|kqFU4rVaYbW$)-hHTc?IzG)+QH;aNKO( zDsB2^@>5$DLe=P2M6Pa$cI|O^Pg zlf4@c9zB`}YLn|PJp^oQf=jB^CXPq2Z^AnMYNQ4TY zkwbox4WF6t=kxK#wvHq5ZCR4W&iD?6sExxDpSmI^g7;-V9DXW}-z(G=I(zy#Jbt>7 zPvnXRPgNT?q?WzanSR0QWYpa+S-wgtHd!?5t?iXqD;rE(!BRHHNhoB5^rOAOBg#qB6uhaGJan0fP^112eD2$9DCyJY|u}9y4F#}rJZRH zwybX73f8hlcQRVfN8K(yQEEqb&Zj01Vo^}^sOHxtF63VEXfso#$($*R1#+4ew3B3-aJ;}C zPQq9xVXTt?rZQ|F3bW? zqAh-3vw=e|bm{7ocZ8Q58%oz$3s0Q|494ULCy8CDjKK4){44Hp>)F}U2L>l1v*!;P zjQ}I27Z+;1lIAU2mHC2}Wo{SQJ|n&JJ;^iY&mF0s9ZbC9?2K24^}4y||Ganp_;GX+J<;#ccHXluO|}yexkLRT3SjR;Wte)ktiNN4%PRDpY?B| zX)H_wG{{negX!ra+Frx4NKN>UK_wCq(bIW(#Q9SPiFaMVlcj=g%pR zp0kStw7-MGHm*T`ea-=@x|}Go!|!z|(9+FVW@TtfZG^B5Pp7Z%x;Zk?R#0#;6YZsTTa4w~X;~M1oaoNfqF(IL0v-bk1%`)>0o;h(Qrsv`TynwM;?k1(A z^oM_V(?u6E#}4uR-@*Tf*pw!E9aNat`Z0hjJL}y#MzPs3*k~3M$k3TQ@0?9&9&0BGgTCyV3 z^|)8=b6P7Kvkq1h;iStgx`#Tm6o<7vrd#`Sw(hLrc76AI=n9ERUh(LD!A;5yRk&DNi;OXnLjklY8_r z%6-D;h0nhLVt%v!;~?hYnYhc(Q7p58ey2B~LR3jr0%b_F$tG-GAN=TpbHxisvKL$$ zFBnE|YM5yDQWO=%(XdVs!Z@xt^BKp|(jr+24kR*OdQgYbSP*R@4GWqk2E(Em3W^3g zt!qef+?)SYdU=mSh5Uclh9S@-bC=hQn5vd077Om$qM@h4K@V15xp5x9GqJq96pOVB z5m#SmS&6k%r*gYZ{LW$Da-4F&kW)egh%0f#R3m2Wgj78gQk4|dPy|z-c23qbby)y( zosOl?`V`%#h!B6z0)JKpWzPCUot&CJ6pMubrw}T7Sj6st%DM-+3PwnbL8cvvWMQOz znGEX^ZN@%I&Tap*-4t6n?$JtH9Wp-Q%6;aj`Y@L4)o5d$O<3+!yx*3bM?Hjd+YnzWeLRS0duEy;{PcXUJf1$qn zNxQBX%>+AP$uEeJhPzF`dbHEu)^Vem^ z#R9x*uMHHec3TE5^}!a4LgFe)`^{4OMBgHSwAP&dJIz7D0uKE_jedU&ww4SY+5noY ziWJNUy9^W#GFHVjJccCvf1JGuU?fL%H(uR6eN6XEU(-E3_dS{!jWjcw(Y;z}c2}#_ zYPGvwX%ETvVq=2=I{~l32IDoxU@+JQ0)aq6%oY3xLP!AH#10{Z(?q%Tnpq-du z)hVh?!p8(|vKJYC#@I6#r07{391J z&~l|kVEZ7|rP2bh|4C3>u;6hbqN5fb{<`Y|6l#g4HD}S*Fsj$r2W!UQU~RBABnE@^ zL4;~Ge1|M!sxYVW1CkkagQm&kJAu>NN=Kh=_rgzh4A7XcAq@u{GzPmSD`5dIL*I@U z#*MF5q@0`#(V@XZgG#WVC4v;o&Mz&9w6-U}(cx-hGNueC=BwuZLw9$llu)((iH~=u zvX++9FfV+gdZ-=b3_(s6W%Jn=Qh7qdn+OeC=u@8GS};JC%}8W&O0Xs~QpvwENib@QK_d7ik|+jG9~x71Fay z!&HvpX7;w{hazH_dd2?#3IyIu2gb$=1^b*LjrHX+erLdQ&Z3Xsk5Yhe3_gdLq7kMd z{%I0w9dt^Mg`A8c$;l{kGK{)2_yS$i*42ois*#9lt@6B@r&DPv4ONa513|(=PLCi> z6;p{dIuJlJMD7XN)8Bd>Y*x!tqeJ^pXdib_XusC2!Pac8GE7EJX<;oKUU%^+)0hl0Lg5h7j5SG+ ze(Tc<%Eu3IfWf=WfUQ?*;@H~2-cuv36UE!Ls^~WgUkWe$aePRXRkiqmZbxNvNF4m%wuWuXS7Ux6Z3Zi{rml>fZrnv zuaF^Gff+bb$berw11{bSDd0#LV$snm*V(^1`F7{lQdyYQP*wYl5C0oGh7@jCOaT5)aj&j+FlTa9aC3_0R(Y zhi1x3VRA5WVEN#5Q7%qV<1;5ODIAzN`K&^*OzKGzo#Y$D7kmd~-+!%p0c?~|Oi}># zmL+)lpc^wWGv=gno2G)|nwm(c>bfEu3f?9w1-x~l0aXz-#ylA>ml1LKQm&!xMlCym zKIc7QaJL4M?(L-@!|}o(NM*hUk`wJT29~SoQl)#MQ9GK$OJzikN`(Wtrz%n=mL07` zo5P*Un&Ea8ir9=X#k#S85Tg`TZe+9AmOyh(S|PE~ z+D?fr8`=4b{W0JU099WkxJ_ludSwT%!43#_3JO?l%iU7DMhSLQAff-8H>M(lrT zbAu*J@1f~>4bznP(t+mmI|xm$`yt6c(#D+H=YZ`*;k~SaUVA?p*!+8t+yek=q3sCz z@f5N4dGH7`F#}SDv4mP?z_4Q=co>pe$~7ag%2uN%O_LEO!KuOLq`lv510Ftk59s(Q2gD%doZb@0 zyXmBG8}?@+fD}j6;@@8)dEqi#VH?$tclU#zOKi5V;@Vn|#f?}jo;ZdCRp<&A2p@(0 zHjc1$hz7ACJ&HPLtt2&v*RZ%3TIIEvDa8{ff+Uaf3BUdUE5Z#ZgPA@3#15F}efzKN zz3OaBu_3;#vOkuBEe(ew>8LLJdp&H4BLl`@cPPxUSTT zw=tYEb=FC~WP2!)Uvmq{k}Mo(xW`FAc*seu`x49^xC-yVW&mVheh+3T;LHVNWOfh3 zEJZEZq6#FpX3UvzNjOhfWb1@+L!MRy7w z_&4gIPkwUa`F`qC;B6xNc@Dkvex%~PWp#_&v>*sK$O@|7*>T@4 zPIw#p1-I;#_i882H!Ho(dS#Rglbw9)?);7TSd47jwx5p9lfC)f_TFsQpQaLyJhc7u zciaAXke5%A{$Snicj{Na!>wOU{P%$US9I!EAK$zP{QcN+8A5;1J;}Gg2m#fLg9APe zbaXBUn*_F8*K=7Tm&;~z6k4SjCNz+1^b+q;h!R4>16b5&A^$#|%aQ#10L=t2=RI~# zeWI6Cz12JPptDVEHAh&!I7jW|9CB^i9)2GcEgvaamC-!7h*rmJ7tz2>gksqJD+?^g z2M@AA+L#}>>88|H7g0VcXLW4Ie$yN<&1zf}taQ8$0rgbz}6pF*PR1k z*;SS;o2H(NSw-O@x}nKoJ*+6Y9xhq(3C+-QCu5*O(1I4zVi8@=$JfH5XPw~H z_^i`#&Z&B)Yaix+uRyV_scsFoBc+OpJmZ`YVcUh;Q=V%koq)TSU!We-SM+zO@6M%8 z9vdAWnF+)egC%{&(Tv!G+gs{QdgTR{57S$tetybD(cvIn_d6x*uh2vo+~% zXh}z1Pda9q?jT~2tc~w=XYjLzEwf=Z8tWz6DA9DOBvn^asdfj|RqZuCG`odIbw1DgE|Ddgf}61Bi#E`$CG7gRvp0Den1 z14a^f%Jmol-~vk$GL1q6_fK%QZ3vM+9`EMy4ddknhM9{u7Q(ajYHEC{ zn2)DYXkJ=K!IUq;U_qfG}T@VEjLg(85*8UAdx4du%;9ZBPz}uYR652T>cBf)|Vtn+8 zrPcJFD;CMmOG8P`NX8SIJ`kp>tyHs;NmN>?RwXUUIU|xvBy=Ss(Vx{M_8^1sGKSO*PPHPl3|);4 zNv)8^2eI`V`u=4s&jqM;n*EfV$PLmju|ne^mebO)johKz-txZ7Uc2%08>qKrS_Pfh zIM?Dak7NFbqvJMiaUJX0aWN=5I&e(aljvA57&yixf>=aAr73ewp#ls7{lP~2a-sU3 zAg;A$r)NRiRXiBW21T`adlULItfw8PXjb5F5682$w3=5^VIv+_KYj5}ZXUY)vWv=; zfh}WM5O#~%#KwE@zFgfrMOT>;9_Il1ER2+JaomwgamP4-&s`DD$FLAukO-L3(I6y( z!H>8RKVs*70VcDZ_jOdfM5INjS}tKhPx&MDD{(=L0Ei0SqciygO#vvgoeD;@q{kj5 z2@_jl_F*G_6ifZbzIu9VYFG@g&pK{WqLUcbacXXm1hGiZ+_gB!7ONjvT$woj>PGP7 z?oM$^%D=3%bo5mF>G9o6HxMnShr+vRy%e%Uljp_DeCPxPHD zu|4(muOySkS-hhn+jp%_Rv`#`KbP+Kh|;_>xV(nuwfM^jX)Ft=;EJu(v9aw0aH zNTTWK_C!MrqT0zq0pXog5`@U9GA!vYdq*Qs8p|P9xmdip_k&F^?RHagx@ zfE>yJoQh32#sPD9xYW*udCpdc;-eXz3-oJU*@}mKH3fjn24@1N|%NQIcCE8h+2-Cx)#?k8%wI8gd|l8hgDS?FheI5T`3pVP!vHN8Qnr%L@QW8YHB>?`Ocem zG1Jq(J01Id>ODgC`PMm}Y8+dyfOGv=;nbqMsH`Zjl3x|on%9Q2#K|5nYd$ag?@iCn zPG9JG+MyN|?dBX}ooWER=MyCoTL6?H`X=q1xDdT(A5bQkN(+3J<1=X<|C0+?4XTD> zRyb@~%iug!WJRu|GqG$c72|?IUI;D5Vh9T=%UDuKg)1jK8?RBPWV!m~olX~YAf0+n zo0=j&obokx8nMM!I4D7e1%hQ4Ase5lOjtI!DfQfyE0*?_Mh7axi<8IR9Ig)4S!+<* zy-!X^$xe2lX5?%1nZwJ6UYLG<{6)e4OJByYEWJR}zoO}5$%~8wop>=CB=#M|bwEs8 z6b+((>_*FEzsrHvm;C4ExfPq z>E;=FA;7X>$P?>9Fo+=@Es6rS$N>JrgAVfF7yL)J4&DXc!tt80VHj?><%g-GjUEoe zb$?5M7>I6i8U9X=o<}?y?Yb^h z!(X^$^=j&&m)uW4HT&=+G<0dV#c>fRUmq5PWzU(yBCJb*T_~%1h*}H+<_B6-1!0kO zAST>+-G|TFrJupOw7qQRNQ;!n1nddkt|gnFxMlQ&dZG&$6s@!BjUD^_AD*YAg)huM z3={xtz@Jk8jd^$)Jp>hFiTD@;)`UR#wu^4rb`Fi`?YDy`sb~?%oR)nnKVQ$shH8njwiI6cgR9kCd)=p)!Es9jW zcHGsFaZC!wLTPyT(~BMIILE9_%*>$5ZY_mb-ZB20u<%a7;ucShh+Y_Yf@7U9a3epQ zIFde_9M0=~QR8~HW?hi_M`n94c)C$Yh~>sEUNNwi--{hj59VXyz%b#9VZ3)hepwkZ zUrM%%v*g4wmK=Y72^^Yo&pn+1b7>anDT5bD1d<0q>x@Q23;BE{u9G6I%eMQ@WEf*W zSC+88WW*K;x)3%5piErHf0W?+W21>?E7y`2 zSKdnP(*A2u9?J~wu0;w5Uwjus&(rki(MyNt4+Pnbf2FTl{3}++qUshAiBNTUv-jbDxGF;m)r*F=#Q$gqm0#CW&AS_I4Q;RBdJgpL6y0Q zqIgAKJop;{Rg45XJbAP-e8JNG{KmijCPQkE}NCa}&kF`*PzwRT%sTAdCC z6@`g&Si%GtBM@K$Ot;H0M{2eBzO~&{SUov4KCVnopvu}Xm0pWt+h1hyWoQjV&=YNY z7Pe&=*d;(a{q1Il}t|;-lrxz4SnnINNW+)nNA1PIG|1XIJf}NsZ z?hddI+#)WG{nkkZc0NL7+`+y%MX+y{(0|>J_B#+a`yGgzIT!P04oWeDsG4!&f@T~m zX$Hhp5gd6V;3^yjpWrZ-GY;jeCMVfXHRDicJ8 zktiP`=^Kwy@)nC7h&tUOkkg92>6^kvK zQNR=vqyR51hcqLkNuiLL5CS|O2rN5s_VK6|q8UwtOk^t>4X}b~EXMl91`!#tISQK` zt|1~jVR8gmOmGXX+5VZY-s%?)dCbxzL3xWDcz)qn^T5hmSN0sgb?S=Jfu$qExkLHp z)RD@SZ*FcpOkcI}qeHKm8(3UCRIR>hh2VwE;eB1fIz|G0xO*X1?n9w4HpL-lAYmB^ zD**r%q~HV~RD?9$3R&8^ZW%hZ!gQ3fg4p0%2bZ3RH;W)81d}@AEh{Kt1)jnmMU*&U zCsk~FbAQSW7K+}R`|2ItdY<hiQ}kuxP!{!-){%@EKU|+&dC_VkH8VYGTxQKL z?llKzVha!442d^xI!}1fxux_Hdt9^ z*+dXA%(9g*0Gcrs;_<6vs|7-}@!KaYln^2YI4eWgSmGFd(Ne>q5T*nz1bY?a>^jX& zr-B?wJ?hW2=o47CI_2bgTEj>yPhQ;3P$wY^q*yEv;H5^boa^R?=P?s>hx2o}xl0Ex z9lK^BKVe+-mey-;-S`j81V6v^HFLM@Kk|BAo#afB69jCf zGHd|zkJx*6yonPV+(o?c2diUS2HW2{Sl`6{_Lct-z^UEKIoXykn)8ja|R9Farum}!I!PjiHzSveb1 z7EL`KVs-paHX@)p1_dGGl`02P;1vKmA!dT@vBSRFfuv%~7BWz$?V8o()$IT-*U`mH z&=-{UFD?&`U7lUfUNp71@{$9}0c}MaSH|;$i+gsZ>8l10FD{fO-}{0q{%~aDVd^{G zg@x|x%lr21Ejc-MCF*;a4)5u%zTcoEnajxQih_b{I0{9^djmcaaQ~FcTc7rc7)K+Gz%{ z82*tokR(N|lL=%-MNJi1&P_D&zlblg(9W2I33Lk!`DQD!b-BX({4zc<+R`sGr@M2B zSiPJLJv+L0U~1(#7b$;9MRrJ-q~0>?;cm?kY^6K8hq0_(h7AaIAVEPq57j+sgQ5UD zP?LjVSj3Cdjn!6#;G&|)S(%n)DI9{N7EuxydJ&s-h@w3lI!8!BoNjw-5c^|a=re(P znGiNCmt9K+|4se3jm3yGStY8u9Wcb+_Tvy|H2&1dJvur3F2w+Onj6u_Qh2S5G#NjpL z!}*cv#W2lsiy;M@EVKj|a5OInc;b3FOsCz@z4m#)jBQ(u_!b>PN9e27)z_>nd}iU; zTUTcPevZCs{^_r~WTsf#uY^Z5jpopgdu8PPBwzCV4eFuUjTgE(lX#qI61xf5gkR|9 zNhO6SO!P9rZHuY`I&6}&1{3nC05qp7g5pnbaYK#)7jg`^5Gem$l2Vp0a9p8q*j3^p zSltQ47i77FRXZ0ht!OMo@|h(*7z}v8j0F$>)s5Y5ZgKXKfQ_clnC_3;>o^G89?*Ve zqUU8~?!RT_mZi7-=TyXuR_R@3PTU+~a)XJid)h05rd zSXnD@CQS#o#t%V(8+TFu20F^y>Z0rzNaTxE^*nAsT|o90`(lZ#T1MkpIT;!rPmEtM z9*gOr(BOD3%!eZ(CE7l^J)p>}MR<1qV(a%Wn&IY{(L*N+R!U{Xhe%zci|Gh`Jvq~U zs%w==Bv8(G(gXh2xZ|*m-{*x4JmnNZCr64=r(btUf#^;c@eUL7kTWq~BbnYZge?*5 zXU2&@rkz`8=N5{1)}q$uKDCnhiThM9|Y=Mq^u zK5}qmsuLeQI<6ep9X)xOab&4}{OkpT^O2&_dIMFND5`qItY&n2Wb%?5_a9yq!%6wz zt1g{9vcGY~MGJDHF~73F{@zPg-+s+}Sll0!Hg<($k~DE}wKALogkcl}8Q3pe=^Pui{6N+w{OwkFWD>|McfJr9lWEs1>ixYTkIf2I!XEGzs zBgNCTJCns&1Sj0*Ib?4gVu8D+HNYwt__Y!&9xTi z;t%}x6GA4#DdOd3hj=sN`WG0e59^y6>Q(uw!4*1rRhPJw+B(=y}$*}P8n&U3vEpge)y}s zVgTpMY<1ETNnv3k!FWf-8;1yMJKlQS&Z4<}ZZuU7k2I~a#RX?8&7;}k(V$_)6Lg?- zs2mKX_1L9L)aNWsE9j;1(#EeJxS3im4aB8{{PuSgtHF&I_iD2fjMMJ(D;%u-cIio@;ra};q9GzIX)zM|5aKXlcLe?EQM zns8#qY;|3s-dZ=a>~V?{Lws^-d`LcS>{?hZ*Y5iG>HmAv(B+q3TrOPvoGa?nXRm+J z(1*!*ud~OGZH}wEyO@NPaI7Z_0nWU@@w|tUD~gzL1tFD0D8&UAEhZEabPW{3gl9B4 z6|lX5+sC{<)_uZ7;;`){umwSZ?T}*<2Cz5i7w)?4$hFEVhF6AfP+qEM6H#F$pqsJK z%=JU`RhRwMMSDN>slBcBQx~?YE5{BO4!`dZyvG5rj`vx>h<>uW7xu~k;5@|iu)ZFN z8If2dk`Y$1#R05qt5#vC$r>l;)|s>(K?09r;lRlxC8o$kI6=fP6}{K#e<4sFy(Bn` zyo-NM$Sc0JdaZo9o@V?rqmAs^le<*Dp?cR{yH9=j>fY?MuYAGf_1*Rv4hrJ;I)dlN zLVw&n6}3WUC=xbgK?!3G#>Dnh$YfLlw=RbbBOEqNGXPU&?>=lmqZw5d6k!=(#HdUl zuHYL@T2<&!Sb)8WS;W)lw?FK&F!iyol6SgQ{(OHLxf^1sC<^X_^DcOA$CYVYz7*53 zAyg>p`DR(JV2er##jVd=Mo|}DI5&J^;B@DDYX8)&bKk$KdvkYVlUkzk-T-!cPf%W5PORrmUaGXC)8i7 zCtmUa2hV!rF}gB8zmfGYtuMgy2stAa^zQCO1{_5h1bBsLoPHRQm}RXe;s&0TL?Tza zGYjY@)uFzUrlc5Flh>IVnrq>x$i} z!qB;eg-<4iv~)HfO_m@Y(#Xh`{J>j+x?X~Lz1f-940><(5*FxUL(Q^PvR^?qbO7>e zu+a2Cy`v~&Wh`sii878SaxQo|-j%Z{d_{aQBMCw@vV<5Wn9c}RjK-$=R-h5}347Lk zQtz6Ko(Ez*~Y1w2?}C z=Ny>bNx4!e>!qqn28$?NQ4;1FD~bV4MJRnDfY*cv6s7jCQ_oj99sl)(_D(i3(Y!n$ z78^i=pxQI!BxA77rwS#xI8zBr`IUUQR#S`lWN>Wd(uD_Z?t!wrZfuBVSo+b8>wNg{ z8BC8WVuT1WAVLfbrWmk92yn21hA9Z9c{qv{87s>3(WsKrLSZ$ms>@D7cP@jlA&tqC zPN%Y1&9G1^g*S{47hEzl%Th9Fy!Q)X+0Poz*@knxu>&c*Wbd8obJtd>#*4R#iM`3haEJiLhwF*d-qij{7co9FC|vzwT3`rfe1M~_y_R1bC#dl~?41Pq zboXj&5|hA!N+lK)Hi_DmTp*Ys3gBu{STq{X={m<<$VLn{U_@9p5{ZX`a###IM!yu2 zLMedfi6;!a-^7!8Bw|o;h+_!wYnow%@RwoT9JAck#pCQRJA(Dd{S?~HH2~rRBywSV zYzi>|AZ`owFntA`X8Vj@!;~vi@lY!vqTE z*mctt@)sPOVccb~@o*ry7*5hfhVNooN0+QM0_#9r07cLVU3J2+Atzri1abSL zkOa6eJS-{lf~skT)SaXk%7#%$&PCDUWO*`^nVjT1OM?s;+`z_~?8NBU>XDzY|8~wH zteaZfhj!yAHO?%^uTY;)WFlPAUxecU8u-9YxDH1 z%hMCU({0D|)h2Pl3JC}PUe^ditW*fVvoV|Jst{U5cv$ZhZlxU`8h9(o6j;$!ys<`7 zQ^3-DM}^hFRH~ZalV#UN2S-b#(b4eCsU`*Ia=_K`sC2$5c=%k8w;gDZt%&5?Ioz3z z-;u}ViE`>_W^(*@Wb&XMc-dKbed@Ph^X+w9?V5L_KGzLS-N=SrH&SarT}c}Y8FJ6* zciOq<3ducRSaEPgAin1mshRiBP|pL32EsHMFrNneMQV8o&dlAE zkEV0OorshZ_F`!}Up;2*1AgW!cGAXx=KQ9?Gvqt(ThfemX^dIwiTo1V%CXjBbyO{F$H|-F92ki zuP)T*cRWSOyA_N*=-`f1td8ow`m)qy&8Uykrs0pc<$iY{>iuwiS%OZNLTT@}Zt6=-6a3-O`E=^Jf!l3dy z7|UuOR3JGT;T@v#4pBKb|HB1c@u4oe`+$qS{Jkz-=$M%K)hM_rddSN_&S+W0Bs5PH z#NsyOWl&OpkXz~4%hG%X1m=!IMrPtXNX#3TR+-p9E7=OC<0f0bWM@$3>k50Onrbx| zPh-;GZpU7%6WcP5UfiAI;xV3&#hmkfLDPas#0DrT5LjktgJEcfPMAwFFVJzc$SG`= zrCF8^Fmx;!q-ep#vT{%TJIx)={hNNPIpQ4ncbGnWs>mnF$^U=Ot-MV%ixWfPq7Y>x z;bK-i*b4)A`fY$f#j~?CJ5-~ZB=%yR7BO$c(XHL17Whsq2x_)~1rRU9g?QWvYYghT zh&MhMy%+A5h^{Fdz^_s#c!kSyv|tCj#YNGMcXQv(K~vr#PN2EfBT)7NFZy4Qy8hE6 zcpm|LWcs>^f<4eKWNU+R?36XMZA0n)d=UI=xlBxc^_sWc|zB z$}Pj*Qua-ge+9!F+3VNB@3DvDL#vc*M#JG~blpORW#M)zZYY3Msjh3fq3OC7i&{ul zPMC^88HN_o5zld|CZZEzk-UaKw&$4xW1ROWduz!T81weN^)vDj63_9G#>#?k$@txuXD z%J$iQx*+kz-`hPC18Ei`rDJ1+60w-;or=Lm90QWXfFu^+5Qb&h4YLq=RS^V5S$C?( zrojONzRhGZk)jd_KCq^mri8ynkxxkBP)L+KnB;BFy7Q9dt38KB-RE_2p_6U0Y==)C z%pGl2k~=~u-~7Pu`$3f9Y~mEHVxAa8ukJ2}WoBjnKHD(Yth z3;B)RBbjVzHEx!x<@K0p#PI*?)%t}HgKCIFXy`&4I#EH@YAoLNWBHF{GO-h7v1%H4 zrxQ_K85;6~`IG-JY5ZXR{dC!ZEIlND=LC-8z3l)~33?mMUswh0f>0)3fa1nMiH)}E z1EFJ5K2mo!iB!Vi>gs@;+*e#-1V6TaY~PXN)%uC$J+X@(e70}zIP&2W<5wRjcXv(h zXb1fSe=dU^1W|az4yqD6h!!odgGimMGQr@Qx9y-R!L*c{4n`N;Z!rn?esm>@;`;&B z5*{#$+*(^Hf-^X8;|wNk+)H=};0y{RFB!)4I&ysjU!Nzqg&*|BJVC}-b;dYu+iFzE z8RJiBjf`>89;1W1>5LIAZT^IgL7W72jQBj(@%2G$lgpS(-q)RJf}C!&u*4pKtfT?h zRLda6a}Xw%C5myDc)wFBct290?xjeTAU`lJR?r}JDGY9s5FpiuAUp;YR}G`xXt1l9 z5wun;D&ksP8Xm6pFmW{pE3(r(PbyLw(rj%boAK}+Y!Jzb@g8U{^_Mf3?kn+H+A8d7 z{frI! z8H_y+tk3)eVtz3%Tu-jgk=hXt=^U-2UfpiauG@{j;|yLWHm@0k*KEwX8$8UqGf(wl z);aely!)@jTA@8gN_WR-KjTf_Gp_uhJ;q?o9wVuPP1aP~c}CKqw_0+aaRFW;RN8pSK-* zTfw*v6s8+RY2#-Brgdjws!jTqJus1T?_?QGex=Va&HKy+f; zM1rF&5~M9s;6fsJTj;P^UX`R;KEBFSqbKuuHFZj$R3FIJGg7S|U8_Q>dG?5Adqe$L zTGOeKN?QCOO;=x?Yz}0^A7BA3odn3NS^MXbRUOTQ}! zzzs94wAZasCjLAdOY#O6OVVAp?0~aw?fVnn{k{FkD7yQT{fswx&$#lt z_80(=vNwiV_Zf5wUEn^WVIg-+^vPlolX;$}yy|y~)sYP(UGWk)e5d5zsNf>(W%62=sGp64%ws z#sCiM*uWR$fIX?L-2#voFS%v%NOgfOFKpz=0lHng1?n1(p}&F3d?bpq?x6hCoqeL} ze6BkFxvCQ*4WGNmfb&TWKJcyRfSRtvz(1mZCa*v_M2?8y#A>a^3#%ME(OFfCMWj-K zI^GBu3fVPtfMQv+78b%h9|rff?a^*Rjl-tqRxVQkG8{Zj+YW93o)^-#dw>?_FMUXb z&DL-^*f~<b z(dA3KZUfg}Sp&X=>@@t0eT26$_w!_J08TBvm+<6;HV&(e)5^Fq zZR`EldH0ugy#G3TZ83v=_b0sjduxmL-obvxo4jY(`U95Rj!Y!+jARTm&N~?P7?9~( z-`=`H`<}4Zci9;O;D9sq{g_4vpr8542+g)8&K~E1L zm1lmkdGY3FwzmiBn+4MTG17k4YeyU3Bkf<^(jMOUKcxL@r2R&(o!a;*Y5(q)c6sA} zecyYJ*G_MyH{ZKMyRsR9cF-@WUy=DaWY6CunP0TmnV&8Ffx2M#w|o7xMdruu$4ZgC zXYRAc)_Z?I=ylkp zXTx4E?wZ}wkNLvxPxSifFrk;-kMfQjtK08u-{0#G|HSD}c>P${|68x0a_>*}`eVL+ zIlTRTp76WfPpeMg=InGeF>DAeDM=i^I+j>k#+S+5;!+)moB z-_jo5cr|IioV4HQwNo26k@l;%w96Z>A?+U^?e}=?^u{~Ldf3{o*zFFM|NSm@Kl77c zkok$b^S7lxQ2&(OpYZj68Rp07M~^$$|IYl`_xJk4AMLLV0R2CP`EmLw_x@zB|6yOh z{7>8O|02wf(@%fJ>7U)XU-`!(9xe(ZjfbL_tnS02Fqz5eizefFVqf1AvY-A}pq=X?E@uU`)J z-yg&}yGiKWe#%}yn}q&ce>)!cXYKVv+Ru9J?)rJzmiF+*t4RATr2R&(o!WR0X@AR> zcG;dUw1#ycj_g+#+4Rg409!z$zkUz9@_S2vp#EdKKik*;Nv|KP7lhx!j(pzQAO4Qh zpY8Pzkp0T;r`-EZaG^;_CyM-TXCcVBVZX*}Ps-~8Q{b_MTq@AdT4`#k+H8?g1;k@M)kgQnfz>eH|8 z^Yoi+$kwk$&!c}0#_j%2pFVM)Cy%qVtxu%Rqi+mG?EYk*JiE`62ibqJPxkGn_j&tS*4FQZ!g==FLEY}p_w5h&dFwCxGkgEYpJ#s=WbOW3-}<=E*+WlkR_||*#qYi-mf>+^>gPs+${Ti@geAhI+Ydkv!UxV!!=NiwN@qJ(K zI&9DQuWS0R^XwXY9o7H5dH;0@-*wo&Iq&m4I|g5e?HvDgtLM8;iR}2i&0lZ+iq`P@ ztY8g+-u#TpF;Dil+ZvwNeu}i8#qDV0jlT99y!J3?Y+n0Kr2R(RPHnu?*Zu~tT?Wm; zYyVf$eh+S^H$K1lUa$S1y>FqH8`QCMY{oQ_E?>el%_g|OruIuUXF#lVh*X&&v^IeDa`SU){)7xSG)h*Y}?tGo1 z?)bdTANS@TG<;0gO+tszw)rRRSWoHA|Lwl^>wWY8YG3>1zWKk&*M7Bc{$Jy3|A24) z-$CYiYrEoa$NR#1Z(o4<&k#OGp7h;*4ai>KHKX1&p8SP*SKMnnDeU{c-gQ_G`>z}I zUDuPxFz@}(8}nZ$_^!ip`Fzjo$!C~%)OX#Q|GJ<1uETPAr{`@x;+yw>0s04Or2QMd zdH*9{`+#rWPy5;r`R4tEuYJuo?=SJSU*Vhg8+`2_@y+|YV1Bo?EB~Zb|eW5qL zv}S+*-oEd@v;P^+Rg7_f`0U{9IK@=mvt!zF{EBqY^7>=o(|696&v^ZD(r^2UuJ?RJ z*-e?~M!zDt9K@%^L;K)nd-F4harS(OWh$Zu`fzuxkk22E7L91MSd2DMsT34=t};+A zDZx_ku&5ZKs0!-jR<+lS?Uq`UY9%+jM{MK6MYHuwpiPb(Tgb;l#vUmn-9Y7IrsaJ}Hr=s5>!FV9lTS z`tQZ-aB}lsk%}Up;22rtR1K+*J#vm}KKkHDi*+&-om`Xg35ur!IV;RYrQ$Hd4zs2Z z6WcUhs0%TIQ|Ue*KTo??LR^qhQS(v!vQH^FA>GGbZxw9lO?ANf8#<<70oajv6T$6veo zZHW0GYr9J9nC!-5WNkl5+F$Oq4{m&&wEsQvlU?um$+8=tB<<(6`11xgK7scFs4Zac z1rmy*JG#q|?Hh_4p-?;?lAtaQ!yKk5g9Zq#P?8mc92X287I;Gtc!5vE;>Zexv^8A{ zu#1u?@st=pbzx=nvIexj_EA+Jm{mTQSviysjy5iv54lcZOVezd8XJ7ik zzC}%6_4M1^$jA5htzr`I@(=hm{)he~((q~+=&D9UH$#XE>3Wa>EK&rC^^cxwH(~8! z9)0v2;H-H|&OYy&u=vV97&%E2bGj9`idF60?$N{c+Kb9oGGRq3#jNxS?h4W(9T2ZpDV1Tuyh%}}@7qs5`q(4&I;;`CGQn>h0j=NI zxbByIL!e)OYw_)Wx@8EY?j@zrH0Tp3f@KDNXGTzDIcvm`#L9BYD#7N0C*U!%!*tv& zA==v!>~%S7XR^3Mpx)MLGA$|{FBiBD6B`)5P|FB%#<28gp{g^HvAi5&_-Gt2!@-pD zBheB=Q8N|OjAAAxAkR+yE8u_IPNl8C-tL$E966`9YqFmC%62>Ve|>gt`s)aZ_hRW3 z2i0fPyXKd@Yv}CP+-o|0*WBY9NBZCG@5%eV=Rqdm`Imq8Pwq3?-ZMxn8Ij*Zee#?`Ar37BEP>)d==MwzES@g_xo_k8pk~KbIiv-#e59)=?A;IuBnj_6I7I- zs&XNuV+{xpg>7EKOm(hp^D@$<`53;l)KyenQSf(0BKQk6&Hshx+MVWOJAE7GWvZE~7NT0*F!8s2>J`J+ zZTYs}!)#1=mLfc>Lgm7)X~c8cEUT)L%xbA@G@8u{c$2gl*A^?Cb0l@k=H3R=``)Nk z*~ZM&9a7Ac(}}1WQG!`x3n$YQZ^SbZV<0MPF~LawqMw(2K8`zG9|vtQJNZy=aQo4j zz;+)=+2D1X^XdnPpY?jr z&zg1owIAE!#~s}G6XM@aduyWO_!(hMFzC~CfG%LYNkSG%qM>di5sxL4K~rIZI@iU@ zQ0$cn)J#A&U*cRFv*{y%v~BP4=g~SUczyi0qh0*a`F;C%`v6@BeIjPWGVbp;zBBPh zJB=Y3izgDkF(h9Z|6Rv`SIyQj?0-S?vh8Dd&h5!R!TKYM_xsP#_uQ(+xHIIT9mxt z+zYa;FfahZ>M?IwP&xV>^54P3M12nw9;*c*)r|ebE9Rn;Bir^agVe=qH$xAkcOR0x=-i+&04Go(= zSG`VK5Q2mIP7Kz^;~oJywfZT5Nnc&2gVi4=Pra?Xu0``d&)dXf0S%sTcnF zi)Z#P4!`uJSLPRHif3-PwpuQaKJV?9XWAOrE*8yE4`coZ-a|C=N~*_uu=zjy?%dny zm!27U624z;#G|Ac39htRdCkG(zH_AyfRE$Lu(Wqdm5DAvct3ByK z?49SJ|DhhI+IS4%yD|SWsA-QNlIQc+QdemkZ=>1^1Z(ww=<0c{8>N1#ZG`>Tjhyc~ zbt6QL?8omDq&`f2oBkq}j(ea2+~W>F=J#BHOgo{Oghwk7$%TRnb0(9@szouvCdr2MKPB#{hrwS}9BjJo}q|OwO5vj28Yo#pK zY@cpJ30io^$KW-I@ecrFb|$Fzs{GaldPd77O)iQ*876cFaU~rUwPf&GlX)FUR)54UF8koqQ~zeOj%0f|nC=qPxN5(=?$m=bU+rY!+zaj;rlxHk2i*73vpI;CTH;^UzR>=S_` zr!JX@6s;O>>XUC&-`F_Nc%w=^=i7%~zI*q}4}E+8XFrSAAUfuZ&qB9%4@9H7uE+qV zu5idSG;C_&fpUt$af-r)LV|!*n*hhfV}^8%tjUPKMl?nIK7uUDVn9`1MsfHGd)NeD z9twQ>N+{ZIaIUW;jt4dWd3VDeX_f6)0pPib9>6+&qXDfHt#PJ~-=_xewAi%&dfCBi zckR0N;QR;SwLUm+`*H39FUls)53sCn)ik)n(U5rGE?Oe7~ zj8K{MXvMNBqv_OW)v~IiB(6KQ`BUmabScqQim2W-gI6<5Qn}hJ=dVtdbS`sk2*q9n zsXkaNL6Egwp#;kx>pZGT-uL$tMlx?1snQ=hzc=o5{s_gabPj7~xvjqu;?Xpg>8I$I z5gVh3^}Bs&6|WU3-Bz)#`XIxR*vj^|@awvoxj)XXr|>*eXZrDTWg_K*47bKdn0>TTIZ+mQ9_ za3>;1zBEi#hyS2i%+61ho5jrh)WF8yWrw|fy=6DH;AgpY-X5D5{{~G`e@1-{v1sIe z#Cp|EpR^?#6QC)?(%4L3QM`GsbB@C6;L&p`sJQ^oRl#;Ab>YMd?j5~jCGk&xpZ#<4 z%s)fZ)E(3p@H10gk=!5Xdji&yiJlBb>%{jbuKYyj4(h}1?fCvE-aHrZ+GkL)t799I zUT2Vj=U!ZjAajXL>BuC^;_oF0M?o4zz0otEI zev>o@{QIe{jcH**ShfK_0A3lQv}GqJLUd9b0Fa@Z2kFnLq%tw&OAHK{X~vY8Vy&je zgqv0Lddz`yb|IkVBcw)0^W0W^k!@KFJq99)qywaMR+Q>=b{X}(!<}hkaBn?TONPv3 zx|$3bmj>dxrUU{BO;ad+YPNKIu{AjdKPReFT`Ns^||nnvD>&ylt*UvWv4qc1+7vphNyS7S66GX zT{BbWzr8^&lm~QszW)->*>~~y(&);&d5sD<*vbL7auZEp%T>FYF2NSSe|)K%1|S9$ zGtFQ;j&w?Af+j-YWbCXchB=swcC$Afr|p7g=iJni(^P*kCNdL{+KFEQOTqDj(-$t5 zI(kg4TSh6V%wC|R!=I5~$A+mVgU#WY-LlvgBvy_^(&<3$!odk`$ford3IDwWB~TT8 zv70Z)qA|3bh!MCCg(NmZGBe~g$019}bU=wrCw0JdQjRo8s#g`=mV9hgdd(GD%66*;4HF9D9~9t42!OQ_U~8 zn^09|XDsgsa4e{Ey<$|rs0GeLa2y-`;^3j@&2pLPPBj#%$f zswD%(2N;sIT}`uziMkMw8s?}Z6DH9`$hqw>XLh~u z3D+X*D+g9_=ntTo6T~eB*5NEgO=kww7O3wbS)_b5DzZk_q2o`*Ymcad`6OY?5)JeNIYjPwc{0W-BdgeK!Y_3x_8NcWj#bPpPuLT0KTrC%H$nSLzrczn0><<+}$m6YgH-+|u7!<;y zH|i~US!>7}@@h64Clc|wQYz^(Jq?V0ra})c*uw@dQDkvNeehD3!|>Nv-eu5JZPxD^ z*hY=Q8bz1yslPSYlA&)>>8wDG&v|0K{@jq4<$}q)vip@=#VN+lO^EB={cEopO7y9k zkW3`%rIhoVfp1uC%v1iayV89jhrq98ZB}mIKBeI;sEytY^_bnh+GKGayU;uG|^oE=?=F`i`PF@BSNb_+1FGN z!zWR*WX3Uk5;bP4`;)OZ2ygSf!THwQ7VTE&+kE7c{iK`OKXsySXzaSaq0x`t-&Y^G zt~@mQ*c7FeQL;t|kTt?M`c%VRrABd82n1b?ft7A2W&&{DC+tpo;X94>gqZ%!j^ojw z&!nV=hQ}GxfO%3;VlltJurf6{P_NtV2n{rX<5P@}i4RQ;M~5G0zQ`~lIboP#X4sWk zSGHN!xjN>$1eRTM7lV2fM`}-J(983ZT9*iW?kl5RhRX|2jT-90dx!zu8yt;x3S=VU zs)ZW#&U2Co@lt`d#_=@*4mw@ivZG!hnTk8gqj3lC91^$ls_UlnLi;C9`D%YpDlXYd zJM;O`wA(2R2|I*P;A;Hp5obo8a$6@ko5iH2N33fNT30-B-L;AcY8uOk&zkk`7fM6li;gcZCX6vNK>(PR-;D)p&r_-9t z;;{tNQ<+$%oM9{(OU9|itS-lt({OlA$!ymGFe&j=bx#sBmLYYB zWduj|P-9-$^6bG7WI=c5-3f@rW@;acHtI#ki{dZX>G91Xet+PPyY}b(i zYEpOV=PZWTY=f{yVLui~QTLjle8!g>45v#0+pD(ais7`Vc^f^wBT3f^?GyEe$)QMs z&&~fBGoxFIo={;hu;-5_GvjqHKPIbz!f?!zFCXi_V}ls+iT20<_ysh9XC!8VuH~a- zEnh&NZ}@I2;Qj(m6tG;tS7mR=GT|(~GJ_$?MdJ!rm&~qEt5_rdkVQ;Cf{StB(v63nn}cb$Yo_= z{0R2Yj;k)bJTU!N^sy2lz#VlU%<`Y3COjcu1_Tsdc{3U{uPN&C{PfW6G)|*bdv68VyXy?PO4mc%( zogB(fbk+?s)*P9+R!z?nlNY@?u_TQjm5@j&$dHb2CoiRK_6!3MSKC@M@B>$l^b5( z;V4Hcc~fu!G8uEoPxR(1Df)wwckgbCwJ zKaJ7DSvYc2RjUlVoizt0^S#pnEwXE{v}Gib7}-)PZW&E%9uA{ zB$A3GdSZjqx%|4pSZr`z-h9}?1)_1k*|y(gBI_W}%)c?K$@(gX`q2=2;3Nu=5xd?U zLK_BZgS7)g1M<+o(9jCSZqI2Eu^9|?`!;^L>4#X1QD+tPLF;7(7xwobT`N z>nj|J*jqgBV_WGHQpjR@c4zk3V@$rtH;PX|fvrA0QOV3w8U#K!Sq(^FD6y%FV zpa$`u)fejEVTeuODo)un*`G?pc|Pe4B!rY;byWi4f>#wpSF9XUa;{_PS|mFc^;7HDZ>(0c*|p;%g=W2;Y>tm_ZJO87MLjT@vU&1$6Oa z6>r2RI|NCU1YY1Xk`hfvi!sI0e)F=x+bNqQc!y?w!)zdQYDa05M}Kt^xpa9&?D)!d z!j6bbp(ke>BCNM9;5LnVuXMov&}B}DuSG6pa@pL0d`8X_QK2`@HxrSFEF_b`rqIh; z5VBZI<|fyZ&E*efvPU97%<0yq1Ww%LYe^@#!^mzYw;VzpdVYR<7j;+CiB3#p8J)1f z-x0j$)!jQA{W3d`duEB&vp5oXLf<|!6a1UAwEDYpW^$#P=Y96563!LsR^D#s-safb z{u_Xq>Fbbb`+ZC@+&AR3md%2qxa-gsSZ<`WTSuel;gcwC?5D*5LxErz zG`KeGk~SvD$%>KTkprVEvw;Fd1w2CJ>EH-r?VX=45VX=$wg<$kLe^?UYOYnkD zz(n)1XurlDlLM)w=5Qoboe_vt!U$9~0(_tl$0N&9F8+l1B5c5;0T+;-TM~5>N)gPr z6TaX;9wNb4(brBQzrIfNb+((lK-I>{*~V2Qt6b@;9H^G%YPnh+D9O#rQ@yY1;M6-iWO zw|(VjmV*5|lwsWRu1dL_D{e}zbSSdoZ2$Gr1a6wcgJTrypER;PEtp%`BvVSFJWo(N<^Vm_~}>ev3j z%2^y1+3i=I(gC9%Iy4_deW-!fppP{iBRjX{=kXmQm8IX!!HxtuTqNcu>(bifTA5h(at?Mwj9vs zDA2)+k$3y8mjvD1m6O9{b<9e)^c{_=(p>)RtM!G*r$Fmwjvm<@F>j9ijOn`r9q|l(cc4$al*9NKhhOCdS<5L} z!5wo--ej*gS$SX%xyR#*JK$9Uk@0|A_PA6=Z9%)xKJ*tLbDwSSfPA+n&NlYW z_QdYJd-fjKw_Dz~d*8lm%+uRFChL`e|5k$kh9;V9dap4A^05h!&nI5FXYam)yZ3Yj z@zwVcLHusdcJl1Ba}()^s~2{}e6f7tgu6^{EY}$?Z$AEybkyUQnx(J#y?YP8bD5dD z{k0`J6wMt|K_Z7juWm;tKUap4W5>PK1A{=lEeeScp zw7(+IUpK&+U*~}?!UPE?RDlzE(MHAvlmEop$+ZWjCgiD!si}4Gk+N)3$D7e;s@_!9 zYEvvUQ|rt&o6tlYho&djP92<>JQ5#~%OmB`U@L!ORV#GdW^P#zp~DcWqO!QR=$r$= z_LgUaFr&lEV)_#MKiEC*6$9a>X~Ld6985PofkWK<@MYms)?dDSVYL3jvV9N_oDGr;}CD*lpekF6hZmaB8355 z@v8lU^Lz`^jX1;GDMP)Tc0*9(P5GLLUD`m(KOo!Gu|(~%s?QlNuDqhQep`Ii-gs_R zU)-kDLxq)jrGWp^=j0VWHD2@!jx|m(IliO6c*FI3rh9g58ri?8*gjNPf9;@8&W>-& zl=~0^wzl|N)E>@s^;7U7 zd^Rd^wc~x=u&QH5KDPDU-+TAgk1_i%^fPx~IKrH!?|l;Fw^q{kiL1$P*)4V&ZzU6Z z7b-Pm2X8WAo89gfF_J`#O%6ifCAwEmDEHgnqI63eSp^le2&SIPF~rlgY&ve2%<;=M zZAwnJ-?7f(a;(KexvBg6*Zk4L@143ZwEDz0FRc4Fpc4$j_o65&pkXxLh>$+$>kIbq z{AfKm65}{eUxGDxQGd~!CgKO8IxFzvRjpS@Q(fPtrXsqA1E?SZr6Db8;aGk-fTFU?wr@d*>FzuN5!zO6-kHlqA%(S`v6;h=4z%ucuoTRuF5_u z;Uoy%4$&kecOc+)gK4moN+#Uyh)U?n0m`hf27p6XF}V9qnQrnL(K|qcgD?Y+@uEE) zr!U&ElaG{EmznQ4(Yz1;V?j@0cO>rv z8tFs386Wj~hv>;I!GS7Q4xL7gItj( zPp^~i-Eva;+b!ecuaS;#`MmV^TgLJIYY(hF7}!mZq~39anLNX~Gp6fiPS1o%&7;Xt zay>z=dyVU7=yfeVihygx@r(EtI*v%QFdavwzOpo+DI_Dld9(ih_uR}CIL?mI`v}V+ z_m${)GbczNk-Hvaf7-nd$}=PBNrpvc!YN8;;8xI^*OY{mIEUlsHsf11xBKCK1mzm{ zV-sRbq~ufN{?aK@2TdaPlhV)OTQ2+*fhxs{Jop$sy;*M$GVp@uIL3?_v&96@RiKI` z`T`C>7{D){0~pA!kw-iIX8ayU*gR{deOE0R&q?rOq^j^#octDrqw{;@IUYqC4vURL zEW?{@m}97|LrJeLZD_(M0UCRbHn&qyyI+?j5b2E<@zaDRpcZ7@nan0c`|lJ`H{p$= zSW{AzlG+Yv!RAMFdScKqQjc3GJ;AeP6T_NF0hGyND4?&bCZu5ofQEmByk7Fbb2@!J zP5RS@0u8&(YQ`qchRFyl>A!ob1mv3n)U=eQXz;T*PP&+U&b9Bsrytqe`F)*EX*pIK zDaVRU78a^-iq-)tfuS72*~#a{V?bD&p|E}?bm7NLXto@v4@J~&F>|CcHah`>0--mj z3T4qcRR@5mwN7dH7Fwsxq`24Wn9}hur+uUx&c*`SLXBWxK=0^7V*uI*!$WUhKR)!! z%|;ow%(l(KnaOO%a&%}J_|oB3g)&lA!1x%9VSSX5x^&CvwhQruiD8S~#_9vKszZGW zI$1AAZx@tw%jRxvE<6M%(S8G3q2thof(_mRwXt!`RkXNqy@3A!n_8qC0-giuh5HPJ2DW_W}eKe33^2lOmtaI8} z)rnCrOM%L1dT9@A2EGN=`X%#P;2rvSh|kuGBSRUJ5k@#jhc+vewNkdDXo}8ypm|T@ zL!?@?@1Rtpj1b^Nm?+2CY$ik-2d&d5b~PO)p7rn_gD?0i#Bww1b$T|3hbA;gltL@gfJ2vOi3ngNHwuehP6`z{zV~I`` z(8~l^9a9(>v*q0~ive$EI15YG0cIQ4`>3i9cbyqhe(a&O)FIF(k(YdA=4HEOb=z;Z z2^>#2D(e*NW*g#+UN`s=j1!71P!RNf)tG8YU5`PB9b?B{@-eTSQ)9-MtDf%G*GeWj zL_K`Klm!*l+dn&PjWWRdVGaUOf*^SanEBj!&nO8PFK4%!c%UX4POH?R^8rmSi~IrC zgf7}lr$PA8zVFnl+jfCRcGhOLTAXIVN{U3CCgTnf&~n2%ch~f`Q;zJ=8QA7Wpx3+Y zHu%JByGe)Jd0qIRMA~h)G3|yKZ2;sD2Pum{c#qy{G-uw{N2SfokxH9+3mN5vH&^Gh z8!MV#7WsqeleV1HOmBA^VwrU6wW!^KnFq%=Eb5T@oOY9PNA*6}DCO&ApQB6-kbMNY z90(uHlNUVT&j(2!Mzom;BOWR{2SfuTsnYXm;0UT543)CiVw;9CH6>N2Q@ zzG17udXm0PUXM1R%h3*WHQIx&LD!-E=qB_AbO7Cnj-WT8{uX@~ zeINY@{RI6p`UQFc{RaIG&0rQ=Fpov-!72{oC{ExE?!hHo#Wg&P$MI^s7O%&f@Z~yH z&F!t)CDP^v*K7Yp*FDSR)&861QL@V{du+dP4ryQZfBaG=7Hjt|x_a4v^;J6JGRusv zh3B^~aeeMNdu(1ZvmkZ*GI`6T5SpID^Z$E|-(iG2WENA&$6|cfE|E6>e|Eoz2pLo> zdhtifET+wuGl>4*xM^){E)_GsTw=7{w#@b0v)OEB!T0U|fpRW(ojvxFZ|*-LGBIf1 z%>QC6%$;O>X=uC=GW*4-pZp=&Zcl_zT(+Z7$Q%`q`OW&vDL38KuY!^l?8}mLeYB$> z4sQS>tSYdUBAbH1tr*f%K*LTIHb#QjYP^7<9P|MejRri&P*MfX!LGQx-jGy{Y0o(IYGV=GK8&R$y?^(Hf zRqx7Gt5){1$bQAlh-(!ud}X*yI+ISsE$W~e&sfN#wZYmT_!0s0P%k+r*_?&*GXBWGWHvk5ABptC z_dulm1-mHPc~ShBl{0g)&2A>g``w}}`OJb~_DQnnULVP`N$eH{7ZI$bpw}%(lHm3R zB`1dX%5I!w^Ip5mnay?^Idb^LxxYYuQ4o3kS8g-Q;C|Aq*zBe&E6bH(^(m&s!eg~Q?Y^^No(=jYGp7F`S7ywDeh z61ecI%)Y0jw#=SRw03H=S^CIp>5X`VkU4R5`9tDuCEUL};mt@iQC+JbDgPB_P^_>B{NwaKh#v#zq3 zhbw&(?c4C#ZGJTz3#dU2_HQVLs|kh@8bY6HxN@K;o&^}Q03)c7HZCXEHrTAzoe&kC zx7#I&Us0>2i^X&*uBA2i;DBeqsMS51Rn5eCv}cYOO`3PpDK zIGbIt^1P(Sy3{>{J>P|uE_jy*6;%D_1tK?7cUm=1jnzGe;Y)*ze-!HtIxXDmuei-@ zQ={z*FAroZAsFgKpv;MBYqS{cQvM2m)DOrV5<*p z#4Z(W41|KA1L1%i4ur!|Py-?K))b;{uPA!G9=WMRf}!xiK=6oiSoHhJr9(Dz%W@YH zo2V|x5*l&mpVy5I=c|Bdv+5rUEk_2$Kse#M&H;KI(SZ1qS3BgR6nMSZa<0AglfjY6r@lpmJXB)a=B10SGtX>1e%$Q*n6|2X;NRYR6bZJ z9*M=mt>oRkE$Q&Q<~>j2D9_Pyp<447Yu((oEv-6F+d9x`t1Sv`-M6H^eBXNf!;N#B zzKn|e6}pXqj)m@fZw2VW=LiIbRdmjdX(O6Z_gAF3Z%QIl8H zR;(E5LN!u|H1m0-SsF|x{rq56u0wV@*ge=88kxLf`A#afxW7b3P;Gw<1sX5Pi9 zqGvv3;FqU{=eY=y?SH$3o}FtEpv&pMw~y+&?(mXo106#_6eryN$;J&jjxoS-R@n+* zWnfGtQpwbTbV5!OW|Zw>nf1m)3K?x7h0X&a8C!~^HGP?6Dt$1KJmT@Te6Dz035mf& zvNE3zy9)05`7(O#=a<5G9)T{@aKG3X9J+{F`|B4C#)X>fX`K#dG0USO`u0iWnfU>= z7xEYe&(x!eLch;~qYp?wA$iaSxIpg&Un`AW0zgbPdqI_r^---h02*-bDfAW&6no@i zPqA3;0$t9F%}hM*%VwiZx3AP&C?4$TJrZw;VkqCr9169R`xcVy63Wy|6YL^Lm()YN z7_=W*Ldo#PMetr+jqoV~a)&POBpAC)%I(ILCg7f?_WT6e^UFg!7h8=WXuh_HO~r_PgkMEkThu?)cfPh>7&oH!w^ssRlxeNNQfCMF~H7kgFqnmX5r}0 zH>2gInoO$EXg}|CI1dQCOc=J%KWjZvb);IdTo7By6NOgjxKlXDJB}>2o>+iiXNK*- zMrD%@s8kEkvtVW=$&T;G4t}*tt-tG`#XHAnB1aMXyPioopw3n3zsVQS_4((|y%+wH z@dcgngg@6sOyHayz~1CS2QZFOq=VIFw%&{t3bAZ< zRQ4*~1F9^mvZ{_+JWkHJ*!pTjDYnAlL0_wIVz8Au?o|)U$`O;LwS@82qS5~B^JgwH zM|Cwh7tt=h_`Gy!*y~G8Rm;-yMW(JxQ1mPhfOYEtT8$n%iNouZr!v1LOh8VJ#aaU=##)8rk?6rt z_{b6p^9#7bv)w6cX}++Gs{G4C`K!xKTFU~xLy+$XoJ~D}&=xfD}&rV`pjrWVNl1gbA9=uT5 z{pA6?K)3y-OLC0)+UzGTjVIT&m1PZn3^qMq0-pSxh6HHlD5e^U=WfbI{H-DBEqo8GRP99K4Fd9oQWZ*4jp8=7W3k58-H$xYMJrdIU6t6S3D40{ma zBdCMz9LpXZW@=uq+w_1(wl6P-Hu#=2FKtlZxg_-L5+(=N(>`!q+{)n0(p__6kpTj; z|1Vg#3f2a$Mb-xG_bk(GcyzHXf`{(6{SY6<7nmQrIn!u(KS_TV--FLF&$&5tXA;tX zP14_od~~Y>>1WCPzoO~e=>4Zj{_}9ZX^h@~4j*RhG(Aq!|3uOz=KCbwpy{9Edl-@C zuar9Z9R2-OAxJ-m-(=KhbuXk}J+l|zjlSXre{GMpFQaw7dFDEN9eTep_Y`G9e42fdFxYZ{w*+_<)t+}EVn#%DfgT)U3`?$d7YyVm*L zHSLGN2R^GV~{>*%vkzg07j7}su?d9`tEb*FxveLm8zN4x3OH2r?M$C90Sf$`w; zbk&nZV~w!aW(tL3Y0Rc=X-P`kSj6N}E|dtfvVc+Pxo1kx(G5I8)O6d~U9Y>Isg|B` zJ=0en$Eu~)4~pix?S^VZrc$D~GE1-7U;pdBdVC?(CMWz#uUiU-)83#LM?^(|eVd>D z`q%&ZDX$iec^yGT;2lLNy64qK>hFW3RV zwqcdX$Qkmf;0G)1XPKX0a95b-h1&J#ea&|{jx z+XS+*ogd@qJoP0^aMV2y>5;t1e^sE4t}`9KRX9WA9g!UT53HFHhvLKGw3X0xEj+Yh zEUv}_9_!V7Uv}-5hqkV+zpjkW@@`x4>a3F8l(5PCd$QBh>+-Qx>vz_6JzQvihuPo$ zmsM|`plxoF!z$)UWFr#SGqA#a3haN};2haOPBId9l*zaJXEP@n3ORA^B?py=8XLW; z?DeW%y7qO_weL?GG4Qx1;bA+@+p%PK+AotOStcL9nX@6}5oryr7mXIbDn(8ZqKv`9S?MxxT!sV)$q30pgE0SmgOEnJsYF)TF9gnMmO!cK+ zKXV1vX1+=0e9+z{1-L{Dyf1K_C!+>z8J;`cS5~XEqZ9EA>=M1G;8NhZXDT}J0OjCeZgR*UOW2v% z_$EFpl={i@4aSPUKw z(9E0gr)k75p)8jPlC+WYV=>|>jB=?Wd^lq9)B>#sry_cr{9NmOJfd8HFuob9A(tme<8nlBeW6iL5J}_;2)CoVVb^v=C}B3%p1rvcN2N~{d7!y6~Bak z$vjSZQl;TFab}B!h#C#nOqL`TlZiz~F=&zns1qu>XHWW|4hB8-x*m{)#$d8s+4I_G zw`KM-kH0f~U++6Z_aGKW8H|6x7K~Uj8&4vh3_Hmxp$(Q89L@BIVVrs4%y%>pa3crj z_5}lezfDwF1Y@THjV9z?3PrlDM$UJ(Q?%oGMC(-Y5S{nE$OE@&^wYy9- z{vQp}M1DU2CQXL5%Tlra0zY#8h&4jpyx$1&$DFPoUl`0!k8frnzyDkE`!MDR#XCjO z#yUg}(bji|?c9hu;6-4c$FC8gC$Z;8!jBk-DhHxI*<XuKQ^DDdQlr!tV_1U!!{q zk#uh%;D-Xf8&z-uy?td+TurwwPJ$EMB_X)W-~n4gmsW(7`3> z5ZswTCfMbzbMAM~cdq=ryL&&q>e*FYySlp8UfsLbS_e?n_`ftTUf}cOn8vPTm{xqG z3;rf!6J)ZjxDDN@rq+!&MsHOp2YJvk1XF-CrW|v!cFTp zaVM@n?($B{1YwLb{{CF1`SGfIxG~ZZTfjF3cKmRJ!j!)dH=b67#(*2pPVPUQaa&&Z zVhD2fakvvsR*tIKiVapQUZ6??H#ZuLi3I*&{zcxt$Qc7y7?TPoOqE(5u<0=H0DojZ z3@VD%)~;=LTe!7~ryFWan<$K)`F*MvD5UV6lNoX5`la`$e9$a`@>MludDjUwu7iA+ z$PZpQm?Do7s$n^+X+ojP!|@a0T=+SE5PJCR5@PpYx0b=!dNMKcRA-dRx2{a8mmlyj z28g%A{+|)y-F1@ziDF?X%QHG<3iH~d9RN705Zde$b8flXIw+h`&9?`=)A^jwzv`Ny zV#_K09kYJOWhll$Qhh*#?`o9H8Jty}4N+{CR2S0WEaNvr_-+qEq_viGi8F7J2H zCl;-hz)2kHmMdR0kYf5Kds0D~k9!=s@K?x1p5FLPxT5mwE9~T{F~6uNjQ)nIZq=Ft zv7y@JCu2Jao_!L)>SzDlDdB4{Ts>HtAuw`kGj{66T57lr!#=Epc z{>y=kfnhYOSb&%R&=BU)&*=KdwY$qOuPhUq+%t3vmLxCann_|DI1=6F@Gt6EnnwmC zfgaTKH2II`v0=b$DE)+>1r3+*R!;DlmW&9La*d6aTv{LOG%rU|cASN}}RnTulxcz{C4UU_;r z2T91fP@aDKVoLXO{BRMeeDR^K2HtQkPWg$epx)x443480;VhZBl(meuD}9qKJ{68v z1W28-pbNPR_cOiG`38SA&j;=I)1O(OSWafFADeBd*Y7U`>plfPc6B@8HC8(UPITpd zn2Z1-PkpR;9|=U^!LarPW~iiP&aljX7l({4aF(#V z$jUiWO~#s@ZI15}IV-I$9s7izZRlZsLMHMsPip`WMmL_5CeHXQSyto{wACK7dF8BC zK5S=|%h$V@s~~sMeS2-(7R+`Ugr46}6S-T4Ufi?@9kmF!i9OW~g}$Hq2B;-p>7?&L zmiPfNc@>pZq^5b&g*^pTPW+{OE~T1i>nGyS^qX!?@%6*C_n^0r&xj=2z!Fw`6ZT?u zG)z!FB~IDZ6-=c1Zphs$afEO*e~6}JN5SdGlPYp(VEoASYj|h8e9x``ns$?%^ydW3tFW7Mj!*rJUGNEI-@O^Dt6{R~o(Gf3lNM{~BfbCcu;2XOu(S-qVaf99GDF3O&6 z+2pSe!h{Z^!a0*3R(vzTPbSl>!II*3&mceevF%f#v$*}H80T{tDtzjO3VL;30*~m1 zcRWVCh$e}gEi^BVKiFB%GJt$L39J>5%Y&a({B_BVIoW<8hm003{QfQ5q=-*|6Xg5|>D-S+TJBdu{$a{*Xg}44rIw9H z3v@|VgAeK5Qwavm3b;A6S<*8;Ma2v&uYF?#9A4w7b}icKyBmQu^H}2CG|S$=F`KTv zda#Xu%v@mqxTZBlMrq^n%$@@4xON*h2$e<%6rDI@;aXf2{Bv(X#m#YRk{pG{np^o5w~V# zuPQmq^230rhpK^G*5o8}G2ayjEwgvJ`nl;U#CZm%p34iK>e0Tr)q!HHErp*tTtuh3 z*V5|5YMsj!YUyf;yH`Mwzc?as8aNi6_?1kt;eqRuHLtO=*UidyxQi?j?=sB7KT(!o?ij#-%dgcnpvj>@| zsBj0dqGA@z)lD5kx`Gt#TMBLGZGN6un?kgW!a|DK6x!g%oOc~RDWt#22olBT%tYoJ z4%lO#A7$q3I+k&y`@4}74KeEGgnbB|#}{O7n~lM@mm!^B%OR{Uefi;L_<*m(d39#4(mU;a z_vBytTAB!0zU}7%sNcF|W(&TuKcF8a1TZCi^nUJR{E|(R~#AJ!+n|IC>E`N z_eQVHTjl9{-fKPUpRe5{9Y3ngJ)_p;tb;Wn6Nj0pbB!^_iS{U-&_k6Z9CrbxvWP0#$Lhk+2 ze!u3e<2AsXiX$(-EDLpK(1pzM>(5U8Wgwz~EVsEbh8TVvQ!+}i%L6fq#y_b9$6*MR zuhsN_mM|=L9>!hrsa?~mqd}6DU1n{brdv@GE?(zwBQa6`Mim+r)APRnUD$w$oc&7U z*mseoIt+G9F=eG<%r0-u3K_M}ZboB)7o(mC<*Kt6zYphBHA2P-1+^@sIVu7t$@)M2bUM0LiT&RlFD++^po!=QW%akXaDP> znGl_ry;TB^`<=O-!}C3C(0qS1a6dok-v1tAvx}vJN<1Seb<3|rY7lTq&Y6d2YR_4( zszi`E%Vi{4b2oR8S*2CfnvAhIrE!mE?M__1oXslI1JyWcb600AOdMHbH<#&+*ElV5 zA7@=p{Iy1IE?oH)D?pL0O2A`Az`f|1SrL`l;WqK!TC+KGWzEs7jn5$Sn?hEKLUt@D zi`%+}%%)A?cgCf)0q=k^U-E>vbyKE!S(cr30Pp&VsW+cUX6_`1wN7((rkOWD$lRk) z=oh8qnLv5Q^aR}=sYi*>Z$oDedT#j)z(mNN3^WuzL+PZ-ACZYZDY6&f5#KrZ;0WaD z&%m5m*mHwcbdF5$t?voWS>*BgK{NaYMIG{Z)Us_R_N~+WW<+iB083fM&|IO79&=+J z&TMgLDSVaE**g1crUjaEKXVpT8FXT{m(^66A*sm^od|@6>6sE|hFPmMx37$^Sx*7( zvw|jo*1^zJ_{f^1A|l2oOzdK9XgfS&wIWy8wgaAy6<3hdLW<9>T5S7T|9e_dsU4Yq zT3Ye09jgA!gEg=`)z(TsOuKZ!)=NKhv82`3Nk3w-^x8IP^@{*saE6ZETXGc&O~#jW zRQOHvvKrAEIh3p41o&w(aP4?kbJ_~n?N}Anzkf<8!?Lo&iYs+%Y3-acRQnC~T}^ur zmdTR&J!6?Ar8$|u#|ce>XOzv{@a1|JP}woAW_lMI*#WX7yEWsjKLM`Q^Q<*EuQfuf zvqkK1uICVlCK>lMS!N7ZL&rWBvS81OW~pJ?(ySFB-xLPfNvv)fN}+>8Jn^WM zBfy28q*SW%;3Q8%DwR=iqbDVm8Y4K$^G&XDIk?i3JXh5QoasrNtFjO7^rX&JBLRnb z;u|TagG)Whj8t{Nsh&heDofy2Pbwod065N*U|qQ#T8Isv0;MMkuB-4Q_@}im7peV_~V^TFjXvLICxa5{`ANM#e;4x~c2p*OD!SyhTN7Z0(K8)m1i zqRHKpoohpWdBeSHqo{e49v%7U9lsdz#sge4Sq*n3^G2b5 zh@5;jSM(dnw~$^xnvL|^okuu=cp@$&6pkmJg8Pz=?UnfV1V}NQR6H$VX9tcVo}>mz zh7*dXs_o3dvBZ<7A*ITkrNUFf76%3xib#O==)v|sfLsHrPc2o!_oSZ zTp-zS;=WXuo!@YrzT|UAH=MdJ{e0&hjtESofkeRZfhjaQqwv?j@A;5&I2kZ4e`g<# z3QRJAq{E4TsU|y1aBN`mCZrus1x(-ExrHM?B}zaN-~>-8589W*^YHd%_y)E$H#;izpK=Xy__ZlqCVQbM;M>Sq(II z6)Va*4T4^M?P1~sjbBCgu+)Q&ufks@GwAnKd=KkO+^4IMKqeZ{=v7o8OFn4-DlCxM z1hjM&7s$E^y1fd0V3Gh$U&TDI^n=c?A|9B7L7P_z57lxCda_!`liS zUf<&9hdte>N|g@2ccpODjvq92<#5!q9z=J2udAs(sOrk9t8+NW>PoAtJwE8_%B!oV zI0)}bieHRt)s!Y*jMP7!tr+2}i+3){KC z9u-XSl4KK1=dwn{m7kRc9E*3=pOxPqBl;Imm!Kch`BzYvMI7V% zmr$3=A9MTHP?wJ$zxFT6D`7ll_OHq-D?cXlFUu>nITrG-%PZeMM&0x7Rp*?InGD(k z_R4TBjKkb}rRwLaVfMXp^$W)^|6WO#`D~bVudK_$Z^= z1_G)eEh07w(!d8LQ{4i7FtIJJCrUWF9Eu#;%L<;Flt`Dp!P2zy$83ld(s&ydF=lRV zl?mX|)*2s21j<7~FIKn|%kY zfS4N#6=wD|0O0VG^!(as+Z#N&sm&&Bj_@26nADntPZzZ3Oq1Mu4ChJtxCYh*G-To4 zbQf9#LVKRdBwc&jB_Ex^m#t^5{Wo|yTeY12$BcaSoC5Xv|Hu@E6O-&(RlBomeLa@Z zz27-++LUFW415wZ4t;;Zw+ZgiVtPBTwmt+qHwgF4i(;tW*fRz2D?8T}t{Dzl)`vHd zl=)V(INRpWw#22C;t@nD{3J9d=MK%dE<)~mDRuwnl8mijnZ-#viI*auGxjy^&5(mj9EmM4B_)+rs0G0w$X>4yb<3MG<-J{pRG| zvO>eZh^W5g<#WOt5mX??1K}O>h2~cI54DhdB#Hk@McE$_La!^Zz#j zQ34r=_JDOqcEM{jz`bF#d5lJhDu(Qj2E#fa1M?Qxe3<@{hbo5YPYh!_&;vIgh{v40 z048wJPHEmmp(k5(e>_cQB&M_H76Z^Yn_ms{>*6a}XWO2787Xs8?yt7^-FU^3+&=}2 zLNh)n)0g4RMUu(500!wUq_-k|;D*p3NuU5|$suVgNUk22BD9i1P624*%lqmi&(dnTQ4B$$Mz(m?Px}M0`R# z$$tY=jW4o@#HhN2{~=JAHX;%SV)mhKesvjW-!iyhzfzrZjk8zM>OFyPm*y#RQSYNPl;iS>hhTN8ushUPHdniB0@n=3C%i zWWEsOT=u7pOrYGqApDwa(MC7lEa*j$zBm7;S+rR$e7w<-c_h*ZmYp}jzt;KrP-PBe z=k8C-Fj1PAriAj2K1^^+c)Wk4~G#}-Y)9z@D-Hg%r(*T^nYueH+ai~6GBEN86f4})k*VXX}f!~%KO=c|Riu#Nm0WVvFrWh~5WGc#UCi{}Tg19X9*L2KRr zq-u70>-7R<%?W&KzbrH~kP~YU4chDKVq;dDnensLgopi$Tt>NjeUZF1J;r>|$^$ zYycDBd%zj{ME{R|_(FsD?+W9;66`O28~@SYJMtvobmC$f4UhZeQp0DmG;ArE`z5o42SxQ&%yMJIOLpb+drmSu}g*y?xl`kDFIB zU9(_x>fixru4AcfwQwE|qB^5j(^);{Ef86I;&N3QOiyn;z{>t~kMQYPhlDOt)kKDz zehsgU4uZYSC(}Y_jy;2FM&UOYw`+tgqx06IB#CiN@Qw4tYrvH!zhY|~C`pdY%!Kb? zTTTq$gfFiNTjp1U08a!(seZ8g+h(VEi^o3lOeYJ!^v#0&QL#4}D<(&IbF(J3uwDNv z#M{PFn|Kn3efqgfuk$&qv+C8+*{Qa_@VfkNdy_}$Gt;e?2twCN z<=)HzB$=!|nALQc(4KOKm?PGLb%&9;+Usr?&r@ShO~0bFF(M~t$vVec#;~eg*xtg? z#a?Hp*kRet`$ZRSHNV)^(>?B^L92P0P>p2MjxnqG{m$6GqFhIBV*kn{XlU{{$Q9l! zou9cm)r*jmzz?RT)El_Eywm=YxI7v8d-~LUH>o+aF~9v#eSbfGU>Mxmdl>M9zx&Wr zw*4`9_CV33($Fb4g>`9m&qnLFp;p}z31xRfS_^5$r)R2f1PeEoLQ7(dCben~DvKpA z=S$GzyOi{gLwmAEwax~%EzmF@TX6#JkJV6;LtAyRt)s{~~UN6;uY7}oSF6R?$mXH|YS9iMJ^tJAAcCZ{WpS%Ft zIv+D@(aGPbb;g8;pA8lk-Vggn+&A-Uw{`K#?X#@E4F@XM;ZpoIIi$Yc{L`Au>oXsW z_$>BE>L^0)&Sa}|KQQHaJy(R%sABIydg@t(5cly}dQpO~VlSo_Zo0Bwxs~HyC(O8X z1OynOx9@0H1zc_=+b65?9a<)<@*jF8Pw^d|Bzk9EiKxJH%N|rUf#uBob19p4W9NLk zYX7$?Fsa6WSW_Lbk7iGU!O}|60{rdGXY5UZ{2cxy(Ld~!{IVO1fcX53faJSsVQOh= zx`k-YN^5OyYGZ0yfeH~0N29GzVu%e%V#r~L3W;LKw8Bs9&9I_M?9J06tO!S~2}ML0 zevel3&z|n7KBlYo0{+v@Mz7z4-<$7vNOAp<*)Ov~)X8uXi zIE_T8ozU7}0}%^{{__n!R>lP_l1AjntAGs;v%CnS#&Dz8FCIkL< zo#OUI9j%DI)oE?cfsoZzkfy8pNTr~@fr&;;y2J5#%`lmnX_Xf+yl8#z&&9RDS+IFP z%gIcOJd?-s#~V`1gn=8sxA-xF_d+K{`@weftzv}5Tx0-xWT88hX!ZEg4g%JhFZT_^ z6b<;b?#2Ey3CM!qiUn&|{fT^7Z&=TCM9X{?FICVhKQ>BTHiXKRnJ0wq365Ix4*RL< zm*}1?XO{SXhpmmfQ}u|-yH!GhqHBS;m-fF6;6qPNkuGe&xaq6o2ejvfa}SH&#(}%M z8QYdShPYv%g2m(gM{?b7ma0Sc^M!eHegZZZlv97QpOb~|^WuN%erfJNpx*e2{63H{NRqb_viEY%-KGJu+DhDt15vp zK1s&iwKK$dV?wMato=%0V@jlB33!&4TIdn-2WbMky8Q!8oWno)^Z8Csvd^XS#!ygC z`n?|w?((#VmDPbEZ6|_9`h2&7?<426;!mMe&C|%yhP7+%SWC7dUbzH6lF=(>))9R> zFO(p0!MA^04|t~eraw&&aJ>yQlF_qtw+x=os^~kooRNKN9JeBTb+&xBJm=QvRt@Qr zvwG+ICO)=KF(BRerFmCQgvk$LS_csr?(JDlQ*u@385@8{8xY;!&9$wOqBHDMPUx%^b|kp8?m~!; zsZs*n8syyoeU|m3%!@+5Jct0SXM^iEf0@vQjJW09Vj$F@Mh7k;-lV8CrP1);^K(u| zhXU80+5TNBV(S%o&Y#r)Rpk^5b8$z9=GUf;{tdcfx;4~n+PK7(HqrCEvPYTp*UCx$ zd!YuiC0N-hX30E`pTbqf8f3`Qn1Y&bQoF~)^T$zk&1Mv2^SC~qs1wN zj+97R%ocD*ebwQyTBaU5C6Drslj)W#GI~2xmt?CglD#lx-P){o>ZmQEv@rFlwfXZY zo0bUG$vqzRnR+5Y6%H0a}x0wv+QbRd^`L&Y8Yr}??vWQRhnyWSFXQW zndV(pN;Fm@m8r$ljA5mX|3xo7Z@tvU=WxZyzbzEm87COUWBJsRrd4%cTdTbam{E0P z-Ed!bbR%?Yv`|~+tmRc*WuUcQb@b2EF0KEhj-I8p`0>~RMh<+M@$S1bBj$t%%yK5- zk$cV?beHSQ`vJ&-()TXFW`0?RriX+X7x-mcPCmeKBmB{5Aw@5uxcT?AClBO~R$?;Z zj!b-F`U)QypTAFX_bwlje%B&nMNhM{^FU9tOVIRo>giFY#kNZd!f)VSseD!OX8ck% zFmn$qq`Dm?8ftUJM*8!U(CCh0)cL}o%hxrSL(bxkP{PjJB@1$AJa*o9oG#zl zGQvKWfYzTe`l9Q%jRTF`p%mX=Z~kn*a9T?^H)W?z?D2hde8IK2)4fb9bQSb~An`Nd z!osm6bN2FPXJ3#u=v+rIQhN3=e#?(CmD(4n+*MzAoAr)r>Z8O1!PD1fUxMIKgFpnA z9V4taNeaZMnoJT3+k^@;v+Nekd2dQ=;!EFMDehCM>1Z^;rU|oTl1pP$iw`~DP8RWH zsf-?c6B<|MwaNA<+5GNHi@D<7ysxm3$tjc<5lHw;%!HQzAo=@cyD6PGgU_yZ<;NI? zXC?LM-|voTWZ!0iV~JZJ+?9x@2Ok)_8eXq2vk{qLwwY73S)luu3ZD!*pGeZ&6w%yY zXg*-6Z7DpwQQNkA8MsSI;~z1C@yWig`$t?Z3?8V1f6!do^n@>60v?d}U8&Ev#Ga?| zBbg(m{)o}V(lbTNfj>qUYw%@_fJYB_x^n6YSP$*9J}k}3bj6o}uRW0`3$mF~XPHCe z=M;DslmWaG%0Q_zT_hP0ScoV1 z5=0)=NASo0v;oW;%o;3ARqNQs%7GP6T#4(F0qdvg+kOUvk1gm`HILT;rEbc38KOqEnY z4frPd*X1CRDYN5CN#U-p`8_vQ);@_wEJkR-)Q-+B$9k`oq+eaebKBJ3+4E{&n>B*? z0z7A@&g*NlILg8#z0ph*KRbI~x_bDBSAL2@4 z&hDF*4XrcWt$POPhmk&f^Rk;(TK;bR5lPRYe%0P}w`|yW{Y{-ukn|ktFTb+x)|Kl% zIVHWH$g>T3cFKK4$B&+A%2nc*|BgrQvOnMh{`7BW5{nN4RTs3O#=vfR`V6~h#-Y{PwXKT z+V+aH6M1&!UGXMW)87y}!EI+r%Jous(Rkq!kXK93P!ml>NlAQK zfT@U`Du0*Yo1c@k26eYk2NjY7rNvR^YcY$-Jf|C!@6Yvk9=j~)87pT`=^$8#?w}C$cV;{TRh9GL?PZv-*_A#OUsi6JC zPiU+a+>*MnPrXb(hw!HY=otIN5fex4O%ve$yc%`n1f5Ax^N-+?u0}bPA+1yHd+z_M zQ7S)8#h7rvE<)_pu;ZDj9EU;n1yTMu0^o~!j6pq>j=61cKSVM5dmNQ$-9JMZBWFT; zdF-c6;3>I&j@`D$s5nS~iY+ z-D~6?Wl1m&=FF;(ebl-4bDg>V+)!?L?#sFT;D?D%?qKf4oF?bX`Ewf3{E<)Yp4{;0 zFGqhjdSUdJi1$ylcdXsHk=&u2I_E`hb*?+t4QeMoxu} z>A4-b`*MA`0gU1x-AMPywDP>?4^}QtLBvet8S{Zha;tJ}7?WxEJoaIKg$yCkw>1r4h}rbDI)^T!36Tx5aI04g`q{b06H|0yKw5qz^2whKL(9MhC$qsRB454mrjgwE3fsl6DI_*snY1CSE@Sr6@I z7e2l6hu6;lYJ818Hlsd1Q~rUI^Rjci)e3kR1$j+YQ6TH6{H)|)dIfD%Q!{)zv^+?6 zNwcL-LSy}b^h4=Qg-vmvVy9x4;wi;z%B9Ndl(#AWT6k~apF*xsFw`0930)H!2rUXN z3Edew6gnFES?G<>yP@|&qhVLrA1(|>!$slBa8tM=ye_;s{6P4*@R!4f!bc*Gh&vLE z6h$f`*G8qNI%| zL?Le|9O@4Bj#0lfv@P^f==-5xgx(DOG4$uKBkT3#KO{ojR5y~zC)GV@&So!obF+j7_BX61TvEji=p+H*DMGUuw!Ri3LjSANcS z&U4Ov&UMayPIpecbNQVU@BHYUqwhTZ&QtF^@y=uKw7fIB5J`((=a`*Ttgd_wkMeOojso0YSaP0C5i?<$Wf>u9sGN?D_9 z#A>t)E8j!36LNPCJwgv-AN*;wa4%%*=jn6wC&?)VXuaf-ypoUZkP0NfWcY0TM zgh#|+xO1dy)9Rg_gB|5%;-Ep_9&2BzFE68mdIP)$_(qbkbq7UqijX~0va{)+L|PM9 zJEBN*E?Y6uJEy<1BM^xU$YInjmo=hpAJNEVg>M)E&GcaSVA-oXcOACU^1+mGMQp{g z#r-3SWyrKs(YbTy{Uf&2NJ*??q~wlsUUcBfk+N7v=SV6B!e-2!s6dRU64qFF=lcZW zV;3)g>Z?MQjfJQa*7u1cxrr0qG$NLb`w6sxLbNXuVOkzMoTcS>7}++bKmQ!2<$r?#ySVb{%uhXIsxp=}>aJ)RiN z9?>MU;eIKg7~s)DK)4HEv9@MJSVz?PM;_6(=5W8j=4C7yY8gwxzK@iH2SuX28=2uE zYkPMf0_K+g{x2j2@(n=wBiad?lpsR&Ax-&u{v~Po)J#xGxN~L4RRn&dP&~*4j+OS$ z>6ExH#ySHeXn8ohxeeuI68vFAYeyusQx4)$^oB>MH{2gv85@X!hqAr>JUHCf^7zh} z7n?C>VZS`uV_Y)-BTxDGhKaZ_--y%>2JA}7gUVwnKTnmPCmy>$7Cmh|I=oXGn=x-E z*Bl!wkit8sjSyHii|N{6ugO;^x*#cIUCUx&Yq)FYvctJ;%Xc2kW_PaZ99-Rmd9X7! zZN<*my#8hkrabZQ4BWxh+i8ZFF~6<648o`FU`!0pIhYm0^A`3WvBE4mJiq^-B-#d$ z5`qmK04dlRUcsHSWnlHr!2xD%a-$>hPmGAz6dI9YQw|DAZ5+|ZRoc3XLyvCA2h87#fKP64 zgdW+@9omgl4VLD^{E>h|mVR<*C}ThYF(@4EKEzUA#p`>t(Y(zm#MQQyM$fxeN$ zNH$$qR^s2*mAh9eDk1QeRW2J`wrAPMva`$7Us)<>iKtvMxMa@~MSuH(zH8e1`sVHF z>6^P}M&F!0)BAe&OzZ1f)YjLzs1++BihIE=RN}DMGvl!0w{vHVXnPlph~bgMJpRtk zSvaB|9-+R4i~0`=@$kUC4?RR}!5JgLdHo~%f&()~y5Y&PXB#{eJm{vjfmDi8V}Bbq zZot2d8^)hg0&#c}2*@Xb4<3G&0}#Ivrwsq^|D-izG?;RKVxKrkgdHWxR(c$1Rk>Zb{2JlJi#1KMtxxe55c06_CdkA6k;daTX=F%X-??*^8Lh59HH~i)BjsKO7d;WiOg%3Rzkv5Of z%{_EAj$=IH==n;h<~UPQ?!uYXAaH<4vl?4PC4e+KaFT8a*aw`(pcN1q_Tmi8Nn}dm z?Cv=t%L*dvFwVVB;qa{nXH&@QLb)?W#08C9o4x{XBj1;AmVhPA*4 zM2+w_p^iztM9s)I8Rbk~O*G{wQ48p6L7FURY}-QA-b~c-98qT(QI`?G^V9<1cplwo z$25dbJ54lwglGn6n}KqA&JoQ5-MwC-IgDWd_0BmqHgrk2NY{sQ7l6iVE)eyH0n|Hy z@&`cIz^ggbfbhHa0Q-oxJ_ewDTQ3o93j^K25P-P5=fm`dwA)V;-GegjsRU5QJt+I0 z=YUg$4HysyW&+4}FY3PcGPanAyB~S(N1po;cK-9d$d3$fI9aK0|goCB~S^V?x%MFhk>(1&sc#5U^Rfe`$5YWQTM;W|18Qou!88{k>^Xme<0m+aGysx z&u59g4EHNm;55-eq&*0FzKSvr)c~mXMTETsIuFA=vV-XBNc;82h+alrub`|~UMKnn z==>(qerqvsiRjy9MBf=A`tBa0qlo{$5kQ(_UYxqa|Dyv$$5GDlFwqI5eQhRinCK@c z|0hUy@)Xg3?t+;Y_5KXyyq+Zbc>w^rezA|}zm60A5_x~sP4vbf(P^Z66J@?NLUiUl z(OLM<9tKVl{TlJVUPtuy9-?>768(1^fd4m@z&WDdt|dATy8kB&!2dscfmeYGM8ER_ z2>%_ze~0kjgTCLt0)WN~WxxsmbzgX$=%NugMf8Uch~BLsx`g;kDEHDZFhcadmx%sU z0CWTEfPF;oA@2QSM1KKIf9VB=fc?O60CoHoW&X`c^moMn9r1rh{0H!VaE|B-!mog~ zQIs|M7;qH00PVpGAUwAb*bkfpF2k@@1}p}Kff3*w3E>4gfOWur;1mf7cN!$5l?H*m zz)|1=2}Kx~4{QSt04D*It3#Yj12(7OsLy*2sljw z>#49-lCV7iyiUTg3wQ-MPr_*>;X+-m9l!{Ha@|PpLA>`c311lrKgtRqtN?WsqMQ)Y zhR%@)50Qw#jcEb6aiC~1iQ--WG$rFCN;&|PS^5}>)Nx!(IZ2`%^;YzgNTcjZq^p9z z>Hvvqq_18JYyprb;{=`{QG@bpkiQ1y*Jgns5_L)d`Rh=A9rD!e1)c+r0vAZsCxHeM z4QN}#3g810jYePxfV54ZqvO+MWf7i5coz9u zk-u#}02u`Y318tpY1yFtu%Izrw zP~WUWz)=8sXCrMd{7^Z?+$|*L!JUtOnC}Hpe%}YU6a~5$3AwS1;7OoOF+Z5D*(`U?W@2g5=*-Qq+7Zg7y?lLAnG1OzGY94 zSbm$NDVp>>zO$=-OHa%m)y* z4Q<|bh{WBf|8A6jH_E>o_1_Jew!^&#&-WYvP6C%n><9zfNZgCG_YIP`|2&BY;sDa_ z1Pu?OoLz7q>L>B=S`xcQNbEUB;*kabagSUe@yTuypThHAl=bL35}!u>kD>g>SCjZ0 z!aj#QPwXP`d6a{7O+1P6p9DSo_Ki6fMX_G_T=a5sSGBa4CeNPK-8iI+j|%ZPvF0}|h?0XhKW|K?-BaRA}p zG6Dqv=>674U6Q7{Hv7!>U|YquOjT#Q^0u=-*y7c0LuF|==t{RB))?_`3~}Y z_cV#4Rv-&(1P%a*KZ>~Tp}g;*yzlJ=jsllSd_M_n0Z{(;k>&?wz+zw+I0T#~aSY`h zLwUzg-?1kEq&@Z?i60{G50UnVyMR}K3nYFN2D$;H{Sngs2x)(Wv_D4pkI~K_4*~mt zo1LgzUfad`8^Uo0evr1qwumeE& z&rXwg-3T-TYk|GMD*)*Dxf93&2>&_4e~$2|0$?Vv1$YiPP2#^$_J5)5|5^+T z1BU>FpRxiS0Q%_E0RUmYMA$DIfI(mva2Pm8;#Ua&RWpFL{0jB`>J9b%k~pmeDuI4r8-VgpzfQO?2q64TqD_UvU6zqSHNU_P)7K>L4<^lzj6Z&w0~fnnefGCO z5qBPSo*x2`{yh5de|7=rxBr3vcTOM+tOFhcUIosR_`MYvA#nkDFB~Fqu@?Xx7eU8G z>w$Qu;Ln$lBY;2`GBO-J-|tlQX2u} zO+5#^N>W*pq;e&Iy30{k1^g8S0PbTIX(!MDYyl9Kz5sJh900wQD6bM} zs>*NLuyY<4)O8)`Sh1g^m7rziDUwzp{i?M9>R*L2 zS0T+Rq*=vr=Yh*4U9SbaKoV#Gx`BRRH82DW15W@b^Lo&9J!o2ua#tTG=?0{|0dY5i zmNf;yA(GZ2-`dB3(E^F$l+wlOgKE|3=C3LwcmgH;^-RgGHlLGxDyhi7aN zTXDt~iwNEMAN)Xi{K~3`)X!zUn0rr5g5}qQQ~y}jMvoW_p1n3(z^`^bZeDC0pq7>^ zuL+yIF?}(UzF1W$oMuTAt58f98AY_Hwx%vq?RGiUA|a{NibjQ6B@L7ZlF2|pak2Pr zVoF1OVPSp4l*EB64$n2@hg~_50P;=__wtw7$mf zo%bKbpH==AUh8Ytd;q)`$GlaQkyw391Jq_@WHgz2z!hT@<6E@O2;CBz5z6)yuGtLt zmcki@*`Cna&EcCvH$U^tGwn~d?Z;o+lkIOmiEf~}+>_#4u=dx|3t3y0*G@fEVT+As zRwd2UlRBI`f5>2@nWcwwrw-}#G_&|{?(7Rz>VbRykjYFliw@^5aX=IS*=7s%*pi&i z6h@dXtfwAV*@O0U+EU{6s&Y*t^JaTN-Wrb5J`YL~N6 z@)RnVEnKnM3Q=5NDE=p2Rbcd%)D#42OZ+ptrzhK;HdnT)uF)1w1)|x?;H){*TV^@j zf$4n)SJ38*1zdW)H&zwT_8P8VAz8FtT3fQnRp7SkO~GVC@ua!>4eKPYq0{8SixXte z{YkuyX{f-BnE-CVWa##6_t}C=1yaGg6}bwj;%xF#Qc6a#dKBt%T zXRVj4lJ#A8&Mmo>LMUrep{m3+K9fV!FDVvagGwzKd`_G`!C=NoTi;yr){+xTz&q*t zQ}^F_6nv5osjAGxL`F3}?_$xS`kErSOWc|2I>)~VU)m);(KXu8l*u$Pp744+KA*?q zUDTKlX?%j8I8<8m@XXn>XU^>Homt-0R1S>3B?lmIECBOYL807b%(Kmu!nsYGFuv3p zw%Ng1%tFj(;FuR|vU}+TFitshkPer6jocpp*1Qx)gGIt)OL-{6`q|cYA*Fu)%wG}()ysky2#Vq+7=8Zn>q?2 zQ|A}^{N?swWl{v3C7yz|q^@aEBHU3F3nyc~vZio)uq4)9RNRzsSR<98ie)8ne@D1D z11>M``D;90QWC5#D(rx~cuhP3IsPox0_WGnBSxdetT9pgL|*zs^t&cxzep%lYTR~G zs}vB!?#9WJJf2CDo7`pK4MFR317f@M4YJbKBc#c5goeil!=mPK8+Y^LCUXpr8;8r| zh;TE~XTc&pdN00IJgP46j}*q2MW-XJ!e}GQLamO{m^&DsHz8(inW{?pOjbUO#dzd< zSYolk-R}|GmMr(Ar&X74SbyuSWzyZSb0}0%UZQg+Jsy=Q zgf;tkH3aI3>S}rDAY_l9fJixxAuJRjp(%#MGz$yFCfKw>q`|9T)QOdLifDnLH4706 zG&z-BDp%BEje1m_DtAL5F)OACXkt^tTGIlPHry4{_|@?q@szJVq{^rZr$!=E3su$X zP@PX@FiLY3=BPbBt4O0MniY3MOp3V@RvfvHD<~y?Al}A3#CX=CR%#4FuQwT$lF(`N z7}67Op2*~hKk;TYD+3wGe=LI#_pyot-T(gY-3LVJ;lo`=j$phV&8-tlaW~LGp)A(= zy`u3eR=I-V^yVRib9@)d94MS%%k>Lp;r?QmIo6>o^)5`Y^B!X zaVk=-WJzsNu%*6Ojq-QVe~Hy10jXztL4siCIgyr$a>aI?J}nZn@@+Z@U8(~&`wV1# ziT0{>k1M!-!Ez$uR6|tf)g{r9j6{>kXe5~}tf(jqRaBsk&fFsL73pOZ4lPWA^N^67 zLP!eyLv)%MDV@IG%8LQofi>XqKH-`7Ma3Z3t)L35Pv3_;HsA(livIjkiIrFI1kWnW zCb%*e<3@=54EIvj32qL^$=qH@S~pKEClVa8SZSt}b08G%$*dVMW=>;fZr5^Dbj&T3 z-SdY6L0stM`zFPK0-A{(WiM@`J@hJ_rAwrytj^d?yVXysf1*~Xvw^~H$bnb0VT7vH zQSUB$d32YttVJOd`*cF5vlQ=kT@&1G=|}gqT(mW&u@tfhhWy1tDz)T9YRUT4KT2P5 zRWDz?L?)m{#G+;h-9iZ8DUzrO`TXIq-xnJF+nQy|Z@h8&vNfW^SWpp-RumY=UD4_< zD)Rf2$;1=SKKleCv#2AP>{yf;b6Hl*z}HKdk5+2S7D>FEi6k#WVRSBz?DcBZg9^Rg zZd2(W*7lLrYQTculF6h`v|JpUomWm+F+1hPI4~cv-nb&Q8Jk(5nUNVRX}WFnh5HPl zMA9LC@0^^z@YP zK`#p`w-%$wB9)hB1q)%<%N_N+H3%_&cBNc2CC5SvXmzh)_6R$yR={bun9^F z#-=(gz?wWX&{V7+T@dB1f?45;xFSV0yzbRcfhLz92~F`71$GW%zptbwU`fWkA~^bh zC@8BBxJyC~Td>IOPer`y5^cD=A-rsfI1z4cY6w_L%StU>Dub%DJKGp=mzI`$14TZg z+38R>>HHq+K)z2VVJ>_feNs*Dy;#Ac0gd()w-N41USwnqcTD9y^#ZhwIP1XNH4*fN z>JYE z682bkg+hv5i5ibbr%Pv|x`*|8e`O`@F1_X!_g3hMZpUsvvwwAZ34ej@FG6F6W{7TP zmHA>d_<#J`(YWT3ck8R`xSLa=mU+EaRu9qNVodFTQo>6Pt0b&9zdpOYprSeA3cAz9 z-j>o-voq}KtEuWLcW087U4i;*nmtve5slT_)!b6c)1zJINro~hpQ*(X@s>@BRdv|S zbJ~-g)dd=ZK`~Y9#vn)(2Veda^TLc<>IJ1v`Eibghj=(X2}v>PqEQLM_AwbId&A) zd4VXF;BP5D=#nMiGIzLJBEh}%f=18g=hdl*H)4K-grm21Fnk*iB@MJse(OHrsY< zuaTKR)<-X*-Alj$*lWr>@G$}C_~^jq2OrZ7{Sk4+%!;qycZa{eugRM(4P!XlGs(J$ z#nX7*47CPYoG5);D3nUEMYVQONf*XaZ%|?^?V+SQS{rwi^-SwdcA3koD=@Zo=%a5- zH{&gVa{A#ByexJp>p)BVUd$vPGrTW}o^bP=;wga{B6l6n6z(GVIj`cMe*vn$tm31K zWR)M`SaRgq3inl>t#Hr30KtlNC%-RMa^Dr9Mg>=v+T~EI9ce>kmlg7`qA;-AU^c6Y zc6+Z;?`F2iuOMI>tRPF!bN?u)#-2 z*=W=|48@(bAzxA2H94E-xfaZoAINhhk+qw5;TD)`m(HrT=u{7D7T^wD3$GQ-^1La5 zjLqeC{rmpDd>teXDtEECc^~p!KmUMTf$F*q?6aj{B7KzGQC$N=ZY1o5%U z)&MRw@5(IC&)EzH)WWs`OBg<*JfRv`^y;+owDN)h)Euw&q82qL;;n#ekbviGwhSSL z5>wGGYV_Ap*)ETVCfDsUnF@AkoBfTA_K2aRL{YWd-XGbm;JL#3f-M7$&o;4Z!-!u* zK%*5=Py#uLGD8nm^Et(wNI8dDv>0nnWt6AFc!H*DX&Ze`QVaz|6L&tKV@ zs-9ZrtczVg`W+||kx+TiJhwYpcGl=i76gm^hDjYoY3k$}S%LTZdj$tb4%iZ3@?R=jYa{)!z@-`!ToD`MD)F9C=xE z4cuffg=#yBqEnlSc74rg(A)LJUC`?i6|TvcP=t5xWPMzmv=`wGC$eeyTeOokYY=2J zs;F0J&9hUf8aeHq*h5T}(^}4xbv&)0DykPh65odkyEbc3@$8UzCP39anYGIt%2Es`YhJB_|{b@iJ|yeE9tH@&jK2U3Zb z^YtnG<2|B7rAgE#JP(PD)hce(r zQS8IH8LnYK3Q~H>lJzIv`mkuM01+EdAwD~LJ>$nyg=#8Ne%QWsS%aDxLd^^zFJE|o zdx~W+MDC?*3N3p91}rPwmxUlJcLa+BwL(iOjVgpUs3awJOt6`viJ1%AOd0(wLmB;>MvF zaAgw;wEIih5E_>ZW1c6iMi|nf+|H;LT@$skQFmM>!#&ID2ljQBS$*LS$~L2itX^cW zat56i9j9X(oSJ=V_L=K8P+=iWsnEJNBqld)G1#`0c4oFH0$akwHtiMw%juQ3PUM%< ze=^-M#)!IUYuzC-+!z^ZHA>h);!WA}N*}5xUFP!3!HJAGad$bm9O=GO7 z)a%X6u1}`4wdK>+bVd`c3#$89{a9s>1hr0s&ZbSJTZ}qS<&2so%YqB zwWfA+>y5)xuitxZ`Rz9za8?utB*ps*sh#JL4zl3)SaU6qr0238cYb4JMHjifymNN) zw3gWluAO_&Cu=B|U+~NBd3l!rl||kqvzxVWK9dzYVgn0cs4JIQ6NC)Cl*P$P53EFZ za@edog;g=6)H#((9WIsWv3DG@=$#ge-fC6uhO+BbdW5vu>2N5ldR?nh(P5zuYN=); zaRwSdUeH=!TViXRoW9>Hn*^*!kB9)t8erEdgXP$n%4R4zKTmQmmWnH2!_jmDK zX+8A55^A73vU5IBEpDt9n=8bP_*ZmCk+dfIiKuk1?@^!hs7KuG7JD7yUWeFY##V5L zSyI8?S-Ht-jc@Wcl?FCgRYKM13T!Sd4b^Tjw1&3e#QdnM_(N#U;hoirz^PvoGSvbZ+{dR1yj` zmIZtzb;0?qzUrjc9Z&oH#afl5P%EW=rCK3bi>6e#OX2~Ic}DZ%YemtULZJ_o#X_Y% zLxAYqC5G;f`y<^4?osqrn{P zevPMZ(j_covmWj-7I|>7r#H)6OlCA*U$_!hk`95hIN*HN1EB~ej(Rs~BQ~33i>Wgl z4sKC&<%Jw?*T?qi6Kc?saR!-~t@51oXs(*Bb@k$SY<7A5l8)k%u4`)(Jqd4HQ%P%u zFHqTD9Lz@jPDksX*%Q? zXXI8uhlKS3t0g?{O;l*vVATjs(6>e3YTKg9Glk3#V23>2Y+8s#i)|1rg_6L@$ApL$ z$5S(|Z=TZ9GNt+Y8L81%U>fhL^eNfLC9OKb37KL`n<{O-_!qUMe z%7|-`STy>V^XIYPuj%?`*Bf19<$oRJ!(N^BsnrVn!q!;ndM=%~bS`^*qc^@)xvF5> zBC&MzPZuwu&~JB+{+jzX&v!on-zDhjBNQH6F~ZC{kmYdYJLA1#X2^Y)g_;M=S zF!)(E96`{@3<+1>dcnmyY68<~c;BF5lZMkt8$@w%lfH;3>T-FvSUMBYEh?GC#!MA5 zlkwD@;IcfE37ECU&O-94b^bhWd{qFO-8R=Tzp-I)YdqPxxHejo@TvozmRM11h2K-w zS{e*%Mb+qA8dqxW=AKzYb5nY=McHZh#M_o2Q(Ho-l>4L{9mD%6165`H2E_)+q{qRJ zQMK8k58*gY4{fPcp+RRuphDOz;iXKLHCV<#Vod(P4hL%H{u%$IHCG-L;nB0wn$f>= zpTo=~J|~x-%DS{FwLuaa)M_lln$5aaq27#($LI*&w6Wp&%866wXzU&a4~KDx6xa!VNq4ki(5d3ickY*J0iO z<0eiyVZCW}m=y}Et<~D0)ybWVQ*zb@z4AHD*cLo*xRKW^ZHkvGJ}pytaI>Ho-Jh|+ z5-NUCbz4WcyK}N@iLa@(Gd6c_>+R*znrVBw1KoXt)fN3STRfwuFen$=KgnC@i8-vI zFxFd*Y6I>HLE%;_T2-4R9upkOV_sQbgFPPVaK+^*Y+?r@yks zDKGi5#tD5FuDrSRLWF1iY~%K7F_S!6jE~YJj7Fi*24p#Q`4FG6%K~i{B1HoGuR1!Ut`)7fF*@n;1gomrnh5UXCFVy3Q!r973w&UZprfVIq) z8PgWv&(G2IoC<#dk#XDQVNk>rFfhm}!`}ycoHk7_jv^G&!tTXFp-_lkh1Ouv&BQR( zd~)=)XY1~|Z)fZ1Z-l?~f&1^Oo4M}`k5857Vm{K9>rfE$>l9=q&WY&pBUA_>hyg0( zDaC@VKvw*`^0&NuMkKG)Q0#ca%%&`P+iYTK$xrOzEjG?J^8xT&&c+a;kW(volkMN6 zk2p6`)?n?XuxE>?TN z<~BtlO>?WN=QM@qw{>>mud_|m&AVfEF)zdO?&vKl>b+y$9ox6x0q|Uw@S7Vf6W3!s z^V7nt&Ci;y-wSQQBa_Na;HE%XJ)dPGjBk^wz~$0!AcNHqHejp+y3H>9JW_{k3x3Z7 z(@e6_U6A8n_ED+c|{1KrCd)BgMVdG&!?Z|$CIPo+vc{z_xVjA_#Pf=pLx z*$uyymMhgt?7pSHHFs{2$7vD9X-MAt{p1K0=f?>~`?Fa-3{J3ionT8+gnbbX;{z=o zOkU}-Ap``HJVF89(FCk)Zwl~Wm^jzf!jPzpfr!7I+%4F^>QL*%13H zJ4zG1n zZjM_J<7bk*;b0q&EX75!Iy%M#*!vad`GA$Q3Q2sWIb%r_C9M58E>?S#UGt!rC#~z& z|H_ln)y5l3-0pal_;TYlUhm}2X|e7dCE`8i5QVfnAf$Kofpk&4B4B{vtH*riv#%;T zl{J*{N?FG97>pv@BjL(+NH&hKjtTc9+b3iEjM0_tm(Z+b(GE?T&puhBhAZ#0;hvS} zxg3Ggu^l{{odOT`cNUsy2s2+vysMMX{9G=@rlL$mMZqRASxu6udO$0*CBBF?ou(}% zU2eB;i+lYWy7McP(w+WVOGrKIL1r z$cG~vz2DiDDsOW{%KSww<-VI%MViW^I-he^Q)OkaB;?T>3zKz;Ig2!Uv!>JNEid=S z18##gT-KbLbB)eyR(BYJEIS0wLU4f|GF*do)glxd)Y!OcCDmq4D{DIAdd_QCu&(mF z$EQ}D_|n`jK~cT(29ygfqY`6v6lM6J+n6l!Wg&}|=bmBA+7DOOMd9K&fn)3&TmkI{ zmEWOmHEqEQ;t)ErN%upM$@{=sNdIx$EPKt;-|BlR-E(cBvVwxLkZrEJ64SnEevSC_ z=!SGlk=0t%k`@n*-dHogDV%Q~mR@llw7ID@8&i==PeX2-)9uEgt$xU0bwUJs-K^MH zRkjYjVQisgVqlZMKXs>7-g|4|;-UiBpLf~3bYg0+GA2q&?bcLj!ni;iubv!P6`E8X z*GX$y9({B;liB&`-YLoZpM81Z!mmF&oaBB2NwN;&6lac*16=~MgKUQIj2UmdPI%Y^ zi47FKSdKfA;BMJQk$2B$oxF+EhmltgjSOEdd@*~2dHE&_PX`^lNWpG4hE%$+yszXb zB$AMuf-OPBg%B44lV{%U507kg<^Y~YaAiXW++$oYrppKy4EN*eTCW8g;97%)|oy3F;HZ7PE758Z#9CWL+thH?X8|74PTwr>ykt`&Aflu^vBZebsYS z{{B&3*2`ATaqmC48Rm}+^ey~jZc%);M`to<6}<+iScYDRXR~(ZvdN#?cVOO?zYG89 zZzR?H15bW(ih#jdU>@Pc4DhTAcIj5T%dE9obXJ$ysKfB7v^EoItvc(FP3yF2Z8jIw zE;75!L%7*x!mkK=OeUS%W^FZ_T6NkE*I3i#X3Lw0*T%GS^HFSCy!ji57X0P4E@=#UZiHP#7(C#kvXyBK_4*E!w<&V1MPpSfHc3JJj$<=k(`$Mf~E$(KE9S z%>U?o1M6l>v<9upFl4kijTWP2gV3r}LrURP3fP%#cB7%yq7_1=%`PZ*M zpQoh`{m6So8`WonDyX7E`NL?nnj993&Q9jd)>fTrvvy)nm+v9m%N)Cl!$-{6`q$ zN~vKBK7RPDD(Ah=1k_SE%z>h4MFr92pVonuqsRrI$b0hrFARcjb7!Dp^+=T8E>C-Ua&W#o<<^A$Al3Gm1{bmJuvpR0Pg0`U-(iuPMG7TTAbh zUfh|ugZ1F1-239D1DY<-6U2+bJdm|xsM$=Li);J`~Z zbFvD$Xg*;rLk!6Rzbc40WDg-(|~^BL!xXDrwhLA z+88;ul2vG}QJcNTJ#3m2DI6vRx&zkgv4xwr3LmcB`ToF-r*R`L4%>@u^|ri?LOu{w zYaX{W#?sR>fpF8@>iPx#d5$7m=PYw!Iufiii*M;1@$5id!@`!RRVzJizVa!Rs;@8J zQttOa+<`x;(9Z8-tRvKZgq#>kUf*!B^lUcBKCRXtvu(FvGbmBi=W`DS=je3CVb%B; z%EnSQ7vyhe)#nc@K5nwYHD6Z2s*+txYNPE%j!1n$Jew}?r`wX@Nik!ryR>0Rd*Zh( zi<^Tw<5Z)@0lR5gONmos>@*od&5KZZ5_CR~@i2qZWm!9hg10U>7yvttao?${S8mw| zREVL9n77(u+U-8RUFVCEVmMORYZ!LUu~>W97yx~VFAn5)nG-B1_>e{BKJ3iu(c@Q} z5MFV>xJ5V!aadYAKCw02x z6?n%EzmtiV7{LPpTEM(2Z$RYzMkxf8hL7hpESgLvU(n;IKK3awOt8$!eS9>2KP zqvRjeY{}0ynQ^aO!WX2*nKzY^<@wlw+c*znnZo+=)bizpRju*(w6Mk97Ih^GtS`ST z9_%cwgTS#Grb7D-lt)WCM{i@cTvVL@i zX{*traBW3?ExB#OYMAAEOg#8}K*&qZ$K`CsR__`Uvslyf*8y!)=Q*prwNp#&b1SF# zs|?b!<_lU~s9{!m^l$Gim}*dsq5>Z8I?U(qNMC?0JwhGXl91N`Q*?;$k%Yn^MsbhM zvejrbd19t0?ko-$%u(+okjg6s$5E)$U--QPvbQOWt@WgzKlF_(Pqe?{uaykrXwMl}r-%kB#+P7;86v)~QYntLNPYwbMXO zgW6#wr^88iTOCeZs<1kpxISvwN+zK-c??#SbDG)GW16l~V{|i^-2A%P_yDtz`u6?G ziJi#(T0RL@@$GQlgYxDAbGx1m>ClD$5a?)cwl8-yw6yr<&8xq;Y*}hE<(!kdriDVS z&DFLuV1Utq%B7jiS{`>ki{Nn|!EN%+Y?*@f0tMU76nw*3!J3kShhMihgFO;^Gh9#V{+x+_I*q`My&+M}Z?)%|l%nGw^td zuXT+oVr2pS*cgMJ5)gG#{0dwM`KX6}#)ne!Ru%-w>RALtxm4b*J|C7vQ!KnSg26FI zrrU=#y{_P}O8QV4$>fhg<=f=AL@JAVhkQvvK2UVQgpr>nkoWl+qp`(Gnrnj@d#cKt zia2NB#U;N%J;NP#`eumldTjQXJzf_deM!uW7hyIOeCDxOQa6edKJH6-u7h?5U7Ix; zaX}XMtys2U9hXnrSdZc(UUua>#<*>BR=#_!-TE#p;x7AEa-4NYT8C5Xm~I|swJL85 z!Bn@twPd`HQ?fSYmdWP}RccT@wS1s>$sK=J|dS%?Km@ah1X z_k}N#@wZ0)R&YyMT(I0{VeZ^c5&w2QFUb0^2YNFGh*{@fTg4OdA=dbvkwQr$j}UZd zFq1eA$yHI_(+~FFg|*@q2TKBbpWP0(tGx4(RHyq0w^!`JX;G^=FbJ090XSgZ5x8_JgA6+1}n zBnCIcgNt1cf1wq2KFP9km`xrn7|74Ez6p2ya2~G$AVBNe>W!h1JZzSz3JSAthH=;_ zv*U*&H=$|Dnp6GQ-5#5~m}l|1?o;qUYj=*M<@66g`4J8*Ubygvox^UU+~-b zdg@@t}5qtWveVRcAee|SOU zGrtU97jWlwAB}Czs@379m?c~loZKS57E@`b=~Ome^#rv+_I(xep_ndY?a?r^|`21CyFf|6*|wH>EsS`Du1#$rXo ziqIUh*)go=F@YRz#FuSs%@}*x_Ma%Wc@-CL$td%0D4~zA8spNl64z>&A?1@}v9x4z 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

  • ++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

    7PqXM+-ViJPo;5?f9%gWqc ztSYBHsr828#Ng2h+vJIP-pl3>BP-G0IC!IBIU_3$#;TC0D=(eBbTr!z@q6?zEUnGz z-=(E8Q?VQl9RSxr(Qgb?gM2f3crRHRLKlxiDyHhxbxwu4rR<^_`Ve0yS~s3wg|NDR zJ>@t7KKK`t`KQ{EwQ+vlUSN*CHC|u!+S--pTb&yOwXGkF%hutkHncWTfc@K1oH z{rd3(kk)NFCtR4|tw?KiECs|x!$kFYSx!U4Epc&O4986Aq}qEy4dX6~XcANl zFU^vA{PL%5AqJCE44B|>vqRpymv$3|*dhfxFRR#@1>Iiph#Xyd?)oqw0NZX4SUpcH zE+{C-M8*PWe!pzXSfhXS^yn@8Id?nsvd*iYi+g`}DS6b(2{{_p=6^@>VXK4BKC~_` z`mEW#>0JQ=gx%YLB`@WStC9RlN@k@aD(t`;fVfEvMsowK(^md@$c0}M(7IP6f6i^~ z?(RyR;evd8X`?LG1GlJ`*QJ(j?q~KOdo&HOlo@oEyTxcTd}l3_wYBgr)rLSQQK!!W zd{qi??~{1kRX(xigSCp|%ab3pkwR3OJNP6_ZxD`&Kv~B>^Y-$h2x&&JT!756H1CQI zAmlnyWTRmN4}xV#`Eop=%?LTx_6XLb@a_2P(J+7Z;OCct`2qq0a;(lnZ06{A)3H;~f6uaoxhN#7oQOwQpQ=w7`<1{QrXl_}>Y2 zteS_1hn@>v*B0*R2p9keY-u?ek>FMQuV*Me>2Wh`q8dQ2Gaja%pfC=m3$ft_T0H0; z5GI$MPe*!w|F=tJYHF(1Mj&9x?%oaQ=XQ}|1?{_?t?hfgf{C>%^I}20_fqNI05pSO z&dA76Qc?l~6&Dv9V~pZ*V`5?emyfXS{&XtGL%6SiWH387rvmbmvNBL`0mq!M2B=Yx z0@l{nB$7pe_WgULqui~`6o}k^yp#t920$U9xDd;3eyV}OGTQBdFy`*!;^OT5unLIk z*P>x&Nnkoahy{P3nd7^dsN0*R2H2!}xQC_X`*!_#g&`@ z>AJuTcrdZr+Of(&h>4b5$`{>Dt*B569yGb#oe=o?%)d4zrw9Lxh6m_v+c`4lJ3xry zkUXJdZpKxeM`@g~m4pcj zRR{Vxu~P-Dbp9`pxWINwf!6)qyUV09K&#C>0ezmmqho$lN%A26oH=dIt~z#>NV>PR{P`99woV zAF8Sp%#xf>7aoycUtbSY2pq0hOn7K&igWGF$MAN2F!jE{-@h4X!(?P+#I9<)y1Ldx zqS-$Jfg8e|#(t?4NCF?N!bE=C{%<{fLnq8i2g8P5eo}0C{#3!Xxqs?k|K7u&-Czf~ zj>1yZZzT&6h52NV3v_oRQwWu;usBs*`!9=X8F_b6b8Ti8j8)Ij58Q zFE#Q1E+GDMCH?<}tL{UoqhX9|GQdDm!NN~>cdicDNU;vto*wIkh5TJ?9$ehHSIP>G fqpWARkH}~4mj^D<^!_OZ-#|3)>8Y1MZC?Hl$taq| diff --git a/spec/ui/img/form_login_short.png b/spec/ui/img/form_login_short.png deleted file mode 100644 index 5854a07122f524d332380aadd86b4ebc7880aeb8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5090 zcmd5=YdDl^+kR4FWy!2IR6rc%TZTjKmlUU7IfcCv%3}-M{yx`@r1wQbx$c0T?@*~ z52d!g0r3~#xoVQpdez**;vCU+sY<@?b^@)e*9JO-#nNj+LU>ics|? z+`hv;_9)cUf|Gw=s9I^DPDXFZH3^m+sFTSY2${zg*Srux>_@g{(GZ*9^0xbll+U-T znJ3icf6ErL71YB-Qe+jy;RV$TK8^|Et@vLcsdmE_owPvIlt7Dfe#njFstY$i z5F2y2ix;S2kM651+}m$%7F$q3zB2r2da`LIo*o+##X@ED3?!|sBEXMTzC)e4eK~Hj zF_NB@b)(L$%oVvZmQgD4Q0u7*mkC`NwdJ(IBT)6O%Nq{b<$ps-Oc@1fDUs5>{XKDw zJsNrUMGYBTb@YmslBnFqDyoWf<@ET=a6+&C5i`r%p+6c0$o1|;^*7>zD!tz(z@Cm` z#&ec4O7~_kLnWo6C%NPM)8$~=<1Y|@e9Le^wtQ<%elSjN|KhOI%Hl{zMUEaGh31{d zEVCu!eojtWR-WE3WWDZbE+G-K)?n8`n6kb7&uyiWt!GCUx;`)ZnaQR)5RphyvlbjW zSmq11yl0aT2FN)Qbc6D>=H^BHK^GNaXoxo8xMi0WW%7bbPO0^d3GI|66{qlxYUT+_ z+BhjolRVJ4_Cs@Nu-w4{H&l){y0!8FY*V6j^!OuD4HJCcbt>qzzoIs-Nu=~A6s%n0 zyWy;@ZYsac-Osas$10Mogk#|&Jz07-@axF;MOQ?hbIiOAX=-EndO>}asO7I;pKiU# z^okDiUw_Bm{sm&L8&zRPd?$S#-)!?>ksLAm)tThZqm1^1hQ$5g%WD5&rHeo-b64Lgd&5Pq%H`cAkt0FK+=9 zF+g)jTOK!ui5A+o@=OD_4=s9@{sX<>3{5*_WM(?#xqN)I&+8(Hts)kW>`#C8SSc49 zT^m*WbutlRKm8>?_(&@uV+V5)Q~nyd)7Ic7f*|XYKzlIxzx0UP2SI0H`G2RuZ!}Fv zkszKm!&}OEF^2l)urDp;V0X6ySJ1iKyyYeRrZTk7V0FugzjYk{7ihHyC)eD8A)B`g?Knx z6&l{_pslK;q@=KM=kts?1O=D8_It4HLWPqK%r{!?w4DHL8 zS1v@0sk*s^el&K0>7T4&5mBSJjy<8{pzX4I_ik;RTcP`Xm`TQ$aVwc9K0e;d$js8x z^61f}?+IF_-aXyj!e-;R8LB$EsQYHZMh(pO`)aeI7)5P7Z77lzi>wT2y=tQ8nAuw! zIW;rVA`y!RL8MsO z3Xk#DIL%HgX8NPOG5K9d2@Fxave2)E;p6}?1VdyArz5vswlWn~Gmu`tJSvq+U5N7_ z8of=4PJ%WzoBiAnDX1QK5@3pV&}D%M%l+xzIjr4~hl-lj$yd*feKZljZrPxXdmAS# zT)TFyasBe_IVa0-&et4t%!oR#hoq#vC$)7dZn3t;OTc|ihyx*FFc{6-KT@b;D)1$C z4+*&_7?iYFNe^Z?z{Q+gKA&&%WGB&8pG+nvG3FN+{mYrz+1b=V@aI&*#{00Iq6>4q zSCZ4(My-~=tE{dF=1^l*ULJ4H0zt*D2pOjoeI$L1pqkO=9^SXF(X%ZF2L}NIL_a7$ zD=U*1`cR41zCl4jEK2NKin!o_JUg`r(B*0CRo&DZ1DuHo@waq}t5JHwg9ivjblnV< zS?=#dfNLO@IJwCYf&nIj5jp##HO;`o$cM5_$4ciu-cvZG*z7xVh#+#%P2HDfr*0M$ zvp5*Zik>3F8kUxpJSeki;Quu(G4r2Nc7xC)3w#s`)n9VCF>$k=SRzr;g4e}}X7lXR zH>#*4z$nxAjepFEUT0$pN}poH^V}BA=zz}rGfDoZ6ze5}Q#%@qF4jhX0XkeV2`IQ3 z(F+Lc6gQiyBwuT+ku*J9ZW_JNWI{*4{q@JE0R?^Qh zbysbnQsFCHCsss%VB2#;``4Wr4*4XKAubp!%49M@0A{JJfBf+WK<)^_6c_yCQ%aUa zWP5u%m>wu#dCaW-#&NibNhsrD9K-##OW;OJCZa$DK^)_J@6CSBb z)%d-6%u+C%FvaIz{JE3Ll+(rud5i=YV8cD?peHHfWAZPyc`hR(BUn+JkE*Kb(CzUo z>NGTc5QGpi_9X+*$Q%dKi@(4B_}G{#0R!|D9UbixGt)dXGZR{~yfTHYpNXpQjGb-O zo2nVlR?vz$fTsaq>*v4Or>3TAK#?GBFQ{+WmU0p{4 zJXWe;OKWe3FAjtOv!D}VW?OrDdcd(4<>l?gIUA+>#0tB8mWS1xj?XleUTLAM@X_er z5^dapg9lUS<7Pnv)i*lx*D7q>vf+MdX(`x!^JWKBg=gt`ud=JHqH@EF@8<_A28#>mOZ0Zd+;=XUzHXWpp06dXJq&5{g7Qs%PESTW^f z@(M*Fu)xf7h80}1(7wLD*RONp6*NDMh8{X}s5XK>F*#X>s8@rEj}f~IJ*ujz%%Xp; z9vZ~(NWj-fRYULD<-ouv1cIRolt*ObBAb1w#>;WfCduLyFyO|<#@N`{$bpa+;HUZd z`G9;GR6Pe}W##bjaDHC}3RoAgBw$oY!VVY$PN)Y^`e0XtfX*;Pj&mkk&x%}FSP-!4Wf}h2H)3v_1B;H)@G_7E+zY#@j}sCSYTv(y3yDrbp-|&! z@IU{8RLOlmyd?Sl5#%EfidnQKXl~8{Q2@(5+5#F6+kd_Bcm=vGm?n04#xEIS zytT`l1?i}0Ca?BHn8*(FOfOqKo`Mof?eAJ*{m-SzY6}Au`!WMe)7$boxmRcPk=!?{ z4dN(}P_u6-vmCRVFMAMBb78Vw0ifF8(ql3%k2KHCd z==AiqQIMtp%SKv~>0iDaj`X?nc+43NodKE^i^ZVaX-(Brx{m;iEO0ACC>k0Xf~p7b zJ2ccJ&Cc*b*^j$;;|pc4yo{2Ql0eD;3Bp<@8u^^vRp~#MFiCPP4lxO^I&P-!3csb)5gvtC9cLiQ;;msvMt)SZF9A4+qP}n?$x$!+cs9)wr%_MzBlg2+2=(?MMX?iPUOgu2$z=? zgN4F^0ssJjl@J$J1ONb|1pokUh5-9*c@x34006*<@KjcJRy1%Uuy?dGwXilJaQ3h_ zAuw^bFa-c`U$4%vNI7hA4EZra)de~RNC~>bx#^pDaT~ilr!9ZVdAy`8XQWCb2@Pu# zio5=t@zZZ4sNsVk?w|e@V;CW$pU-e0{d#WC94>u<;GOS$ zp|d;ifeo6Om_hc9LOgz%(fRO3-Z&A=rE9x=ptCUU-szQ1m^t|H_?HX)^w3k@y;iG~ zoeNz(6ELI9`*Tuj(M|Wh;q%eATC9UXG3>4={{6PKjY;x_Kfk;5ii?!E?{?@T+kdB+ z;6pnS>aDdMt9IkJm1mdvd64~aaQ*V#EVjeS7c+x+2JfZ8=QWhMdBE>8d8yd&ACpC@qbF%tzh{Hj9?};XV*V>P^4~@aqfRPXp z5dL41d{8R}4ajpnVqX8G(YOOrfV||UG~;oSr8An=;%b)B9tUfRdLb`ZCWNp=^17w4 zIYLzy^qWz8yij3Lf)r)5x<$<+qh&>Vie{xsz-FECT7(Ld)v`^~q9au`t5x+AtLG&o z40X5bMfD4>sB=&N*a{X7->dORx@nHdvPI(*?=Ztx^%FQ;TUJWXD-_dg+&&7J$RyNlPG#n+}*SbC)% zov+IS%m~ZL4oH}ILf4{1)wsl64V>zI43*KWcH*r!b*kAt8aRzOWUA_?UDZ1-7}T9! z5X{Ir2XZ^zdJdNO#!}Vj1ic97vCz4ZE%xA47G7L1SBUH`4wisq01(3LroRhn+&q%9T_OEPBz(YJ7G0KHGXhN5p$)< z@EDlh478^&9V(k0+s16zDj3A2S?$rX!(H)Qo zi%!66?%4Nl#N@;%8#Io>iio+hP;^17Kj;#}q*_Vym`BNA{?Noo4^q~mPm2_W4_wQMx1)ssvAvk@@4S6t5`b88t(!JSSOsZ-%>gk2vjPyvN^t{ z)jba|EuFsrFydix=^8;?;R1wy5WWy>gm@-gv9&SUu);gHz$10aP9(CZfK{nGoTp&m z8SR13qM*9nsZ3S;IDLJ}tF&1|pIwy=2(t}n%=~OM1 zk`kT~oL>Ad6B?8!&`B_6I~2WXAY`N{Gax`la^&KjeqqcxDSn+p2N!uB-#XcuhFyr> zD%|HZShy!U^7vtfSL4|NaQtb5iV^}ekQ0qOxiA|SdlsLl1ygV}Oh780j#7h+{KchX zEP*%7Ym~HJYdD$Aq7O_=f-Ec+Ai#ZX~K+tkb66kv_5bqcjs3t&b zAjrOoWwW=khAl9NsKq2Pp7-P^-i6}!qI14KggTgg98S1Niy%YgIs|Pe&2sgn*(#iG z={}(Z8IzcurXQDs|Jbd;4k-H_3cFRW1D|jmxe+V;i7}s2vY5_F^&U3pLH&R#W%{--NZ0C(w*>qW&#Q0kb4U4kwSlb&@+PQ6o_h0^T?(S`N49nc(1q*hLp(AJV8Q-3Ey* z<$2)#+F~$s!b!9Z>5|1mE1;4xiBx>FK0!TTZ$|)Z*LahH`F--%;7!u2fIlABV?`rm z=6MD=Wli+UDEMMSb@N_e&rDfhAI59HJ$uw|p%;NAg`DYh{)WJX)b;-eTZv+}tYHj! zl&I+e`I%=WWGF&Ws3t*<8Q_u2uyj-Y` zaV-_<6>PTPcx^4$l7z07A6$|eLg|q_G6to^%#)u8f!E-s8RPrd{2jXU6 zEZ_eV0*(d68V`ono`l`Xtw^xrL&anNMz=3>(*AW)*HbeagvNh-VzAIReFcw_MmJ+fg&mRQb`*tA_uwK(=NL2yc;vv|g-!nM*KgRC&(K+8;!)$K}vsJd0r#VR8>wnZt_IrrH= z5WSRtn2FwDX%s(4rmKz3cSRf+6_ub;vt2wDd)&g+*j9OqmeoZfFu_CzBqm`|pq@aG zR3NcuNxj;zO9KLv-sE?~T{G!Hne0Ex$;g82NHrYVz})*n?C^-;XQ|ke9=>sfnevLT zD1pM>-a0${+&}g3u6aje$$qqmoJ##w`Cbi!WwhzWQS&!3W}!o*?i0_AgKp*I!VJMMH%Pzp2zcsIm~<1L7g`-4MTx~nreqK9{L1{@INKHE-9PY5UMt#%Nk%G zKFlGQL$4($FN#EYOEqyIDGT!v>;1L&2of8Bd@@W_J1{0@-mO)!I@19=6NqC^&sL7~ z^twe!Qn|yn;-^G^x0y3oEcYf(7?5U3{{e!FyE}a(H+84+?y`?DQNet(oHjBuAZWun zw9=>0ZcBp&6l~3R>8k(&h~JH88UBQbzUG3)g}4W?E7LpZi$RuWH6hdYM-qW=(Vb2~ z2G<8{82+ZzK&UsSnmh!XmX0#KsPv1-S40 zgdOxuB4LkgERRAxx=+vqkj_0ecp_;|4iiHEF_%t{g@zjLp8{l9NiBFx2U5A5qcB;x zRdO}_0*>HImnemV)yRGxvoDkZTxWeGaCK$Io3yy+t8V(TRmn6${RQ z0dQ&ifE~w}qoDJyEm_4^oR?}h1+90DX zIU=`*Iby%}9YF#XlL20^2o!Zz0$hpH$5}_mIwa~Es-Jq=)cyHI7O0s#-|E~&E*_X} zEJ{uYGk9uFrO7032F=i!p;V~}t($~{2tIZxNeKqqH^dkyYM=@y4Ft{7gV*-q3DbEk zu^k*_xi6#I2+@m}PPyM*6BtxpAfSci&+f7Wx}KhPkz_BfbbI^DY5daFD=PL5q%qjW zy3PoociRHC@MxTSO+2SAI|NSbV)o8!waIwIE+OM}TPu`N|A50sw-bx}{~8 zTO%T*uGvONg@89ucKIiPkumNOiG3Ijf_MmjfabK4IA`Bo?`G(wf=iByPD+gHerR`o zDR*!&i4K7;*ibOzyM=Iv8L%`*m4MOaBrf3dsa*>FaVRMUCcKA zVuh%$K0(&3Hbg|Z4u8RO(}E5Pji8HJHg_^wgT!ir`Q5jLVIijiMd&{c&TYH&d`{vR zpDj)6%uR)<3on*sV^${3848RW@F`?aRDlQ2tUATXOd|@DYTA1wa_vM{{NX`_nUc;; zE!>lnq4CwKXjB47ym`2zswpN>nziSSd6Sfg^7U|0_|RdCM%%d9J@7Hl=QY%$L}815 zAZd57FhVTbIr3?iEZ74D<;V*7=FbOlD(6y4mAKyVRpb-#!D;)=UMc8((e+A3Mll7N zNGNJUyVv~OI>*)a8K_P^`rQUmx>-5md&Ra9lhwg6QS6|Jg$-Y9Q1SLK#&nXaHtj@} z<3_ubLhhG~{B(*$1X-8z3g8UFl2K_;qX=CTP%%NHY{H;lp5XdWw%-Df=2tX(qI7kCHdj(J= zg=>P3G|!^U4tP&&8t!^qxGc69$RRz`r}){NQ%4x zVqFY?tWp%UdkA{|Pz%aRJ-?4?OS2g4Dw#GGF+0BiUQ#Ql##9wlAiXssNb_THIC>YJ zSFuA>5z#SP_VNFnadbWjlFq~VN77bt@g12ln~{BJuwyet03GxorULe|o8AEnNH*kU zuPNwRHgTvHb3V9lM=?cc!l}UuP|UC&t;5pK!gXP9i45=;@q~MjJ9j|=l@3Qx9002r z-$ie+PmCI~u44lL^WHfxz^qnPYvQlDS^E|DULo*Mu2hb0ZJngi;KeZ@h&u*j6KNT zRdMS< z)^+?{aZ&~WlsBMjIQ__vjF@1}_V~yiSOL@BwSNmTR*lx8Suk9`PfJQv2jUmhB|)lL zu$H{(J;-u>KGZs9(@)0D!}B##{P zUCA=kK);@2nBz$@FiFX1=vs_};ZY+(!Q@DQrBrxji>>qrTrSn9)Jj?RP-vm!u3x zcpoM!F%@A&Q4KIBylX&}t$RnyLq8S7yNd1mVE5^vpLr);*}Lna9)7U@DROK)u79&O%X51}`9j`b*+oG!wZ7gl?onqIPB+nMeiqfE{3Nu^ zn8nb#N0b3k@I9HZ)@!V|9@j;F5-db4)n|qjViWN~6!;oUyW{xhMPyGzP`&Ovz2dM# zem($5QII*6kZSCe7a7Cs?NzT=|9B0B~R#wP?3a~OZPnm`1u55G*|;X5DCxj!r1DfzZv-Dj{XgKCHsIjrroi@u0oY&z0 zL%2Jcbw}312+HQ)6uh zTjU+n?cbq_PMty|*o5J&F0xDn55xmJ%RaGYwn@GhsMK^%teGhq%Zdx%A1al)cJ-2M zg2^_qiJ1k$0T%9>dV@C*KlO0iU_B0;`^)K`)^l*NJ!iI%em^MqeHbZ!$V~ldZ|6+a z7jdtZEB-jeY_LGn1T*?RaMR5orqvpzZD<2`-{H(xiZ!$4-mIt0#LXS^a*f=z>U{~}GW>#Sb9Yqr8Ch$*=(a#0#$h)sx&f3=0+;RGbMDfw!9wbn4j zTn!`~#WXx%io7zMCI<(cn{*HSccK#aD%;_UW~Y40-=e{)Z7>#2ds!GRqcKoUd*$o2 zwP6Uu8b{uX*^#O$jf~poh7mUlNryRFKB++e297Y$HMA7h%C*koPf<_z0zK`EdP8uV ziZl1a%BY(ZvONgytv-`n{6+UpX(4p##L%*4(NnnkePy{g%l&-c-#~zF=@UGN{i9!;zsNga9WhY$Eu*qv9;^ z@{3R04!Qbmv}p}O;N*paNeRc}3_vl_kWA)LbL1Y;F{(2QVNLuiNE*|5-ln~p&;wzE z?WpjWFgIY-saZy0nZj%Vj|T-}bn`LlfFa6w7BGi#c{&|IkhG7Plh;ow{hp&g6R*Xv zC1qzIm!xRj25vI5dWS=52$=R5C%u^OQBDFvgp^?T5LgxL-HyBD*%OdZR(z;7=OP?$ zVCWESXcHME zQL2swlyz=59_T(|Y|R$pdZ3$I7vRq(RCOqQW&jDo`M#<~vMioxy>arrxaPupr z<%|lj)6vo(`A;f{QL9DAN7lBHo38j7TYgLGGIpShEypdL-uYcDeQg2%^oIlvhuH#& z%~`k$Sp0+hlH0-(q79CISo5T&GL&!uZeZhy@4F9YP1jkoN`tM{XHC6!K0U)&U3r9n z4pf{;17v&wOk;Th3B;2TY_D(3%ft&AzXs|jhAO|^=jT_ArOyYn{~B@;_wWEn`1$Ph zbosgV-{~y~dM*P+ZD_bQ4LyY`5sj6v9Iog@kzhM{Y$HiA$7U4u&$YE0U#T3W0(f1N zGuMItiYqUoN86?pxLb7>;c@oKV7^&u^!kA|ikPw+5X|WU000cO5E7D?5EA--S&83V zM3zrHkN6-z&aj>q=^q+6G!%z_^4Zj35$u+z5%PqKP}Q7i+V6zS7UGK9IG`(mLHLm> z;OJ&LxZ0osx4=VFQxbC`lAn5t=7JlrmfTJ#yK{B^xBY zWw|ZqLBsLeYurCa+D{$h%tWW8J!9A&b@g=jIj0Co>itE;5%TjQV3Q1pWh-SPLYS|}y+4C$^oUXgYhdXeCkugK8!o_q zf_AnvL&6>CD6;@K^>9v%Fc4e=M5i2jVsT3yfP!-ZsJf487X!}Z=B;RGTtOaffzelJ zWY&Ob-TVW{g;-70pypuEp!z;AeU#u%J3&2FySFnw*nI#P7gf%|*x5luBa*t0AFgYj zx4(H7E^ojAWE?$;#;FZ{lSN>LQewgYKmYmUb(bdowm{m8Yd8S_KqLR>`x}_c!uV|j zcb1S50Y3tVg{0)z4uPNt03ZO65Ef8&U%%{j^Tt(6|M}r%a`H;8>9A>E8FIBQ<(!fw zCL|2T5`>^hI)dg~ec#ea(Q#cHVC|{vqm@#(1kxY~Rz{l7K3|PN=8DPGHm*#q+_*^E z!FO^gwvuQ${71uavoevw>}Hz7WHz17_27N%fmi>&Z$(Xl6fR5@FaAG&WPwrEK>vR` z(2MK||9kZB+`}e;L>+?v)lrHz!RaaLM;P2h=dnQ$0{y@KiX$9nLV|D2CT1o5$F-G? z<12n3%=q;83X%)b%weOaca+ z%hKRLspTU%2kQ6{Pw~Ki2iI)J)=@78#t`caq0Ss!$?jdq?u(<&Ig$pO1T513&*LUR z8iPDGX1^M3)c4qYR_`s8&E`rNtI+cG&NU9${&7eQO~D@7!;nkU}qFT*%Cel zi;;$;(GsLNMH#eJY#cC8C+ZJ!K+tbfmgGej<@ht`T=px-a9*afRNQNz<|eQP7OTtd znN*?41R_R?GTr}@;L#}CaHr5Bqpv)YmwoBk1ge}VH<4ERR2N(*vH+&aoJj9Ngys}t zK@fv1CxE(n!|V3BXpT{&sVk-cI~gMUb%0_GjPJUi+NIWcUmEQ)pbUa*D@m;I&@Dbo zOUT-SCsYe`fk^G^aOwy|FR!gZ~IiUDYnk?#IF%b;(FnvGJLVlbDTwLwb?^A?q zg3m{R-2}}(K7repM*US98npy7-T%e{X=o*K9T!@iI+dBl!zdYZ*9*{c}d zch%O}))G*&3Vz=GetV0f4zyv{e^A@}*f+=JvOrauffsid}MRCHw8L!j)DDuFI`z17E{< z{V+17i^H+KWia$#K|=$Yc%3iyM32P;TtGzg*u*q7sSZ-{o{`9u)<_$#P9^q4&?arj zVq<+upuuv5doIdF_pzl9ir}r^*GmA>GfgsW++Pz(2%@f<9L8X}DMy+hCGEYHe(yTk z79-Q{V+eJXzW+X&F*}+`UUMGkG{hV8Lgd)=_0QY&f6AY5wm%hycEE97z1PuOh-hNg ztAhJ$Jo=idh`pZ=IBqIoGneB(xSXzHS*V61TcJvY+v-pR2ru_$xzH3F3(@sbX_(pP zMb2BC_pfC4|0P`>g>y$3^t+=22IzbYlqc9gtPX@&AZ~L3@H6Zd$RG6MPV7k^j^Y zS5)LtoGUyjE-=%}Sj`XkBLESCWR$G`HPbxp(0ytzu~1s}qMjI_kCNmHMli34kiU$~ ztie|7iu<3qo<%YefmVq7EXH}R=d(NJ@X~M}`josQvIc6dQh+<8koBU}__N+^HPYO> zUou5L{9Sp|?fiMrYc|;Sd>v&O~al-u#5@#P; zn?O5oY^Okpu=cUxDtFFMlt^vV`=4myxQX*|v|1kzR>+6#x-LheDm^rgy&QW#7tMZ= zv_}yL34|xQ(VDop`b>^QMP@iGlUcg-Eo?X(JnA>mg5y)n&W}D#m-U;CHwM>3;+9q`xwx~?;}dwr z2T^=W-ysE?Hsu5-tJ5xP+E6Va%2Q_R%e?34?TRN+WIcJQ6%!|lx2(d0cF_`lll&uR zpuYzoFT=k^a@Mg0Bd+qL@n?ke6mPU_j8nH2dND!Z>ln_`^)WuybL}O^L|>rHCawe> zZcqAX6ap#b&%fo5wV&(aU+7ljo(b%1%}0A;Foh}gx!gi;RlMgyBu&JWyCQF*3)RH< zS>1W4xp*D2VLP~M6H8h=uVfCjm|xhK8Ih^2b9kV-6WuwJPBZ0woQS{I z#d4BY{s(*={=shNo$eXeyj1y*f|}aIOV8WP>sL<&bT|S~F%Foi#u6glns!VnTUVdo z*Dm?t1887Bz>02j47|@SS)eapyLS$kuQR$F?*q=5vZimRqEus>{q zuJ;e$_giVw+=BPq^DkG&>qzTQrkUQVyW;5H*>=ytQBqL^Qb|ZDozQ{QU-4Fus}3|K zK@8hYTM>rS0mbC;jsbea5qn8uuFrq6(Ij=sph`5AR!2=@15NT$V884mzdMLR4CRPb z8xHBga;_T==5Is+)O{j)j zJql)e{t~+ULOGHiMlpu-#%N9Y(6nXWMrMwDn>{D)>lbeq9$km7AX~)(&DvQS^S~Yg z^zqbj#Z&72E^+K#-(V~QJqETDq8dsFX(W1`=@OJ+K0yS+WY*kd$VqK}V`Zjdc`y-( zY$^)V|&~Fz0~US zJGNrmf1@V9=%>K}$5pIa9meqzc#iS#Q))o5zJY4iONmKx_6zY7!AN88RqII)pSMN{-9)(k7(2N)hl8yh9ekfyzF$q8iJLf*C}#TnOnupR=Bzwd z(e~bJuhRBKE3vqrbfRmpn%VxN;Mj80)2XZ zMw(0a??(QYY;bL@eVGxFkJof#7n#eX4b`N;h*5(z*ctYSq`sdPAu^3SI&Ed%VJT?4Sz~X zXU82LPInNk}oc^2HHh)wHWmGk+({5xn z^JhzJ$0(S`SEp1MFDw5AZgvs+o9J|>Nj|BIpjJZDXF=(C)_;VSALR{W+1ZlO7dxh5 zaAn=T_iA|*eceP}f?wwIJAq#Gy4QZYh}WJm6FKnS%i^J~l!;qW$+<2&;nG4!qGPAJ zn7lQ6`{eLaSK$jTNxO^+d3|0Exr_jPo81rkyvx`^ZaK=-LUTNs=BTp3IBcX^S4WVD zr?l+a)SB??YKT+ccG1*@*8BKY#Bs9^u)dwA=V4=&H+SC0m=EXW5I?Z{KsXW$ za2WN|3Qf^_+_k~S{P|K_ntzF*81^KO=_g{D8MWwYg%{y_VmYcfM$9{e-OL8f@LiB{ zS3>d!)=Lw)On{)`ee+ymIbOog4ykPIOW@nlT8s5l%MkJFwmWRtL+g59I11K_V7kG+ zO3Y{-ykP!4kp;W=k*2qQzW6@TSl>0A*&o`!#9-T2x+1iKMWHB!1NM3E7hepHV3EVn z2fzD}jqxW8H@Z*iKTA^OqJ4IkUUYfu-4&k8e~Y^CXwLVYa^Ep>+pdl)OmMSxyg$77 z4v%PRf$X=>lfCyEbIXLeAP8R{N9{n__xAhTuNGi~@IPNqxLg(F}I;`5hj9T-` z&n4`3GLMo_PiVn(oOKv8|JC>gf*YErBLxWEIlhx}fhO(E(`WrDQNj(c!a$=PkB5%1 zEkJ=?4AfCGY?BS5uW}%UxLijwh%jJ_Q4X-*AP8?~K^d^!hc5U9FN*R31v>U=sO^Mb*#Fb?0)wE3QvB;o+d?93;tNgSeht*O+VH{iyt9WJTNW)H0j)-& zO`mkL>5hV)R1+e>)qmeNU#_-ip6IPJOSZ|Uvy~<%PoxrpTyD7m$S9?=nXx))nmO!w zRC*lNmr9s1em)0?RTR*0)H^Itao;^UrKM^(Wh4**-hZR4bZ|_1T1r+56)@g)KL%nQcZ!cUSEtYdOETFtt{%b1y&!wih?w@Iw)AF2I^~HE z27R3hLObsG8eb>8?wrvex)VrTC4w)t;d{P_;dX{9 z2ms8?sKdTZ2~v&+Wiai_uZ0Sw^cGB*rhf*-M~bIj&vTl+7BvH-)4o- z>#O+&{JJfM|==dmdIYGQMFFT+S;v7tck9P*ruqO;dR*96snx&-*<3TE|z&Q2RYP>P#o#qHPU|1 ze4>GGGbDrM%*QM#CbngFC%)u3gnf;}wqs{UoU&@pQ|!dTsViV*;nl5#Asec`8S(k+ z&Kk|981`rTGU+){_mbRIAuIzONvxGE+{24Hw3e$dS0I3?WadA9H>2ZSON{e6u>Soy zu$)|GafEw7pb0G34Nb*XOu_hf%T5lT%`?^hFv?}`bC1h{+vniENb=WQ!O)$Ej<)Yu z$Uy`e{?{XVzx~oTCDM2=wN!Mv~0pk#DkwdC^B|&MMryf(#3T z7FN2k|FKCbk-z6aM00;1DFOcTmOXT`VhCwJ>=f+wROp3+GJu!hL=?OM23Z{QP1ZwC zBg`>w#4I_M=PQNY9tsc=7g?|qzNZ}9W~%|QfTlg&lq=E(H78QmduwoJ~*yMi4?)YJ`Wcj z(Du7hvHqQC{6~b9%}@v;AVfrBt#!g)tI7SECXCKn!I+pt$y{$T*2^V@*1n{AotK}^SP zJ@i^lA`6@7UNDPehXaIv@XN>gXQud37vE$|uVv4w5!WavHP~j)&?#`;?0`6?PK0-3 z?n%^hv(=7jV7P3iFm~AeYa{Zkw;uw9 zCY#~p>UK0k00Qmj32#%UWufLo$HjSjUHXSb0SoVx@AxhzhKyp7Yi#;S@#i1Fbbq}| zt7R_cK<|d@{R$6f-^Gru;EW8c%E0ici}yzZ&Zjq3eX{`;9$wzb))NZ0_T=|9p=ECU zaL_4o(B=2X+wamtpMJdJ?nYUwq=-nBf~b1~NO9_jeH`*bD=EeDCpfKqqPZ_a6(BZ# zynmtJcDSy!T&DoG2{tKWwDnZ-1)S2f@+sj;FI5 zIcgo^MD=oN?X(AKU#5X}*QPmrA7i4s%=!(!jV_2>Vb#>3$g=Qr*qW zF}=MA&D<#1-4%X2cq}h!Wt5*;mH5h(E3>k_SH>^QvKx}3eSh%^ztx-Hq@se=l$ngo zbjUxH{=G$Y=TS)q-kXwe^|Rp(U+SlXMhD2ow^DCqAHm9ZTOtXb$;3OQbwXD*8Qx1 ztjKhJsqJ`iQ2Bj1C;M>K4OX=9NifSCNag-KrXBs<>HP>1rSAtms6Mdy-H8EwUh(+^ zrRr`EwD!ITeZN`xsc5J{^yB;NF?F>$JT##X<&^mVyzo4pwoSyK(8?Nrlw7gPg(!%y z-MNrD6h#(k1^zlDuLTt0pv}KDp~e`GMrkOXGXF@D0(8suF_X+N$!JFzRr+t>UW1j< zscxx`{W`scXHWNf8GsZ-DB6+&Os4`&WCq*2!|=o6oO8FY1bF5C`pdWh-R|;vDTb#60oZyg< zHe3@v9=In{~(cj_)O@PYGSEoSA7=n1Wb(^Z?JtpE z@@nYQ+^7X_CGX0+!ov_|r-$Zd_8rAxHXJ5unjibmNeFcgDDOL7;Mc_bn{6ljkNO&n zUf?V`xS{=PW+&GkRdaPl!@6_{orc~EOD716yUx1O(!uH+8__&PyU*#=i~ z0{=cM*LGIneV>$AH0#Z}eBTVlJ{WHRZo)-x%xDdl&gf0$@;-W9uk|!qZY57ee;&8M z;|=$4jC?B>($=(n8k#c4%IvUb;ho!k@5h!!F01RxO ztqNZ?eynFKHXyI{SaiB^sVuC-|Cy~T4-)Sa@ia|)oJ1h41s<$UxO)`{iy+>i4VGz+ zlSd<>HaWx}pqcGpFRTKxYv#dq_@WbVC(pxNU5_^tYz*dgU11_9#kw&3o@{7om=>qP||MITyq z!_d?aH~dGg>oON!vL+*q!v~L+o@dTA>lppM*omWp;_~?I9zbqebaWkiJl@*W-^%^p zpxmr)8L)_o`{kIKy6-ZQH!oeKYSz?5W-F2$Nh!7NuT8#OPM^%)f>Lj~vO77N(!#`w zcvwxuZo59GDyytCnG5uo%v=}`2>MHb5_!+1@*guR84LLbrBD`VW3-2c_hjR5$qm^b z8w3xBuzYCZ%lCJ|b3Dwv;}Bueal=0tyv^s;UMyzHS&By4s!$zz!%Idx7s9zQ4E7?h zUO(P&bL2+CxlwyIGioBRS#W8xA>KwVumDy`eM;snd`@mEVm*IEkWcvI1sflN@oGu) zP?YE9k$1e3EOC;Z>>w$a+aWIhMR|k|Z7Gm+E6bbP@16Za-pnBK6$n$5AC7Mlf${$* zbw}Ae=ff`NT9ay+jjU!@zgb&gc?q#K#8K2+JQ5?tlD=1)qZXquE@L(OeaWvOjzMNu z_GrA>1a`%?!saS=ChqaNc<(a_U)pANBdvR0b99umF41}v@I|x9+#6(9;}x>gGPT=k z!(<)_UeXk+B;o6x(ZC~&dqMkPvFL>9 zgI&>O*?T81@L71C^s&T&a%HgIy6RiW9#}~(vaJ;DSr%&9mg`xT8oL>CE<5sb4Y1`h zv3`?5vTB+UWk~Hy!W~^LsVv;8I<+HDq z02KR24t;8J`=mo=zoZz7$)?5JZ-^c#s|@=`eydEK;&B!HrUmoRV4QEl?0-{Zb3A(v zFO_IlMs+9*71JR)N!oKXoAo%+ba(|92^_A$L-Sx+;Xuu`FL>R(s3E^ALlLq?*dlSW z2NP=v&&f1-hu`J^zE5WdT)V`jsR=zc=Nur>0yuB|)-NQ8lUbC-5(W1iITlnvHM6i( z>3XormIl@2=;C=<0uL)f65HL5O!NE()u#hJoH#zJNPksz+-k#3TA~d>aMzi={q&QC znPn+)0^R-Yh-N5J!tsq8IEX=awJrUkMpup<$M7oTWNvGN{Qp!#ctjd-US=wi+U3}5 zHTF7TsJX@WTog3<*`ndLo-uDNNPP)?sf47(irm0HJ#NeEy>(v4`SZXO3R!)2jN!EWA|ofv|#bM%IvAFp4N zC%W3?xye=)FQ+12&-cBe?s<%C1x=@+0PoYP$LCo__GZ^B0vjFg(D63b_xG@gb5VEc z&(oYqEbdj90~e!d<&Ny;i{A;3!xUGrW=*)-&nbcBa^8cGjPusK@CrC~I4`czh#aR} zWs=CR3$oyK@b9Vlc}(E5vvIV!Hl6RxaD{KO^x;_4^t8kdysPEd%u7$Mpexl=hTR87_C+4ZS>Rv>4=;YcaRF*H{npwpsCAq4*GG5e)?dI|{ZJN~+;`n# z0b9)Pe#7!y<2`6uEf1HAs3&mk9L`TbmfNSq4W;bMVN)E%+#RdkjM2NJ9B4Tgep48D*IK;vLGJszC^DpvH3QJt1 zXZTDlX-6}5b6#wDy#XYJF!y7vHI~E~N#3DTg3WDW<%0nw5Q|m=Xp%ML)&<7dtu>^a zp6BMH>_F46`+Okl3*EWvUdJO_lb`$Tlrgsj_da7GN`v*vNlt-84pLGQXANt_soZ28 z|EtzX1qS$?ko~|yB*#k$Hc)YCdQxpR2sC<}HR49UsbitR1J{kj?FM=o=)Z&gn;eb* z36ocp)H|){uEXPsDu4)<4IxYDZnlMJFlm`vml^$L85@mGY@LP78q%{+LzDsOjL6lv(lL|+AsH^U%!y$5+#fOc)a{4A?A2om{j!# zd@H8B?5^ah;DZMUa|TB@fjb<&#-SZ$Hs-UGI?mov85uK}CJCyv+Qp&r1kEOOERJ_#j&r(8ovF^7OFann$o4i@;M&oA zfy(uMD}lnk>27+qbZax11}537zP37dt_2V3sK z`DPC>k^5}O|EuM0p(4?9Ib@yd!-v<^^Oz7(DBV3M zt%P)Ui7<3`gQSQwh;%6pLwBbz^w23Wq;$R4PksNt_bylq*4#MvoE^{J``KrtoF@zV z6&2so;%Q!tnhVdSBUQGNJ{76$J?QI?lc%|k20M=WqBq8?(Og~~1UO#nid8qq@~=Ed zG?||Erx^7dr0@CEJkHl9QKqodi@mbwuJpq!aLyM0uB*tumn%S!Hsu{~tMWL;JKj1F zRg)4|LdUIG%ftgWKX?y^^2KucAG)_)HNu$dDhMaqcGstfb~rF`nzYSLED3?A6o@2G z+zJom1FP}qTnXh$da4LIbW06WVU9LJXV=_jA%F3Z62Ql>eR>wur7tbYqW51|FzHFY zp*II!=CVv^H%~ar6`EE?j@Q9% zsVe%y?3E2ZEmpsK$}}P|g%oBUiwxCUDp5r2h}Wh3iaC8D1y5^Rl<5v~ z@J_I3;R$q7N&qvJu7!Xd!1W zhq@k3oFzs(Z>~B1mfb3AxP$zp6YN%UkIPuS;EQWeUfSUP@Re%){D{Ny_%xjrgY+;? zY)xqp0~9YND80G$WU%HQ%Ye8Smi%Kerhg`ULQSL-Y~u^o1%3>cP(&QSOpRjlqtPeO z^_KS-Sp#pUIrUuIi*o1<8k&YnKIoOIPp9I%;@<0ke$Bqv00Zf84{gMP_iKAERu5Sf z8ccsK>>bhltKB+Ir~AcnpqxKDa>%6Wc&z5}g(`&39V`63ir4jeskp&U zp@9v#+A|CF_l~)@8ZBtf4CZS1NjuR)Vi{{pmAvZWR;DA*j^Tq^QPR!cPg_ooqCXlE z^a<-QR`Hlblfk{Z^go9}80T+yY81*T6r$ZlRu4Jwyr(ZNo){}|)e7{iHc{-+P)TE9 zE-9mMm6nTkXHzK*k2gnVljd*KZvz-y&C|I{%f#AB(aB!?+tp2C4_Pk0N5Gfbdn2*HiE@&1TBeMLE z7v0W$gt_>7Kw>9sv+PFi@HrPE*2U_rX>k4TlFea)h`pt8O+tuN5Bn<;J>BsVoj}Cv zyKmeUJ}m67H$bSS??C_`-nLsC+&_8NI;_00&|ak2aO}b8nE#Y5i zfadcojb3kzW9-MaY?KRcsSrdH_}hmHAh{M;Ot!3bko5-)9$A=pNj_ow&JnST3%FCLDJiBPf0)_Nuo8^g@2@s6;ZJaw-$mb~Mt@f0 z0iG>1*_%i5SkF}K$;pN(*CYv?;NA(J;cE1zY26vG%~Oj@EqmUc2$VNd(~*(^E=8`( zy+O0C*;G}^ZJ%rLAI8FLR(iE#j?IfYe*E&*58{CG0!ll-B<0`$+UL|C222-#p}DZe z3|oPe`amWjy3Ds1K-MU`Y}UAMJiv=H?6n=indZ;Q#et@`oL#%FCVC{mt?Zk(?l1i1 z=AD`ih)*_~Y|Bmh$CeHh3M^Sg|EgN!FMrN|OlJX6f2}I8fP1f>hMFhynE- z^tSZZtZ^+J1oNr1RZP-ACi(qGf`_a$);hOeU3iUJxOFNx^jN~~ve0aoGw*=NVe8-A zFH=j1e)*4gb$dQTRiUY8P+sOP%J3LJ+I%Ppuh{F^{OJ-fEy4PcPe--X>non+06E&aqX7J}nf&QrH!9~qw@C-S4u zRCfEjW?{31dVM*HDnz(DLZdSbMdrR5xvwm?-#lxEbVteRPYEGjWG{LI*8Sks<*iBM z=gqjDwKiJqm5KoD6|Nw7YcY+Ttu$VF@Ik{?AB&ePdhL=*9Q)VfvI`A@@m&b)F)BrcU$5E6{_KU0#Bs6yWNnDH(IgHk(sv1KVeRtf(DRfZy=#t{#}`VZMUoAb z>SDqhD0%|VXxm#;IxWxht>k_#;kd?U_`-|h1b;Z|6|YTb8*w1e4WTr_i4>JMsi_6^ z=z!di@qRY}Qr-J#+Gng-=tDL|SXe2tbO%hZ)qYq?N&0&rYkQIZ-fNpyZ^r+dz#_#G zX&p~3OVq9gK=8z%CR>;G>IyTR9e?kCL5ubw`Ez{3pj?Z&j5OkPalGqW^tYPtqEMsk zkIRHis!nmCy2T2kij?Rv<57NXqc|9xiCX3ODsepb!_$3^)<}7w zP)l747h%^WGMAG|w&>S6fs(7PA`Po8(_(dNUZ`mC>;^#6_m7+8a^NT}{XD!iNcxmz zXs+n+byZ|o*vgLi*nw_lv-fkKOR5eYr9U|KbmrU1vQan(R@G6wwfdRCGa12;hRHHxA(U&21<6q=R>I!JumNY!cUcr4$FnN?(vqtQEuk75goa%+%Jt z0=(Ytl@4a}gAHBhteVA+mptc%`t1~LTm9bcW9M7?d{Q57u@@mJvw^1g3jj1O{_|nT z{)hS76qnp zcTr3sDROu+i8m3HF<7y@UHZ`=7wry04|xKK8Db zX_rOp^4V3tLsy((rAK=f(}(H##2N>^WGcg#WE&}baRr%-rdmPZzv#qtPBOc;`<77X z3t8fe4??edoLM$7DU-w0c;xo16$82045Wn9vxOxu7qqIeCE_$VTq{C056}S;>TvS= zInPv++n-kx&qx?|q<=N_NL*;xrVboF3~_5whrfQMmrhag(pU^2NyFVI=6-ghYrbr7 zgOm!8B#hcCz?uc8snv=7)Iv=V@ zo0#kYD#*^Ot8_f`i#>jHPk`)LCS?0rCI@qxVzTJtrJ&tHHL)g@Xpa)qVzhM2cbkx= zbKj}vL+`wu=izf4H`hOq`!fV}EOjim;$Y)gE+f*A0+sF z9p-ErZ>XhvXw@ZoSdtKNu(4P@MSnAq>)wsW?%}SPORBteBCxVF`tzDj1hm-GRRNcK zOUZV#-|Fg{{}G5e*&>1+Ji^I6+&6>`?(6H51<()V6AkbgPtD9uH_W^c*mDT|L}bq% zFIMHXM42&_%DK%O*4iYxG7=ris?KgqQpY9SIkG|4xU=K?`6k6;zTeUuTB|>`n97kH zy?t`klecp=PYhlZsvy*?ngeKbMU-Qv>MHR31F?qoFjs{QhPODU2?c0_`%hsv48A+l zC|JY>MJ+VJFzCobyu0@@cvisaf;9C$ODeQJ4qX)+7k6&w-q7v0v0*er4)k{!HNfl= zwF*GihTZ1^OfM=gtEGt`hju^X<(qq)MMD%+&WaqL5*l_JJU_Ef$<02>WmVk1e#A{S z(dZs-s*jE!T1Tv1w(C=)KT`+b7=TPyH@`x>9CD3uS@MO=YH@lrh_jx0wuR~_edXBX zG1Z?&>HY{1fWHd9gDloCr{m>)Qx8ht&Bwr5WaGy-Zl;HM`n7Szc~(ko;w!KxoYdhj zce;wksdW91l$*+WToY&zLZf1wt{Z>Y3k5m7_iyWy>L)%^7{^+ZCrQ2D zlmK{UJ*3jRI-q!fdg^(Ez)QUn!OMRtS?WWD^>tcu9HmAQ-}7d&R-zhBu3EBfOb+HV z{`yknCy$I6vhJ-;Kl@KG&{(4esf+ggks?lGfP?e_a?Z7X=>vbCpbB(-0S#NO6=0c5 z;VPmaAKLEq?AABlR*`XTF07$TSE8Rsd|R+DCEf3?Up(pk6n!tq0brP3{x9Zzgka#) z#nVHN6Ew(5`0Rd8S#!j4o4>2yrs>R@BOXpf@yAfd_c&1n^gb7dI}xDPjIl#|iSrZv z#=Fna2n~-pa@V`#0W!{+=>)F>hj-V-0X7=5eKR>gV=aTZALBmWu;Wl2_G~zv&8sZ; zMMyXjhL@i~9KhRB|Yxw`xBV;J4czN2_DaM`=^_ zG}k|GUxYQQX#7PYsP9at@=Hx0>KKx(j`csSqc(fHf8thv{w!*PdSrco=%q|ke2flR zKsA?rEBagfp5z&IfGh9@72x({mUQ*>Rv=n8$$NT$fDXH++0KqrSs=BVq#)b^Pv|xn z-Jh~QdOl4-$ImNWJ|_1V#RN3^#ng^h|MXKBM`vc!{^G81Cg_ULRexi8?{DApw5&*D;& zUjsiE{B?Nvr|-n7me1)SUGtg9qV6>k7dA4K?Grhql2}yg_Xah=bl}*Zb1_61);E}^0U#S<<9np zZfz!movw31gyZ!@T*Zd5$J;R~W@#d!YCq$jtvp#t-$+K42!~o^gtGbK z9a~b|LfnN^*4_5QN|p09PgL(`s_o}b!tE=Iz@T{XI>h1HUx#oR^yAz6Kg}g74m3@s z$8+kG0~T>c$2^H+r@shQ@@!s|ma4IkYzdbB-|ouIRCGF~n5IhYZ+pFKYoRh`3kSS~ za}YAHZSDPOlbN@ui6XLc={-i1ud8wV^(xDbv)CW(25Q?+@jd9K5h}m9TV)3Ar0p1q znf8k|`MpM$xE+kI1X6#CUYFux4^ya7GO))zAk_J=RIqrHb6I7woS8V&W+Pn0EUHNq z_*}YiCM40IH6Cb+JyoR%uQ3>YtyvjbEX|6ZSXEOMqsEhZu0z>YK9%|l>+PRj-sBf} z;bFmmb(*SiNK* zvK%phbT2Eud7kClCYhsCtcVryr(Qvbg^G^^=#$im^m9Ek`e!(3M)47n9cYpQDc0{< z;&NF4CJz!KC>iC%Gt-VEzR+e$`n3?1@|&iycVfy_I$dIKs=%6>PQqDFLJ*(fU=LS! z=l$O{9mdb*++Q8aKED`xK!#RB8FdS7ir(@lvO!m4`;F33ZyDM-TlaiJbLokK@S^T( z4ti^bN=n&=k)RhFaBmB5s0@3Xd-s=vqZYS6f4A=Ahvw!MznO2lSI7UNNtDW>IaT%4 zJ>a1xJGI*Lq#Ll@0m~;Fi99&{w%O(TuI`t#czlBV-)t6GZC5hZzMzxlaq|Ni2es2? zmYb|E!5mSqNP7b@fy%RM2^q&|xeIscw|W-RstdR0Hp`BGN;}Kxf`2OR|EK$$$A*c7 zql3elo8DlqJtH+d$TFR*u=B9r*gx?Co*i8-Myja_wrpfQq}}*9=%#Xv=s^XMkJ+uaafx|tN1%uF`Q`F#*S*(< z=%I{k=?KVLIp}!FRh@-oq8wMG1kCOSJs$~05t%vW-aV83mkTf#M@1T0#Tr*tg@}xV zoEsGwQP-Bb?Uz4sNvapG-0%gRbST0XqwT^UD%S=OSx zw5vJu9+>v6v@qh0MtYWXUV@8g$6n%v$YHL2P%l2}(ka_kZ z&oA{l0aqBM1e-K`m>k59O-d$UWsfyojf;wd1!E<%*VnDqN@kDGp3O$?_-(0jS$01< z%XTy?oa!~(oweYB#LU6f!Ka8tD8jV6XS<4&89YZLyrVc~_+4{Nkh zkS#Lg3A7W44hq`k5j`r$o_B5X1Hl*Hx<6GFm8lX{Zs);5hHgm{)a<(M2)^m=;KNdc zG($xgAQfb&^NNM{{6Rsm{l5Cl+*xqEprJB6LU9@FcueLhK4wqKkwOWphsD=`VetME z*#204mSF0l2=c;Z0X)`F`k%u>NZ551sRIeKx>4gwKr7-z(7I*3y4ucvuTG*4bibIG z#a&llE6<^AUl_u>(P1fc`?)SFn9$uG#5PP0wY7b`pQhPWzlA1?3Dd$I8ZXv?t2V|o zmlizKH0tUc0x=pN5$-V!27Xf32So>&H5okVqPtteE8NA3vxbtdv$I>M*>qVJ0272g zT{kwxz7zFaO)nU>QBctKRZ%3?lFeI!T0Xwd%8ckFGRG)LCKQbwGU3v;SOJWo zX~X;5SS_$Q0Y*K2ZbOc{oOe4nnDt6ha0%ZagtbXCHdtR}R*A;EYxqo`Z1wI)Cql3d z0S9|0Db~-H_BdCbdDc}tHjb|SOK7bFXkHN&3psvPD*roHH{VAAfzL6$Rba|)KGre{ zC4t18g0>(#rVwC6(ezK~@hNOC>)QPxvv2di6LoXF2iwsTkAoRV({+0g zC#|e>+G`Ew-3VrLpZSpOWiqc-5kks4cKeRw`R9)|6l5HP$SH~R7|tQr?)KSOY%u4; zkM&^MXh8n7O?7qZr}xuHp(zsl-{6<-+r2TO+FMo{4I*_bTG_KU*~&J#-+Vs3eigko zD*o9x)09kl=q&~bv8grt=M%ERU0^oM$xtWym|FY;ZV#gBFG-LcZ(BTDB$)M5DMviK z#IB@XnX$7sFqn1~6j<=u5KNGT+pM17c1D_7vSVSjJRlSfCt(r@Imowt8=seT!Awp9 z2hiAJVqHnm5mb@QyP~GR!rJr6;>X`g!P_o$=?ZPuPrNWfyG^7v+Cuj4a%dAK39z8~ zy<2;Dkt|&_IHo2hFp^!17m%?YQY^F7F}B#g1wRvL8z;PCg%4et9uDgW47VT<&FJM) zihB9-I6}$-YNK}Yq;NQl6R(2{d-5aWav)8`iV8hN_mD*nd~~?_{-2{eowsd{q=jo>DJ{l^LMIu%c;}GTs3A*|Y-6^7$~&%~ zIxJ>Zvz6xN1rfi`L}^rfX=QJ+%o+$LV?tHdW8AsC$Z~q9>m0ERufncmCk;>N?dce+ z1DWqa;qdmyp7j>EivFFn&u#cF#m@`t?MAX^wCi#(eB1&gLB9kRVsLD-w7xS1@H>yQD5I4S!)#vuLZX&S0kphV* z2$OO^qTXf5ty1_vQzR?b$6VOQg6pd@1qc8{JO&RA|G*lzfP3Ma9H&2#)% z({!eUQywu1PNVD!eUX>l2*$LMv;;YIZHOr_C0c^r-!}_!VIU%UVign18bA#6#J?Ks zy|5N7v=Mm~U#*s_q(rrByf7)9228GXa+u`?CW@0!tHo!97JpEXe5!`nD;GnmG>s_=0bxyCd^RLL10J@PE>hf}7G)#FS&A0f4$m7imf$Q`2~TZlY)Qk{mCY>EGZgFZ>#eSd&Do3vs@4hn3rS04*{Mo)$T zO&?svyx}$+b5dqj*O|BT*%2HukS1on0xs!$D%u(2%A)`c5?KglfLFlkCwwCQ^{>yC z6uB~8Pr_|X^aPSkH<^r5Q|n{5c<5|H63Vus(;($`Fzjhm)P~G?RI)<#PCCeFy_3*R zXX6467)}X>i@LGcbyJhWcaX@zaGDtOw5Gc_X9kZxlq_pC*Opaqvp(6kRjnAY_*$@h z-^QHVIq<@Z)PkMzp(d*MO1HRp4mQFgR@lt%6EF>g>X>3KvT#DX8^1+U8gt3F6eKB@ z-hM}ZnNd)egKx|=XLLqS9G^I9fsv9Nj0lwVBpKIhL)4-48H4M%s0y{RS+z=%FA`{H z7GDn*zljlFBH-YtG@bhPrHal?RLF zhKBXKb^s{YCMGLitWf^evAL@Fgz%RbTFgJ6K=W5Z;hUJb zjxaDRpFnxyL&Zu2Y=bWGjWBCW%h!uxi1>b{jmey>kHdf!4=`7NqLf$=K)1R!&V*$e zpf;6siSnPLdbt&?-Q`Y--ykL64eET68YQSfq7+XU@T=34sc@LdboTGr&RJMom@eS8mS*6vipz-ak#SmrmGw}!}RiscOu zQ()`fUQ(=2@4;^MwlE#t;S%n(6TC6vD|aN2zhZZOU0aZ%$dZAmk3<(XFN$c|givZzs#p5-{Q65Q0B2 z+Lq)+{WG-#$5Z^C2_7?H3Bwv@6se7Grb$TVP{ThaGA$1+O)s+B+;y%>_6Paa{GfL$ z7iSQBzp_k%hPDe!Cg&jRu9q{oMT3d_w!=hWkE1?JxLdayW|~=y0mDMyL}4TmnIojR z_NDm+1%WNAz?cC-Uwl3*iR>0OmIvv)#a#Pr7ThaC7XC^kjd5Y_OPRi@DTVB<2&`VA zZyhk-$~jw=tb`Su*gVYnBXfI14n{3I*~-pLIsZHjomy20eo{?A=j> z5HVpx+ZTc|&<7Eo5)BTN#2Ts;SZx13LzW`Gt<4z9o6NQY?5mTj%v!~H#Xg`053{Jz zH5+AbShNR>GDiv~WL8Qfi+*7-CTUbCK?T~ealUpUic+gjNr6s6j2{{5blXBk2FOjW zlCtB#kVO@HGjtzS{&^z2pE2=`=d)c(GNy&&{0OI5K03_b;5o-)$~u z%{wjnR4r;@TeWa>1RhpaV}WbzP~f<}kX%ZZ9h6X{AhWLT8~}p?e8K`!)<%Cw(f*4+ z=qEuDD=?u(JUf;S&-K%Z+_fMMY54hgbcNt{*D=L=F9E2H_s!q!BlU z;h_KdOKE9TNtF;%GI#yHd>rJfMwCsesH3|8*~=|3oNDhfVcCED@>RI#|G7XuK7{nA z4Z_Mb^CNAu>Qz8f9X3(swd40%<6j=a-YkxE{|$~O@DzJ>r((s#^{QV&(aR=J4vdsq z=%om$2<)9u3Bvqu4ia8D7B}Gno1p9nJiYh-4&jvJ^l*Wr=_F74Pq?-^Hj%#j?^OJR zWfs1}1?^U`N>vXd_7d?^MTg%T*)zuzZ4`<3u8%aYJAf2gQHSOn4BQH2;2Y)81~A z9p1g45(JVntcaEpZ{HWWT(icxE0aH4869@cI}Q8-ac zpM;f2z5L%B(07L+k^b*rXZd8ylJ9}8<}iU|OYAFm;)ef8H-3U?w>Tapd2x&8|1RLU zdyl2_)Q}VmGOS2^82QQV*7@iO5 zWPh{!BP;p-3_Ba`*R=C+wd?l(GtVfXcCu})PV6!hKev_olL*M#vPVu6@eop_orv#) z)GBqj;4o)1velPvl@ywqA_H}@|6OeHeyQ@Qa&xZ&uA2}CFR95d^U+ZK*{*n_&`+f0 zLikK69a;Np))iRG`=Ynn$94VTD^Bfa*gFjl5?tRoaUtIS4LdS2MjkD9%;Y{(^*H)% z$G&s&;}V18xTxc(7z?(mzw(T8@N?&$n5&N7fXB-KUawONj@I95S>V4WDZ%`w%sku5 zQe7GB^j0o@J0mC%=Tl_lfc(X&{eX_+?m@^a%)lgFMDIT)-!QjSM%*fW(==P5FC>cVlDh$9n=h+rX%Ayu+KPgqh^Dw)LX%joU_7cdxHTf=#^^!ucFcb+vrp zQE|h8Mw~|w{$VjK+R;z)G)tmPL9L7TT*Hv-_nvLrLlIxXi-j(%jYxXN?_5Cx-(Y44|3Hk z>Rzantx0W|^xApe`B^9TwQ7q5MR9_V@Hy|6$d8rT7u%>y=_@^7+^zav74@51JvT_f z#JYO`GXr1O)!&_pe)qtB)!)A+m=cu0j53qK|L!0{Wi-rZIgBzp49YChnF5>bHgxEi zv{9Daia+W|p$YeqKqNWFjqkcLyXuR`lI$Jj6apJTI_7sG1iM!_gQ3h=u(u}C;|)43 zp4<}I@p9B&7LxVaM#AZw{#*N@3^E55KMJjmsF@Tc;@*NzSo@Sy2mBsArBm!7z6aZ& zt}dQ&n(g+cB)nmoZ@LyY;2>4E8d--L-{>DcoU>=uGyG+G@E8}UJ znj-SfBR=3u`@1y7?Cfm!M)^jAe8oho_y}<$PMA0~^`*DhsKy&S`~-Z~B)11_Z=A=u z3bx>AE0M=Xm3XNhw8s=zW132AE|NJRuMQx|rTNV|{W@dl}>ZFgrH0o7<}=n=ci1IS!>yuv2PN#?j2V$!K| zbr~`ax{jmOoaXa44%9Je~eYmiboN%>);JDG${kh@`x39bvL-UuWALNlq3vHaC zDh}}4?_gOOhvZAwncgr`qXC#h`)IkCdho5;R#Ex$XRPZb?P5K9nz#sf951$`10LN- zzB-W{wKaZKI%?@{_?Va~;e&(i=5}}07w|mk4X{B8%CK&=FA7bgiSXs37p2GJP4Wde z;9zfGsIeuOG}|jzowkb$OQL1d7s3DHK4VV1l{9dpaCG%7;F6z1=Y;zo*dQAi#?Fp1 zo5V=qE0DD<5N|Erb}^o>c6Yzrx|IA_UK(|Db>Adp(cxLGD>lzY_l+;XguoHivB0#F z;n{YHV=B#!FT)KPmV1DD07(L(Q+MfD4W7S0ccunPKjP9#rd9_%u{92)Ii9)j95;)FTc7_&!#&EV^+C7z^NleVBSv5nU@)duwl}MNKetb zfI|m$KJ00BJf+THZnRm*sPeo48jbk!^?m(p)&+@D=vK|sqI`-%*@Kwq^>s64(7mhw zRW}XJz{Su@IhV!X>*?tb;G9K&CZKk0b~BNdjw2dIJvbb$aUTyR zriy*({IE2=`2@7^eQ6^<;HKx}b#_X1=FY=@V^)gxldN>ofJagxQzBoF5<;DZo8_+C zPebst#{N!X7tx9gjmhR&^PO9%nKk1S43Htt_>tqJ^wL?Jdgh(=@LErvHR@4h7Fwh0 zuG*r#V7$c5uRuG8E+^%+M6kXSZ)dnKh@;u$3z}@?WHiE-1XxoE)BiZ%#i} zzx?YR%-qnv5cY+~(~r~l(Tmw{sy!3g!+%5}rOw;-!H*J<1UNFOktbb6`-4bbU0sCV z!BCmRDDdky&>!kt!;+ps(fq^K=0i_CIGE1*g{m0IM!Eh&#BjwuTlAQImko_X%8!iY zjp?22ttG+P%bU7Im;Q=|^(Ia(^NVLzcW03KW?SZp_B$k7W8XN}7X^Yee_V4y-W(%r z`)Yf;JHV@ktz4P$N{jYe2oujh%RHN)hIS$uZ}=l+4(kFS3gk(2SDOlsJKk55QjU{k zbG`^h%P2G;#G#PuY>#s>=IO~539OV6cQroo$_WL1{*3aw?u z6_IHUxPEar9kE)PxH>bt>Ok%O!K9^{a(M|2*Owr8`D;5h1VekwP3_e^OdT!SB?Z;w zT9J9K`UByCo$G~7w=E%6Ate&Y~EaAwn!Hu9ON>O^vQqk=h6t zT#zrBE&#DSX}s~KrWQ|^r82_@AS5R4@1yHk&QLR&#b(4qf5M?)N4W1*St2IL`hl#$ zsfv*HYGpPPVL*F4)T?oUz!*g6-#Uh2WFXXC0;+;^kFpr+po6^esXcKeT&kf)GvN`- zA;v9F)rT|r)LSw1Y8&kl8F`NftUULSh1v)n{1eoD7&2jp?6zy7<08Bw5s7#4*G+89wjDpKX#MS5WVvJ9RIR>BPXR{xR@~q- zR^_P59d3#jEi1~d@|>`xW!uKc=!_5OGc@TX*5(DzoMhG<(0}!8xXgkBvUzftv5!tl z?9v&P#3po(rRBc|UA);i+8urS2e)prxXGp*;Ug$OGL#a~T_`C;*l8$Zt6OTnXb!b< zPTF#t? zft{e#nT0{u1|qks9sY9BMIxZ_a?3uL0~>VJyiou$jrz4*z0fnO;x!{6Js$P&!^!n@|qv4(@A<@mLc|FtDWlkdP$ zydkU}k;`kr6@Ux#I5h7I$5K%`0Aq!y<9cXTI4bgWCtGiHMu`%!c)2w?;=xn!@yPaZ zqjpFT=~sUw$EU%MyXCMnUI#?NB1KIn`@gky>Uy4yP*1;^ zJwTAa)QxM7-4W4IL2Rs4UK&ls0)a6o0Qbq9k!G*<~`9Yx+OY3cB;9n!8b zCT2f1hduAGmg9L8WjGo+x9lQV#JoRlD?d?ropR->FVG%hAHWW)x7%*ml{ zkV1GOWjZGQNFS(NBVd)qMcU1EWpc)32g9h<*m`Pf?UTUtf;yUKKeSOJmU5iZ)|e^% zR!v2%dB$k1gYjRnNF2w@r$k%+Vq}{TYTRthCoIwZqCYZb7Zn)^a%3V@EIJl< zPb!PQ$H=(3EzKys2V2_dlKWswp}mo|;L;3R(|+mt>{jdgGF`c~t zKM8(SIF=a;hPBjg?@~h=J!X}Sybj5g#rL1J-TZjm3}HVq)fa$TjrQ>=8ToF{Q%~Rj z6?`VFJx3pL*roO_zP!B#my;bYIHp<}B9V5wrjIiv-p%bmUlEZ@;-Vn24b?1Gg5w}; z7fl8t@&HhjvXDmQ`08^gtaqjeIjm^9ue-bR5v;Pferh!$9CSJ~F$J&K8kD2n?6v-C z7hv!rX>*3gFJ5MceJvlCeeD81cBOhFt2ch&UV|=Y?LNwv=1}|Ae~tRWh(3JZR#%VVCg4uTLl($<{n< zZwgXBzfnzoqnfF_F>1vP&iFDcvj{I--rqvbju&h(IvhYTjN?zS;K@vS!_A+T&z400 zS$Sj7stP-#)@E|=_HO*CrCyrY}6<_ z{@foFaN#}g9W%SL2jB6QEXybm<3a*!Q@b~fC|CbB!PcZ##^w9RbiLAPMk!8K<@ihjaXG!@mWP% z8~2yQ?Df5GL+Oj7rs!(jwq{#x$kt^%^{C*jZu9EPK}J#me(om8g^Je~p|8a>3`QP3 zTkk(SW}FCR7yp3Q-)%c>Tq#A+PS)-6Y4h=K{V4gY(golCSk3eBk}The>^x)E{irXS z`TkUCqu=Ecf#^qo<7lifr<7JVl}QZZ`N!4>#ZQk5{M8EG~ktFB}`xe*)VkIX398cGZH*Bm2GB zi71Z!n(30(qnbpb5(g#3+Zhu~Z0I|6sd3{|l1_|+IwHUKJJ|~i&r(o$i(So4H@yGC zDVxU@E8S31`$Zd-6@3fYe{!;m{QP{$>hM_Qa`<8w@YqJQ;(R-2B zQQw8vc&-^T{wg{SX_qf$X2#j;Yx8Wp`)mQ!x4o%p9Jzo>$;M`lnV;Xl$fTnMMBlN5 zjm=hCwm&UtBe#*O>R%rKf`WZ|E{CJ5=UZ%Yc?t(z-VheF6}Pb|Re8+RAW`{Dke?sr zXyhpR-HYB?+YeX25O7nMC#R;^sdRy^^xiA0ujH>8Mo*D!CN9EXGdRzDy2-uCl~-YT zM<=(J?zI2z@8mjGmP!HCYhSj7>SJX^2We}6@GFvSj2CPldmCyR8dh$9gOrp;#CpEz z&G5~W;GDVBc4ScF`Y0xjhIg`<1Y0^82n;W3M3tNfZRAbh`y47m*dDxBB*feO5KNWoB#tSg1=x^uy#CUZTgzN>C){J<4XF+Bd;>SIA510RKecqceODZGXq*luE7dT9y zXOWfgDX_5?l6dhTrsgR{#O7^PJEg$9mHKSgnLy|Hxy=9ofuXOmmbUm@R*DHi1 zOl;5jBuqYZJdSGEwxB?Vfw8v-yM##n>0(Z+DA9VlYThZ%7x#0@_z2E8Y9&M3PagLt zv9Z4Hfog$>`Gy?+0#;Z7q))e~Sm1l2{-Aamagn1Y8+P^)@u;(Xw4mMk(Z+eUN6w`6 z06l%L(!%hv4K)s1PepHMmvb^KypzTU&(m{>@0ymtR4=9LI{>A0_4I}|TJP39 zgTcJ*Roq8Sq{Blu#I|N1Rxyj$FBGWvW9EDzknNp6H7o1x8P#d-A0y46s(+jd zU#V|CApS1oUJ+4GD>EB_7WHr8AY=qBGn08*ZW6vdX0-Tx5xs@{qobamU(wc@M%2Dq z33ZXj3kbN6^bKUP-rSKBOk-Yv-|yLz zISGW2LpLJ_NT-^Efav;W-!wJ<;!o@`%lH3rJO_ZQ{0{tPHE4YXS+>| z(4PKN{=ll*5!>mtg{hp4K zH&ejmw*|?-R^;R7eyui>zs^+C$FKZU_xf=PH%XM-dX z{_!@|@kFUh$DUks`{1P=_ZrUev%p{1CYTtW>V2#3e^>V~Tg zDtrAM7H0@gzJ2zpH(e0Oi(9Xyy~PTdRZ0Xk8!T>Ky0|%UrvPxqg_wBG3)M)r-|ViT zT-n2~6qutZ*PqEu#T)Uz7IFFhRZ7$ejQY_SF`L}Iy9eqey07Cey-t5LvqisbUSu_p zmkD~+@BtET-TZ>n@%sm~V;%U*${$e-Vmf*Q@|5y(mShGrI4=5{n#-%bp)*=-hToWC z{wzk6&?)x&ee2D8tml`h+~!j?f8h#g)It8(ST88gj|{Oi?t%ipg>9+iUYYarR6{G} z%n!Q1H${ymf{-f%0w7x-RrAQyHTX9B2PosafrMgvrIrR46T$A~#r-bd!NRoP?bcQd zD~H6U3&ZW@j=0v~&=8`i)?lBkkmENW*z@Nxtel|VDL30ze{kUX*XEq^ za@gr4w|U&+Qr+#vtFPoz%fOSMTi_}o3Xvc95CXyhh0a)4IdQR{EygvUO@`_rn?Kx{5Ps2*H6 zI3pJFg%}N|l23&_wpX7x(;(BP9R6uVZG)8`ZR(Lqpz-t)hxH5f-q2epN!hT>K%_1-#SA|fH(-Q9=^N|!V!C?Orvozeo5i>^g?=egF7_kHJg z{yH;f&dgzEyGMcb)Yae5eLr#pWm$Y%H>s(~S7X9&*c>6f#o`dyC|mLWV|n$hDGH|r!?#UN0)@oY1qG(I<}^eq zF!$Jlx%aLH4`f^tdL4DOL}}x-Ba-TYqrV#KtSg^X66;zV`=d*kR+L{+;fRuBhT$J+ zn&TQi8Lcy04DFvkY^)IsWuBEo@lHo&X|#!DEI+WYKfe}FMIV$}ch+QxUw%a$GS0RgHmr(5Ww zgOgm`Hd`NX5(!3m2za@-BwSo3kX5T&p?l8O-}@6kM{{$rF~`rJJ&+5~#hyLgTB*`x z!(Qaj7XIWD?T4np1YilGMe4QxKw506McotfDsFDmZSjX0%ShyF1y zzevc8BK6!vFB2r`hpV0?Fx$+aeM=@;J?BwDC~Mul&0q4L=U=B)xUhkUb{gjt7e}9% zz)Wk)?M|Y;Uj4P{+&aV9-kYcufDQYNF=Hqg8--2(iw0^7xbB0wIa!U0Qx$Ht1W5fN)QL4LEQo9% ze&*!dMY>oKS)N(2mF9t+*{;5r`nxR9N4s|eze+=a-Pl6p?#&1XCsrLky$wy;yJa0N zAtr^M4ezQ}i?i%HGbV?p&5$>;f zI>ZsBNR3jvRTWJIxw8jOvRv(%Z%P+5j7Ts-_Gh|Jeu^Y3hI|be;pUcE5v$0+<0N{0 zcer$Va1z7rbf9v>R#tSoMZUxE$kKwDfbNc;NA}g#9!`4opH>u%uA8S{H-E*jyF^D14(%ih zI=%c8u&aj06yS9-h5q)cDT7c9-Ci_yk~CrgfqBzsG$i9)CHQ@4qDjy1v14tabYe#5Vf9d%)Z} zt>rR@vMfhlUXn+fa4L7UUj9?Hq8^K_Tz$sFJM_o;3G4bTQJTbs$%74K?WAY?RSI|S zk;cbOPfVO^HoFB+PkhkT!==Ch$+nM4EIcW&3oXXVs#aQ*m3IPi-tebmW?FxyyE9g0 zfCZ6xPNP<*kD8o5)KKb})f^$yVaU%IHDkxjeEKEr17gxWg0sZDp5D6DQ|RuDkq2R& zC%gOu6K_>Pr|q*iVrf@vW-ku>*|dWRM(66?0qukTSZw{jG!F;cjeAZWS#@X&k6hXA z&gf~fuCt&!rtWVb6F%a(q&@NodP8+Pjlzj^r^I5Vq&weY!4lDO;Iv`rrgU!uy0iL? z^p<(uXp@)bh`=tx*ho1$ccJdc1;dts!6y_LRLb`V>`HX(D`&?OGbeb)Acvx& zY??b`eO&{+ge*xfM*c(|tgkAZ9PG&N?YX;yoiQ`$r1rErMq{D#vBVq5QPwly;K)o= zmQHD$bu~Ai()VZ_+d5z5TasO{T|;y^3!QER5}DhSyPl1?HR`a?Kcoy#&uy->WLJxr{s`nP}ZHL~F2ty&|5EXXgjvPv<yu=nN%1ENQ*If@2yH7=K-Qn@ugw2T-v5Qhhw53j zp(|7oeA=v`#lX;3dD;{gCzhuFj1WVMTr_DYU4}oUbyHL_NVkWrw&O^rHd(7XR*aI6 zG~Ysk>b9qln`6ByJIC%stWYe;Lg$j*@02bI^h=saJUNpm{c5k8ykz5BPGAj;&A0y? zU%x*Pi|7t+^^xJk6WvLzeD79|noCw2wWenL{5^?etg^}7wXa_-zC)ekFYgi+@ zvnlw;N^_l6s?KI}Tf~v6!tM0+31RJKf6P%|Pf@pp&gncbS9b@8+LE6hV|<=mmZT&Y z){oSVY42Uj|N7%o>+|QT!rqgLwW_LZys{BRyjJV|J6V!JGqtqx2atjjSk_Mil&@`DiNbDyJ3@VV2}huaO+muOXrsi z>am@-MUi=x(d+NjZ)8ePuaWzSX|^tHGT6RdzpC-;=Ao$vCplIpGD&YP% z+M#P-Z&_XO_1!)?H?}r>*i6(*-zuIO*{q8hf)~2)YJzhm14erHNf(Y@_(%KEd&FR~ z(pu|K*0;gWar5HAl9`s-G7h3XP1deywt;CjD+$U|e!_1qp_du{>M$uA6Al0Ak)$4b zZ5*7 z&RX5nFE5&d&e?$DI+apf9GT}n&p7^h(x#Qne5CMwrXsvKW`si`gk09nj_oN55XY+Kh!$-J*<&={9yR85aaMJHyn=Sc_i@cukd?g}EvkI8rFJ-z zNsyr(sdnQ9GDs^UGm|Kkho$CF_p%S#!I)jh%`z!bnPibfgO1M%s;bZQ^r%>?cki&) zo^E@ayTOSbo_TsG-&;y&P)y6$Z@cs3#}9vrRMdflb~-tSOU7qC@v$-Z*NXd9YCVN< zaBu`N1Vqu-JG9O@U^E<&eELn^i^{TW8bi}%{+_1C-azWIgIl#GO0in#j76{OP83xA zX{uD)J=^deOEq8nlDxorD#&Mfv{P>}Jv_0RX%Rb?{lH+N0@eWV!OGZY9vJcjtWLWo;ueX#n9PSA^ zu1?{49YQj{$D~masn5|Cz*;l>_l?@9+8Hj;^Sev{cggbfaO>5pS7>a8orFKKvfR#i zXS#SN^?QmjUMJ()AhYSAv`LnrN)bk^P zOzZ=bwSuBz<7ehK0?d_*DFMb77W2V^>ve@pnqFrPa87Woa_M#Ava&cNJm%VsA8?$7 z$UifwHdHvQ+^o4)8c*~5^X6|c+@(NNOa3c=V2jg+He&imR&GjRVK~3tLcVtWWm7Y= z>lnVLGX%9$k&1HD*+tzA8wW);vl6d!)Wi)8Xoj@Bglmrn@`h_X1nnRqwln6hW=ORBgTbKohOzY|X03b)fSVV1)^vS?wKS&9FaB7WI+pF7r{H3H*58c^+$K?i+5Cie7h@e8G&WG+BE@PM8p- zR+tHo*I&>#4Jd1k=OhOaaee^DjO8?MuB!aI)8yv_2e@nKxJl3Pj7$T*uyaYjGe5|o;m z`O%NUvkXBv_d;;#TLho=6dKyjLf6XOvKSE$0c5h5$oKEx%_nOTPu43#I#?>R5e59< zWHy!Kt6=&mDU`3XRqDSzi!e4fpX-&R0FPycCG<6WIaURpXRfreaZh1bT#iiA>x$!s zZ?IIZau{~Si9d{*`5vvQ3;*bQT+z|q9wX?)f-AI%W;T?2^~=|>2Ek-3G|+M7VVk6%_)W2bGgH-TX-F?KV1e>)9Y)TljCA^(B{&7MobcYO^_mk)l-D`@N*xQmhjc7gcdpii8)jLG$4bO$i2bJ2a_z1K zq7Vwud-v8tmQ3L;yld2X$jFF@7KSTMux)1uB;u4XdWC9wKID}2G)-H_fF)|H;&*j* zq20ZAuNMR!2%cTVCjDg)Q&mbW$xzn>9y8Z~#ftJFE^cmik7IkZG`U1+u&+|V+YmzC zX=P&S&~b$xSy(XpJo@4>4v|7mRh0-LA+D^ftowFEauZvi<;ian3oT0VU`Hh-C2+RX zey2Zz>t(*comICY2t_@G;MUK!(IwBVS8f>YuZ}RO75j@`9QBxw7JsaEJJ_zhIH~m= zq!5>=SY9@bi;pjdAQj7PhI&if;cN(4>vGlEDg;OBoSd97M}&pS=VpUw4GA~{x7zdm z+=OS3YVGaDvJJ`HZCQ~&m=z!Vr8Y5Vqk$Ck6u7(}7f(Vqc~c~y7% zxk857*|2>Dhv)fcIwd7$2O8^^mAk*2ab%BK9nA?GX+Q4NZdQ@lv*CbzBe$?@JAhE{Kec za-30!;2@JYl!rnva%i}%|I1JvWkpep%9r!ahFC1i=kY1St`(?c_s@=chQRBrO8ZAg zZ+K5`SZS4jwSzL-MH8*wVC8l4CQ*s#Wk>k41<6#IUAkEg<#h_@M25 zy@e2akc8#uVsdNpDV+*FvT0W4V=ECw(8~m=DS6s0nmfZEdTT^+>hB9ad7z2&-r3dr zr8H^x^${jyX)#-BdF=M!>$h8chCI(lS7?Z_Z9&*qq;8mY@1a z=UADqKG_S%ii!Cir%F-KL_9;?Xh1TD(ZHS#Ix@&^*M-^S5^eaS2YzB9z({eg}mXiQGGC6ZkK*J znCchs2uZHX3?-K1qf0XumX@?YX1b~)HnyCr`V)1?M5P?p&`KeotMncR`cxPj7|H>O6*OhOZ&m(U8zb+W8?Fq8(9xK zX7qA$I)NK_V!>?4^X4$bh1ORTKQ$#cc&Scz3d_Ji2%==|!-tfd*IJhk%|G|7AzHU8 z9p}eOOY~m7R&K?fqAZOsrIVS8j*6-hy>cm#%7dkLc&xKssGq<~z)J+z@!D@qydc~9 ziRxE#X>l+D?af@{wBd;TmYW-FFECz{J3D0zUb?rpw^lneFfi>{3EACzINt|q)hKqo zmKU0u-5+pB1b*reV$^HrpJ91Pf+wT7pUzTj6jwpTgAnm24M^!VPLH2E)@=K&9tF@=SN zZ%2ejkLNNJQV;h_Ysb$I>?dnH1cv_#bEqN@LR~r3noaA#FjkbJLN;lLeF05iLev;~f6Mz`G`63@3Yzu9b_74{5{ZL{txu{brJ6!8@H5I8`(P!O6R zw_ixS!Jizhj5eus+*{oGP>}(J+~*BWo3E^=^Yim-wb7qHhs&jZlt@L@7f&hc!N=vr z#L(gKjMvPGrz(632&l9u{r>%`w;#D{hVTX#AMag>rt#I@@z?i8pk$oW>nu z(%LLa#|M`RM$CCOyrscm1)bJUFILB0++PixU2F}>gtygfoHP)J=f4wvDE;DYw*Slr zlGnZX%mc40&(&6kUa#ra4qBagnyvIzD7`7T`y!jtA4^v?JfBvdibOSr&4)U|!_d>~ zXHQTYier7tQ&DoSF|p4Av2*K7GrK%!@OsFTpYa1 zWp-~!Yr`h7<2RqEV`X)Z+-hCjqY3vN*@}vaU)|k?ZQ(Rfaqvt2^o$h}5|WaYZPw=~ zFdcY^+%7KWf>1^!kIu+rLauOEqarK%sHP;7Ss+%G3xTC{#KHlwMCgO8TRx&O(X(qCe zmEBQLKJxROiI5%h7c+dYtl$AJZ#1f2LizXcu`7z++}_?!5FNw1aRbVI>14$Rb4Vm7 zRA-%roN%**lO(c$mW4u!iKFJC4o+BP*cS)c6T^bHKmyBC(^tC z=^M?-7iqOnbLFcrxo_5E7MGUJTJv=yGJamiqt)h!O-R1Ngz8e5 z)XPHOzP-HAlN{2ls{nMEw=gj96jAKicD5{4D?es> zi{DKW+10{)^{RSb?^cvxG{zJ%D(dWpTEeg#l=ro;@&G)d6-s&3(i$j8tDwy6-lI$N zJD%ZEpsRv*2zO;xua`eV|6m>ZQe zG|0TpRWgh6^c_>Hlp<-(|09=LGt@e%#3$I1TIRx3pjw7Bb4 zJ94I`rU`Z~$uW!6;)e;&(gMPBK&;kb{P=$^>U#f2)f z`}+D+%B&wiuRw^6ae8)UVroiBN9PCT5D^*q^x3oPs1XL3%$RKl^OY-C_|k=_7D0#VYLUW69Xuv|)KI##wY7b%s!G`2 zwsl+^75DHEj-ZoIgPu}Z)8+lQZ`76*OSHjcf(xA+o6SA`5!L&nX3zrJG~)1vhKANb zhhRIp6vksYCZ(iw4>k1&AYfgX4G~?xeT!dtFk4m3(^CXSNl0kizrn4I)^xpIIqo^S zQHH)%T6@+NJFJoVO#)xc(Q!Z2MTnQ4-XFp*j+2uUs%Gk1;(wbxSxu71O0A1|C~HW& zfz!}`rnTEqA&}M8?RF zaua7d*rnd{FF|}P9g(syqsl1=Qy3WVSZK@$4xC$IV8EWc(Yd%hqwKc7%kQC7S;~u< zk~)HatL_0VuJrhre<9-8^0IE+K)ZfX>{P^p;1xDMKfUGE)hOQ-A=(e~A3ru8tM5n6 zrm%@56==nf|7h+BIrYEhcywa-OFw0-3y0Uw_ilX9VYgfw7qRTsp>2A;`8x z<41KvNEmS#&b+Tj$}Q7YY+4X3B-``St!H zF)=yi5>kH*Yp;o3%H4~3@%t~WvIZM^Q|-Eau!Q$@kubb!DBbUja|K`omEtl>MX1QLGu^l68kG5>F!uS~_w!X{NmCHO zC+*a`ecR~g#>I8)rqz@p_ZAmoi(NneYXTZq=ncyk7dJXOyX9t9mR*@kU7R;%WU$en zsh-(u-yb-`b`Jbzr%Hj}5>a1YK?wYUlpz0$uYWH*^2f#i#q`)(!;Uj4C#U+em485L z0mZXojRN%eloVIy12c1dHRYjb%^^x&UTO6!*TRWOdYmb+f+;Wwj>sKpsPj9s#(%Gr_m%L$3KNmx_pBN!bhNUX*xe(GJhR%} zs-LDbs^=nj)>(^vl_ibphLthjZ2Z$t0sEJoMd=r_gUxcH30iw>DH^xb9bH`uM|HCED{**M9Uh1pEeg4@6TdO z;2iRiK2>3={>=OC-KI~Q{a|Z}l{Y{Ahn@25>p1fn5^w(gRG4}yhlbmAxa`Gu%1o?C zZX-GOP_gUt=bO$aONogr>G(gkwut`Bn(yyYZ(?Sv>4F6q}XuL{)O%8s{Gh|#ph zoFiL;iesNZBSU-gln1`c?I&b6S*$E*GIN3!2VXa+sj)dYI$kU-*713JV2+xnGe-YglSl3pTrjBk|Cv!wgM+iPh4=AgQ@w zaa3*WWHEz+9$w&DY;byP98HWH@|gdFkdxD@r6s!Q#k3=fyz#o;mB9bp8mV-E?Xb>` zw!WQ?*b4eSs=pplS#c;~!JNv-*fTCWbC>Fd+~yM1wcqBXRa^pzv=JQ)$rA15LeUm< ze*+{CK@#Ax&AeS=5=f|J8X+SSdhx=$bih?k3n|kl=62AlIrw%X zC-c9*sigoQTN&G*WQU&R)wxQ{o7fptUS%ACzwIE-{_`aa0L;u2BMSLSh>3UdP7V_e zX5VNk4LJR7(Eh?Blu+o6_OQAtV{h}zU>8nNJP8g4Ix_}(ZlQK3ERJ^L=SLSv8WfRu zeRy-m7_%SE&Ix<(|MuZ;C_aXzc2kaQYnOMK($tg;&R2w&@oD;h(mg>7*L6#J%o0#j zyxXhk=}TC)NeI_LpZxsa=W%-pMIjR`pDZ5Yl4v83wBuY>V>;#qC4y#JZ{J3ruzEys zy`<-<9Ywv*;^P}PW!9G)`08d!+L8a=AHcPLcY~7URh$e#NofA{ zu84ckuyKx(FrQZ_fyZ|`dtbQSlx(vkIYwr9%nf(ylZ82Hq-zL&0NSq?!qNZUY|5E9 z;1*c8h_PQ)#yPf4Pc5gV?Kr9{c-R*YIlCqec#iu}2N={LN(r$^uU}vKDKxCBvwmNu zEplBqvdvob|M(n_VKUNH+avL)sCNnClq*Hk2+6{g{UTBe8^G*qj7C0s(X;)Y-*z$L zr|C~A;kkVBYlS_b=lj35>0g#s_g;!(V)r1uU)=Lb@`53GMxH2Z>z`rCJFCBnq~4NE zSz8}XHyU}ElN?`Dmtkf#+D6+kBJ`md7@*o#|93YTe}6NuvfZzJ#?*8V>gOv)nw#CL z%K=$UYxKCn($}LKm!3R0aN89hk-TYzi~9o=B%L-^^~Ghoye)YciAg?YW|4&b&+}4O zoO&{M_xvugbXHzohXXGeUmdy;KTh9uyvhpaCi8{X^y~NUmX+HG(Ps>8FH%XCl_r18 z52~Xw2BQD+_oqHI4CG@3IbE;(Uu9+5ZNpXJ07wx8`|JsyImoNv%%bfejq_!)} z%+>gAetvjMYr>1H$iazqSC<#J&Rlv*(aqdF%3XFAG*<$7NR-L>>fZf%HAqLDU!A;n ztq2iocgh#Byz-2NscCqmt=ptu&duF#6cL*c(QkG%8Q#2ZCKoRIQgo?5rIZVjVSx8JQe9wg%E=#{v*!kt@nniLc_-JDbc>ilokV;lm43(s-LnrEEazlbw@y;!|IC{HshDtu&$}7lZbFW*Uy(Q zl+WqdLZdl37B{zHH$V#!ky8dLU*#T!B)_k=EKn`|{q>Db*pjJFo+3`hJtm>kAuOyj zFOROEWWV^?H;sbh6UDpuE&JYRgNKK|2YS}bf+W_V4vRlOS69=J)fQ_cvU)>C)Fzsm zs%m%hPHOThjh2=zt(?A#1{vN%Mz{F^>*n=^mh(gBB?)N?E9Y!yI|8dG7|iQ zO^F_@U213Y97|74&EM3dzV_$6jeW;4K>=$*YYbnV8EC}}2*LF`Jsn5%jl+Utw`1aEAXo`&`Q|uX@qJ3K}z(!ct zXPS~m+sGna>6vL2OW;edhg7NYrLkP_-PS%WJaUI-zvH4R!_%9 z=v)7LNB9;YhwbDk20CBG#nRGj$6>a)kjJU(T@x#lw5k5C;!+jSNepW~iBpgI(8NUH zZL|NDBVvKRdFd20gVznvB1w1jJZ!Klm!Ghex?a9D-QWF33QIZY2Q5toksrFINN8uk zNyOrMJz4ipC+o!um3I7Av?=9@C!Gsa?^ewk`ui?Da?7~>+!bwLWSWca(7W;Rb{ui| zxeZ|>TV5?A9!p$^mUU0vtB7Wqb2<{qxqED9KfYIA=1%vR0FAL|7mg$mQT{o&UhQR9csBV!ggN10(Gz zk9J+1rQK$JuGi9DK_qK%{ci)K)sB0CUbzW%efUDzJb{jEqxGpH5|2!<*yFpLxg7dJ zZ%c`(p{g~L5>25o zB2k;~6k-^0aZY~Au9gLQVzQw9z&Z#zJZW@EerO7!Zt>5bIOQK=IgM`O3h&+uz-R7D z_a9aKD*)9zf!yUE5P+Hy-nzwR?DOI5?+FSXj7xDJ>o)LIVLKR-%E2hX*|V z42-Gz<7GYsfv9R^cmi`txPkc9$!5^ zd)ZxNIqL^xv4W1xvn%h!FW(}(9n?6zScE>Q&2}q_Bk9+ijd1(BRvJYu2V)g2%yBBZ zW0JB%Q<*RJ6X*oQChUALTy(6|!1=pxv;90XJ6oWZ1M}*H$jG}exy3N3g{hqB*d-1^ zY(CPsCADKo4;r!P%HHlz&zjMM5;@b9VGZZ_N(q|v2#K8=)1(4P`^9{ap@HFTM%sG? z)wKG+nV)a=I2dnjCeQ-#bhi3nVm8(&sealz-~Gr|B8XTV z7y=MJzh-3x)Sk|>qK1~JL#kWXUqwTK07_Y}3mjGk$tm2uE>0$0)_x8-?{x8AiUH*l zSM-$a`DdoDKYvD9xzCcQJB}EjCc7|C_Jki5Om;5^Ql@;Z1aa;9^{-`RG3m*k6+P3f z{ps>Z&_*dmM97OqI+HI>jYLj28`nur`sEdYEnMtPH8C?oT>*M7r*~;7FXQX%`;3fO z5p7NTYlx%q4NplJ>!L-_%FYN*9^L%<_3PZi!VFA;6&3qULVo7$3n`7GOkJYFd+{zu zZcTJuj6yN5D*f20KvZP~a-I9=N~q0V_0z!k4>?7NjV=_0UX6BBi|g*}gyT|L#cvNg zpD&qOO;5EbXAB?Z5-aJ4Qq$2XYHG>>R0di{^<@IsnpP&3`qifhpSaXchwyYGBBIiA|^BN?(7!jh$WUw{Pz@H?2Q?`b5vfM9s+= z5gK|cE-ns46Tm}4qoaoy55wZ(+JPKFQz^(rU{*egcDUzr4J>B2m5G6mbHNrvw>Bhg<4dvfT<@g%Y;=Y%S0?iTO-5|MOs9Ef zAnEHpUU}R!?gqSC4#tA`&VPBO2Br7f3`g_}yk_z(g1P3*-apmLuteyS7A5XJ& zR0c#{?TKlvl0}9}xyWY^!%WfMQtEB( zHFzADeF&S=x;o6D)A}u)K)NY}9dtZ*;wPm#t=k@{9A6>)6$xyN} zaGhI4KRD|k5IleR@(wCNFe>N54$hw|3!MBB|FQrZH6&;tq>#JJ-3G5~MTHm8u$t!D zB6=28G=3su|Hy)m=~KtsoIDJsU@`27V5A@0C636gPX1C>fcDK}ja=wV?C{WwLL0!2 zXPw{p11qcx>=5~pAMJns+-$q>@M}+y)n}@~jj;LxPIfCshBhTN6}FrCl9F=S%ggJ@ zlk**F>qn2!AUNp&2$ii-`59C=(9HdMhtGBd1O-U~nj1j-9w{=yRaI4e_kJ&_g_?sS z93p6e(}w1R3zCfVrevONK|uk;Pmq0NK`8?tZR+UAl8gnhWx{zD2W`Uh#KLiX?E0hE zukk_MG#@Jq1H$LdojVQS5bA^cLP81I*-W5vbOC1wBCFm+l?(XdZspnWj|<@7exZ~- zNl8pVO*x{Xq9Fcpg3M)fG&ZIVaF6VxN8WZ`?Ck6iqP9VxS?S{MOk|Uw=2K%D&f_d%nOhK8es3&2WmG#(zPt^Q6_Ilf2#akTI9zQxF+c^{#NxN`*uzNMMW!i$C3 z@Fzy7h<1|o(sQ@T{`}R#UuXlL(S82^2GmrVO_lUXS+3_Ce zo173$jbiaAzJS1Jq-5khkfpo>zpwcEHLMNeM**MkF^`;dD{^yLlH9kSL5Ov^I6H82 zw-FjBs4(r}%#4R_Gc~zb#2!eIKvc+%=9~yXnlG{p&uY1yoE1%NGz3$jHf| z;pZPIpXlkq^=m}oKfn>9$hq-Kr`h%O;P`kFU<5#f>m3`DfdmAEq654G9N0ey^5MzJ zJq3ELC~nuT_~bgkgn$F+lp+`y80w9=1iXBcrmXq$Jw(JmbQv~ITTg9l$U}U9kN6I{ zDjZ+rY*#TnB0@uii`Vni8J-zE1H)Gk?h+D6Aq`%;v8-h@oVjdOibz!4PdF50U;yQ< zJ6EI9*whq7g~!DaqZIBFCMKqDfM2&7dlA(f-;mp-Gq#~UlQ~;ru333K2el8Z?zLRBNFdHq&E#4( znX~O0UjOqT9CFVCzlFJVH+UtSA~HRroH`-#BI*yZwNl9G=u_a_$kY&#nY4Jz8PHkjgoMV*yFr}=ltM*CCFFq<9j=S;mN*j1 zu+=S^<+-N@bkU+)S2qIW^AeVaneee7gx$S+_ZB{W3zSKp^72@9bac8OyhQ^`90M=t z-XAVDQ4H}w6=67%K2ezg#9KU4 z(m=3_fr0VHLV(TaA3n78d>~SA_Hp*7T28v~V8mW&70PC%bT^j295(XCIIdjGN=>sY zZ(qpnO@tIU6kmFAI!&TKaVY%cj$)?pCXt_$*V8w%UP-j8rdIqWT8VtCj$^W#rYd2N zL&L+Lh>O49xd2!PSPi}%&cVUKm&(emC`JIR6#^t&BVWhHcx5!;aJGk=C|Z_*mDP!; zZ1dn?V@u#sUiqQ?`I$i}!iJBudr~|74j>~CUZDcAV-a-SrRRwcnwrwier=YwO_!!G zqBGmFp1JbYx2H<6*RUwj=1hJS0cH|!Ra4$-HN3ySFMGSb7EbBP`npqWkaJyxB|UgsXjEe(_3yNJ9 zg-p(82?gF;J66aDBl47=UxP={5zZINPPf=C1r+cM+1CpZ!+WEwnH?9U#By__+xz=a zScLogUjr{is)Ldwp|4L3k!5(z5v9>PJM%&IMbX#5x4=L6k6Y3KR0E_0SRx@HDZr;d zZTVF>U;Ep#{23@3lEI`)+`@KRE`0j>)$(5iul-K`()=hPH*fBh#{-WwD*#0Rf~aZT z25KZMEbME9Tbf*N>zt6JW25$(>7o)v>!XQIs`N{8%5=AD-esmhsSN3IIjmB9rs*S- z#;D*MS6Dy*J_V3||KMN?)H6r00D;eb@fI*st;YWQ`;Gu9xVgs)xtwbg=4%C_pXa(#Y9cLC6K2*9*7No)B0Sx|dsP=qb=Ao0VTe6h7gKoFPm)3%W zb(PxTq_dpAl8Mv|34TXehh_S_G0yko(+K(VO$`A=c9U!cp>J;xOgn<((|MK3AKKt~3e3mRf)2wopQeWIkM ze&_9tMk}8r0|*#Ys^?fq;XWEejBl950} zO}OIT``w?g@55bW4ZyJco~L}w%*>FvbU0#B_}FLB2!)qg;y7#LsWc5$Cp8m!&O3K< zop-`ThWy-|Lb^?jNj!_3oXI!H@BP7dKkmI#6U8iZ(sn6Dgnv}e#ZAhoTDGqWaaZe&owF_eGQC7IR7`W=as2deGwqk_mo>p8ZQ}35pYUn>-;W zA|h&PZQTL(JrbN385mrdnR(sH$_no77!~_)+xE^56r+IveC50;6^PD*nij?XK`jFn z&f&UK?Q?T;Ca7^vfpn%86pV-H1VyoGi8&EKEl!?~JPXz!iJ}&uJbV6JZ{Ua0;o;$K z?EN+K6?N!Npz-fG+?tIQ^%8;3)1hV%QWOL=RFVjUtr1}n7hKUo!d8K2f$+&2UYKu& zg?-D)c^`?DYdB_5I*msvKD@}_3|rK@7Zdx9OAKc`(^ub9sF+=gfuNFka8p&T%+Psz!X-ocfrspysCaxyZ3JA3UN9pzJRv996Z&@eFt zLIDothI+6&AB^gtGlG767Kv;H=ON@ajqE6d#&>Q`zoD@aWz3wMMXfdoKhD?I)}R>2 zyLaz>dO96IV89cimTSFz`}P_ZmL6ITCWU(_#4|YYcIMKtl!%2VU%#Jt@^TmI)Sbi- zj|f}5)bYK@&#ImLx_)9N=32+lA?~HpQ>=7!I9Pm8Ly_(@gs3$?3|hnrkk>iAy2Ivj zva7O=ckAgBSHryR>r1hRS9Y=Ua;Vl9L<1%}-TZ2%La zCUdA^4iN8`wAaVVi%Uwjp-9>r&HeJl8|pluv`X0w+V8?@H6<{vUw~af9fyv2^A-U? zYoS30EJUG&;?4kidgydMK(Ak7HQ5crm-5+QK@d#WzSqot-ib4Gjr9j+e(g zPu5UVAy^Os&?6qLjP_FBcgX24l$7QREg>SKGAJQs87w-Yq@q%-ap%`M8684}S9zhW zEAUJp@<6eJT6hABshS!aeW8Dfgta-*6fNZB2KZA_;Y!|P5uh4x zsO%FE39^Z}q5}IP1XAn21$s( z@S&f4g#fWr)FUEj;PRK%cMkSSh`ES7E6UX$`(AoW#PEh+Np9-tBnesuYd4MVseOx< zBco01j&a5>WF4YMr_|w&i0ci_OJ8BTS~{!IGM7?oJ}a!(S9zayOGD!bbk3LW-;D}i zWDT@~RkFo*q0-C5L^ptzv3xd^VEyKZ5}bhMC(6nMhDEV9vn}kfsXMqf13f)Vrf(hg z{Mvzx29v*~)m42+Rj3g0;RA-dyF2upjk*Q5$jE|1LgYirx9Mc#n!bwpsbf5WaVIP@ zxKd$+&F6l|1_%>aEeEXhTV7s1gq)_n5SXu)17^Vihl0@)J8_Wv=~gRDXR4~J0q-U~ zIoL?g%EE%Pf}{K~Jp$-X|IkFG#WgNFu89xUv^`Fr&B9#~yK ztrO>41Bt}+^in$}JGKWLe|V;y??)y4U~RH2wVV5O8?|x^wdxSHo(f_-11!e@WN{wW zz@bu*(AjQ(w|aVcdAYuUfemV;5+07KsR;!gnX;7g20sdZ^o#f9w=ry}8gx09fXxelcY$i&MJ7pwm zr}LkB{P)df+Y)D;v$#r>V}pjg(CQ4VI@f-#FZU|B3l@bg8(OV98`1Lk*}zq8GqcjC)N74w*2`899Rxgc`K$5?23(Z0Q2Yf0nZH%qQC;hl5p zHhE728wXmEcxe+l+wnlV4nZ+mKEnLf0&-7ffzOwER*Ok7s@827llhyKR{JXjq%;)I zP>PMgkQ)^`NcpV2(*fsve*LeNSf~Y)LR(FE(CaQGf`y~LjIv>c0Aytp3Jq&-7nhf3 z0LHh8Rek~ktslnQ&HBac3^RNq*BwaBcs-KxQrt$VF)>Jm(?V^nmD+VYxmM8DB{1_y zrF1=>jpgUmS~-yL;G(xGqG!b4dz+bwcOf=N-Y?Ocx_|R#4;HfSlRoLXMEJR?>{#0I z^a=m4bD;O{Yopn+ujV(>+&5UTCD3agf9+0q*`bRm^c60JgKDpqhct1?&Od~gX zmQsIyAdtN`KboKPQ2H+s2ldAXM$8UQX_Yv&OOL{uLrSIfMwAF-JhBMTbS5lh0!*jO z82pIH#<1(MFz>kNXx+fxu{6WHDQy{;I`hN$i=c_qDyHGv1MZoD-`5|#$;ZSY@*zzk zk+2JAMf+%$^~`0~I{9(%w0VR0&KB0qm4fUxUD}I?AgcX`G0sbrRqowP^3UA@qQ*D! z&ZNi4KrsJTD-GLOXc(q)w|mLn>uHhBq};#SMd27?xH7$YTj_$T|1EtDe{jjQJjKsD zB7NP9%8b`19n70*2*T4lDTPG7w-z3^i$yM2k`y@X;|AS#Y0vJ*U>#M9Qda|KGP8HDv$$N+x7Pe0_HUA7_!?G7-tx(|l!240IJW z*}FW4J0=c<6w2@Q>;gNH`D>QiN#svF4DZW6tFgaQ;al&$q(XOY@Vdb^_;yX|rBn<3 zT3kxSmax#zBYLXM=cLQhxXYABpA`PtTnOc%-SOFkoQ$*tc(X&JW{G){1Y4JwJD+FI zT1W7D4GVv;7|@~malX*`=#$mQbnd>ap$ZlXUNzmSjE)=4l_mcdbzd1)<+`0-OUscK`9AE8U;a-?(RmqyE`V`OwM@M+G~IA@6^w89j>+f zAxO>V9nTnd4Sz0F>a|;Qdp>R)dpLOdoaD}B_@^bLRwKuBu%vgzMcrH}Vn6vO1!@N} ztgy9QaxDtqxw14jghf>EQ_ex2m7Oi^&h~H7$qOH=we2m5VWF=CuY>j7Q#b;2pJ|?% zeX5AX;5ryiX*`kqs3!r3Z_2Ww89&&`3UzTrw4k~W%9kdY+`uF`)=`tX&w%UOk8bjg z&xNpzi1~D7iQ|NXqh@jFECpq>lqEXFiS)^5w;f*oRWMd5zP!r%(s=S>%BSRXqIPc1 zv$)wDG?lj}&5}0Nx`X$oSl%meBLUlpqEOo3+j9hTq8v;S$%hCM<>ShfptWviz=3*5 zNN*jW2_rUQ>GdpXtMw%#rK1y18KeiY6nx_oGc(@>yc)1H-1ldW01i}^*qUhFdTbu8 zBo#JNaWd^ULxq+%bTg*zc}gd=Vs1M)A~?KUT@)<1>SQ5Q-bUd$q6_VW#4Wj-R6E-o zrDeiKy7O5)JGIt{C(~F~k&D1g*Qa)Qs3&2^4%$zS3h*4C(CGa3ogrVgoF61_O7o}b zwR6Cl%AVyi@6~|j!D@Gl!MKya)zf)*^8nX7=wrM8idB?hz2#{Vl%^M#DnKj5? z&b6L-0GB2tM)VjrN3<9q0SC}uCGz}Bec=i3M4)qM@J^jN1!ERbllv}u3=B0CTT|Ox zThjnC>H)#S%gakJU@!mh;kBDLeIW)y-h!Kg|Da2e>DcCOO1L_6XxB@DwW&as%wK79 zws)i?9P)EUI*xgZu(3~W1jCgOCN)uR!%OhVuS?&&XY0S;b4FS?KOq zK0N#y3*IT^zSbE0dP~@d)n=nj&}JN8H5q*7j4#erP6kRK6z3YSJuC01G&wSa)NfxW zr44)N*7H@@jm9=GY98GXo-Wm3pgLDz1e7j-H*?!yF2N@9o^<)U^e{>SMF^APRDB@y zfA_SsM&p+AfBcZ~|1~zc!Ng7J4@eSU&4p?6oNT?vTv&>8ehZg#upD=b*swHq>V|2X z9lGCbpq%2>!qsX%$V!@~pQW%rTfDN0_W{zyJp^WFKG5Dhk5BacTj^S=u|uKRe2kP- z`Qy7CS@%Df2e7=@UDplE7@D7za$TI(+TG{bza^-qv3Ttk-{pR@YGM6-KS{ZNTBKD{ z?K)EQN4| z$p4MtkOLcCCG^x_g2@0v5?Zj{rGVSE92SpZ04YBAR@;>Qb$kcWQK z%MuPxV#Ars7ozXg_3U0G=lQV1eBLWkJIVUl?rq9t}L9Eqq$ zqB-#5sTO>nUWj$Np}E3FJ-m1BvhdiG_zwiZFrdRwZwzpfsA%c4aRva>A&X^vX-N+J zo8Y)lDl4O%k9lqkaVl@$y#p^&6^wkqFq}dLOlU*>v$D9cpaH$(>?{OBdT40q1zK7K zKoY#XykPEu3HKggO)#DaQWF8R<%}ziAP?YFzykTpWQ7MdkRaFq&B64%5ETKkzBj;? zcMS|IWVOO?#sEexM;8~+!63vsg5^C~MUq2+w*YwzHcVeFNBf&jzzACkQoHq{VBQAU z9V-KJS%9N>2+%fI@E}^nx1mAixw?8|bF)oeAJAUN&nqZM9@$a{Hsq~Y>N=$53}%v3 zP(y$O@GouV9G)X0n)Se^)fvn&hS_Y?1ucruv;f*FiXZa=VvayJz&kum(|8{iMg~k4 z9hls>00-Y4bqO?#al-Si_W0kZBy3`jRS@(F&JVqqSPc9M5z>l?R^-ebfM&&yCWvL_ z<-ez-_#GX&M!S-M#O?i#$@hZF!0qqHu^UEaR@BcDyFXs+{w--`kf$O=^y?rp3BQYS z;=OkGr+#?@1^3BOUEYjMGE(y0d$%8{YX)}ux{N(+8D5Pdn_Z~9@7~LqvIv>UgdzEg zu}kWdfmTN{d{}pbG93@`i*6Zi?9e+ur1U<&Gyjd!qb$^N8c|-sbD;{T0R)m<@6)g$ z92giVZDLc)db_>U2Yb-@)4&&~jK_9h4SeDTc=N4C?D`(5sx~;3ZASA90^}CM2&OLF z^H(lhxKII5T@wubLvtU;0j~jQyb&S2flWY6W5_59n>dgu$I;o@8lLLy>nC7EwL#pM zi@(x0AWPE4krr0FAN}k17P`Q&*~^WU-?H1a8?&)JN6}Nc;KK~0O5v2Y5>K{ zWiblyxX8hXyIao*&=}J|fB~lAiRcm_n`U@q1fa;WY*%x0b_jo9zIwHyu>8vxauAQ~ zLw?BiEcL7cS*T!F9Bu`qX-J$teYyaSw9|BuG?MKCR@p9;n7-lfaU{$E=rxDWfge6h z4vk^>A#h<5UV8(`5y2XEK_ew~9bT0%6RM#E-_7 zmYE4}I{Q&Y`sNqNYYa- zD$lQVS3+}F=CySBW8Zw-pdI7W62I&0iLJ-)kgw}z(4O%N7bNfrR;t{FhTs5-pGj^@g8h}c%J;0S&VAk;Xq2KDFDd{mW)qMB z7lbYV@i=&RaH-ASf)D?n2yDbXKKu4)t4pzPqv4N3=5fEPs;|4ng|3HkV-v4nf6vMJ znqYblTQ=mh!o9d_9?POM^)B@R`PbAtH@)Bc=-uu*HMC!*onBHgM;qO!dS{*GFL*UYI zU^2!_V;4bTfduDFPfr)@x`A?u`$fYA;N!`~Tm_NrAE*%6NvlqN1Skw-|gL1wP5_=Txef7+|`d-$-Oc898Z>iOg_p%stwNnNtg zP$5+xpd1{0e0}b4a8a*wX$u>*Uq$Z2-LY%~8ke&4YHV8jVj55;xw;0VM*z(+!y>+a zRvfb)Sh(G*KC%F%z3v6~se<@zZ%4)+<4J5OtwYXFF1^Z`n^X_-G5Fr4r99lbzQhe> z8>bkQ@s!G@Odjx~-sfV9>0X-U%~m(Ps-3Z&)Zckl{lV4)=o~mHBPg;_G_$I~ z!NHLP9fury;akYR0zud?aoZ`txIclBUg`1Ud(g(<;^JxvpGe%hC$eKRzq>g>?cFl4 zVk=}-sIfYhC{0RB8!%$-fX{|SL@oHbdIHATZxZ7SATk(fbZ+>nFyP}eg;uc@q^{RI zk$8!Zk8iWx^Q^e*Au}m|WNH_GPz<_Zy!Jf~TbyWtQSS2*FrR{VH$$)X16quQSa=T5 z;Zty|1Vmc1B|JVrBpKquMzo;-|1yWXhi)u>l<{C|VTvonCpMPO%E}55;br^c`t9lY z2^(}QI|;@fD_LCub13&Rn+_}J)DG=4l#A*i_6>6BKSV zeI~oh1J!UBj-dK_qDNU8V3>drY4wEG8W7}SX*0-0XwSD8BTC11oDDaGr*ymI{nMw; zBYj`#-%1N#VH077xuer%XY*tUATSwwqUdZ!h*x~Co3xp{{oTnALf1BVm_VDV@dScI`Xw^BB7 z20gJ@F6IbQ;CXuV_C7^YjRM_2OPuo3K3;qVpALyj0w_HkxEoNiiM(<`eD@%^q+P%# zriCd`&SG_4C_s$EyQ}?)q+R*qlu&p`;Vy4Q=Hj)g-HbX(2z7wUeoHmu_3Z2pOLah0 zNH!0IcY$WL=p?!+w^Hh{)oEb;~X*XoJ=xcu@$nryH((7K>7u> z0?V(5+5q+<60AdBKFB=y4(u&5a)GKJ1O*^pMfA72)$cmm+y9DWgc=BaGQ>O)9VUa# zhLyEx6Tc|a#Qhr`s8JzOLbcyPF;PlV(n;i{`wPsPW!vpeX+QD_yBx0(^W8l*w>_>{ znPcJ=0U$;|)e9;onByv5V8fQAL*l8J0F25^l$af zDkcI11iL;7K-WOxTx>y7kkHfECy{4ObK&LZ&%t@m^Db~-M0 zoQl>)cZpHAPi*qJCRG^KkfH4vp+>r3_Mt_0P z21qO7j4T~f0m;LNqJiy9%LwSgfxAPf8z>6loVurBjpA1q7hs5>g+rv}P$ovNf?@!Y zXC@1pQ6QTwfRG@BV+y*lkuC{0pgp2&T5lt& z38ZI3XmUs>+{7HBmk5w%dckWjr6nQOhATWIosp9vVBT*6i~wDZahJln?ry0`G)A~n zRdTtV@t0#{C=~a{e*kQB66_qIgzDMd*XMEs(FEXOs}&t|2NiTeVj`j*f@~5ZZ_mU; zW*Dik@d$MKGj!pC0U$|HN$CP1Ag(c4etwG6f%b(6~e&@q}?}QPBjEB7lzPgMnQ)c z;ypl9-?6vnM`G20ZAVg^5HT>Y@XC)LS3!@DfD05*s2HXE#v@G9IwEIlV@~W@pH8`^xkH}dWDzYCw#4Z&VSxlK_Thn zc8ExCKGqom!lbtGWupBvhEZk`HrqB9BbJ|6{zKHMI;=$#5A@dFub;g?CoQMShb z6FZWO673%63PMuojA1;HP*Un+XWxXdG=!^0gq@Izv=6Gfks&1A1nyQu5dlwjIc7Uu z19iMjOL7#Cs2-5y4@8>**Bh1?$Eqp0g^%YyWK={dP`CyBXFRH=VAX62vocWJhs;bBp3C{vR6dCp_&)*T#wL-+-y>jA^Oi#=iwgQ)X-Zqt6wgIzRn zMboF7h>8nd=7%vN;c!py>eWgor=(1S-i;pQB1lpZ;D*qwW(*0pQk6prEIiqW{sM-f zbydT0)$R0@lmv)hkqu$i%~VA|Ie=I8_V=wiB+0m}ChzZ{$I!W@_lb6Y^R%@CP6Wz_ zDr78&S)x_lqSUVY2xiR*5ZF$Fyq6JP0+8{YMnXVHVBUr=-vBBQM<_6G`mOLe0+y2o zA+Z-3Es#=zq;W#GjtnTPBveRlDcn6EcK41nFM1D&x%Vx;ko{^N?0Z{!y%a|%od3q$ zhqlJTNt^T`f`TtG9T=th#m<=B?$Vd~hqil6q_?!dQ#3$L;A$t1t<_xLJ!n3iF^N zhg~m*q4FDY&XcvQW3;5zs2__ARK-v|KJz1kd-mB7=S~LSxIZ(g1hWE~b8_z~&nnU59b0)*$=QlPBNn zNP@J|Ta2fBT2_{*j`a3u->JP4nhqC2i73wnqCbi;Jqw}Lya7|HFd(SEw3f0kit zWhY#9N2AX>!eh*zl2b?URr@ys%j+)bvUpdgQoqpxA!{i_eQ9NQI>=sxktp!Da*2&i zAn|jVxrgww2mYc^NCy<>A_ax4f7HTF@_NzOMIxvG4VB1c#W&b(MFopcZX@a z{{a8fbE`edA5<3})b`8#CQN<1Y*97-Xs+4>{q04t7fpWB#0FRJ!J`|p&B-pSb2`U& z@5Sq7@bf8^*zn-0_vv$jUOCV@{l-jMakHeIE^TqS+TE^7>@TivnfbiR8Ez6RsXf`( z3=E=`Fu^10Z9Xn<6F)$t*57YIbgz9Qvv;^m?$Beon7o14o?+=G!w>Uy{HsD0O$`Ol z*&lGwGkzm^oo}DO>7XvOwPtQY#=fH&et%-iG0v@HwWjTtPyf?El-W(J-ZR>-va7C# zUy#>-bqG=+y0Bo(UD>3&0WqfIPReHj)->`Hz9xQ%*4`e)ukt=}#KU;h=RfsMEqvc1 zCoaagO7sUY*g!lxT=T%3DniaRWBbQ`6D9Uu*DS%)&#KN(j&Dl83vsc#*h_vAKYRX1 zPSE;OlF!@tE-Qr}`CV^)p0*9lS^Rc9ZKg3|vP6CHvc%w8W<7zHY9!S_`ML=ukxC57 zF77|;Dd4G?#-Gu*-H1iLsq?PS}7f#JvHzpBgMew8*4~H;JFaJNiJ22w!%}2;j>Mq0V8A8YO#LE62-!TKF&sx4d z=N)<9aM4`)6juLP@!BiYX`}npd0jY9;u(In62;T=opJd>Oiu8HIPYTc*!`_{p2(rG z-CEte$}bus=9wkhc`n}~j=>_IJ(%ZD8})`KMVM0UO0~7@8S{k2?F=?ALYcb&qIoJhTVu+*NG`;h;r>$Cbo_*w=$1lXy^MYl!rKPnk5I{a6dj# zd-K)1Z!FSdPM%({iifjDNx8N)-P(EPGUuy<6e5oZ{TKmuG83}Wt|c^4A`Ci}D!mZd{u^|F4UG$q-xR{RyN~nm@@SOkiiqEBAOnlS)eB z7l%R^Nm8?n=SbK{?$;v|?bCMr+ER5r+#-2bu<`hxNp8&_%xMP6RQ|>xFjF`7?aY%s{+!2=m!($XlnBUu`Ul$emsU^X`9Tvb2p<*p6wJ&V4w`S30&NtW*yDQV8%QGFn|m)myL!-6K} zLnHRjHKXttRK}nk2c7}w)>d$x6(tOVE-~3kF}PBvVy5$9pS7N!RJ=jLe4?wLf;nBp z`HE($1N$@2v0R<^&tWm6I4c?5%$zQzn>LN7Etd|9*>adPF}MuB8Bw6ah6f+JeV5J) z*kLmEh^gbVtl3U(X5F8ixkqokKoj0rE)@!IXt5JDuQZQuyua~Umu7XdepAh|AmNn6 z&l@*u2CC@{=tT8<&(3IPudVP*iLJXWzZl4RiD<1sK7Z;pBDRJR`3;zR!C_Vb!fV7l z*!|;?2zZ^3j?t(clCG|;%4-r`4`A*v_EC7yub(`*W3{4h^)GB z1qbTtN|>fS1+WTLaGIb4_k&2_EX0Vy_T08}yL36Lxd7z9SbMPfq6%?0LjON$r2#NK zl8n3>hkFO|iqol_kc+94%BwCZ#BQDDEmM?N>eqLo&12t<+zvy3%vLC6v6p#%`5h$q z+$_}e;LVC0=3LrNE173U%{WDVNYt_ZplQo;t5ZmoU2O6r$s$B{|MvvX;3oy+-Ftt3B-IxntHPnBH|N>oK#>jR8ET?> z3IRS_3m(@!OQ^6}@v{REpAL4P39e=ccS7iY-RXuP$iZ9(g*O*Cl%o__5W^|N8Nj@v zll#07b~J#2Y7R=lG#rTf3ClJ3$aQG3C#?(NTSqc>4TlR5*cPa~YBcJ^1yD6W)aW7F zceN}P))};Sch>+MR50^dT}DBHSzJ68rqduW7GmpUsyYI4L&2$o1?G_D;X-ALGBWW8 z$qZrzUc-YrS7w-E)|SLuxUl)8Dm0nUbXI^~=ee!O}J(?9L2Qh`qNMH9)Wv9If??Q+eeedTt4Zke& z@`8|HNBBD@xEl)rEkW)_MbYg`;HsqINPt`&$H}v>yrTiZ&XC6=9d&G?r$1!jBjHUn z1IWYFO8(d^S@|9=AWrVb2hrAU2pt2&%-IUyR2qM!mkmzz1Aq%D$GL|Vo|P3aMeAe0 z>@olQ3S5p0vr^h8*X@`JQykarcW$|Oe+|QsO~|f{G2(05o_D7YI+_dI&A_Y}%8(y0 zwhB2U9_Dr|NEl`FZ}!~WeVn69p~i!*p}v$Tb$Q`5$jm`m1t<9iqzpivX=p$LnM_DH zBQ1VFqMm0u0ja5pMMV(^62O~xQW66Q9^_~v5^*H49xfIVnh`6?5ODlT1yDDF!+#&l zWd6-Fiyt{aya9Gj$oOr8$B7(5-a-99>jZVD7C;n{(DA)a&Fi`yfqk~dXQF$8}NUWUr z&}wcB9tp!(H-2y)t!{wa12zoAyU*>Mu0QvH+5&Prz!8n0zer#+;&yuo8QgGNE*7`- zcf^MSp9}>vM;Ha@8=`hWh$duHiTHk_A{J8dAP##bto(=xvcZvf2gE{;KS-yd2>}cM zx)}hH2~S@~zJ)e|6OE!y+>p%;0HPtm>%+URPcZ0{y0NiX~ zBN+OKET>Haz$*8ECa(i&^V<6Q{?1#Q4N&yZ{_1%EOoYqsDwC+_NW34?N^G`?$3l=m zgXo*8NaWiF*MiO3_+40rGsDip&Q6rn)d-@28~y5uqW@?CK*SG+{wCx`RJXOIOTc#e zZDgH}4(R#7y@iOM!1@E00W1y3FG+cx`vC>V8xb3THeTt`BdexuJE7>+*AGohmaGWP zN+4Yt%2WFrMdU^qIhHF3q&VR`|EajILqlDmIETn$$CV~ zV@>ZIV<7Dvl2Zzl|&(EE7_)o*&3wW_u`BhNB+blfj?~)!qvrdwA3`hgL$v!a_cO zo*ktHD{S-3w;w-z!0pnTuH6P<0sz!izThSSoER1fKrYboP<|i;-8gG@7ipKfL+M81 zu|YA@07(PJrd!LdkWiolcMFg)$VCHf+O6L_G7Hv)!||&$MEC&M!HtjPn8VJKzio!u z5C{Pb+OT3ET^bR&HYA>G`GKa zVo@}v{Y$SqM?k;x*7l92I(5}uacrXx=zc>dc>lZZINE0?i{C`-Q#Ia|eji{gEyP^) z8sfKY&@M0&Wh0C+dud^8(AV@*g=}Ww&Ej|0vbJbw5lFz0g@oCFj^}WMSRkInw{{Y9 zxW-{;UpzAPJ{VL!ptGt2;nfXRR-r`<5#8yb!NEm#LpZJo-3lRsh)4vaR0~?(Q-~mM zZ*AhvVHYd1EDTspz%fMuYR1nV@B<3RAba50V;>eOIW6zDht;M1Ku?s=4ACQaIplFq zffNWZwuQe7cU_d3y>!3cdhchwTD$7UjI#W+7b@NXHbd3K(dmk(42KM!_bv~xZ z@|x!-BVBL*FRXDby#A-I|99S4B#~wmUPJI*#X*V;aLMq}mEf`8Lug}cTSuLhHRIRO z3M}klkd|ZnTj(w1K<5vM(ryXEk|wy4pw|doct!va)h@fFw?I&uY)&d8%UjA;e*jREU~&|C>4%J$Q?(Z-RwaC6I4x4cGvJnEE1LwPvh{0QAn*^-`2^pF9fN33Ez8Z=VtwY6UPIkQQ ze*H}w+qf9Izj$3*-!n$rEB39WJa7ApQ{(}TbF@$s`i@KK%0!vy2DMR2Y9cp^Ll*m8 zQ5VruTlW>3lrl+)&Z zJwwULnc>a|Kh546pnBg(Eje6~`9h&AU>hwWQQK2s;5j88!fX3=dyW5D0%* zQ&$JHk4M)6I3Do<*@Y($dSKo5xVs?V0MZ$06Tv`*NJ_)QWr6I0G^T|Mx8_q75->nh zfCdXndC!DE@fPNPNiAa{|IgI2Wx9!TL!~D^cnv!vT}p%&I<16vq_F2@K(z`hLtenO2gcICpNT|3%=}LT^DW@o9E-?1hyvUMnGqByf`S0 ztHu~Gl1`!0{kvgo`ReK~Y}$pqh8^d~r9tQE+ZU)wz5I&iil+;`N|Q8Y|W5d|w2LJPKGr z1_wS0h1rLP>#>^J0KGQc!oZHha+*(fJ@M87G`L7kK9Bj92NXYYk%4?y78Jnwqs})$ zg`xR)3~q85hCn7t`;r!eyACVHzJe?P`a2(ht#->Ll-0l|>Lat;Wnjj99Oc^>(k1E&W=+US%v%z9un zU466-YGG!;EkH2_2M0nbpf7|M6d8_SB_Sgi6X41PlW|E}TLz>M!3-~Pf;oooL8r!t z1bFAzZmXdcd-#@tlU+T&eCd)UETp?|`LZM^KaqY}TzqV)!5hXd=vbs+E{2j!KqC~I z-73^K; z(4vt%9PNV`(0a%$9~rqJeFhQPD-=Wl{SQ<0Z6KGsbX6BJ;pchxOxx`f zWJiI77F2{2D9juRRvF&$F40CE^TAI<0lNm=)wJ7LW5g~60C^X@dAbK8TGim&6Ip7+OFyUJk zY9O=3KVJqaaW-G7ciUl3@CdKqT-e zjMJ`&Rni6lVaS52{Yq!#?Ebkx7^W%r7li8EMoG3$6#o6i|O0;%R zErNvN__QY%Whp+@ROcZnCC!``nn8sBt3>KlR%X@(N1Qu~-_{cb97;PFHMMf$fY^S;# zJiKA=H^I)Tey_pgeLTeOa-7B<*j$+pkH=+aZ@oUdx-1&Xk7qemUO#S0;i7VQ+l|2W zc=&1x7v@E43yamhgYUy)%MNNZ+Ag$~zBYtyxscxL^|_n+?zx2e#Om0iM%-L4Cbx(f z*%d-T(8<`2CU(5K;n2DP#c%z~zcZObfx4@yW>#{23WaW71oQT(Agg z+GPj|{czJbDR21sPBqUPCAQL`w{scwObYb-wXiTbH{$DY*|7Y~*xh%NMuvsa%|t_^ zbRu8+=3P4$BPzcxmoihl_RIeuMEG1|xU-6b-)uw6y@6P`^mErloY5R}YZL99f(?i- zZ%_!^yoi~Mj&yNtzbEAI9GeWm4f03qsZKyvef`$0;zu)3ppX>kO1h42LM@XXS-a4=Xia|=c%gnqWxG`>MPIkm5T@3eMd zpOqb#Xz5$+7wFph`Nny30cK8`^uPwUc6O!lPh zDg75(G(xrRN!@3}vRILs*fujR%^Ed}uQnFbsVdJC{b=UD_MQKxU+~!u-o(6g;m{4M z8^)V*arh2HRIfFEeRfK?Y(8|y@;+}RNzBq`-rlF#D4RnedA{#n-Jw^Cn&$~qTKxC$ zX~&+^KMJHuF0$Ap1FODzjg?}>oS)oS?{dWj>XY|Um@o5AO2-! zeiq@#wxgqfh<7ypBw6#Un_zjsIHsu+Yg!v4I4!os~lQyMMOj22n#XIQablrCBZM^@u^qL@SaL>OPa>Q-Vfyzu9j!_V&@ zi?!%1;V6n$d2~0S`McD`+Y*10&LdT@Kt`*JP=RHE$eU7Tn&2xR``-^I{F$Jxy0GM1 z-AATuV&ZMKZe}(fzxq37T%$NTJ2FDX3ojmy5-GWimL;b) zF7CR2I-1xzDrDKd)!682?pKcnNE1(aO2AIW=HZdExBm#1#ms)ZAa?#t-0%-BtT7hN z1?0~B>#fsF_4xSg#>E22DQ8h>9X@gmZf+9ke8tGPZ)`AogKnx`J^x~V|9nuM!0mA1 z;NX(k@~@deCi&)~28H4ydH%7qb6nIue$&YoOV&lr;#z$Id|bIHeqWN46*l+sb0@}z zA8vVIZ(%2%`ktA2B+MS*fQ_xV;8vJg7So((f&Pf;T${MHwd-)=7Sz)O=_uDeg}Jb? z6qLp2RKSjd3*#Ru?uaSMPV{7OMkua{goeb!!jXU8Y^g9$fAwuW7hNAUdzqhW^~{P( zRvPC+z_WXjxB^d9H~~>517c^OkzpmN3Ewd%`9tR6j;^2wpE4Bl{l?a40)PJ*fuBDw zEog|WbXWcBHv%LKo1clT3QLpZV%TjQQNX zU!R8Tmn+H(3!9q=UKx$YL<>`l)mHi@H8n4&tJpTps3!j^%+GpkfiX_x{I8W3N8^e8 zrhX&kV@r9TIyzp(nH$7aSF*v%J(FywkyYOCemc6g2v|aOupeZ|t$VtYng~xV)i3!c zeQpXtiJ$wLh52mSu*SyWE=&3O#Fr6D>doUvu7Np;A1~z9)@5-CesL=+yA=L#uRvqV zN|3yxv+7Gkgo1PsL35j-v!kFdk-C6H(dR#O6C0jfr?aUj3to(gJv1|;$qTEkSqmH= zr`4<%c;o3bwG4`K?Y}RA#gFLYN>3-YYY9W2&@G}&Of*-nizk3YvwVA@`muO9(a-~b zsi#27g?+qWP*Z1pj5&TwBhpW=ZKO%F8}`ZSncn0Lx}}M`=aU+1KKKz}s7da&1jRcN z;IYEv4gc(w(RJ~_50e|w!dybsG5Z?qiBFzo{|Kq=pXvTH0DtT}&xIA+i*vS}eda9L z-@Ph(dhU03JGP8nx>(ihcA)dD%kE}&M5OG^8|y`>*Z4mlc6AC`QY*W#ZS5M$88Ela z&R%qac6R0X{P}Q-%eB&)yjfp++5!uY4|&8n*9tbuuUtHhjknfiHY8-)eElXP8@_VOuIatgZV%){JN?bf9=>`tnXbwE zMp9%S5RT;k(!xydeQ9a;^5vpyoj@z9JvjI4;zd>JEAOxc2S(+lJg_bA;}_FkeVsN> z%(py%E&VX$1p%SxYSwY7Z9Dd!lq3liiB(g*gHSWwNasCQ7GGslXtclRwduEG*{nK0 z%f-9OkFu)srn9)20VCw+=u)uzG4|+7os)c}+ZCr+i{jiA4fo@JC6^?UF<)CVu-TNw&(*?f4G3U{&79SFR);&8w^$dy zyv*tCb0}Jo$lgyFJ9N-wcVArc{h8atD4Lh>_MHD2AvWGqVgLSSj>aFRrusEBPqoTN zI=bwd8#rXGWglg5zcMLJOcx2LsOk{($i3pb>(<*7{dl0KqeF}AoVZpC9yWeewQz!W zOk$Aqw?E4h&m%s*--AV;o_+9@wHNBSI&%M8muya$SNG6w1F>`Ggl0C#-n|{)$P$y% zu;ZIx?~@Hvzd-5SRR5F|eq}ALHD?GGgq}yK|GSDP3`8xPiU|iK4N7RT>qRR}(hwaC znQoc9(!1ky+km5sYMYI9lH%7V?e9s-dfhzz;yI?pG$l9}SQ#09-1fjN6b>=rendvA zutyRvFII|2{xK zPk+C*&brS7+ixhJxSE9VmR@r59&EJ`_@4MJlT18iPeF=2)UMLVSE5Pco)8W@R`ANs zj@N|ZY}DpOTfs;C952afi0)~!FBV@lVwBEF{SPG*J^>zWV1U8sc%@d-xd*JUXk1xi z?v8@y3lVX zs0T~b4L{G@3YH`aI85+ru|?xh2o3G7x2tt+{>QCcH^#tdyuE=_jY$v8?VbjCKOz3jWg<3CD4(I-zaF|967NP1ntQ^uocYd7{4ioBSd ztyA52X5N&>zpJ1k&sO|DzPfczZ47B(cF6F|%vm=HGF=b!bpwzyD&if}f@!-($tcy|UvBX+M89 z?~wGhkMor_nD%;E;r$uAQS@mo9*2CHQi8gyh3Qtr=;E9-<^~SCs~P`6 z?4;5Al-XJ3wAkE`iZ>Qy@-OX*nmD*9e+GP5R81RcWzytaoSb}zm)_;{3AFakI5a~!fQDBSmT3}zQ2ZD@?WY6Sw?x{?d%=$ z49Fe8X01`-#)?`(e}A~y9GmRYR<31Sh#r@)c~gFf&bvd}au%cF=gSZ`{9r8K7u41c z8#4}-Drz^Ys>qj^L~|3~%H6th1qUZer7)kDS7)GjXelqMy?xYagNk5vbAW@>2Q$Sy zNj6V$^lt&(Sbz~1mL@NElJK9sh&vX$JHMlNAJK1oov})tjXo(ZOb9E%=r>Y#&c!NM z^L}CrQ^oJ4`1v*_$46x=Z#FjCg+@Zc z3#2v=>dStc&c6FXK3VD~68=QBVX@5ZhCodJIoxB|a`(G!w~!C3s{nPx5cxx2q09i8Ei zQ(f+L0|MgT-(4WVI?bRLzW%%XtltOmnXET#vIH^iRE+6Pdj;C0pFY?68DiuI3n-FQ zb{dxt?;r1#pD4sW>I%4N5!)fITjhqDcr(U6ULuTAe6e^necu)P-j{=hVw!-%`jcY^ z1CdROKvV}swOv(=he9sLkNikc!9WxI*{)gMwK+St8!p2B>#-{Omd>b%5*?%K3aA42 zc6W2~P}J`YIT%x>CWR6r)t~RBZ)}hX^?DHDmyedyov^Epovt{m5*0E`FN%pgoyPv7 zx_hyzdyyey7bgVE5 zAD@V(s?0o>6i&fwI3+>1?N1-;Uvx}~`&gmS%eUWFu)akRl z{Vl>k(obS>-$i_T2uWx>*`?VZ0x@&wX){fniy&#QjGn6o zQ{UE&Z>jCxqOmNN)vMSvQux$qOxJx37ZmrNS&2BUUP+@Wh(&a;?EYelWltp~*SoT^ zh!&9EO`m)Hh3PH)!1bELo|YDkOq6)#_O@m(-V?^E0Uqv%>F+MWrp0zc{8_*`lTrUB z($;SBm!jnQ7^N(!ulXxe?uMt8cymu@v-F@|SxgAfUz)f)#*WuTfT9I4k^j5n7cP0-AMjY8#A$uD{(?R@4-mD<4Gbh+mEGaO|##ur0-h zd=?MV2J}$_F=Kmda{R2x=Jrgk`!O^KcmKOC(5gTvR%Nz&T*v();!rko`5r{YZEd*NGD`jp{!-}v3r52oNwFu7% z+mk@&gLuJQ4~!3ScR=>y^<6G(16+96umq|FNxcQf5a@>>Z;1y)ZLnShB6$fw^g9Wg zW4@-PrB#bzHp0rWEbD0;IPDfy5EB{}d-;(ySOU)h7mWxTU~7X_Ip%*UPK5Qp=g*!y zcUlMZk`M&xnaF4^1twl3TGWq9fCzTNMDUsHfkaYqDxd5ZJj5XFc~SBD6r!8}F-BmY zLmup5g~j$*U{U_Aco$Apkk(aRvFH?E^wnDvw@eB7menxql1nyNocQm8L7`alBA}+@ zRs4%CGE?o1XO_7qKlsSy31X~-8wbP_TY7)5MhV=|*!@ZQWSX}j%2m`&O1`pwSq;NLO<1O@)iz0rkDAauY&r8v%AFYsfc{ z);22m)qb7WH*u^+E#+u4o!qGzoEK$qu8b_^7(DE zVS)qsf^!6TANX%o>+sU_xkMhuqB>p2i*-QcQZr*zy>JAn1R^Dk+$KkR0S_jaSN3^L0{GVdQhI`cO1`MorNUX7{DY-wIQ z8*p#MuFMdJ*aC%>%=%#F^ebj~c||aLQ$SAv8S1j9Gv zgp>M9RfB^Jd?Hw&iw2z}B5u~nAENSG=_aEBEfSe>k^&R3uwb$OD>aK&bnu7j#{ySo zI1zz?hN-izm5V2|0+!EAX)`gGw*)R_GTlrV-Iu#`?sI(|w;ft5Y|5=QYGQ}Su%I+( zNO>0B){KXpt|__X`%UYV3ZBcFQ&Es{P{)>_l~*cW$?)~X%Xb>u($E4fBg6e&X*8k= zyo$c*mp*;iotz4{n!m8h{=xlb>eI>WET6WfWZ_MYa^8YvR!vU1kl+TM$TeGskwd>h zWjR$>hTGCR&0d{&njw^Ai0u*b?Db)nx+{>_hygBu@Wm4Q6%e-|UOUijwJ+F;?DXr~ zB_c7;@Hio^wAErXx7&d&mQ)~Z3+Pr=L0aCGC|?axVW8f`(%~fk0!!Uv-4AZSLUm@4 zKS2o2`06UMhNl|Yk^)LbASi!@B58%07Kd^DY8(^lTkk5sx8f!oGx`sq~eeLXY{fSGI z=84vQ$NaGlOm9bklU=6fPp-)RonBMenapgwMUWI1e&L((eP&{&qFqjVHuZ|U{Fpl{ zGZOh+*_5KFJ1VCs%FT7AOKWu;as2AH~S4~=ntM_^*_qsXQO`YK2aN{@%w?IqI-aE@nXx* zwe6RWG=^W2ZI`J&+8sojk&KaLa|*ttCbJWy{8iwM@|+^W!`JTF;CLA=RW1Df{g>Q9 zX7$95dhc>+3RRa4a{MxFY0Ue0_N45A6cvh_(?Z7a5v8?W&r_w+`;cM_qOr!dw)$7O zkDv7HJy?U}op0bC1zS6!r$HjIU>_K#wu(%hUM4)Iu+Inr7`jKt>H=OuE4DoJ><|~} z$&kwi;r1ZeOD}r>gwXgvtRkrbAPt28A;g#dDi_`Z%r<-e64*%NAd{-Ib1-EVnAK)r ziypa5!A48aF2dd|FH*zoh~_X3!=t_RTy0lMRR^~v(tF4`HS_G0_peh_oah+i{4}f2 z+5&Mhdb!>1(mUtQ&2=|ot6X}i{3x_#wN2~pPoa}Ha>l)n>ZzLQ`8ndND>5CI7;kXJ z1V!JxPrA`7sl(csbd3@Bb*c7IbcMYpoKa(gbG1K($)hOPXl(5o4Kd=9dTOeHM74y3wDNEem$!dpxyEC5+}aJv!t@#3SCY zrwQL(3Eo@Hz0tSQe?9bpJsT?gL)F8S&#Vu><6cTysUK?(iYiq{KEs>P*xTz}s8fPj z>k<>CHvAeL1y=g^U5{Kq`|I`&~_zr zO4KD+vlj+M?r7&{cdug6oNl7Z9X8x{j(NhmKa#2cEJyQyF!z>GRjysUw}POw3IdX% z2uMmdNJvS;qC>j7Te<|KrAxXb7u}uG-QC@FuC@1mp0m$+$NPRbW4vRWF>rkl7OeZe zub9`I|M~knH8)cS1(K{$Mq)pDwP&n){Dgq5)yUUNSV!A&cp{c(YARO!ww9|Szxhb9 z_O|0vHiLwmKD@KEjDB@ZeXMl&-CIZQw=G7z21K*IDLhzGDJOK>@`~|n_cJV%V!>-0u$a^~|eK`V3tD}n97JmEJ0`#V}su;_`S z1WW6)A-_rEJoW~=_uUu+8Hba!$mkFJ`<}#vd?hQYio-g)YH%5xktxTF>^JUBYWDZS z$`a9AUV6#^iCmS-T&m-1sQsFg_4$z5Blr}@u-hoYRiexAf&~`!qvL^9qE4!h1Et#c8|Uc&SUsy$kfZU{50VF#ieqJU zSTvwII?$=#Gsc@v51NOpZ5ijMh?zlsNtzQK@U}~w+f}_`xzTUVtRd+N`S{-v z0#O{{NbGy0Ze-T7vPMTD#S3HPrKB1r3@KzNE<2!0=9S12M30_0E3i6O&>qAEHKtXN+C!<;_i8cuo^0$Rg z9?D;G1%0nFh|S>Gs?p=Cc*u+#!J+ji?-qO-8EBdDqOnH|^e9y+DrVFy)>OZ&ot^!O zh1n{=K`3x?f@HpWZ$~irSm2U{A^_ut zrNscq6Cl`zRrG=GsA^X)$;A2TM?h~EmWhdosIj0)#D@Zbbto|}Fe}8u)~-;23EP2? z2xwM2OC&&hec{PhcHq$g1eaV7z9)UJfkZ#7Utb6Gd|=_=z|5^c@UU0Df2~9v<2-Q( zYY$nHaXDee3$czt{%fP>6J~K2S+~GP+MD&?oOc*D+H5s-*$}1tg3={5)eNPRdQ+uC z$B${AwerJ%vcffd1ds?>I_l#_T-K*ES0sa|^%UE$dUW zOk4=%OAO`cFSC+nnNT6X?#4}h}9M{!PZLGB7 z6~-{&ST)oZFFQ^+5Yx#~Tz1U_(+DhUbzLpxQBo1|c9Gi7LW35d^t+E}e}y6TWbUPguw7>|OJ7wBfg2wl?9 z&;Uv!=ZpOi$!s04YXFC}-#}IdL=m6;(FwP)q)L^j?HKlfiWcU)5t`)}k8(ZJJ1`(r zsDMdG2#%zC2-!8Mfg@`L{{);g8a2;Q=bqY}CWNtmc>N70gS~l`erE?cDKbXNqhYAWmZ5K! ztV`3B!^8J>_RG(0oWx-$=MaHT>^E71>OOYW(PkF?_Qq=p5RIO7MRIl;=*SO$zztq* zinY)wWEpXqB$lbkWj`IO4K*tFOj{+KrNx0@cJ=iMW(+-l`EuEjq!J8GQZlkq*Q;ZW z5d&Ra5aWje;0O>W8WiJaW^@?B)=XeH6c7?(7xV&n@c~C2+Se#AH=-4s7BgAWPM9JM zY}N6#Ci7;Sq8C$R zs?UqGQVmwm+~qY*4;J#sjl2yzVyTEXGiHABq>A8xF!denmBMK9Mp&bV2-}puI*!Z* z3cABJCmUIE=`x&=-H;!%iUPCdgg2d*mZ#J$3+<1 z7--4tVqio>aBvX@`z&YxS^}*##nAj*5PEXhZNoU3kAN@iB1l>ofStj|*Y{}A8{-(X zQ?=6HffHoa->$P-AZ-9BJfI8eF+f+fe*O5TL`OIlBOZtsf$Uo#TQUik!uS1 z;?(vB6}hoS2=N3tSYkD#?L7QH{o3i3p(@A!BuDKf&hfBx&gXs5SI2Wg*>~jJY zGGob1fh~b6FAvF38wSCbPrAa{SMWMD&*QkT%%pLX{6agwSiCWrU`2cIqaA2wEhh}; z_J59>^ywJhqgg$}ZZuZ}41Yqzkaxdqh;QF6Z#h?v!T&M6z&KbGS+=+l*t^T`@!673 z9^tJW6RXJW8+s2B+2HYc4}2UuJLFXY#$+Y@n=ux_s@zF}@nV+bb#(1?NlHuYEWh|d z_@!UPJFQFI?B!WB!kN^`BHPzj&z?5A;wOv+btw9SFMo$e_6ZdO8^!eaB?^jK91u{S52lLQ*tE6_VVv}GF-gb=9GDOUG* z^R=vVdoOsMx#=m9O;NbGs+StqSN>9a$-<^SIj$X%!l_1X^jLa0^W5g<7qnqs#WuXe zwnp!_+%VjyogFFpSR%Wuu^!eW~j))mb1mq92^{uK-T%k8uU8lNQ)ESptU?4cC&&IM74G3Gj^$KiRC(-^CpR>XGHPyjfX3 z$bQfRK`PAK5@vd?tQXPTG@{ns?l42phCwEtYr?4CuMRW+Y zP!AmE{h7RyoR*g!RbH6?r!xiPn5pxwm9CB(4EBf`JH3o+U8Mb=-xF#(tfWlPvE^RZ z@@k5=Bw+^bGbVySmtdjhW&hNwpy)Lpy89U|;nRgMU@zw~=n(3)5zA3Y&l>h=Yh4n| z7%LTn&ocHI$PqZ%dpZkw9)GO51RSq-KG1co#$qIA&Uzok&ek7oPUce~nnG|kSAv#4^T?2;fnahCmBwawF zr*lgq6~EQchQk>1sP8Uv7aW~%*5Xv9pt=j9J`+_pp<4FiWG?75~cE|S5s{)JWvzRyEevdWK^ zey1Rvu$)|55MFHy3MLuhiK)#J#`YHwb#@gV>b6X{{hp34+&-C^#k#!}d%OM>jW9L~ z^JwmBKXiAJ-q%R2vXqV7B_LU6CF6+t7x#>^Q$0SAu8M24)z4`E0Rf!X2K^ zS1H7nKaw7w47_n*c}g6%GASVAxSoI{p8M#NXL|Fm&!RY*vcv&T-k2*Z zM@V5QBm0LCt0cz9A~Z+q`Is+uDW9cQ$-;jd7!kKN{P0fOCIBVJEc!R~`}oYKI%(1V zg?p2t_$F^`baACs%Q=^C-ol~BqaxbTf#X=Kqh*%#7A)63tuW1GN@Gi}%S+D*4$ zNB{@UIDGs0@D<)$x_(gGT^ zKHEMkc+-@DjD;-LZyXx!SO(@a#+0+MX%EZQm6+c8$ zkwT{~1E~)cSb7pO=xcs$_N0_0{v*Hp1ZqF9S;^Bz;D0Bj{nw>|+drgDp@#z-+y5Ot z&(kyi*UtpLqk<}`_P_m5`~QtUWErXc#^-sVDsQkaj{8mFz+nXvQr*&qLx0S_u24|U z5(NnnRTLi-1LANLzxI&S11V(h)DDzw~x7 z{q4PyeA}NN&+jpb24e9-c5VNA>zJr=As^Z@VN1=>^5yg%m!kA1Xe4=Y_cdq(bzJRx z-LN~aZr|{q`!Up3qf~gBS3o+T%WuK5qN*HNnTO08i~x*mTQ z%2HUu!|mDw?^9H4loEYLdZBmWzP=K}bN_Qy!LwJcpzPNl)o0w`s0xKM2e-LWDPQ)P zl~F|1^N`~tm3{}e8;zsedKzpE>mgUPudDs6ItmoJ_gIn!m zNC`eCfB7@H-d<5LDF=3N8-RoJz-@15cK0|GQmCKb+*I%BIUAcCnw2Mp?)9HLZ-wwn zA@g~9F6>EJ&Dm9|ypE1pw@y^g)m7Gh3;rZ?Z;hgHh3Ua)AUW;OLe_uYMzS5D63rj5 z{w5HGq|J`CBdigeWU z{0%Fq4_aCp^@K5gJMD9_$axMk(a?T0OAf{_bXybxejHf33+^yg87!N6BGPS=kg=lVnXemr+aN7W69#d#mm_Rm8I!2bN#1w?|I zns1-d-9{{#+?HLi8?=r=NAXpg?=kc>Dm6OBMwOUdx07iTtaum`y8_YJXOh%Z>*LbY zOh!klULHK%xOI&c4Q9N*r$$9Fk?WK)fsPa=voe;pv`j88k!*aW!qh1{vNhj_G(OJA z%S}_4MBlTv{$sb@M)mlyb?e{d3@{1#|N1Zqvi6>aA+z7EK7SUUh8_gLci;r|59l9- zznj%AVKTm6p?pQ$(XQn%G+NRbh{D@&!{&`{A=jcZ&j_qF+*85bMvTU4cFF8j|!9r6<`6a#aug0j5=jQgSO+lri==5JQ! zBF{cNeoSzFy80^t|BCVz_M0B#_w(9msz5HkwpQ&rvM^$(E2)4T*3tIWysh6}M*4Y) zmX@H#=v?@;>H5)kRHDF;_R)Z~CsTV|G0C9`!O*=CRK)vXY-c3dWHDZCJP&t}Q zt%-<%<``{jC#QOZDX=UGx3r2Lov;7$e@Z?(O97$y_yKFvjOBLM9+jC{P=(q@5%NM+ zL(nhWW*X`t^0}ocno#?Mr&qurc?u zdYST3m1t&BcLKbj&|_S>yt~;?X`kGty`*Yh%_ zf1Enh)!!LbOAw3yvW5J`3s+UCUY`+j^IZoUo#!o%y-G(ykQ$Klg_efv(1v@|Ra-^Vi2@uoD%WpASvgHqzq=k_YP^Kd9D z@!6isJ&K^-`>?$^Rf8I^#~BT$D=B`_fo2qM^frrHSg=3EcS5hkx(g0cL+5?@s@+6O z>(|6czjCOoDEg0dSx^6`jxGYy&*z7RzULII#th5mMGfbt{WHtTpY%iWOEn!|jF@vs zRyoY=XV=Y|1e`L{v(~4c|Va?en;Zvm5`|Om|5jjmL(d(o!4O> zE9S!iwQcPn(-eoQN}*Vx=A)qC2qF!4PqT}3S&Btdr7nS;&)M$YhkrOa+w;U<5lr0^ zLbA%}nkaKvt4CwNzFUsB#Dd?*>omMpm9nzzC{vtW6W+^_DgBX`BH$?#9ubdi&Oid3 z8zVyi>a#cbFCLG)19Pms{b;kn%?|EQ{m5|D!c2k(>kr=)Sq;gEVCaPz<*P5#&|=ob znd!5FTt3Jk{#hJeNTPSF6}pB6VSz%68rJ787#JH;FJ35~R!aEtHyfzXq%gPQQ~zhn zDiR+7S9{V)OYZcMgz#JW$b11e(Lj;cryxp`$T!W?l+J!pA4}b6fv%y>vDckP)TmR~ zUppscktG!WP)+8A+m6%gBkOj3gR-iE?~0tZi`iM*Jd}gt{@hznh^RX=ezCMjzxtK+ zE10g@`&3@gXo{CJ)IR@Y6Z-ZpPZ7tU;&?d_lO}J*K+0l)qm`?!Zf2Kx%%siD?j^Gw zPvdxkIW&yJV{CHow#MEmp>d(hq+sHB-My0#WJQ*P*2lJNVaMUIe8m&M$YlgNh1nU$ z6la_SC6ypWC#R&PT5TPta|XB$9F_I8_6b7H@z?trkall0rdM^79$eg0L^vDPvsI(= zHRGdI1QQe5OCGXv>Y+D0w4uc+hL0LQ_)L^ZJsMWste%S)Y~K0MteqQK4u5GO()Eh< z1vdXPnZ|+Edy$216kXwGB##bJpJ|Pz7Y`x&s-KnCogvnIca2(oy3XvJoN6!nUFDQ{ z?>eL=PfxSEhHhd{%0ooHSSuu+CGR2$)peQMZ%|X>;k5_(N3x+c+x=vo*`r+pyULsM zY+haPJCp9WmTP*ET;OZsm88Fnj#f~T+p{-&BW;aNV%3$@!iSk|w@+gtT8F4mv%JDi z2uehz(ad`NvnChEVn4J~U-8g#S+s*Zi`AKX!x+K>8E&yU;84wH$o0hST$65egKJ&a zE=PdmP}|F6b57qvZ^bd8p^(hraHEV!*- zKtLQi?|3z_=hnjcNf>0ds&cu3McXg%{jE`pkM`B=Dw)KG0 z3$tEh5Hy85sPjgGLJ3ICudc5%7z_{q|FA1SrTRW)st@?ktZjkY7EqhAU^0_zcsQj$ z0YyLYj{Q=I>(87|aqR3yIO#BGGg3$4l0qGNd+Apb!Y5NvyV|9LTBQl zlS5q~kR&}lAO91vuU`{*vT6{wada!1T1E?(2Hn{)*rXgXQ;$V6|($ z67>@K7`YgS^l)BTbs{ zCbY4y%&|aEZ=5KWNIS*c@W#yK^K&6npGY;d{JSiI z{$R_Oct~)jpN|10Ca*t}lHf4D$rLjGCv|ExagQ#S>)zU^e3bKM{Jgi*^h!Oc>sXXf;|daT<$rnlehwdHr|L z5POP_)4sy9`1@HeeCE?RC}oH+F}^Ge=Q}lCtjM9jj)_jAk4x$nws~{d}ZBE z0N7hLEksPL(GaAqQ0VKx?OP{J(Pij4_pZXv=CFoaWP3~TsKXeO47U9bIe&az+k{&yT#(CmD#g2;{rxa`U*RkeIaN`=yNevbh9-+IP5y^B5AO(q% z9{jQIw7vI3_j!Moy?8h%d6Lh?WhLh#ZEK1XosF{gq&754OwT)z*~%%tR3S5AxTD;> zqLBE$nzKQ281C!J0rb&F-L+5IOO5MKkH+WO^v^}~RG{+q>j*4LziU5_=gE%|3;)*X z#L8->D(+dkOuf@WXY*gYTU-6^@k7=4?nrow%ujNq$46 za~Ph3^2ovM@d9fb_eQ*6>onA25R_K~f`c;vssJ#-q5!S{?hxp)j{v&u7_43Je=>wI zU`ba1{R4j91**_cSnVIsC|(c{^a1Y}Wxxb8pzS#Xef7y8GmP;KD1U7JQ9?d)2WC?? zz!L$mFJRsP08mn*bN?9hS#|Q>zW}ukke9V+xFQn{C0GK4$hI9*OlW@sD2(Bi>bj@-T-?fb2>s91uY~gT3SDf`dps)j-2akua zyyKVrnAgKA4cST$vkz=p^=m_lA0%f6hb(x=KyBi-MJJa9@|<8HDc+b-n8j_kY5@P` zEJ>WC!}m^Aize5spYIZQ$S#_~Dkd6xLW(jBo)7J@fb@6wZNHOKY>h{iEcgUnSz)v$ zjfS_jwzy28Df4bYt55H(!P*jGm$H%>oZ8zZ{Or4An=yT4iOoCV#;ZyC2K7c6TU#-keom&}+=7BWwo;@l!CQi#;JAOclUD>)l-MQn;rlt0vC z@4z=mw)$JVC}8}6;lu_25y0yJMwS6Ygpw)KTd>-~Ts#5Bqfeg^=<-0l4`xpQK$YKs z!y^#-!94CK_s$V@IM3SsoX@t~LE#!;3t<*uz~UhZU`bdgu}9;X^$L3yUI#rpDOz>R zWi^o!R6DP{y{Pi6)jkP0D^6`p3!qUZq0KhQt)R?zzHFu|>YR#3cE3@DBaGF5ek~W+ zYXr8OG~nvf-g)dik%t=mMQ~5~!8WUOB=JKZLK813oD?x{>_{$mg-<(qgpF?FEbdII z$+5}_4E_)FLqC~}UIHW!5-6jkWd!rg?Z6hd|5H`tsKzQHJYaXNj7agq028pXGC(i^ zV>w{-=K^!SgTXt2KGH4%TRPzlP_r)qQmQV{FoH%K7{8+PGCRc`4~R;EsM!&y^0ww` zFRt*#;ddI80B8ohxoYty+-t_7F^SmY_Q;Q2G(){yybB$jg$_cklkWgm%7B~c=Ur!n-XXdZZAE;%61llpB#xytmAxlb(d{;22!7~JB@_h&ol8G}AJIb7;(;~wG$7Y4=8U3w|r zn%AIxYx+q`8tUjXN<%eyKR+^A!0dRvg=c3PEa$*k@fK;%m5~AqXxMB}gZH@!K#Ko* zP;+dG78C?c6{y^@skMO|1NG;b$L6#{BuX9<4E+H^uY!mX#*+j_oz;L$Gr+6kasdlH zsMV_e(7OSs0^md}gNLpI3c9nPTK0F5u)VYM1W3&P3ONCA2zX1hYCc>mMj3dIp|yLd z)MgbxrdSKk%^r#+1ud`UR!8meEB;ndo=q4Uf+=7Uf#=RQw4L@=Plei_Tv*4hxYh&9 z-tyt7$3#x;KqVTIg}kAAh;S@Lu(TL+rklC@o=T7IznaO4zcrItlS0fcKGKB>8528G z)i&fH+XSTQIu$CwE6(_o0VaX~u0;SV1(W(*oot){=Qb^tgrux8C29b=EKs0gHn7M7 zmJR=Bn#oa2#~V;t1oiEV^73<3GlzW~>80fzFIM|LkmXO#lW)vx+z`RZ_Dbikt{Q-CxT&JX~B(x#3a7wN=j=8u3{Hz)^8lyia>P}v&gl&Z-6PP`D`A2(Y*edVq!yutYpV4*~vH4LYH zjY@u2yM{$jZmWQo5G3!Nsh{j*|sBGeW&rGb{ZgW_~8J zoYCWUqnjgETT+7qZ15Yh->ex(-kxec3N^j`(M9AJ$I5vvs+B%|12C%hpmW=PS1D+);YTIV*1$L_0GbAr@rgTo%Ps$(0?pBB*tUS~ zS<$?{a13AM=rUkOH%5{=yLK6)mOqR=S2d4+Y(64~z4JMib!6L?aLv8yHVFCv)_>{& z4$tcJ?^Ua+Nh%sYdn6;BEFF@z7%}!+q=>gikJD?0+m040Wn@&SSvy$rrZ8~;^Acv{ z1M_&f1!NvTD)I&nHshikObWn=i849};4uN)heqC@mIB5f{{L5cX}LX}n`TD`_&FdL zga2(l#{ugb>2w7!%~gPC(FQ9xv*(?ub`npzPLweq;-D0?2(aPL@~0Uq6{QfImX7){K4C_dCbY)6Vu~= zr1z^StR64wmsp-0t<0ig?bs5aJzM;t&?|+9R!#FeCh$4G8dYVyF(`wJ9($iqa8(8a zxzZ1pMPXs--OKUlQ(Vs2rp|61H2I7ygNe?m#a(Xpim9ckO@Xd`wc9lrtl{yB{ z1a0w~n#kwh@#;OTe(FxT1C>y$t7EM0JVHh_v5dzndtvtJnYu8qpMxbSB`dQStAqT$ zF*sU*1)HLu>tTJX-SY$pl8a*a*Muf&vu!SSGDm-g08R3w8Ov@Zp7ZTFjyqZv6#oz7033TeMK?mX6Q?epXuTmxIlWgJ&=gojtO^_v}tEF;0~v!rvoRwA38t%{htE4P|nykq7Gl7y4-jk>Yvg30otOv;{!V1tm!u{ zso6UVyEHWlnHDPor5zN7y+s*O?-lRUb-v_4lx0-JwVWya1~ycGCDG`vE8`%c)*j4a;|lTu!AK6kkL|1A}k$_o@Id$Lcn{$O)*5 zfZ)9^i8B^hgu&bqC$oUqW8CRC0jK?UAPh);XmMIc1)fwuhE5Mq<$!$;V_$(t&0fX9 z4XCQ?ciaIg?}#m7sqS}h9$2nnnAUm66*S?6Kvp<6?$>T>%#N2PMayOv_2%XU0bv_U zcd?rWQfZ4LRcz?(71h2M zRsB@`_5m3o+smu#^la@1l$F=fd0h4K%QKScym$D#q$ki2ANzd)+XK!muvAsnpO8jp zBCKZbF3!Y~Kc6kZNkd{C0g{Pbm4>b(zY0)={}{bmay8cd#9>nuMETbePH~Z(<3KXv zuUPr1J+tuu#5RB2cGc`@GzEb$$dnn|j~m)@H1pUP1v;KxeL%dVZr-kH@dmVoL*y)^7_*F;-?b@`koRLX)YxsoqifI1%@+^S+$;F7R~EnAa!CLY%Qc zXOa8eYWvB;;GHe5^K58g2fvc+!?c-9b%rzrE{_K@{sYTExDQXKd6}$Cl&`;3s+#UZFU2gSmm)+$}JoN)MP&pnkD(A@VLc;5R;{zE}>jO4}KzBr<$c5 zLX)Ql@^YHp-Ltx#rR}46rY(b{)5-c$YQV`Jwg>}=SW_M(U#Y_Q6~J%8;GEQ&4FnlO z0UHQz*R|DMA{svnL_|bj^ms2XxY$A#TGwX~d3k9S6*0iH=e<4j)~Sk(#R2_J;Bc8S zvIR@f05xBMMtwZcWDWuIK#ulEmE7G*}gts?WJRq&PZ-|7qavHZnSsJh8bsFECuD z^;hvuN1W&RI67)6TNq>W8)=}~BoogOh@){#Sx~R8V(-nhp`0&YbANmK3fY>U|B{9x zfO&p?Rph0>v!M>Bt+yX-iTl8@Y`v|LIdQVmZ$`h-J8kAs=)>-c| z%W!pEaY}rZH#nBHXQ~=#`Y8xhm7zQ8Y4T~(88Z3!_^@dN07C&Pa2x?6p>E(5;IOM|YgaZlgvG>y z-VN9m{lAGcjrTx;M9(PtsfIBohZLie&;)(BR=&B30}YHe!G>Y6Cj1M@Y#-L z8lupW`4UGj#N)*$d$XJ(Q~B^A~7id0fLK?|3!6i<0Z%ZJ!8tvZI|~Ad%l3 zYQ&D*Aoz3M5fWfZDO-7#*BG|Ob2I2N;eie^R9IUG0H_1eUFyURIG;W?u64)ba{LJN z<+HXU62Nh;dVrxLj99AHeh>76>H-%!S0H^lvuB0?BWoa~3Mfmy_1zq@(N7YTY#fi`q=G#3-l z^!0#SLFiLWpbZ6vb6SAr2Q;t4Wd>3(Qf2lPz6x}NPnOaNL>d4$tJfdTylKnP$!mv# zyw8GTM};&yZr}kQXI!Sx+siSB=5*3+vKTBOj$)$sXL_*Nqh*!;^B@qNz9~15Elxq@vC`1yvlf|sLUgG2 zK_@wB{H3Q3Qh+V(I3DhZFF4T|dbeyc*>Y((!z3CX}~VKPt)d;2;xhW zeZ0a9$i)<>;3)^XQ@|p6ch2ls=pEMl8i-&++gJ+-ky^<) zUu~FgP9nD3XM)TJ+vVB}P&_d;aDXqaI{4o+1$I0hAyWYrHOM2m(^tW=4w!Q;xJ#mU zLx_GuTcJpfj!%C$9FkY(#KSx%!3bFfj_ojCO8`g)9W{Z@m`{KgEG!xXTO{ze5d?;! zFu5dX=dAy$6V7n0CmQI1y#W{ZC%|X|yTd_nbPtluHj$^!fp~ZrwWvgQiW%#?=N1qv zc64#}8$EBZE*Q-os4@YWTNGq{E!7!ZF8ytFBuBk{UVs7FMvf z9zbVs1eWwLYkFWAt^>w*DE4#Eu>xZOg9d3iY3U}g*cvS~)B`SmL`&Hq&le>nT+phv z1`>)z4sKM6MY_O`611%_*sO~;TrQ)OtI)vw2Y7gR2-vNCa5M|d*1=7YoOjwF1l=E- zB3X5ZEhvc`Gg3D&cLiXn3p}mYK@aq=f`UFH_2Rl?WLWPe=o#Svc6%`SKJdDPb8v6~ z#!N6%kU_2!RPYWmkQhS4X8~@e0YZg0{Ndr@r`uyF-@r}pGnxfROx6bA|Hg(YO1P^ybGWD|6?2Q$VuojRd+xd%it*AD>IcQ>eWPj&EqAnzn@lZbTd&(4x=q?(>B@u+=ZOrzkGg6>e$t3bA zk&0MZXsO8*T&G>#0k6fMtb^Ypu0OKb_lZF^ zGjNwZYP66Ff2{rsh;L?RnL}MvY<~ajnY_Ewez~70Vw9n8f>t*8b?b)s-2#IfE&!<;1Le0pi+Fuk2*Fp;v0oKSiZAmL{rL%kF3%4 zkO2IBYZ>Nn5LMCxr(D?C=)2H6pyJd4LSr;ZUNC5|sg=IXnHvBTDQfkaa+#8(U>yPB zFd{twyM@K7Fw=>;IxY>jGl+0-h@bY~A@Xc^wt=)Q3DE6bZVR&EKti7^Cb*casQ+&w zR6EUQW?L1MbLdgbY#I=~%$28cKIWWj)^+NSWA2?V7pQoXC(0Bu{l{l=+ZTQLbvT#u zQS3%*4>6F6Bg-w@Orj`3sc;RXKt6!Z5nYR1{Oln^7-iPudL)I-@i3L3P@w?Y-twjK zZryseE5V{;_7h`05Hg(Fy|~pJF2ql%Sfq`a{dO@t64=*kV#$#p){d`UTPiuigur}I zRIpl7Zk73N7(L=4vCYP;i(o(jK?9};rB6c-~Dv+2C#YoUmt$3glTCX9D?k{Uv+DfID?$tO_*=?T-itSWc=Zi>(J>~f@`)-3VpRCRZH*9w7>WH}-Br}>O@!7OM6n_X zHW2%b-|rl1OkZqn;OawXWYpfG+a57Z`Cn9A|MJaA0UC*5MKvkDH|pH|_bOg8`i$_~ zTW@<-_d+VuTdq8v*HJwN`t{Z?)aU0*nQ$dM#b%lCyy1LON67%E< zQw?YC@~-Wv%pNE|VCnsmQBV_c^nb!XZC4Q41QhF72FY)Bx_Df@y@rIL!fDd7QEo4N z)#A+*f+f`e6&`?fsfD)?V!JlUFxXdA>&|ltCy6R0_Ui>yBitx z(->(rAhx-=JiN%?jmc)7${G4N)Qb{QvL6&aaO`6neQ7=l^+Ym+@p49-wF$Q{NzC(3kMZNo3x&7)Y6%w10UsgGbx$eKD#>N*` zrye##?r{^OJ9Qcrl&_k?_Y#u)^oV9d9KN9+Jld#v|0=URarOe`(fjJSs8xNAm?7++ z60Z!)LxMdaaps9W4dqqOY33gc4jNiB3XUHhcn!$nPLo9sNTW!<2?l-T`y?&%;}yPF zdcbZF%63i6*g_uhY(>HKn7aCeUu}#!Rk~LW6W`}34R}(LUy(w{TYCEL9)fW6zO-?N z&T2R~mKQd$jEoy@DJL2_EH=}i54Hqb1%_C<;*7VP)z}PTj^=NTsksx6%(mX zaV?)Yyl~A^!YLI41Hd73EX_mC);!fm0))qT{xbfOl})L zd&cHji07!|!d2T_cQx09`tmlvy3<1{`^!PG{fegQigM(_*%zOr_b(6juVj&IbOtZ~ zNE+0>VtxLwphk^P#WvP|zD0)Vf%fd%w{MsOkS%rPZtfYV4p*RBwB6X#83bB9<2;ws zvI>inur_p#gPi8z>uKY2v-_ihTpO&aALa+C&7b(BpTB7A!_k7;Kp?LMudnSBbn2mX ziIcat=fpp0X>Ym7{JeQREbm)8{dqtzGth5VmY7=|$H~ArHC20o6t=OToNi-KTd%6I zAa!?(JIp8jXtCqgHKx5?YlPczd~$hJP)OvNn~n8!f3U(oWV_Yx9O~7Sje{7=op+vU zSTZe#e_lG@D6VV_KSG3GJJTQT;Zm+$Xn{Im$D0XT&{>VDMR$Z9Bjqv65$^DLhhYNX zFIB?ftfIG`&HI?MHQWR#j~g(cAolk8bcBwzjdU+KQPI_HLvp*3u zEATd+hjcXgR#(?;t&Gq_uxU>JX?nl4ML2N7MB+*85l+4o`1|9%48-?>u4dsXCiWz| zg?}F%g|nomC=vrr72rx|-`(0`B!3Q4Q{S3twzYUa z`!~m#Jwwu>YsD5^hvW>U=)n9$Vd&Px07N;e+CROI+j+80%ilG! ztPhTkE}jFIr@Ou;zV^$P!OJ7x8Ph&MDEd9o6#5fa%WQ~L!^W}yQG6)A#h{p(7$s0md4P_xQercZRuDtQ!+}9FgH{dg?jAHOEliy5MC4QifVHpP3v*y zMyCEn+w6+7rBKuphRv_?v@}(M4ZO1IR-DfQVBShw+{@_~mN80ov=7blrEW?WiG^ck zHuF8LyH4qZg*WJ@{!Db^j`Ryff$~o~sd%JjE@j>Op1%!^Sva`)rO@^73QSZh+ znUeDDDi)fPotDl!x{Wn@lV0q)u%r2{qKn12^Vo=&MC_K|+T;#_q9-1&B{*nWg7^9J zPgyd=%73$i4W_f*-3bv9Qr|1;Ib5#UgKOmE-N=iQ+mJ5m2^FNWBq8T3{IvYh`nwR% z=4zp9##qm*+}yf|gx>e$&*w0pQ$Ljt&9woyna1r%N;@;4iOXDqWp0A z99!{@r1*#Of=`$UQORE^sq_f6w|A;1qgouGXFu3?qOV8CFqAYTJLbO{G>`dx6aM4* zF^7{4{Nik%xW-&{|ouC|kl#u77&gQc_jZGgq`;slvlUkp9MP+QR!=L+nWlasqC8dTZOQ%=bt& z*TK}gbSOK2F08n^J-uYRmKPP7X2sf;c01APT{T}{O+i!GdR2dX?D&Q*ESH32_v~E1 zwwCj1U|^RO?*ly^Qpwb_@~LOPRRYaSN%I<#55YYS3g+yS8hRBxH?Zq=^U>~OqMV96 z*28A%gn$7D5@VMMZPd-OvyhnxH*{EimwA)^Rw{|K2SqY5CEmzD~r!=G{bhAXj7{ zgZJZiiw00ky^5DZv*K!Q-1I=Mii5M_8ZoC(JHkCVhg+!d(%MF}tA9-;GSDma%`rDu zm%ZKlk#^tVltI4Sp@5Wrp{jnN;w-WVV`CB856#)$OXH97>g%0)Clp`(JrhJ&=@+z@ z;#&CCwzsGI@grk|G^`mO_H^64Vk8F4^Qy ze%k~2kiFJ0{NcIqi6c-zbavWk2nl8P3Swculu_#H8gV4Rc!j+@(JamL)XmK)Jy-)i z>1uQ=diBy#$o|h8cXekD&g%<<75dPl#`f;O{*sbky80ZmXEgMstQPCx3zWaXUNJRGj!1 zE1Nx+y3)_D)Lp+h7(7Ko+($!NYF*XcmRiBb^I!G%ITUMjN4LXBMk|n%tV>Gl6DA~0 z!1;@q7tZ*lni4~zYIW#_=<%B;t_$m_0>cP`d^!*hgd}DCnQrP@F zDsYaes2pD^I@;0Da0P$T{7mRVkRyjdQ1!cy5Z0=d5839$ePjAo0uTw=Qd{-q1))Z11t5<_=MUs<^g&j23M}JG@`n0i{z_zba#Vrd9Zj zO^)*NTMN@3XLktgBEpBz(lY(*m#?joUfq{WPQb5KQ@`pk?Z_J0_=w2F$_ViEm(wcL zXJ?KR6Dt~;VIzZ{Kgkpo@%r@f5|eV76FyivkdO3->=hN6vh@paZV~w?C4@Aip|wqn zX&D(dK^urtuCHUhD$8LaCWMfc#R(Z07^|sKoS%|T^oOL(&MCVfdx`$Nr5x`ZSI#&A zzDloJbhb)HK9wRWo^2lh?aL1974^t1WnVhpH|pSi&=Hiwe1K{R)NTd8#Jutk8>HXc z(XBkX@Pd0;RwmWU{u@7}j_2z)Kew33EFzrYj8)tan!uDOwOrwu_0_gYbLS*Gj251Z za5r=FRJsrUY-he8Xt20A{JPxWR&}p^xg$rzOX`C_xcY3bCxr%kpCO@|i>7cUjAtna zHoX#l=A`;2zWf)hxJ&e}`6XW@#tupJ^7gjF{wq+1y{!IXe&m6H_MVMCoC<^BO?B#{ zFAC#G7R8jLK1nh%uK3TJDpT;=rLvf9SP#GIlE%tI=qY(qy6Ro%S(phg?2T!#&;9(% zKD_xBt)W5CV{b*>xjrO1kG}EkkrzB%sL=y?S%@MHwqIv^xRMN?t;`D^1O#$do?vaA zspl`6h41f~@KJLzl_g)T{mZ6eM5vmwmKCfA`y&5h`vM19mhT)0f8Ub7$CLWM0n)%? z^WVU1U>{)ifAP23wy^$Ms$nl(ak>nXRTSwyOIn$y=lLyz6)(IW_iXq5igq~?;Cr*M zru=)_W!+_x1v3iuD4VI>KMxlJ&n*$)lGTQM6cx}s6DWTd&~+N_OJkNSNGmR6V`g(`OG=S zm}7{d+B%kS9Nj{)$O(ZOUfutShBBIV#jh>ggYWOxMr!nyZKRM2u zVJcppqCkT3^S)b|^_D(P3i>YQ#)QnwMZub`0*5~cn9LO@a1sUz-e%sfM@w8`F$}`t zIumtAY9~cE-+S@4Q}&RbR#9S<+$KA(^S;0b=LufH<3YTX@6FHpw~upa_sM-hVlTO3eNbP1Yaj0&fL%R|2n)n{ z0~l1SEb!UBjW1Hh3=2P4Z#Yb&)IWvYxLLG+mh&Vhq-mt=LrTeF*kD8|!<$ik%UfoR zUoTr=SEG6fd{;X9@y9;rVEp}ug_z1#$Od*dN~T|9e+{e289u6)j|`%8<-5~2CO0|5 zc}|jA)u!*P)nS& z#;*b0C$@~;qU@e#+TBVPX>7 z=dg}C(w=}1!yd$RB?N2T*dknVoU^6^uI|Ubrr!C-h@gcLdb#?|S*G$#2(3a=xq+8x zH;E?1!$l;ekSva95vr;l(z?z=PWoN7e3MY&nSaXI^xNn-Eeif)_S2Jizm!z#s*j@^ z_Vjz6V$+TE^9E#{hnULNx^L%W&)y13Y{GbBlX7)g*=v~CEDrQDoE;g19-w@T7n~OC z<3`E`Q8mjGEfI1jk7P_em-1JibMtwQd_{d@;uk4Pj;W6^MStA0&EmGiAm3w9oIT?feX!N!ef90zZEz%NLsFSuytoGR6F52qPSp6oZ1YcrWUABUl26Es zWxk+&-KgK$ot`w&J5nbc=ohHj1*^I`)VV(6fxEih^ z<@t9$X+c!=lDWz$ww+{oR7w^r;rI;mMysUcT=46KjG?tPYl2dgEFRRB)9=@1Wn+`P zX#@&B{cr{cE$fk2D11LOkI$cl&M#vWe%Rh;K2rTCu4vz7Cy+*a>CZc?w;0|$Ao^l~ zCgx7pH@;8DZ_{kUT)Dc1ji=eJ&B_S_Uq2*09>nQDWlez@@XS(HCEhq>2J1skJ>r~= z1Nw*cR?ZGKP?~`d8Ki+{K~KmHg^3ZG9A*v7`fo)!c}QxsqyzIiN}N37j@d3LRzq+Y z!_l;Bdw^uFIlH*zn07OQ6-jjOHYnYjz-iCF?&S@TH~%YA9uaI#O-!7sf*e_}JwbBE zQ9BE>v-LUbD3@w~m*t=!F6$+%Z^dZV$Q#%C ztT97nw*+F+jDqLaQhS4=#Jm=;l+?D>kmvvSF!WAGGw+5vJPW}T1GA7 z=>%ThESDGo(5g6AMVBomcwx}UeV3pBpBP_%*^$c8oRfR#5|KV0?r~O0SpF4k-M!oA z^L*r%?vu;u;81>V*~W=y^z`%`21O_#tzZ;beMPWnHOE?2__Y~LLAk#PuQcRZE-o!a za~cza12m$+4W#BHP48(20lUjgxGLbyT9_64UT!Xf#*0R6G2+1R!ZU{m0hb5z=As7Q ze5n(^#PHU&H&lML>2vG)lr}am@Z1mIA-OoK2jovaX5Z!M|J1C*Q5#Znom?=_?3|AL z&rqx3p&&f&BZg36D2XRz~X+cGBZq((fuvU7d38A-WC zI5=bD*287){F?2{v$7_SN%u=1#Cgj7Nq$z)qk}z*4m9d( zXsjDzWPKVJcOSf`$1J1E-F9sU3?m_Evkkmmn&G!Ng{a#hH}Zj;;KmuJVHZaAe1S=`LwaIF{4~U>u2!*M5`XD<@lmB>1_U)r!QZ=+?%4q zHi9bs9P9+{3|U#lW5I1|d~vZEqODtyZwINaB&uv$%ZHH`+#0b-;$YbeK2_#KCx3gQ zscWuV^h&eF*^B!EPc=4ZakDBejQNh@+|uH^K+cM;IGh`?I2u!YOH}3y14Y)mA`4Zdw_WG`?4w;@j}@-oWyPM#^C8F0N^omkIuvL4P=0c+ z;$%swt8)L<>#()@Zqm*f{?(IDgys8}ay^gUgm<*v+&Yw#ES~TjK31oknUv6$dOB&% zU9o$4X>9+3XQ;N=dS0($SVDb6j^Kn(DKDKQmTBOPnAbD;z7ch7Bs(Vj}fy zufy4ExD{qUVeXb`SI0NyMl z3DlWz(H1a2C8nYs{J?2sW5mn!L3b$lwYZxGsd~t{dk#gLk%VUZqgPL4OnnG2nJkP7 zYrgt@ttJ`mD|1xK7csdr)DbCr{F?hzX6ZwCULnt;ieqWgBi_fBcn|+(w!qF_IL|52 z{>dQkh3U7nUfdqh_#Ikuqr7Y2Qdr`!1X+V$va>Iy_dF97tzoy)hfY9ASy^6Lxek1I z5vwX_z%*m)-Csf0DG<@1C!3u$!a*`x5n+9ACbJG3@;{J04TSy&pLXEdGqg%0;Auxh zhhX&!5$K;vN+{EN{2_2LEiJ8P>R@jwgwJ{X`pgWod>aVJ?I08uqa-*nfe3t%y@}S= z2%Gz3Zfim*a*3mxb*TX!PMB(nGt2+h0#t$rYa)m`D9FjlD~@+G{s~v1{@B?Rm>%Li zDMa;+ne_{%>|$)2e?i)eK(53?3j7^ZYRRpT#SenqHJ#T)Yu>nO2(A=M(IsS>g>~smwKMoZJ1O&x8PKy z_s3+rA?+fCi0`ZZlMMIO9Zp9S;S+kQF}Ik-N$Lz4qTdnZ@+D4G6_-5VBJqc>aOc@^ zXzPQ-Q`v`0*o)B|vqf1epJ?w3kXHs5YC*Gt(&&U z1TwXccgN;(8fXzmNaUcwc5vYZe(H2EZgQP~`jO^ky`akOFeA>zEt z)Dz^wf(i>;OM0MdD}$S%BmmU-V$^||#i4;cbnMQ9HJ4LSUrhSsU{Lu{Ab($fTjGl* zn(n0Y__p+M=uzgF0(yNtBzN}RAU&q%?TArLQ-+?HxNO0)gU%&k>s!eu>y+MU=6Cu} zXo{&K64rO_Uf@_?Ct0zLo;{!(K7MnJZDH3LPyD4VhrYdS{j^2>^zxfnx$850K4XH% zhBf=0iy>i#Y<%qF-v^ctHf3U#%-j15a)vDWQEhQ=W|rHJ^@c-S{u_^CocFYj|D7fnDL3J>Qjm5|a~kjLyR1B<^@-Au)-h5l6H-?iHE!rpQSVtCbm0@9d+202sfPmv zWeeY0dc}&Jc?$h+!i$??Lx0|iVif*?*Q~mYX z=TO;J6In6`k<$lg3WAUbDW{dV?h+d6_g*kjJR8*;_uMa%mBp?+W+NOWd1K#Wr9js3rkq%jx z6-B2gYwB82?EXo(h=QuNnBJm#goww5M;`AkesHGss2{DZ-%T*{s8JX5q$w~we6g`C z{l+y>3i{H(qGQvYOs(40EUev2DlTe|d?UEm2}@3dk$aV4AvXH~kIeu*9rZ!zh5TEV zE3FGZM1Fo?t?DL4F7+<7LJM0fqcJ&YL&q(y{Wsi1JE>uvO|9$K&vx{U;#hMxVV`9&(p!HgEqT<*o2m=!f-)CVt zzCJkT;X7jVwd58#G#Elk#;>Y%lhV@sKq+5P%tTyph{!(Up##K}dtV?2JH5}`-H+52kQuOPU9 z4V?6moCC;&mXMJlvb41HA!$rIzCm*>1Ei;4ii@LRH-Oj;MZJGRNlQxx)~ldix)=n;vvlzg2`3IIjv^Kw_q@*}r+I@|SzX_!PYxUiI0=149O$ z*gMf<=;pfJvd6Vmp$6`yuPUZ28JAKSrcv6DMrW`5sWjuxnbS(E@@~w!Z?t#jyT9%2 z!EG|QY9^~jQG_L{Ad2T13r`TBvKlVUeNQ*PaFKKQ{Npgz z@x#b9)9#kcPv7INbd2^Im3lOc2Ij@$4~byO;m$hHa=iD1i4$(M!IHpI^tnT)qa>fj z%Z*J<5KtLDK0e+{{t_Q98wCXgA66$LW8=@*3g<1taDdY~o#vU%Ss7TN?&UYYLZReY#HfoO>u%zlv zm1E-Oj`;HBmSyF!V+FL1vOY22zkmO1HC6$Brnn%#q_dt1;^6>u?Z=Svz>T6r≈h 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 diff --git a/spec/ui/index.rst b/spec/ui/index.rst deleted file mode 100644 index bfbf51df0e..0000000000 --- a/spec/ui/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -UI -### - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - elements.rst - actions.rst diff --git a/spec/usecase/action/index.rst b/spec/usecase/action/index.rst deleted file mode 100644 index 55cff63307..0000000000 --- a/spec/usecase/action/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -Actions -####### - - - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - onhost.rst diff --git a/spec/usecase/action/locks/hostprovider.rst b/spec/usecase/action/locks/hostprovider.rst deleted file mode 100644 index 9a3892e93c..0000000000 --- a/spec/usecase/action/locks/hostprovider.rst +++ /dev/null @@ -1,6 +0,0 @@ -.. _action_lock_hostprovider: - -Provider Lock After Host -################### - -In case of action on Component, Service or Cluster we should lock all Hosts diff --git a/spec/usecase/action/onhost.rst b/spec/usecase/action/onhost.rst deleted file mode 100644 index 79c3c548d0..0000000000 --- a/spec/usecase/action/onhost.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. _action_onhost: - -Actions on Cluster's Host -######################### - -.. toctree:: - :maxdepth: 0 - :caption: Contents: - :hidden: - - onhost/cluster_on_host.rst - onhost/service_on_host.rst - onhost/component_on_host.rst - onhost/target.rst - onhost/on_host_list.rst - -This spec is part of changes introduced in story :issue:`ADCM-1620`. - -Main idea of this case is execution of some actions defined in cluster bundle on one particular host. - - -“Used” Use Cases ----------------- - -List of child cases which is a direct detalisation of this one: - -* :ref:`action_onhost_cluster` -* :ref:`action_onhost_service` -* :ref:`action_onhost_component` - -Additional cases which is explisity define one paticular subfeature: - -* :ref:`action_onhost_api_host_only` -* :ref:`action_onhost_target` - - -Actors ------- - -* :term:`End User` -* :term:`Bundle Developer` - -User Value ----------- - -This functionality allow :term:`End User` to make operation with :term:`Product` on one particular host. For example: - -* Start component -* Stop component -* Check application - -Pre-Conditions --------------- - -* :term:`End User` has ADCM with a :term:`Product` installed on some cluster - -Post-Conditions ---------------- - -* :term:`End User` was able to run some action provided by :term:`Bundle Developer` on one host included in cluster - - -Flow of Events --------------- - -#. :term:`Bundle Developer` adds an action to :term:`Product` with special mark parameter "host_action: true" -#. :term:`End User` goes to installed Cluster "Hosts" page -#. :term:`End User` see actions available for a host -#. :term:`End User` choose action provided by :term:`Bundle Developer` -#. Action executes: - - #. ADCM creates inventory with right context execution context (cluster/service/component) - #. ADCM adds "target" group to inventory with the host choosed by :term:`End User` - -.. note:: Take a note, that ADCM doesn't restrict :term:`Bundle Developer` with operation on one the host chossed by :term:`End User` only. - ADCM just merely pass the ask to playbook over special group in inventory. It is :term:`Bundle Developer` responsibility to care about locality. diff --git a/spec/usecase/action/onhost/cluster_on_host.rst b/spec/usecase/action/onhost/cluster_on_host.rst deleted file mode 100644 index ef44df5bc4..0000000000 --- a/spec/usecase/action/onhost/cluster_on_host.rst +++ /dev/null @@ -1,81 +0,0 @@ -.. _action_onhost_cluster: - -Cluster's Actions on Cluster's Host -################################### - -This spec is part of changes introduced in story :issue:`ADCM-1622`. - -Main idea of this case is execution of component action on one particular host. - -“Used” Use Cases ----------------- - -This case is a detalisation of :ref:`action_onhost`. - -Actors ------- - -* :term:`End User` -* :term:`Bundle Developer` - -User Value ----------- - -This functionality allow :term:`End User` to make operation with cluster on one particular host. For example: - -* Start everything on one host -* Stop everything on one host - -Pre-Conditions --------------- - -* :term:`End User` has ADCM with a :term:`Product` installed on some cluster - -Post-Conditions ---------------- - -* :term:`End User` was able to run some action provided by :term:`Bundle Developer` on one host included in cluster - - -Flow of Events --------------- - -1. :term:`Bundle Developer` adds action to a cluster like follows - -.. code-block:: yaml - - - type: cluster - name: My Supper Cluster - version: "1.0" - actions: - restart: - display_name: "Restart Application" - type: job - script_type: ansible - script: restart.yaml - host_action: true - states: - available: somestate - - type: service - name: My Supper Service - version: "1.0" - components: - mycomponent: - constraint: [0,+] - mycomponent2: - constraint: [0,+] - -2. :term:`End User` installs cluster from this :term:`Bundle` -3. :term:`End User` adds hosts -4. :term:`End User` sees the action "Restart Application" on the host -5. :term:`End User` runs the action - -Exceptions -~~~~~~~~~~ - -4. Cluster "My Supper Cluster" is not in state "somestate" - - a. :term:`End User` sees no action "Restart Application" - b. The End - -.. warning:: We need to be sure, there is no troubles with mixing states. It should react on cluster state only. diff --git a/spec/usecase/action/onhost/component_on_host.rst b/spec/usecase/action/onhost/component_on_host.rst deleted file mode 100644 index c5f525fff4..0000000000 --- a/spec/usecase/action/onhost/component_on_host.rst +++ /dev/null @@ -1,83 +0,0 @@ -.. _action_onhost_component: - -Component's Actions on Cluster's Host -##################################### - -This spec is part of changes introduced in story :issue:`ADCM-1508`. - -Main idea of this case is execution of component action on one particular host. - -“Used” Use Cases ----------------- - -This case is a detalisation of :ref:`action_onhost`. - -Actors ------- - -* :term:`End User` -* :term:`Bundle Developer` - -User Value ----------- - -This functionality allow :term:`End User` to make operation with service on one particular host. For example: - -* Start service on one host -* Stop service on one host - -Pre-Conditions --------------- - -* :term:`End User` has ADCM with a :term:`Product` installed on some cluster - -Post-Conditions ---------------- - -* :term:`End User` was able to run some action provided by :term:`Bundle Developer` on one host which has a component on it - - -Flow of Events --------------- - -1. :term:`Bundle Developer` adds action to a component like follows - -.. code-block:: yaml - - - type: service - name: My Supper Service - version: "1.0" - components: - mycomponent: - constraint: [0,+] - actions: - restart: - display_name: "Restart mycomponent" - type: job - script_type: ansible - script: restart.yaml - host_action: true - states: - available: somestate - -2. :term:`End User` installs cluster from this :term:`Bundle` -3. :term:`End User` adds service -4. :term:`End User` adds hosts -5. :term:`End User` places "mycomponnet" on a host -6. :term:`End User` sees the action "Restart mycomponent" on the host -7. :term:`End User` runs the action - -Exceptions -~~~~~~~~~~ - -5. :term:`End User` chooses a host without mycomponent installed on it - - a. :term:`End User` sees no action "Restart mycomonent" - b. The End - -6. Component "mycomponent" is not in state "somestate" - - a. :term:`End User` sees no action "Restart mycomonent" - b. The End - -.. warning:: We need to be sure, there is no troubles with mixing states. It should react on component state only. diff --git a/spec/usecase/action/onhost/on_host_list.rst b/spec/usecase/action/onhost/on_host_list.rst deleted file mode 100644 index ccb14f6436..0000000000 --- a/spec/usecase/action/onhost/on_host_list.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. _action_onhost_api_host_only: - -API Listing Details -################### - -For any :term:`On Host Action` no matter which of type (cluster/service/component) action is not shown in cluster/service/component's action list but shown host's action list. - -There is no proper way to get information of host from API call if it was done on cluster/service/component endpoint. And there is no story about running :term:`On Host Action` as a regular action. - -“Used” Use Cases ----------------- - -The information provided in this case is in the cases below, but this case detalises this explicity to be sure it will be tested. - -* :ref:`action_onhost_cluster` -* :ref:`action_onhost_service` -* :ref:`action_onhost_component` -* :ref:`action_onhost_target` - -User Value ----------- - -No user value at all. It is a stab use case which prevent us from error. - -Actors ------- - -* :term:`End User` -* :term:`Bundle Developer` - -Pre-Condition -------------- - -* :term:`End User` has ADCM with a :term:`Product` installed on some cluster - -Flow of Events --------------- - -#. :term:`Bundle Developer` adds an action to :term:`Product` with special mark parameter "host_action: true" on cluster/service/component -#. :term:`End User` goes to installed Cluster "Hosts" page -#. :term:`End User` see the actions marked by :term:`Bundle Developer` as an :term:`On Host Action` -#. :term:`End User` goes to action list of cluster/service/component -#. :term:`End User` see no actions marked by :term:`Bundle Developer` as an :term:`On Host Action` - diff --git a/spec/usecase/action/onhost/service_on_host.rst b/spec/usecase/action/onhost/service_on_host.rst deleted file mode 100644 index 7fa1873efc..0000000000 --- a/spec/usecase/action/onhost/service_on_host.rst +++ /dev/null @@ -1,87 +0,0 @@ -.. _action_onhost_service: - -Service's Actions on Cluster's Host -################################### - -This spec is part of changes introduced in story :issue:`ADCM-1621`. - -Main idea of this case is execution of service action on one particular host. - -“Used” Use Cases ----------------- - -This case is a detalisation of :ref:`action_onhost`. - - -Actors ------- - -* :term:`End User` -* :term:`Bundle Developer` - -User Value ----------- - -This functionality allow :term:`End User` to make operation with service on one particular host. For example: - -* Start service on one host -* Stop service on one host - -Pre-Conditions --------------- - -* :term:`End User` has ADCM with a :term:`Product` installed on some cluster - -Post-Conditions ---------------- - -* :term:`End User` was able to run some action provided by :term:`Bundle Developer` on one host included in service - - - -Flow of Events --------------- - -1. :term:`Bundle Developer` adds action to a service like follows - -.. code-block:: yaml - - - type: service - name: My Supper Service - version: "1.0" - actions: - restart: - display_name: "Restart service" - type: job - script_type: ansible - script: restart.yaml - host_action: true - states: - available: somestate - components: - mycomponent: - constraint: [0,+] - mycomponent2: - constraint: [0,+] - -2. :term:`End User` installs cluster from this :term:`Bundle` -3. :term:`End User` adds service -4. :term:`End User` adds hosts -5. :term:`End User` places "mycomponnet" or "mycomponent2" or both of them on a host -6. :term:`End User` sees the action "Restart service" on the host -7. :term:`End User` runs the action - -Exceptions -~~~~~~~~~~ - -5. :term:`End User` chooses a host without "mycomponent" or "mycomponent2" installed on it. - - a. :term:`End User` sees no action "Restart service" - b. The End - -6. Service "My Supper Service" is not in state "somestate" - - a. :term:`End User` sees no action "Restart service" - b. The End - -.. warning:: We need to be sure, there is no troubles with mixing states. It should react on service state only. diff --git a/spec/usecase/action/onhost/target.rst b/spec/usecase/action/onhost/target.rst deleted file mode 100644 index de9f7da11b..0000000000 --- a/spec/usecase/action/onhost/target.rst +++ /dev/null @@ -1,49 +0,0 @@ -.. _action_onhost_target: - -Target group in inventory -######################### - -This spec is part of changes introduced in story :issue:`ADCM-1623`. - -We need special group in inventory to provide information for :term:`Bundle Developer` about which of host has been choosed by :term:`End User` - - -“Used” Use Cases ----------------- - -This case is a detalisation of :ref:`action_onhost`. - -Actors ------- - -* :term:`End User` -* :term:`Bundle Developer` - -User Value ----------- - -This functionality allow to be sure information passed by :term:`End User` is available for :term:`Bundle Developer`. - -Pre-Conditions --------------- - -* :term:`End User` has ADCM with a :term:`Product` installed on some cluster. - -Post-Conditions ---------------- - -* there a new group "target" in inventory file with host choosed by :term:`End User` - - -Flow of Events --------------- - -1. :term:`Bundle Developer` adds action to some object in :term:`Product` bundle acording to any of the cases: - * :ref:`action_onhost_cluster` - * :ref:`action_onhost_service` - * :ref:`action_onhost_component` -2. :term:`End User` run "on host" action according to any of the cases - * :ref:`action_onhost_cluster` - * :ref:`action_onhost_service` - * :ref:`action_onhost_component` -3. Action executes with right inventory diff --git a/spec/usecase/glossary.rst b/spec/usecase/glossary.rst deleted file mode 100644 index 8c2e6e92a7..0000000000 --- a/spec/usecase/glossary.rst +++ /dev/null @@ -1,33 +0,0 @@ -Glossary -######## - -Persons -======= - -.. glossary:: - - - End User - A persone who is using a Product and control it over ADCM. Typically it is an system adminstrator or DBA. - - Bundle Developer - A persone who is develops a Product by creating a Bundle. In most cases this persone is on Arenadata side and a part Product Development team. - -Objects -======= - -.. glossary:: - - Product - A bunch of software provided by Arenadata to a customer in form of :term:`Bundle` and inteded to be used as distributed cluster software. - - Bundle - A pack of special format created by :term:`Bundle Developer` and distributed to an :term:`End User` - -Terms -===== - -.. glossary:: - - On Host Action - Is an action provided in :term:`Product` :term:`Bundle`, but show and executed on Host, included to the Cluster. See :ref:`action_onhost` for more information diff --git a/spec/usecase/index.rst b/spec/usecase/index.rst deleted file mode 100644 index 3c8fbe2f5e..0000000000 --- a/spec/usecase/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -Use Cases -######### - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - action/index.rst - glossary.rst diff --git a/web/.browserslistrc b/web/.browserslistrc deleted file mode 100644 index 80848532e4..0000000000 --- a/web/.browserslistrc +++ /dev/null @@ -1,12 +0,0 @@ -# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. -# For additional information regarding the format and rule options, please see: -# https://github.com/browserslist/browserslist#queries - -# You can see what browsers were selected by your queries by running: -# npx browserslist - -> 0.5% -last 2 versions -Firefox ESR -not dead -not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/web/.editorconfig b/web/.editorconfig deleted file mode 100644 index 6e87a003da..0000000000 --- a/web/.editorconfig +++ /dev/null @@ -1,13 +0,0 @@ -# Editor configuration, see http://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/web/.eslintrc.js b/web/.eslintrc.js deleted file mode 100644 index edadc67435..0000000000 --- a/web/.eslintrc.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - "env": { - "browser": true, - "es6": true - }, - "extends": "eslint:recommended", - "globals": { - "Atomics": "readonly", - "SharedArrayBuffer": "readonly" - }, - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "rules": { - } -}; \ No newline at end of file diff --git a/web/.gitignore b/web/.gitignore deleted file mode 100644 index 52cf416285..0000000000 --- a/web/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# compiled output -/dist -/tmp -/out-tsc - -# dependencies -/node_modules -/src/assets/config.json - -# IDEs and editors -/.idea -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# IDE - VSCode -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -# misc -/.sass-cache -/connect.lock -/coverage -/libpeerconnection.log -npm-debug.log -debug.log -testem.log -/typings - -# e2e -/e2e/*.js -/e2e/*.map - -# System files -.DS_Store -Thumbs.db - -# package-lock.json diff --git a/web/.storybook/main.js b/web/.storybook/main.js deleted file mode 100644 index 61ff63914b..0000000000 --- a/web/.storybook/main.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - "stories": [ - "../src/**/*.stories.mdx", - "../src/**/*.stories.@(js|jsx|ts|tsx)" - ], - "addons": [ - "@storybook/addon-links", - "@storybook/addon-essentials" - ] -} diff --git a/web/.storybook/preview.js b/web/.storybook/preview.js deleted file mode 100644 index a20381a89d..0000000000 --- a/web/.storybook/preview.js +++ /dev/null @@ -1,14 +0,0 @@ -import { setCompodocJson } from "@storybook/addon-docs/angular"; -import docJson from "../documentation.json"; -setCompodocJson(docJson); - -export const parameters = { - actions: { argTypesRegex: "^on[A-Z].*" }, - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/, - }, - }, - docs: { inlineStories: true }, -} \ No newline at end of file diff --git a/web/.storybook/tsconfig.json b/web/.storybook/tsconfig.json deleted file mode 100644 index f01af58ecd..0000000000 --- a/web/.storybook/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "../src/tsconfig.app.json", - "compilerOptions": { - "types": [ - "node" - ] - }, - "exclude": [ - "../src/test.ts", - "../src/**/*.spec.ts", - "../projects/**/*.spec.ts" - ], - "include": [ - "../src/**/*", - "../projects/**/*" - ], - "files": [ - "./typings.d.ts" - ] -} diff --git a/web/.storybook/typings.d.ts b/web/.storybook/typings.d.ts deleted file mode 100644 index f73d61b396..0000000000 --- a/web/.storybook/typings.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module '*.md' { - const content: string; - export default content; -} diff --git a/web/README.md b/web/README.md deleted file mode 100644 index 750953a4eb..0000000000 --- a/web/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# ADCM Web Client - -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.5.5. - -## Storybook - -**Before starting:** -To run Storybook, you need to have been installed Docker (https://www.docker.com/). - -1. Make sure that you have been connected to ADCM VPN -2. Move to ADCM web root directory (usually /adcm/web) -3. Run the following command: - -`docker run -it --rm -v $(pwd):/web -p 6006:6006 node:14-alpine ./web/storybook.sh` - -4. Installing dependencies and launching the Storybook will take a couple of minutes -5. Navigate to http://localhost:6006/ - -**Tip:** The first starting may take about 15 minutes. - -**Tip:** To stop container just hit ctrl-c. - -## Storybook (development) - -1. Run `yarn storybook` for start the Storybook. -2. Navigate to http://localhost:6006/. - -## Development server - -1. Run `yarn start` for a dev server. -2. Navigate to http://localhost:4200/. - -**Tip:** The app will automatically reload if you change any of the source files. - -## Code scaffolding - -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. - -## Build - -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Running end-to-end tests - -Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). - -## i18n internationalization -Static translations are located in the folder ```web/src/assets/i18n/static/[lang].json``` -(```[lang]``` is the lang that you're using, for english it could be "en") - -Example: -```json - { - "display_name": "Name", - "version": "Version", - "license_path": "License text", - "license": "License status" - } -``` - -You can either use the TranslateService, the TranslatePipe or the TranslateDirective to get your translation values: -With the service, it looks like this: -####service: - -```typescript - //async - translate.get('display_name').subscribe((res: string) => { - console.log(res); - //=> 'Name' - }); - - //sync - const res = translate.instant('display_name'); - console.log(res); - //=> 'Name' - -``` - -####pipe: - -```angular2html -

    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